Kelly Insure Data
Overview
Kelly Insure Data is a Busabase Cloud App-in-Skill. Its canonical product surface is the AirApp in Busabase, not a separate local-data product. The same Hono source supports an explicitly requested local preview with OAuth connection bootstrap. Use this skill as Kelly's insurance data-entry and data-governance cockpit: it reads one Busabase Drive node for the file drive, one Base for insurance QA pairs, two Bases for featured information and insurer notices, and one Base for user feedback — surfacing metadata completeness, missing fields, and review status before data becomes trusted insurance knowledge.
Default behavior is AirApp-first. Unless the user explicitly asks only for explanation, give the user the clickable AirApp URL. Start localhost only when local preview/debugging is explicitly requested; it uses the same Busabase resources and never offers another data provider. Use chat-only mode only when the user says "纯聊天", "chat only", "不要打开 UI", or similar.
Mandatory Dependencies
- Read and follow
$kelly-app-skill-creator for product behavior, visual
quality, responsive layout, and the complete canonical content/kelly-insure-data-app/ artifact.
- Read and follow
$busabase for connection, target Space, node discovery,
ChangeRequests, review, and merge behavior.
- Read and follow
$busabase-app-creator for resource modeling, AirApp
runtime limits, security, validation, and deployment.
If a dependency is unavailable, preserve this skill's local artifact and
product contracts, stop before the unavailable Busabase operation, and report
the exact missing dependency. Do not invent a second data backend.
Architectural note: an operator-provisioned workspace, not an app-owned one
Every Base and the Drive node here belong to an existing production
insurance dataset — they are not a Folder+Bases tree this AirApp creates or
owns the way most other Kelly App-in-Skills do. There is nothing for a
read-only reader to safely auto-create in someone else's canonical dataset,
so:
content/kelly-insure-data-app/app/js/config.js declares the Drive node and the four Bases (by slug)
for lookup only; page size is the reader's own concern, not a per-Base
declaration, so each Base is read to exhaustion. It does not go through
resource-provisioning.js's create-if-missing/ownership-metadata flow used
by every other converted skill in this batch — that flow is the wrong model
for "connect to an existing external workspace."
content/kelly-insure-data-app/app/js/providers/busabase-provider.js resolves the Drive node and
each Base by slug (via content/kelly-insure-data-app/app/js/insure-client.js, a raw-fetch client —
see below) and degrades a missing resource to a snapshot.warnings entry,
exactly like the retired lib/data-provider/busabase-provider.ts did. It
never shows an "Initialize workspace" setup screen and never creates a
Folder, Drive, Base, or record.
- An operator provisions and repairs the Drive node and Bases out-of-band
with the trusted scripts in the skill-root
scripts/ directory
(export_busabase_snapshot.mjs, restore_busabase_snapshot.mjs,
backfill_pdf_metadata.mjs), documented below.
Architectural note: Drive/Asset reads bypass busabase-sdk
busabase-sdk (the vendored package every other converted skill uses for
Bases/records reads) only wraps /api/v1/nodes, /api/v1/bases, and
/api/v1/records. It has no equivalent for the Drive/Asset REST surface
(/api/v1/drives/*, /api/v1/assets/*) this skill's file drive needs.
content/kelly-insure-data-app/app/js/insure-client.js is therefore a small browser module that talks
straight to the same-origin /api/v1/* proxy in content/kelly-insure-data-app/server.js with plain
fetch — a port of the read paths (resolveDrive, resolveBase,
listDriveFiles, listRecords) from the retired
lib/data-provider/busabase-client.ts, with two endpoint paths corrected
against a live busabase@0.11.0 server during porting: records listing is
GET /records (not /records/paged, verified against busabase-sdk's own
recordContract.list route), and a Drive's file listing/metadata come from
GET /nodes/{nodeId} (not /drives/{nodeId} or /drives/{nodeId}/files,
both 404). See the header comment in insure-client.js for details.
scripts/lib/busabase-client.mjs is the same corrected client ported for
the trusted skill-root scripts, using the operator's own
BUSABASE_BASE_URL / BUSABASE_API_KEY / BUSABASE_SPACE_ID credentials
(never the AirApp's ambient OAuth session), since those scripts also need
the write/upload endpoints (assets/upload-urls, assets/confirmations,
node/drive/record ChangeRequests) that
busabase-sdk does not cover either.
App UI Screenshots
Boundary
- The AirApp reads the Busabase Drive node and the four Bases only; it is
entirely read-only and must NEVER create, update, or delete a Busabase
node, Base, or record (
readOnly: true, no writeProcedures).
- Never expose API keys, tokens, or cookies in UI state, logs, screenshots,
or chat.
- Treat insurance data quality as high-stakes: the trusted scripts preserve
source attribution, dates, jurisdiction, carrier/product names, and
original wording where possible.
- If the user asks for data entry or cleanup, propose it as a reviewable
change (a manifest edit plus
restore_busabase_snapshot.mjs --apply, or a
direct Busabase ChangeRequest the user reviews) — never silently mutate
the canonical workspace.
Busabase Resources
Declared in content/kelly-insure-data-app/app/js/config.js and the generated template sidecars under content/, resolved by
slug (IDs are never required):
drive (kelly-insure-data-files): the file drive — insurance PDFs/docs with
governance metadata (policy_type, carrier, region, effective_date,
status, ...).
featured (kelly-insure-data-featured) and notices (kelly-insure-data-notices,
legacy alias news): combined in the #/news route, each item tagged
featured or notice.
qa (kelly-insure-data-qa): canonical insurance question/answer pairs.
feedback (kelly-insure-data-feedback): user feedback records.
prompts (insurance-prompts, 预置提示词): the preset prompt library read by
the insure miniapp, not by this AirApp. It is not declared in
content/kelly-insure-data-app/app/js/config.js and never appears in the snapshot, but it lives in the
same workspace folder as the four Bases above, so an operator provisioning or
repairing this workspace must keep it — with the field contract in
references/insure-data-schema.md.
See references/insure-data-schema.md for the exact normalized snapshot
shape and references/restore-manifest-schema.md for the backup/restore
manifest shape.
Views
#/overview: counts, data quality score, metadata field coverage, and
records needing governance.
#/files ("文件盘"): Drive-node files with metadata fields and missing-field
badges.
#/qa ("问答"): QA Base records with question/answer, source, and
completeness.
#/news ("资讯精选 / 保司通知"): Featured Information and Insurer Notices
combined, each tagged featured or notice.
#/feedback ("用户反馈"): Feedback Base records with content, source,
rating, and status.
#/settings: sanitized Busabase target slugs and Base field schemas. Never
exposes tokens.
Backup / Restore / PDF Text Backfill
These are trusted skill-root Node scripts (own scripts/lib/busabase-client.mjs,
raw fetch, the operator's own BUSABASE_BASE_URL/BUSABASE_API_KEY/BUSABASE_SPACE_ID).
They read local PDF bytes from disk, which a browser AirApp cannot do.
cd skills/kelly-insure-data
npm run busabase:export -- --output content/kelly-insure-data-app/.data/busabase_restore_manifest.json
npm run busabase:restore -- --manifest content/kelly-insure-data-app/.data/busabase_restore_manifest.json --files-root /path/to/local/pdf-backup --dry-run
npm run busabase:backfill-pdf-text -- --drive-node-id <node-id> --files-root /path/to/local/pdf-backup --limit 5
busabase:export writes a portable restore manifest (folder/Drive/Base
shape, Drive file paths, sanitized asset metadata, Base records). It never
embeds PDF bytes.
busabase:restore previews restoration from that manifest plus a local PDF
backup directory; add --apply only when the user explicitly asks to
recreate a missing folder, Drive files, Bases, or records.
busabase:backfill-pdf-text parses local PDFs and previews the Asset text
slot write and generated governance metadata. Add --apply to write the
text slot (PUT /api/v1/assets/{assetId}/text) and sanitized metadata
(never parsed_text) back to Busabase. The old
busabase:backfill-pdf-metadata command remains available as an alias.
Demo Mode
?demo=1 (or ?demo=overview) opens a deterministic offline dataset: 4
files, 4 QA pairs, 3 news items (2 featured, 1 notice), and 2 feedback
items with varying governance completeness.
?demo=files, ?demo=qa, ?demo=news, ?demo=feedback, ?demo=settings
select named scenes.
lang=en or lang=zh forces UI chrome language for screenshots.
- Demo mode never reads Busabase, tokens, or local production data.
Local App
Default behavior is AirApp-first — give the user the clickable AirApp URL.
Start pnpm --dir content/kelly-insure-data-app dev only when local preview/debugging is explicitly
requested. UI language supports Chinese (primary) and English chrome with an
Auto default.
Deployed AirApp node: hk-insurance-workbench
The workspace already contains a deployed AirApp node, hk-insurance-workbench
(港险资料库工作台), sitting at the space root beside the 港险公司资料库 folder. It
is not a deployment of this skill's content/kelly-insure-data-app/ artifact — it is an older
hand-written five-file viewer (package.json, server.js, index.html,
app.js, styles.css) that predates the AirApp migration. Treat it as a second,
much smaller surface on the same dataset: a read-only tile row of record counts
per Base plus the five most recently updated records.
Runtime contract, and the reason this node was broken for months:
- Busabase starts an AirApp with
npm install then literally npm run dev.
A package.json with only a start script never boots — the runtime reports
Missing script: "dev". Busabase now rejects such a write
(AIRAPP_NOT_RUNNABLE), but nodes created before that check can still be in
this state.
- A bundler dev server (
vite, next, webpack, …) cannot boot in this
runtime at all, so renaming a Vite scaffold's script to dev is not a fix.
Serve from a plain Node server.
- A running AirApp is proxied same-origin under
/api/airapp-preview/{nodeId}/, so browser code reaches Busabase with an
absolute /api/v1/... path, using the session of the user who clicked Run.
There is no API-key handling and no bridge prefix in front of /api/v1.
- Reads use
GET /api/v1/records?baseId=…&limit=… (cursor paging via
nextCursor) or GET /api/v1/records/page (numbered pages). Record values
live under headCommit.payload, keyed by field slug.
- The cloud engine is Nodepod, an in-browser Node runtime, and two habits that
are fine under real Node kill the dev server there. This node hit both:
fileURLToPath(new URL(".", import.meta.url)) throws, because
import.meta.url is not guaranteed to be a file: URL — read static files
relative to cwd (./index.html) instead; and
listen(port, function () { this.address().port }) throws
this.address is not a function, because the listen callback's this is not
bound to the server — log a captured port variable instead. Both throw
after npm run dev starts, so the symptom is [dev server exited with code 1]
and a run stuck before "ready". Busabase's own PURE_HTML_SERVER_JS demo
still uses the second shape, so it is not a safe template to copy verbatim.
Fixed in this node (version 0.3.2): the missing dev script; a request to a
non-existent /__busabase_api__/api/v1/records/paged prefix and route; reading
headCommit.fields instead of headCommit.payload; the two Nodepod crashes
above; and a hardcoded three-Base id list that had gone stale. Bases are now resolved by slug from
GET /api/v1/bases, and a slug that no longer resolves degrades to a — tile
plus a warning instead of failing the page.
Open question for the operator, deliberately left open: whether to keep this
node as a thin viewer or replace its contents with this skill's content/kelly-insure-data-app/ artifact.
Keeping both means two divergent readers of one dataset; replacing means
uploading the full content/kelly-insure-data-app/ tree, including the vendored SDK, into the node.
File Contract
Read references/insure-data-schema.md before editing the app or
content/kelly-insure-data-app/app/js/config.js, and references/restore-manifest-schema.md before
changing the trusted export/restore scripts.
Safety Defaults
- Never create, update, or delete a Busabase node, Base, or record from the
AirApp. Only the trusted skill-root scripts write, and only with the
operator's own credentials and an explicit
--apply.
- Keep real tokens in environment variables only; never commit
config.local.json-style files, local PDF backups, or anything under
content/kelly-insure-data-app/.data/.
- A missing Drive node or Base degrades to a visible warning, never a
blocked or broken view.
1---2name: kelly-insure-data3description: Insurance-industry App-in-Skill for read-only data governance, backed by an operator-provisioned Busabase workspace (one Drive node for the file drive plus four Bases for QA pairs, featured information, insurer notices, and user feedback) and trusted export/restore/PDF-text-backfill scripts. Use when the user invokes $kelly-insure-data or /kelly-insure-data, wants an insurance data workspace with UI, needs to review insurance files, metadata completeness, QA pairs, featured information, insurer notices, or user feedback, wants to back up or restore a Kelly Insure Data Busabase workspace from local PDFs, or wants Busabase Drive/Base data surfaced for data quality review and ongoing data governance.4---56# Kelly Insure Data78## Overview910Kelly Insure Data is a Busabase Cloud App-in-Skill. Its canonical product surface is the AirApp in Busabase, not a separate local-data product. The same Hono source supports an explicitly requested local preview with OAuth connection bootstrap. Use this skill as Kelly's insurance data-entry and data-governance cockpit: it reads one Busabase Drive node for the file drive, one Base for insurance QA pairs, two Bases for featured information and insurer notices, and one Base for user feedback — surfacing metadata completeness, missing fields, and review status before data becomes trusted insurance knowledge.1112Default behavior is AirApp-first. Unless the user explicitly asks only for explanation, give the user the clickable AirApp URL. Start localhost only when local preview/debugging is explicitly requested; it uses the same Busabase resources and never offers another data provider. Use chat-only mode only when the user says "纯聊天", "chat only", "不要打开 UI", or similar.1314## Mandatory Dependencies15161. Read and follow `$kelly-app-skill-creator` for product behavior, visual17 quality, responsive layout, and the complete canonical `content/kelly-insure-data-app/` artifact.182. Read and follow `$busabase` for connection, target Space, node discovery,19 ChangeRequests, review, and merge behavior.203. Read and follow `$busabase-app-creator` for resource modeling, AirApp21 runtime limits, security, validation, and deployment.2223If a dependency is unavailable, preserve this skill's local artifact and24product contracts, stop before the unavailable Busabase operation, and report25the exact missing dependency. Do not invent a second data backend.2627## Architectural note: an operator-provisioned workspace, not an app-owned one2829Every Base and the Drive node here belong to an existing production30insurance dataset — they are not a Folder+Bases tree this AirApp creates or31owns the way most other Kelly App-in-Skills do. There is nothing for a32read-only reader to safely auto-create in someone else's canonical dataset,33so:3435- `content/kelly-insure-data-app/app/js/config.js` declares the Drive node and the four Bases (by slug)36 for lookup only; page size is the reader's own concern, not a per-Base37 declaration, so each Base is read to exhaustion. It does **not** go through38 `resource-provisioning.js`'s create-if-missing/ownership-metadata flow used39 by every other converted skill in this batch — that flow is the wrong model40 for "connect to an existing external workspace."41- `content/kelly-insure-data-app/app/js/providers/busabase-provider.js` resolves the Drive node and42 each Base by slug (via `content/kelly-insure-data-app/app/js/insure-client.js`, a raw-fetch client —43 see below) and degrades a missing resource to a `snapshot.warnings` entry,44 exactly like the retired `lib/data-provider/busabase-provider.ts` did. It45 never shows an "Initialize workspace" setup screen and never creates a46 Folder, Drive, Base, or record.47- An operator provisions and repairs the Drive node and Bases out-of-band48 with the trusted scripts in the skill-root `scripts/` directory49 (`export_busabase_snapshot.mjs`, `restore_busabase_snapshot.mjs`,50 `backfill_pdf_metadata.mjs`), documented below.5152## Architectural note: Drive/Asset reads bypass busabase-sdk5354`busabase-sdk` (the vendored package every other converted skill uses for55Bases/records reads) only wraps `/api/v1/nodes`, `/api/v1/bases`, and56`/api/v1/records`. It has no equivalent for the Drive/Asset REST surface57(`/api/v1/drives/*`, `/api/v1/assets/*`) this skill's file drive needs.58`content/kelly-insure-data-app/app/js/insure-client.js` is therefore a small browser module that talks59straight to the same-origin `/api/v1/*` proxy in `content/kelly-insure-data-app/server.js` with plain60`fetch` — a port of the read paths (`resolveDrive`, `resolveBase`,61`listDriveFiles`, `listRecords`) from the retired62`lib/data-provider/busabase-client.ts`, with two endpoint paths corrected63against a live `busabase@0.11.0` server during porting: records listing is64`GET /records` (not `/records/paged`, verified against busabase-sdk's own65`recordContract.list` route), and a Drive's file listing/metadata come from66`GET /nodes/{nodeId}` (not `/drives/{nodeId}` or `/drives/{nodeId}/files`,67both 404). See the header comment in `insure-client.js` for details.68`scripts/lib/busabase-client.mjs` is the same corrected client ported for69the trusted skill-root scripts, using the operator's own70`BUSABASE_BASE_URL` / `BUSABASE_API_KEY` / `BUSABASE_SPACE_ID` credentials71(never the AirApp's ambient OAuth session), since those scripts also need72the write/upload endpoints (`assets/upload-urls`, `assets/confirmations`,73node/drive/record ChangeRequests) that74`busabase-sdk` does not cover either.7576## App UI Screenshots7778<table>79 <tr>80 <td width="50%"><img src="assets/screenshots/overview.webp" alt="Kelly Insure Data overview"></td>81 <td width="50%"><img src="assets/screenshots/files.webp" alt="Kelly Insure Data file drive"></td>82 </tr>83 <tr>84 <td><strong>Overview</strong><br>Insurance governance cockpit with counts, data quality score, metadata coverage, and records requiring cleanup.</td>85 <td><strong>文件盘</strong><br>Busabase Drive-node file list with metadata completeness and missing-field diagnostics.</td>86 </tr>87 <tr>88 <td width="50%"><img src="assets/screenshots/qa.webp" alt="Kelly Insure Data QA base"></td>89 <td width="50%"><img src="assets/screenshots/news.webp" alt="Kelly Insure Data news base"></td>90 </tr>91 <tr>92 <td><strong>问答</strong><br>Canonical insurance QA records with source, review status, and answer-quality warnings.</td>93 <td><strong>资讯精选 / 保司通知</strong><br>Featured information and insurer notices combined, with carrier, dates, and source URLs.</td>94 </tr>95</table>9697## Boundary9899- The AirApp reads the Busabase Drive node and the four Bases only; it is100 entirely read-only and must NEVER create, update, or delete a Busabase101 node, Base, or record (`readOnly: true`, no `writeProcedures`).102- Never expose API keys, tokens, or cookies in UI state, logs, screenshots,103 or chat.104- Treat insurance data quality as high-stakes: the trusted scripts preserve105 source attribution, dates, jurisdiction, carrier/product names, and106 original wording where possible.107- If the user asks for data entry or cleanup, propose it as a reviewable108 change (a manifest edit plus `restore_busabase_snapshot.mjs --apply`, or a109 direct Busabase ChangeRequest the user reviews) — never silently mutate110 the canonical workspace.111112## Busabase Resources113114Declared in `content/kelly-insure-data-app/app/js/config.js` and the generated template sidecars under `content/`, resolved by115slug (IDs are never required):116117- `drive` (`kelly-insure-data-files`): the file drive — insurance PDFs/docs with118 governance metadata (`policy_type`, `carrier`, `region`, `effective_date`,119 `status`, ...).120- `featured` (`kelly-insure-data-featured`) and `notices` (`kelly-insure-data-notices`,121 legacy alias `news`): combined in the `#/news` route, each item tagged122 `featured` or `notice`.123- `qa` (`kelly-insure-data-qa`): canonical insurance question/answer pairs.124- `feedback` (`kelly-insure-data-feedback`): user feedback records.125- `prompts` (`insurance-prompts`, 预置提示词): the preset prompt library read by126 the insure miniapp, **not** by this AirApp. It is not declared in127 `content/kelly-insure-data-app/app/js/config.js` and never appears in the snapshot, but it lives in the128 same workspace folder as the four Bases above, so an operator provisioning or129 repairing this workspace must keep it — with the field contract in130 `references/insure-data-schema.md`.131132See `references/insure-data-schema.md` for the exact normalized snapshot133shape and `references/restore-manifest-schema.md` for the backup/restore134manifest shape.135136## Views137138- `#/overview`: counts, data quality score, metadata field coverage, and139 records needing governance.140- `#/files` ("文件盘"): Drive-node files with metadata fields and missing-field141 badges.142- `#/qa` ("问答"): QA Base records with question/answer, source, and143 completeness.144- `#/news` ("资讯精选 / 保司通知"): Featured Information and Insurer Notices145 combined, each tagged `featured` or `notice`.146- `#/feedback` ("用户反馈"): Feedback Base records with content, source,147 rating, and status.148- `#/settings`: sanitized Busabase target slugs and Base field schemas. Never149 exposes tokens.150151## Backup / Restore / PDF Text Backfill152153These are trusted skill-root Node scripts (own `scripts/lib/busabase-client.mjs`,154raw fetch, the operator's own `BUSABASE_BASE_URL`/`BUSABASE_API_KEY`/`BUSABASE_SPACE_ID`).155They read local PDF bytes from disk, which a browser AirApp cannot do.156157```bash158cd skills/kelly-insure-data159npm run busabase:export -- --output content/kelly-insure-data-app/.data/busabase_restore_manifest.json160npm run busabase:restore -- --manifest content/kelly-insure-data-app/.data/busabase_restore_manifest.json --files-root /path/to/local/pdf-backup --dry-run161npm run busabase:backfill-pdf-text -- --drive-node-id <node-id> --files-root /path/to/local/pdf-backup --limit 5162```163164- `busabase:export` writes a portable restore manifest (folder/Drive/Base165 shape, Drive file paths, sanitized asset metadata, Base records). It never166 embeds PDF bytes.167- `busabase:restore` previews restoration from that manifest plus a local PDF168 backup directory; add `--apply` only when the user explicitly asks to169 recreate a missing folder, Drive files, Bases, or records.170- `busabase:backfill-pdf-text` parses local PDFs and previews the Asset text171 slot write and generated governance metadata. Add `--apply` to write the172 text slot (`PUT /api/v1/assets/{assetId}/text`) and sanitized metadata173 (never `parsed_text`) back to Busabase. The old174 `busabase:backfill-pdf-metadata` command remains available as an alias.175176## Demo Mode177178- `?demo=1` (or `?demo=overview`) opens a deterministic offline dataset: 4179 files, 4 QA pairs, 3 news items (2 featured, 1 notice), and 2 feedback180 items with varying governance completeness.181- `?demo=files`, `?demo=qa`, `?demo=news`, `?demo=feedback`, `?demo=settings`182 select named scenes.183- `lang=en` or `lang=zh` forces UI chrome language for screenshots.184- Demo mode never reads Busabase, tokens, or local production data.185186## Local App187188Default behavior is AirApp-first — give the user the clickable AirApp URL.189Start `pnpm --dir content/kelly-insure-data-app dev` only when local preview/debugging is explicitly190requested. UI language supports Chinese (primary) and English chrome with an191`Auto` default.192193## Deployed AirApp node: `hk-insurance-workbench`194195The workspace already contains a deployed AirApp node, `hk-insurance-workbench`196(港险资料库工作台), sitting at the space root beside the 港险公司资料库 folder. It197is **not** a deployment of this skill's `content/kelly-insure-data-app/` artifact — it is an older198hand-written five-file viewer (`package.json`, `server.js`, `index.html`,199`app.js`, `styles.css`) that predates the AirApp migration. Treat it as a second,200much smaller surface on the same dataset: a read-only tile row of record counts201per Base plus the five most recently updated records.202203Runtime contract, and the reason this node was broken for months:204205- Busabase starts an AirApp with `npm install` then literally `npm run dev`.206 A `package.json` with only a `start` script never boots — the runtime reports207 `Missing script: "dev"`. Busabase now rejects such a write208 (`AIRAPP_NOT_RUNNABLE`), but nodes created before that check can still be in209 this state.210- A bundler dev server (`vite`, `next`, `webpack`, …) cannot boot in this211 runtime at all, so renaming a Vite scaffold's script to `dev` is not a fix.212 Serve from a plain Node server.213- A running AirApp is proxied same-origin under214 `/api/airapp-preview/{nodeId}/`, so browser code reaches Busabase with an215 absolute `/api/v1/...` path, using the session of the user who clicked Run.216 There is no API-key handling and no bridge prefix in front of `/api/v1`.217- Reads use `GET /api/v1/records?baseId=…&limit=…` (cursor paging via218 `nextCursor`) or `GET /api/v1/records/page` (numbered pages). Record values219 live under `headCommit.payload`, keyed by field slug.220- The cloud engine is Nodepod, an in-browser Node runtime, and two habits that221 are fine under real Node kill the dev server there. This node hit both:222 `fileURLToPath(new URL(".", import.meta.url))` throws, because223 `import.meta.url` is not guaranteed to be a `file:` URL — read static files224 relative to cwd (`./index.html`) instead; and225 `listen(port, function () { this.address().port })` throws226 `this.address is not a function`, because the listen callback's `this` is not227 bound to the server — log a captured `port` variable instead. Both throw228 after `npm run dev` starts, so the symptom is `[dev server exited with code 1]`229 and a run stuck before "ready". Busabase's own `PURE_HTML_SERVER_JS` demo230 still uses the second shape, so it is not a safe template to copy verbatim.231232Fixed in this node (version 0.3.2): the missing `dev` script; a request to a233non-existent `/__busabase_api__/api/v1/records/paged` prefix and route; reading234`headCommit.fields` instead of `headCommit.payload`; the two Nodepod crashes235above; and a hardcoded three-Base id list that had gone stale. Bases are now resolved by slug from236`GET /api/v1/bases`, and a slug that no longer resolves degrades to a `—` tile237plus a warning instead of failing the page.238239Open question for the operator, deliberately left open: whether to keep this240node as a thin viewer or replace its contents with this skill's `content/kelly-insure-data-app/` artifact.241Keeping both means two divergent readers of one dataset; replacing means242uploading the full `content/kelly-insure-data-app/` tree, including the vendored SDK, into the node.243244## File Contract245246Read `references/insure-data-schema.md` before editing the app or247`content/kelly-insure-data-app/app/js/config.js`, and `references/restore-manifest-schema.md` before248changing the trusted export/restore scripts.249250## Safety Defaults251252- Never create, update, or delete a Busabase node, Base, or record from the253 AirApp. Only the trusted skill-root scripts write, and only with the254 operator's own credentials and an explicit `--apply`.255- Keep real tokens in environment variables only; never commit256 `config.local.json`-style files, local PDF backups, or anything under257 `content/kelly-insure-data-app/.data/`.258- A missing Drive node or Base degrades to a visible warning, never a259 blocked or broken view.