# M10-05 Status status: done task: Simulation cache graph/source/revision identity binding updated: 2026-08-16 America/New_York ## Scope Simulation cache manifest schema 2 binds every cache to the Geometry Nodes graph ID/hash, the committed source `.blend` hash and revision, input hash, Blender 5.2 build, and the declared frame range. A deterministic `revisionHash` is calculated from those fields and the storage key is `sim2-` plus the complete 64-character digest. The payload hash and per-frame hashes remain separate integrity checks. This task closes identity and stale-source safety. It does not implement Simulation Zone evaluation, browser bake, cancel, LRU, corruption quarantine, or playback capability. ## Protocol - Schema 1 manifests and undeclared manifest/frame fields are rejected. - `sourceRevision` is a bounded committed revision; frame values are bounded to +/-1,000,000. - `revisionHash` uses a JSON-array canonical encoding with an explicit v2 domain marker, avoiding ambiguous delimiter collisions. - Graph/source/input/revision/frame-range drift returns `SIMULATION_CACHE_REVISION_MISMATCH`; payload or source bytes still use their dedicated hash mismatch codes. ## Storage Contract `putSimulationCache`, full read, frame read, and list run through the per-project transaction lock. Put checks revision and source hash before hashing/storing the payload. Full/frame reads re-verify the manifest identity and current project; listing validates all manifests and filters valid but stale revisions out of the current project view. Old rows are not silently reused. ## Evidence - `WEB_TEST_PORT=5455 npm --prefix web run test:simulation-cache-identity`: unit 3/3 and Chromium 1/1 passed. Revision 7 cache recovered after Worker restart; after save to revision 8, the old key was rejected and omitted from the list, while a new key was accepted. - Negative checks covered forged graph hash, forged source hash, stale read/put, changed input, changed source revision, changed frame range, legacy schema, undeclared fields, and frame payload drift. - `WEB_TEST_PORT=5456 npm --prefix web run test:simulation-cache`: identity and existing Worker-restart smoke 2/2 passed. - `WEB_TEST_PORT=5457 npm --prefix web run test:simulation-cache-performance`: 600/600 frames, OPFS backend, playback completed, 600 published frames, 0 pending requests after terminate, 5,072 ms total, below the 30,000 ms gate. - Full unit suite 136/136; typecheck, lint, production build (73 modules), local dependency check, and `git diff --check` passed. The first full static pass had one unused import lint failure after the read-path refactor; removing it and rerunning produced the results above. ## Implementation Hashes - Simulation protocol: `974b006f1ad4cd1d3d294122fc777c89c3a7da04fdaa7aebedea12b545bc65e5`. - Storage Worker: `a7b31eeb601e9e71c74eaceda95704f1d120653e9ade6bfbee6d262a42edaa74`. - Unit test: `591582a4ce77b699a4462e30d587eb89034f29ec0a22a94c81f8ab7306f2524f`. - Identity Chromium spec: `2446060a9c3955ef466adb479966bf424fd9e9c351b65cd8525e90a1a1032e4d`. - Existing smoke: `0c8c001290c8c6b3482eeebc105b2f217c55b2eded0c62b4fee4595ec277a11d`. - Performance spec: `f6c465b7afa012030dd8516d676e2663f4dd8298aa156defb905b3fa0229a84b`. - Package: `f9e28fb23af28720f56f97b249cb636599ebd92955ab2ff6d234b821e6d5ea44`. - Error registry: `4c6045b1cab8348f0acf180a1e618a0d691ddc5092822ca288f974904e5e13a5`. ## Rollback Remove schema 2 identity fields and hash helper, restore the prefix-truncated key, revert Storage Worker project-lock checks and stale filtering, remove the identity unit/E2E/package entries and this status file, then restore the M10 count to 4/15. Do not retain schema 2 manifests with schema 1 readers.