# Lab Report — World Builder API (WBAPI) **Filed:** 2026-05-29 · **Ship commit:** `2d42ea2` · **Retrofitted:** `77c517f` (2026-06-05), Appendix A added `8b75986` (2026-06-05) **Verified against HEAD:** 2026-08-13 (§DOC-02aq) **Subject:** the authoring layer over `play.html` — `wbapi-core.js` · `wbapi-server.js` · `edit.html` · the CLI --- ## Abstract The game is one file. That is a promise to the player — no install, no build step, no dead CDN, no version drift; you open an HTML file and you are in Birka — and it is a **tax on the author**, who must edit a 24,138-line JavaScript literal by hand to add one monster. This report records the instrument built to pay that tax: a text-level read/write layer that parses the game's data sections without executing the game, exposes them as CRUD, and refuses edits that would break referential integrity. **The report is a ship-note, not a survey** — it was committed *in the same commit as the code it describes*, and it shows: every count, every worked example, every line number in it is byte-exact at its own tree. Verification 76 days later finds the architecture intact and the inventory superseded, plus **four defects, two of them still live**: a quest-dependency graph that answers `{}` for 98.2 % of quests while reporting success, a node-index duplicate that has inflated the delete-cascade guard since the day the system shipped, a save contract that has since inverted, and a prompt-cache promise that cannot fire at the model it targets. --- ## I. Intention and inspiration — what this buys the player Nothing in WBAPI ships to the player. That is the point of it. The single-file constraint is the game's most player-facing decision and its most author-hostile one. Every alternative — a bundler, a database, a CMS — would move the cost off the author and onto the person trying to play. WBAPI moves it back, by making the file editable **as data** rather than as text: | The author's tax before | What WBAPI made it | |---|---| | Find `MONSTER_POOL` in 24k lines, count braces by eye | `./api.sh post monster key=dock_rat …` | | Rename a monster in 20 terrain rosters by hand | `monsters.rename('commoner', 'Rabid Monkey')` — one call, all 20 | | Delete a node and discover the orphaned quests at runtime | `nodes.delete('CY')` → `{ok:false, blockedBy:{…}}` | | "Which quests are at this node?" — grep and hope | `location.get(code)` — node + terrain + monsters + quests + NPCs | The measurable result is the only argument that matters. Between filing and verification: | | At filing (2026-05-29) | At HEAD (2026-08-13) | | |---|---:|---:|---| | Quests | 210 | **2,853** | 13.6× | | Nodes | 144 | **416** | 2.9× | | Terrains | 69 | **111** | 1.6× | | Named NPCs | 6 | **204** | 34× | | File size | 1.77 MB | 5.51 MB | 3.1× | Thirteen times the content, and the shipped artifact never stopped being one openable file. The tax did not go away; the threshold at which it stops content being written moved, and everything above is what fit through the gap. --- ## II. Method Verification re-measured every claim at **two** trees: the report's own (`2d42ea2`, the commit that introduced it) and HEAD. Numbers were produced by loading each tree's HTML through the current `src/js/wbapi-core.js` parser and counting keys — the same parser the `:1367` server uses — never by reading a figure off a document. **Dating (instruments 18 / 34).** The header says 2026-05-29 and the git author date agrees (09:50:57 −0700). Two independent artifacts confirm it and sharpen it. The commit's own tree contains `play-20260529-162839.html` — the exact filename this report quotes as `save()` output — and 16:28:39 **UTC** is 09:28:39 −0700, twenty-two minutes before the commit. The report pasted a real file from a real session and then committed it. *But the header is now true only of the prose.* `77c517f` (2026-06-05 13:21) rewrote **47 lines and deleted 16**, substituting `./api.sh` for every CLI example, and `8b75986` (14:36 the same day) added all 109 lines of Appendix A. A third of this document is a week younger than its own date, and §V records what that retrofit walked past. --- ## III. As-built inventory ### III-A. The artifacts | File | Role | At HEAD | |---|---|---| | `wbapi-core.js` | parse + CRUD + save/export/sync | ✅ `src/js/wbapi-core.js` | | `wbapi-server.js` | HTTP layer, port 1367 | ✅ `src/js/wbapi-server.js` | | `edit.html` | browser UI — Map, Bestiary, NPCs, Quests, Dice Lab, ⚙ API tab | ✅ | | `api.sh` / `src/api/wb.js` | primary CLI — queued HTTP, auto-nonce, retry, `--ai` | ✅ *(retrofit — see §II)* | | `wbapi-cli.js` | low-level CLI — direct in-process | ❌ **retired** (`5e48dd7`) | | `wbapi-help.md` | field reference + cheatsheet | ✅ `docs/api/wbapi-help.md` | > *The original opened "Three artifacts that form a complete read/write data layer" above a table of > four, and `wbapi-server.js` — shipped in the same commit — was not in it. The prose was counting > the pieces the author had in mind; the table was counting the files.* ### III-B. The anchor scheme All game data lives inside `