Context
Fourth leaf of Epic #12986 (the vdom delta-stream contract) — the Option-F stateful core the #12942 divergence window converged on. The per-batch guards (#12994, PR #13008 in flight) catch grammatically illegal batches; the defect family that motivated the epic (#12930's two-nodes-one-id, #12939's id-less insert births) is cross-batch incoherence — each batch internally well-formed, the wrongness only visible against the live tree state previous batches left behind. Stateless guards are structurally blind to it; the registry is the state.
Release classification: post-release (contract-layer substrate).
The Problem
Nothing tracks which ids are LIVE across batches at the enforcement boundary. The census (#12942 comment DC_kwDODSospM4BB6bh §F3) proved the check is viable without pool false-positives — the feared collision class doesn't exist:
- Pool recycling is updateNode-shaped with permanent-resident ids (
grid/Row.mjs:628-656, grid/Body.mjs:676-726,1175-1180): reuse never manifests as remove→insert, so it is invisible to an insert-ledger. An insertNode whose payload root id is already live is genuinely illegal under this architecture.
updateNode.attributes.id legitimately RENAMES a live node (DeltaUpdates.mjs:768-769) — the lock-flip identity migration rides exactly this; a ledger that doesn't re-key false-positives on every legitimate migration (verified load-bearing by @neo-fable post-census, DC_kwDODSospM4BB6cG).
- The id space is three-sorted (element / fragment comment-anchor ranges / vtext comment pairs): a DOM-existence probe (
getElement(id) === null) does NOT imply not-live — existence semantics differ per sort.
The Architectural Reality
- Enforcement boundary: Main pre-apply, post the mutable
update event — the same placement the guards wire (#12942 OQ3 [RESOLVED_TO_AC]; capture instruments may exist at both layers, enforcement only at Main).
- The deterministic ledger model is the
#12942 Step-Back carry-through: {windowId, idSort, id} — per-windowId partitioning (multi-window/teleportation isolation), explicit sort, id. DeltaUpdates is per-window (singleton per browser window), which gives the partition for free in the common case; the model keeps it explicit for the registry's own contract.
- Seeding: a ledger born mid-session starts blind. Options the implementer must weigh (with evidence): seed from an initial DOM walk at attach-time vs observe-only until the first full mount vs accept-unknown-ids-as-live-on-first-touch (the conservative default that can never false-positive).
- The kernel (#12987, merged) provides the action vocabulary +
STRUCTURAL_ACTIONS; the registry consumes, never re-implements.
The Fix
A registry module wired into the dev-guard path (#12994's useDeltaGrammarGuards lever or a sibling useDeltaCoherenceRegistry flag — implementer's call with rationale; structural pre-flight applies for the new .mjs placement beside the guards wiring):
- Ledger: per-window
Map keyed by id carrying {idSort, bornAt} (bornAt = batch sequence for diagnostics). Updated as batches APPLY (post-validation, post-apply — the ledger mirrors what reached the DOM).
- Coherence rules (findings-out, never-throw, same
{rule, deltaIndex, detail} shape as U1–U4):
- C-insert:
insertNode whose payload root id (vnode.id / parsed from outerHTML) is already live → finding.
- C-target:
removeNode / moveNode / updateVtext targeting a never-live id → finding (sort-aware: fragment/vtext ids legitimately fail element lookups but ARE ledger-tracked).
- C-rekey:
updateNode.attributes.id re-keys the entry old→new atomically; the old id becomes free, the new id collides only if already live.
- C-remove:
removeNode/removeAll retire entries (removeAll retires the parent's whole subtree — the ledger needs parent→children edges OR accepts removeAll as a subtree wildcard; implementer decides with cost evidence).
- Observe-mode first: like U5, the registry ships logging-only until a falsification run over the unit corpus + an example-app interaction pass shows zero false positives; promotion to throwing-guard is an explicit recorded decision.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
| Registry module (NEW, placement via structural pre-flight) |
Epic #12986 AC-OQ1-d; census §F3 |
Per-window live-id ledger + C-rules, findings-out |
Config off = module never loads |
Module JSDoc = spec |
Census preconditions peer-verified 2× |
| Guard wiring path (EXISTING #12994 — extended) |
PR #13008 shape |
Registry hooks the same pre-apply/post-apply seam |
Guards-only when registry flag off |
Wiring JSDoc |
#13008 in flight; this leaf rebases on its merged shape |
src/vdom/util/DeltaGrammar.mjs (EXISTING — consumed) |
Kernel exports |
Vocabulary + STRUCTURAL_ACTIONS consumed |
n/a |
n/a |
Merged (#12988) |
Decision Record impact: none (epic-graduated shape).
Acceptance Criteria
Out of Scope
- Signature shape-classes (OQ2 leaf), capture API (#12991), replay/NL (OQ5/OQ4 leaves).
- Production-mode enforcement.
- Any change to pool-recycling semantics (the registry encodes reality; it never bends it).
Avoided Traps
- DOM-existence as liveness oracle — wrong for two of three id sorts; the ledger is the oracle.
- Ledger updates at validation time — a rejected batch must not mutate the ledger; only applied deltas do.
- Throwing from day one — observe-first per the U5 precedent; cross-batch rules have a wider false-positive surface than per-batch grammar.
- Global (non-window-partitioned) ledger — teleportation/multi-window legitimately reuses ids across windows (@neo-fable's falsifier (b)).
Related
Epic #12986 (parent). Blocked-by #12994 (rides the guard wiring; PR #13008 in flight). Kernel #12987 (merged). Census: #12942 DC_kwDODSospM4BB6bh §F3 + DC_kwDODSospM4BB6cG. Motivating defects: #12930, #12939.
Live latest-open sweep: checked latest open issues at 2026-06-12T17:13Z; no equivalent found. A2A in-flight sweep: clean (gpt on #12957-intake/#13002/#13004/#12994; disjoint).
Origin Session ID: 3e1566f6-6336-4db4-8726-189004578d8b
Retrieval Hint: "coherence registry live-id ledger windowId idSort cross-batch insert-on-live rekey attributes.id"
Context
Fourth leaf of Epic #12986 (the vdom delta-stream contract) — the Option-F stateful core the
#12942divergence window converged on. The per-batch guards (#12994, PR#13008in flight) catch grammatically illegal batches; the defect family that motivated the epic (#12930's two-nodes-one-id,#12939's id-less insert births) is cross-batch incoherence — each batch internally well-formed, the wrongness only visible against the live tree state previous batches left behind. Stateless guards are structurally blind to it; the registry is the state.Release classification:post-release (contract-layer substrate).The Problem
Nothing tracks which ids are LIVE across batches at the enforcement boundary. The census (
#12942commentDC_kwDODSospM4BB6bh§F3) proved the check is viable without pool false-positives — the feared collision class doesn't exist:grid/Row.mjs:628-656,grid/Body.mjs:676-726,1175-1180): reuse never manifests as remove→insert, so it is invisible to an insert-ledger. AninsertNodewhose payload root id is already live is genuinely illegal under this architecture.updateNode.attributes.idlegitimately RENAMES a live node (DeltaUpdates.mjs:768-769) — the lock-flip identity migration rides exactly this; a ledger that doesn't re-key false-positives on every legitimate migration (verified load-bearing by @neo-fable post-census,DC_kwDODSospM4BB6cG).getElement(id) === null) does NOT imply not-live — existence semantics differ per sort.The Architectural Reality
updateevent — the same placement the guards wire (#12942OQ3[RESOLVED_TO_AC]; capture instruments may exist at both layers, enforcement only at Main).#12942Step-Back carry-through:{windowId, idSort, id}— per-windowIdpartitioning (multi-window/teleportation isolation), explicit sort, id.DeltaUpdatesis per-window (singleton per browser window), which gives the partition for free in the common case; the model keeps it explicit for the registry's own contract.STRUCTURAL_ACTIONS; the registry consumes, never re-implements.The Fix
A registry module wired into the dev-guard path (#12994's
useDeltaGrammarGuardslever or a siblinguseDeltaCoherenceRegistryflag — implementer's call with rationale; structural pre-flight applies for the new.mjsplacement beside the guards wiring):Mapkeyed by id carrying{idSort, bornAt}(bornAt = batch sequence for diagnostics). Updated as batches APPLY (post-validation, post-apply — the ledger mirrors what reached the DOM).{rule, deltaIndex, detail}shape as U1–U4):insertNodewhose payload root id (vnode.id/ parsed fromouterHTML) is already live → finding.removeNode/moveNode/updateVtexttargeting a never-live id → finding (sort-aware: fragment/vtext ids legitimately fail element lookups but ARE ledger-tracked).updateNode.attributes.idre-keys the entry old→new atomically; the old id becomes free, the new id collides only if already live.removeNode/removeAllretire entries (removeAll retires the parent's whole subtree — the ledger needs parent→children edges OR accepts removeAll as a subtree wildcard; implementer decides with cost evidence).Contract Ledger Matrix
#13008shapesrc/vdom/util/DeltaGrammar.mjs(EXISTING — consumed)STRUCTURAL_ACTIONSconsumedDecision Record impact:none (epic-graduated shape).Acceptance Criteria
{windowId, idSort, id}exactly (the Step-Back carry-through), per-window partitioned.#12939-class id-less-insert-with-stale-baseline scenario in a unit fixture (the defect that motivated Option F).attributes.idmigration produces ZERO findings (the legitimate path stays silent).parentIdresolve against the ledger, not DOM existence.Out of Scope
Avoided Traps
Related
Epic #12986 (parent). Blocked-by #12994 (rides the guard wiring; PR
#13008in flight). Kernel #12987 (merged). Census:#12942DC_kwDODSospM4BB6bh§F3 +DC_kwDODSospM4BB6cG. Motivating defects:#12930,#12939.Live latest-open sweep: checked latest open issues at 2026-06-12T17:13Z; no equivalent found. A2A in-flight sweep: clean (gpt on #12957-intake/#13002/#13004/#12994; disjoint).
Origin Session ID: 3e1566f6-6336-4db4-8726-189004578d8b
Retrieval Hint: "coherence registry live-id ledger windowId idSort cross-batch insert-on-live rekey attributes.id"