diff --git a/packages/durable/docs/pico-v5-handoff.md b/packages/durable/docs/pico-v5-handoff.md index 2605c8147..885a4c106 100644 --- a/packages/durable/docs/pico-v5-handoff.md +++ b/packages/durable/docs/pico-v5-handoff.md @@ -107,7 +107,8 @@ never reclaimed and default no-fsync behavior matches the specification. ## 6–7. Tracker transaction core, definitions, and typed access **Prerequisite:** `@earendil-works/chord/delta` exports the canonical -Astra-immutable-optimized `track`, `Tracker`, `Change`, and `Prepared`. +Astra-immutable-optimized `track`, `Tracker`, `Change`, and `Prepared`, and its +draft placements reject values that are not strict JSON. Experimental variants under other Delta directories are not Pico APIs. Implement these packages as one milestone. Keep the implementation layers @@ -138,8 +139,8 @@ unresolved acquisition rejects: seal `Tx`, abort open changes, drain and abort the pending acquisition, and observe its failure. Callback failure aborts every change. Callback success prepares every change before Storage admission. -Validate strict JSON in every prepared operation placement payload and every -complete value selected as a base. Tracker branding and revision checks enforce +Do not walk prepared operation payloads or selected bases for strict JSON; they +are strict JSON by construction. Tracker branding and revision checks enforce ownership and staleness. Evaluate each staged document write exactly once and pass Storage only the selected base value or operation batch. Keep every previous immutable revision unchanged through Storage settlement. On success, adopt every prepared value by pointer swap and enqueue @@ -148,9 +149,11 @@ Storage failure, abort prepared changes, poison the Session, and publish nothing Preparation failures roll back normally; Package 8 adds checkpoint selection and its failure path. -Loaded roots, initializers, migrations, fork copies, and replacement roots enter -exclusive kernel ownership before becoming trusted immutable revisions. Values -assigned through drafts are copied per placement. Astra empty batches suppress +Initializer, migration, and replacement roots are copied into exclusive kernel +ownership with a strict-JSON check before becoming trusted immutable revisions. +Loaded and fork-copy roots come detached from Storage and are tracked without +another copy. Chord copies and strict-JSON-checks every draft placement and +throws at the offending assignment. Astra empty batches suppress ordinary writes, while replayable nonempty structural no-ops remain valid writes and publications. No runtime freezing or second operation-payload copy is required. @@ -172,7 +175,8 @@ snapshots and stable prior revisions; empty-batch suppression and replayable redundant structural no-ops; multi-document preparation failure; uncertain Storage failure poisoning; old-revision stability through Storage settlement; pointer-swap and replacement adoption; operation/revision payload sharing under -the trusted no-mutation contract; assignment copying and repeated-placement +the trusted no-mutation contract; non-JSON initializer and draft-placement +rejection; assignment copying and repeated-placement independence; authority and prepared-draft non-escape; terminal-task rejection; task-derived conversation identity; retirement; reincarnation-bound sources; and unload/reload. Include create-task-then-document, diff --git a/packages/durable/docs/pico-v5.md b/packages/durable/docs/pico-v5.md index 5afe3ecf5..5e213a4d7 100644 --- a/packages/durable/docs/pico-v5.md +++ b/packages/durable/docs/pico-v5.md @@ -57,7 +57,7 @@ Required invariants: 5. Entries and IDs are immutable and never reused after a committed write. 6. Document drafts are fully revoked when their transaction callback settles: the Session synchronously prepares or aborts every open change at that point. - Values assigned into a draft are copied by value. + Values assigned into a draft are copied by value and must be strict JSON. 7. The mutation line remains held through storage settlement and committed-state adoption. Listener callbacks run later, off the line. 8. An uncertain storage failure is fatal to the open Session. It publishes @@ -939,9 +939,7 @@ callback fails with no pending acquisition abort every open change; persist and publish nothing callback succeeds with no pending acquisition prepare every open change -> immutable next revision + self-contained Chord Op[] - validate strict JSON in operation placement payloads Session evaluates each required/ordinary document write exactly once - validate strict JSON in every selected complete base prepare every affected loaded conversation mount revision Storage.commit persists the atomic batch while the Session line remains held storage succeeds @@ -953,15 +951,20 @@ storage fails A pending acquisition that resolves after sealing never exposes a draft; its change is aborted and its promise rejects. The Session observes every such -settlement before releasing the line. Initializer, migration, fork-copy, loaded, -and replacement roots are detached into exclusive kernel ownership before they -become immutable tracker revisions; migration callbacks never receive a live -tracker revision. +settlement before releasing the line. Initializer, migration, and replacement +roots come from caller code: the Session copies each one into exclusive kernel +ownership, rejecting any value that is not strict JSON, before it becomes an +immutable tracker revision. Loaded and fork-copy roots are already detached +strict JSON from Storage and enter the tracker without another copy. Chord's +`track()` and `prepareReplace()` take ownership in O(1) without traversal, so +every root they receive must come from one of these sources. Migration callbacks +never receive a live tracker revision. Preparation, validation, checkpoint, or mounted-view preparation failure occurs -before Storage admission and rolls back normally. Strict-JSON validation walks -every prepared operation placement payload and every complete value selected as -a base. Tracker branding and `baseRevision` enforce ownership and staleness; the +before Storage admission and rolls back normally. The Session performs no +strict-JSON walk of prepared operations or selected bases: roots are checked on +entry and Chord checks every draft placement, so every revision, operation +payload, and base is strict JSON by construction. Tracker branding and `baseRevision` enforce ownership and staleness; the Session never substitutes caller-created prepared values. The prepared immutable candidate itself becomes the adopted and published value. Storage receives that complete value only when the Session selects a base; otherwise it receives only the prepared operation batch. @@ -972,7 +975,12 @@ version transitions still write a base when their prepared batch is empty; an equal-value version base does not emit a watch update. Values assigned into a draft are copied immediately by value. Repeated -placements are independent. Draft reads, draft writes, and all `Tx` operations +placements are independent. Chord checks each placement while copying it and +throws at the offending assignment, before the draft changes, when the value is +not strict JSON: `undefined` array elements or nested object values, non-finite +numbers, functions, symbols, bigints, accessors, symbol keys, sparse arrays, or +objects whose prototype is neither `Object.prototype` nor `null`. Assigning +`undefined` directly to an object property deletes that property. Draft reads, draft writes, and all `Tx` operations reject after the callback settles. The prepared immutable value remains readable by Session-owned checkpoint and Storage preparation.