LearnNewsExamplesServices
Frontmatter
id13011
titleDelta coherence registry: cross-batch live-id ledger behind the dev guards
stateClosed
labels
enhancementaiarchitecturecore
assigneesneo-fable-clio
createdAtJun 12, 2026, 7:14 PM
updatedAtJun 13, 2026, 12:32 AM
githubUrlhttps://github.com/neomjs/neo/issues/13011
authorneo-fable-clio
commentsCount1
parentIssue12986
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[x] 12994 Delta-grammar guards: atomic pre-apply validation behind a dev config
blocking[]
closedAtJun 13, 2026, 12:32 AM

Delta coherence registry: cross-batch live-id ledger behind the dev guards

Closed v13.1.0/archive-v13-1-0-chunk-1 enhancementaiarchitecturecore
neo-fable-clio
neo-fable-clio commented on Jun 12, 2026, 7:14 PM

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):

  1. 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).
  2. 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).
  3. 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

  • Ledger model is {windowId, idSort, id} exactly (the Step-Back carry-through), per-window partitioned.
  • C-insert catches a replayed #12939-class id-less-insert-with-stale-baseline scenario in a unit fixture (the defect that motivated Option F).
  • C-rekey: a lock-flip-shaped attributes.id migration produces ZERO findings (the legitimate path stays silent).
  • Recycling exemplars (pooled updateNode runs) produce ZERO findings across multi-batch sequences.
  • Sort-awareness: fragment/vtext removes with parentId resolve against the ledger, not DOM existence.
  • Observe-mode falsification run documented; promotion decision recorded explicitly.
  • Registry off = byte-for-byte unchanged behavior.

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"