LearnNewsExamplesServices
Frontmatter
id12994
titleDelta-grammar guards: atomic pre-apply validation behind a dev config
stateClosed
labels
enhancementaiarchitecturecore
assigneesneo-gpt
createdAtJun 12, 2026, 2:35 PM
updatedAtJun 12, 2026, 9:37 PM
githubUrlhttps://github.com/neomjs/neo/issues/12994
authorneo-fable-clio
commentsCount0
parentIssue12986
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[x] 12987 Delta-grammar kernel: op vocabulary + universal batch predicates
blocking[x] 13011 Delta coherence registry: cross-batch live-id ledger behind the dev guards
closedAtJun 12, 2026, 9:37 PM

Delta-grammar guards: atomic pre-apply validation behind a dev config

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

Context

Third leaf of Epic #12986 (the vdom delta-stream contract). The kernel (#12987, PR #12988) ships the vocabulary and the U1–U4 universal predicates as pure functions — consumed by nothing at runtime yet. This leaf wires them at the enforcement boundary the #12942 OQ3 resolution fixed: Main-thread pre-apply, where the final batch truth lives (post any listener mutation), validated before the first delta applies.

Release classification: post-release (contract-layer substrate).

The Problem

Today a grammatically illegal batch fails in one of three accidental modes (insertNode console.errors, replaceChild can natively throw, everything else silently no-ops), and the worst mode is structural: an unknown action throws mid-loop, leaving every delta before it applied — the DOM now diverges from the worker's vnode model, which is precisely how stale-baseline defects are born (src/Main.mjs:325-346 contains the throw per-operation but cannot un-apply the prefix). Defects of the #12930/#12939 family rot latent because nothing screams at birth.

The Architectural Reality

  • The enforcement point: src/main/DeltaUpdates.mjs#update() — normalizes the batch, fires the mutable pre-apply update event (:890-895), then loops. Guard placement is AFTER the event (final truth, post-mutation) and BEFORE the loop's first dispatch — converting partial-apply+reject into no-apply+reject. The existing processQueue containment then rejects the operation's promise loudly: the failure surface already exists, the guard just moves the failure earlier and makes it whole-batch-atomic.
  • The kernel consumption: validateBatch(deltas, {useDomApiRenderer}) from src/vdom/util/DeltaGrammar.mjs (cross-realm import precedent: DeltaUpdates.mjs:4 already imports vdom/domConstants.mjs).
  • Config precedent: dev-mode levers live in src/DefaultConfig.mjs (logDeltaUpdates, renderCountDeltas, useDomApiRenderer — the renderer flag the guard must pass through to U2).
  • U5 falsification corpus: checkStructuralUniqueness (kernel, candidate: true) needs a real-world run before any promotion — the unit suite's delta-emitting specs plus example-app interaction flows are the corpus; the #12942 Step-Back binds U5-as-candidate-until-falsified.

The Fix

  1. useDeltaGrammarGuards config (new, src/DefaultConfig.mjs, default false): dev/test-only lever, same family as logDeltaUpdates.
  2. Guard wiring in DeltaUpdates.update(): when enabled, run validateBatch after the pre-apply event, before the dispatch loop. On findings: console.error the structured findings (full batch context) and throw before any delta applies — the existing per-operation containment converts that into a rejected caller promise; no delta of an illegal batch reaches the DOM.
  3. U5 falsification run: with guards enabled in observe-mode for U5 (log-only, never throw), execute the delta-emitting unit-spec corpus + a portal/grid example interaction pass; document every U5 finding (or the absence) in the PR. Promotion decision recorded explicitly (promote into the default rule set / keep candidate with the blocking evidence cited) — the run's outcome, not a default.
  4. Unit spec: guard disabled = zero behavior change (the default path untouched); guard enabled = illegal batch rejects atomically (DOM untouched — assert no partial application), legal batches pass through unchanged; the renderer flag reaches U2.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Neo.config.useDeltaGrammarGuards (NEW) src/DefaultConfig.mjs dev-lever family (logDeltaUpdates: sibling) Boolean, default false; enables atomic pre-apply batch validation in dev/test false = today's behavior byte-for-byte DefaultConfig JSDoc block Sibling levers verified at DefaultConfig.mjs (logDeltaUpdates, renderCountDeltas)
src/main/DeltaUpdates.mjs#update() (EXISTING, modified) Source :879-943 Guarded branch after the pre-apply event, before the dispatch loop; throw-before-first-apply on findings Config off = no new code path executes Method JSDoc Census DC_kwDODSospM4BB6bh §A/§E; containment Main.mjs:325-346
src/vdom/util/DeltaGrammar.mjs (EXISTING #12987 — consumed) Kernel exports validateBatch + (observe-mode) checkStructuralUniqueness; never re-implemented n/a n/a Kernel PR #12988 (this leaf is blocked-by #12987)

Decision Record impact: none (aligned with the #12942-graduated epic shape; no ADR governs the boundary).

Acceptance Criteria

  • useDeltaGrammarGuards: false (default): byte-for-byte unchanged behavior — no validation executes, no perf cost beyond one config read.
  • Enabled: an illegal batch (unknown action / missing required fields / remove-ordering violation / id-less updateNode) rejects atomically — assert the DOM received zero deltas from the rejected batch and the caller promise rejects with the findings.
  • Enabled: the census's legal exemplars (differ-shaped updateNode runs, recycling patterns, fragment/vtext removes, dual-payload insertNode) pass through unchanged.
  • useDomApiRenderer is forwarded to U2 (pinned-renderer payload contract enforced correctly per mode).
  • U5 falsification run executed (unit-spec corpus + one example-app interaction pass) with findings documented in the PR; an explicit promotion decision recorded.
  • Guard failures log structured findings ({rule, deltaIndex, detail} + batch context) — diagnosable without a debugger.

Out of Scope

  • The stateful coherence registry (cross-batch rules — its own leaf; this leaf is per-batch only).
  • Production-mode always-on guards (dev/test lever by design).
  • Capture API (#12991) and signature shape-classes (OQ2 leaf).
  • Any change to the kernel's predicate semantics (drift goes back to #12987's contract, not silently patched here).

Avoided Traps

  • Guarding before the pre-apply event — would validate a batch listeners may still mutate; the OQ3 two-layer resolution places enforcement at final truth.
  • Throwing per-delta inside the loop — recreates partial application; the entire point is whole-batch atomicity.
  • U5 enforce-by-default — the Step-Back carry-through; promotion only on falsification evidence.
  • Swallowing findings into a boolean — the structured findings are the diagnostic product; a bare reject would re-create silent-failure with extra steps.

Related

Epic #12986 (parent). Blocked-by #12987 (consumes the kernel). Census: #12942 comment DC_kwDODSospM4BB6bh (§A atomicity, §E placement). Siblings: #12991 (capture), OQ2/OQ4/OQ5 leaves to come.

Live latest-open sweep: checked latest 12 open issues at 2026-06-12T12:35Z; no equivalent found. A2A in-flight sweep: clean (recent traffic = the #12988/#12989 review cycle + my own epic broadcasts).

Origin Session ID: 3e1566f6-6336-4db4-8726-189004578d8b

Retrieval Hint: "delta grammar guards atomic pre-apply useDeltaGrammarGuards U5 falsification promotion"

tobiu referenced in commit 1d2196c - "feat(vdom): add delta grammar guards (#12994) (#13008)" on Jun 12, 2026, 9:37 PM
tobiu closed this issue on Jun 12, 2026, 9:37 PM