diff --git a/docs/cultcache-migration-cut.md b/docs/cultcache-migration-cut.md index 93bd98ae8..338503a66 100644 --- a/docs/cultcache-migration-cut.md +++ b/docs/cultcache-migration-cut.md @@ -1271,7 +1271,7 @@ the behavior change. become single calls; `_all_specific_stores` (`:304-311`) deleted; `pull_all_backing_stores` (`:111`) iterates the distinct stores. Tests: `test_second_generic_store_rejected`, `test_type_claimed_twice_rejected`, - `test_types_route_to_home_store`. Command: `python -m unittest discover -s tests` in `packages\cultcache-py` with `PYTHONPATH=src` (pytest is not installed; the suite is unittest). Soul, Cut 5: the siblings did not enforce C#'s "a record's home cannot change after admission" or refuse a record loaded from a store that is not its home, and TS and Rust rejected zero-store writes the contract treats as in-memory; all three are brought to the C# reference in a follow-up commit on the same branch, and Python's `add_backing_store(store, [])` becomes a generic store. A later Soul pass over the sibling series found TS and Python write paths touching the store before validation and accessors ran, TS open to async interleaving, Python accepting a global under any key, and Rust `load_soa` non-atomic. Operator decisions (2026-09-14, all option A): a TS cache serializes attach, pull, writes and registrations through one per-cache queue (its own mutations only, not observer delivery); TS and Python store a global only under `__global__`; Rust deletes the uncalled `load_envelope` and makes `load_soa` atomic with the home check; cross-runtime error wording stays as is. Every sibling write validates everything before touching a store, and a refused write changes neither store nor cache. + `test_types_route_to_home_store`. Command: `python -m unittest discover -s tests` in `packages\cultcache-py` with `PYTHONPATH=src` (pytest is not installed; the suite is unittest). Soul, Cut 5: the siblings did not enforce C#'s "a record's home cannot change after admission" or refuse a record loaded from a store that is not its home, and TS and Rust rejected zero-store writes the contract treats as in-memory; all three are brought to the C# reference in a follow-up commit on the same branch, and Python's `add_backing_store(store, [])` becomes a generic store. A later Soul pass over the sibling series found TS and Python write paths touching the store before validation and accessors ran, TS open to async interleaving, Python accepting a global under any key, and Rust `load_soa` non-atomic. Operator decisions (2026-09-14, all option A): a TS cache serializes attach, pull, writes and registrations through one per-cache queue (its own mutations only, not observer delivery); TS and Python store a global only under `__global__`; Rust deletes the uncalled `load_envelope` and makes `load_soa` atomic with the home check; cross-runtime error wording stays as is. Every sibling write validates everything before touching a store, and a refused write changes neither store nor cache. A further Soul pass (after CultLib `15c6a5d`) found the TS queue could deadlock when a store awaited the same cache and swallowed rejections of unawaited calls, Python's reentrant lock let a nested write corrupt a load or registration, a Python global stored under a legacy key made the cache unloadable after one `put_global`, and the Rust batch was all-or-nothing only for stores with an atomic `push_all`. Operator decisions (2026-09-14): (B) a global stored under a key other than `__global__` loads as a compatibility shim that never writes; the first write to that global stores it under `__global__` and deletes the legacy record in the same validated write, and the shim is removed once no store holds a legacy-key global; two globals of one type on disk are still refused. (A) Re-entrant mutation from inside a store, decoder, accessor or updater is forbidden in TS and Python with a clear error. (A) A Rust store keeps receiving its full current view on a batch, and the default `push_all` fails closed instead of wiping rows partway. Version `0.2.0` -> `0.3.0`. - Soul: the nine tests; `rg -n "mirror" packages\cultcache-ts\src packages\cultcache-rs\src packages\cultcache-py\src` empty; `npm test` green including the routed-file reads.