# Local video replacement state fix

Status: DONE

## Result

Updated the initial and daily local-video replacement paths to store each replacement under a new IndexedDB revision key, then commit that key in localStorage before cleaning up the prior blob. Failed IndexedDB writes or metadata saves leave the previous saved metadata and bytes intact; the attempted file remains a playable, clearly labelled in-memory preview that cannot be submitted. Older records without a revision key continue to read from their existing canonical key.

## Deliverables and checks

| Deliverable | Requirement or verification | Result | Evidence |
|---|---|---|---|
| [app.js](/Users/agency/Documents/Agty/KomplexLogopédia/outputs/rita-journey-20261002/site/app/app.js:6) | Daily and initial replacements use revision keys with legacy-key fallback; old blobs are cleaned only after metadata save; fixtures and remove actions resolve the referenced key. | PASS | `node --check` passed. The implementation is covered by the owned headless suite below. |
| [verify-local-replacement.cjs](/Users/agency/Documents/Agty/KomplexLogopédia/outputs/rita-journey-20261002/evidence/luna-local-replacement-fix/verify-local-replacement.cjs) and [verification.json](/Users/agency/Documents/Agty/KomplexLogopédia/outputs/rita-journey-20261002/evidence/luna-local-replacement-fix/verification.json) | Failed localStorage writes preserve exact initial and daily legacy metadata and old blob hashes through real reloads; failed IndexedDB puts preserve prior records; failed staged-blob cleanup is disclosed and leaves the old metadata reference intact. | PASS | `20/20` checks passed with no page errors, bad responses, or non-GET requests. The receipt records before/failure/reload metadata and SHA-256 values for prior and selected MP4 blobs. Failed previews played in-page and remained explicitly marked unsaved. |
| Successful daily and initial replacement | Saved metadata points to the new revision blob, bytes match the selected real MP4, old legacy keys are removed after commit, and video plays after reload. | PASS | In both cases the saved/reloaded MP4 hash was `2ee832cc3f2440fa485aa28efbb18bbbb8a6ed8f2c9cb9083d1d9f71146c8673`, with post-reload video ready state `4` and duration `8` seconds. Detailed metadata and old/new hashes are in `verification.json`. |
| [14-day app-loop receipt](/Users/agency/Documents/Agty/KomplexLogopédia/outputs/rita-journey-20261002/evidence/luna-local-replacement-fix/verify-app-output/verification.json) | Existing course loops continue to work, including all 14 daily pages; the focused suite also repeats the prior state-truthfulness checks and responsive coverage at 360, 390, and 430 pixels. | PASS | Existing app loop: `114/114`. Focused suite includes all prior 13 checks and passes at all requested widths. |

## Limits or consequential decisions

Executor: Luna / max. If localStorage rejects a replacement and IndexedDB also rejects cleanup of the staged revision, an unreferenced blob can remain in IndexedDB. The UI now states this explicitly; the saved metadata continues to reference the unchanged prior blob, and the failure simulation verified that relation after reload. No backend, authentication, external writes, deployment, or live host was used. The parent-owned server on port 8764 was left running.
