GENERATED VIEW · PRIVATE ARCHIVE · DO NOT SERVE
RobCo Industries · Archive Museum

record.md



BUGS

bugs/cross-game-registry-leak/record.md

sha256 f5fd27daeae6ffe7 · 4830 bytes · original held in the private archive

--- title: The Cross-Game Registry Leak status: IN-FLIGHT repo: app observed: 2026-07-14 caught_by: owner report, then independent audit that reproduced real data loss one_line: Loading a cross-game save switched the state in place but left the boot-time registry stuck on the old game — corrupting every registry-backed surface, and silently deleting real campaign data. guard_location: js/ui/ui-saves.js · _applySlotEnvelope() cross-game branch (persist robco_v8 + reload, Protocol 22) verified: red→green in a real Playwright browser both directions; regression Suite 228 + render-check.mjs end-to-end exhibited: true lesson: Boot-time-only globals cannot be switched in place; an in-place cross-game apply is a data-integrity bug, not a cosmetic one. (Protocol 22 — no parallel apply path.) awaiting_tag: v2.8.5 provenance: - commit 2210b57 (app repo) — "fix(saves): cross-game local-slot load left the registry stuck on the old game" - planning/2.8.5/audits/AUDIT_registry_leak.md (Stage 3 independent audit) - planning/2.8.5/mockups/FO3/audit-crossgame-BUGGY.png and audit-crossgame-FIXED.png --- ## What happened `_applySlotEnvelope()` (the shared core behind LOAD SLOT and VERSION RESTORE) detected a cross-game context mismatch, confirmed it, and then applied the switch **in place** (`loadUI()` only, no reload). But `FALLOUT_REGISTRY` and `databaseCSVs` are **boot-time globals**, selected exactly once at boot by `index.html`'s `GAME_FILES` manifest (one of `reg_nv.js`/`reg_fo3.js` + one of `db_nv.js`/`db_fo3.js` per boot). An in-place apply left those globals **stuck on the old game's data** while `state.gameContext` silently flipped to the new one. Every registry-backed surface was then serving the wrong game: location/item/quest/perk autocomplete, the native LOOT/THREAT/CONSULT lookups, and the AI's own `databaseCSVs` system context — not just the location box the owner first noticed. **Correction to the record this specimen was drawn from.** The museum mockup (specimen 08) framed this as a *cosmetic* defect — "a New Vegas-skinned terminal showing a Fallout 3 save, the wrong wasteland's chrome around the right save." That is wrong. This is a **data-integrity** defect. The independent audit reproduced **real campaign-data loss** on the pre-fix code: the AI-import path (`autoImportState`) validates state arrays against `FALLOUT_REGISTRY` and **drops every entry the registry doesn't recognise**, on a write — so with a stale registry the campaign's own FO3 collectibles (`Strength`, `Perception`) matched nothing in the loaded NV registry and were silently emptied and persisted. The implementer's "only lookups and suggestions, never what got written" claim was overturned by the audit. ## How it was caught Owner report of wrong-game autocomplete, then a Stage-3 independent audit (Protocol 8) that reproduced the bug red→green in a real browser **and** independently found the data-loss the implementer had ruled out. ## The guard The cross-game branch now persists `robco_v8` synchronously and **reloads**, exactly like every other cross-game apply path (`onGameContextChange`, `loadCloudSave`, `restoreCloudSaveVersion`) already did — Protocol 22, no parallel apply path. Boot then re-selects the correct `reg_*.js`/`db_*.js` via the manifest. The same-game (common) path is unchanged: still an in-place `loadUI()`, no reload. Unsaved state survives the reboot because the fix sets `window._loadingSave = true` and persists before the reload, and the `beforeunload` flush honours that flag. ## What the guard costs A full page reload on every cross-game load/restore — the heavier apply path — accepted because it is the only way to reselect boot-time globals honestly. The same-game path keeps the fast in-place apply, so the cost is paid only when the game actually changes. ## Containment Reproduced then resolved in a real Playwright browser, both directions, plus fresh-boot baselines and the unregressed same-game fast path. Regression coverage landed in the same commit (Protocol 13): `tests/robco-diagnostics.js` Suite 228 (6 tests, including a vm-sandbox proof of the real extracted `_applySlotEnvelope()`) and `tests/render-check.mjs` (end-to-end). **Not yet SEALED:** this is 2.8.5-era work; the app is pinned to `v2.8.0` and `v2.8.5` is not tagged. Promote to SEALED when `awaiting_tag` exists (`git tag --contains 2210b57`). ## Provenance Commit `2210b57` (app repo) and its full message; `planning/2.8.5/audits/AUDIT_registry_leak.md` (the audit whose PASS carried "one mandatory record correction" — the data-loss finding quoted above). The two capture PNGs referenced by the mockup exist under `planning/2.8.5/mockups/FO3/`. This record deliberately **replaces the mockup's cosmetic framing** with the audited data-integrity account.
STAMP · generated for RELEASE v2.8.5 commit 06e5180 (06e51801b38a) · archive input-tree hash c07fbfbdd2e1ddeb · 754 files · no wall-clock timestamp (regenerates identically when nothing changed).