v0.119.1 — AI Policy 1.2: say what the code does
Merged 2026-10-08 (7531d017, tagged v0.119.1) — built on version/0.119.1.
A fix on version/0.119.1. It also carries work done on the version/0.119.0 checkout after v0.119.0 merged: a dev-server fix and two roadmap documents. The AI Policy (1.1, 10 September 2026) made claims the code contradicted. Its fix is small on purpose: Removing generative AI may replace the policy later, so this one corrects it rather than changing what the product does, except for two fixes that make existing claims true.
- [x] Release bookkeeping: v0.119.0's notes move to docs/help/changelog/v0.119.0.md, with a line under Released.
- [x] The face detector's weights are served by us, not fetched from tfhub.dev.
tokenizer.tscalled BlazeFace'sload()with nomodelUrl, so the first tokenize fetched the graph from tfhub.dev (now redirected to Kaggle). The policy says in-browser models share nothing with a third party.- Done:
apps/web/public/models/blazeface/holdsmodel.jsonand its one shard, from the same pinnedblazeface/1/default/1URL the library used, with sizes, SHA-256s and the Apache-2.0 attribution in its README.BLAZEFACE_MODEL_PATHis whatloadgets. This is roadmap task GA.20, which both of its plans need.vendoredModels.test.tschecks both files' sizes and hashes offline, that the manifest names exactly the committed shard, that the tokenizer loads that path, and that the README records the pinned source.
- [x] The sheet importer sends the user's own AI key.
CharacterImportFromSheetModalposted to/api/ai/parse-characterwith nox-ai-*headers, so every import through it ran on the operator's OpenAI key, whatever the user had entered in Settings → AI. The token modal's sheet import always sent them.- Done: the modal takes a
getAIHeadersprop (it lives inui-components, which can't read the web app's store), spread into the request under the auth header. All four call sites passgetSheetParsingAIHeaders, a stablegetAIHeaders('character-sheet-parsing')inutils/aiHeaders.ts.aiHeaders.sheetParsing.test.ts(what the helper returns, every call site passes it, and the list is every call site) andCharacterImportFromSheetModal.aiHeaders.test.ts(the prop, and the request spreads it).
- [x] AI Policy 1.2, 8 October 2026.
- 1.1 said "No generative AI ships inside the application". The server's own OpenAI key backs sheet parsing, AI fill, the map generator's descriptions and its gpt-image-1 assets, wall detection, and the OpenAI and Gemini background removers. 1.2 lists the generative features (text and images), says whose account a feature runs on without the user's key, and says 1.1 was wrong.
- 1.1 said the in-browser models "analyse; they do not generate" and "share nothing with any third party". WebLLM's Qwen 2.5 generates monsters and encounters by default, and downloads its weights from huggingface.co and its runtime from GitHub. 1.2 keeps the first claim for the image models and states the language model's generation and downloads.
- 1.1 listed "tracing the walls in a map image" as in-browser. Wall detection runs on the server (SAM 2 and GPT). The one analysis that can leave your browser becomes What leaves your browser, which lists every feature that sends input to a provider: the generators, sheet parsing, wall detection, library tagging and the Replicate sweep.
- Not in the original report: 1.1 said "we do not store your prompts". The map generator keeps the prompt (
map_generations.prompt) and the layout the model returned, and its route logs the prompt and the raw response. 1.2 names it as the one exception. HelpSidebar.contract.test.tspins the new commitments: the generative-AI section, the operator-account fallback, the language model that generates and Hugging Face, no wall detection in the in-browser section, and the map-generator exception. It also forbids 1.1's "We do not bundle generative AI" and allows "no generative AI ships" only in the sentence that corrects it.
- [x] AI Features lists what it left out: the Replicate sweep (Extract Objects), AI fill, the OpenAI and Gemini removers, server-side background removal, library tagging, name suggestion and encounter generation. Each row says whether it generates and where it runs. Character optimisation is gone from the list (it is unmounted).
- [x] AI Architecture's model table said sheet parsing ran on an in-browser Qwen 1.5B. It ran on the server's LLM, never in the browser. The table now lists every task with its model, where it runs, and whose key pays.
- [x] One invalid roadmap page no longer stops
pnpm dev.- The help server's dev script ran the manifest step with
&&, and the rootdevran its three servers without--no-bail, so a half-written roadmap page failed the manifest, stopped the help server, and took the web app and API down with it. - Done: the dev script runs
publishRoadmapManifest --lenient.buildManifestleaves out pages that do not validate and lists the problems inmanifest.problems, which the roadmap dashboard shows as an alert above the table. The rootdevpasses--no-bail. Builds and CI stay strict.- Selftests: lenient mode skips an invalid page and a page with no frontmatter, a valid tree has no
problems, and the dashboard shows the banner only when there are problems.
- Selftests: lenient mode skips an invalid page and a page with no frontmatter, a valid tree has no
- The help server's dev script ran the manifest step with
- [x] Roadmap:
- Chat commands gains parts three and four: playing a character from chat (
/i, attributes in dice, the Action API in a message, @references) and a lasting target (/t, a Target Mini-Me). It's now four releases, about 40 tasks. - Removing generative AI is a new proposal, blocked on an asset licence: Plan A removes generation, Plan B every provider capable of it. Its note on the policy's false claims now records this release's fixes, and GA.20 is marked done.
- Chat commands gains parts three and four: playing a character from chat (