provident-storeroom 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.guide.md CHANGED
@@ -30,7 +30,7 @@ preflight REFUSES when these two lines do not read what it computed** (`scripts/
30
30
  one check, read-only). **THE TWO LINES ARE THIS GUIDE'S OPERATIVE FIGURES; every dated paragraph below is the
31
31
  reading of its own date and is read through them.**
32
32
 
33
- PUBLISH-GUIDE-VERSION-LINE: THE VERSION THIS GUIDE DESCRIBES IS `1.4.0`.
33
+ PUBLISH-GUIDE-VERSION-LINE: THE VERSION THIS GUIDE DESCRIBES IS `1.5.0`.
34
34
  PUBLISH-GUIDE-CUT-STATE: NOT STATED -- this document describes the behaviour at the version line above, and the cut-state is the release's to state, not a shipped document's (`D-57`).
35
35
 
36
36
  **⟶ AND THE CUT-STATE SENTENCE ABOVE IS WITHDRAWN, 2026-10-28 — THE CUT-STATE IS NOT A DOCUMENT'S TO STATE.** `RCA-8(g)` ANNOTATE-BESIDE, and the architect's ruling verbatim (`strata/decisions.md` · `D-57`): *"Drop the cut-state."* **The two marked lines above stand BYTE-FOR-BYTE as the reading of their own date and are read THROUGH this clause — not one byte of either is deleted — and the sentence this clause withdraws is the SECOND of them, the one that claims to say whether the release this guide travels in is cut.** **THE REASON IS MEASURED, THREE TIMES OVER, AND IT IS STRUCTURAL RATHER THAN A MISTAKE: A SHIPPED DOCUMENT IS SEALED BEFORE THE TAG THAT MAKES ITS CUT-STATE TRUE**, so every release packed before its tag ships a document denying itself, and a guard running in that release's own preflight can only ever confirm *"not cut"* — `1.2.0` shipped *"NOT CUT"*, `1.3.0` shipped *"`v1.3.0` DOES NOT EXIST"*, and the change list's head was stale within minutes of the tag that falsified it. **SO THE CUT-STATE SENTENCE IS DROPPED AS A CLAIM AND THE VERSION LINE STAYS**, because the version line is the ONE figure a tarball can be right about: the manifest knows it and travels beside it. **`scripts/publish.sh --figures` GENERATES AND ASSERTS THE VERSION LINE AND NOTHING ELSE** — the cut-state generation and its assertion are removed in the same act, so a tag set that moves can no longer redden this guide — **and the same one line is asserted in THREE shipped documents: this guide, `README.md` beside it, and the change list** (`DEF-AC`'s remaining demand, *"guard the release notes too"* and *"`README.md` still declares no version at all"*). **THE TAG SET IS NOT DELETED AND NOT DENIED: it is a RECORD OF RELEASES held in the change list, PAST TENSE — a list of what has been cut — and never a claim about the current one.** **AND WHAT THIS CLAUSE DOES NOT SAY, SAID PLAINLY BECAUSE A READER WILL LOOK FOR IT: it does not say whether the version this guide prints is cut.** That is not a document's to state; the record of what has been cut is in `RELEASE-NOTES.md`, and the registry is the registry.
@@ -71,6 +71,8 @@ measurements on a locally packed, installed artefact, and is still not witnessed
71
71
 
72
72
  **⟶ AND THE FIGURES MOVE TO THE PREPARED RELEASE, 2026-10-28 — THE ELEVEN SITES READ `1.3.0`, AND `1.3.0` IS PREPARED, NOT CUT.** `RCA-8(g)` ANNOTATE-BESIDE: **the eight dated paragraphs above stand BYTE-FOR-BYTE and are read THROUGH this clause — so do their readings of `0.5.0`, `1.0.0`, `1.0.1`, `1.1.0` and `1.2.0`; each was true of the tree it was read on.** **THE MANIFEST AT ITS OWN BYTES THIS DATE: `bindings/js/package.json`'s `version` is `"1.3.0"` and all five `optionalDependencies` pins are `1.3.0` with it** — the six figures move together and never singly (§0 item 1; `PUB-DD-10`) — **and the five platform manifests' own `version` fields read `1.3.0` with them, which is eleven sites and one rebuild; the rebuilt artefact is stamped from that manifest, so `version()` answers `1.3.0`.** **SO THE SITES ARE RE-READ, NOT RE-SPELLED:** this section's version line, §2.2's five exact pins, §8.1's *"an installed `0.5.0`"* and §11's manifest table all read `1.3.0`; **every `0.5.0`, `1.0.0`, `1.0.1`, `1.1.0` and `1.2.0` this guide prints is the figure of its writing date and reads `1.3.0` from here on.** **AND WHAT THIS CLAUSE DOES NOT CLAIM, SAID FIRST BECAUSE IT IS THE EASIER THING TO GET WRONG: `1.3.0` IS PREPARED AT THOSE ELEVEN FIGURES AND THE TAG IS NOT CUT — `git tag --list` carries `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0` and no `v1.3.0`, and the registry carries no `1.3.0`; so nothing here says the release is cut, and the tag is not cut until the architect cuts it.** **AND THE TREE THIS GUIDE DESCRIBES IS TEN COMMITS PAST `v1.2.0`** — `git describe` reads `v1.2.0-10-g14787b5` and `git rev-list --count v1.2.0..HEAD` reads `10`, one commit past the nine the paragraph above reads — **so the two behaviour changes and the four smaller items `§1.3.0` of the change list declares are the CONTENT of `1.3.0`, and `1.3.0` is the version that carries them once it is cut; the `1.2.0` tarball carries neither, and `1.3.0` is the version this guide describes from here on.** **THE ONE THING THAT IS STILL UNMOVED IS THE ONE THING NO PASS WITNESSED, AND IT IS NOT A FIGURE:** no `npm install` was run against the registry, so a registry-installed `1.3.0` is described here from the manifest and from measurements on a locally packed, installed artefact, and is still not witnessed as a registry download. **NO OTHER CLAIM OF THIS GUIDE MOVES: the `files` allowlist's seven rows (§11's `2026-10-28` clause (i)), the packed set's `20` bare / `21` assembled (§11's clause (ii)), the twenty-status set (§11's clause (iv)), the fourteen own members and every API clause stand exactly as they stood.** (`D-41` item `1`; the change list's `§1.3.0`; `docs/specs/storeroom-publish/contract.md §2.3` item `3` — the byte-for-byte guide stage this correction travels by; `scripts/publish.sh`'s eleven cells and its two generated figures.)
73
73
 
74
+ **⟶ AND THE ELEVEN VERSION SITES READ `1.5.0`, 2026-10-29 — THE PREPARED FIGURE, AND EVERY `1.3.0` THIS GUIDE PRINTS READS `1.5.0` FROM HERE ON.** `RCA-8(g)` ANNOTATE-BESIDE: **the nine dated paragraphs above stand BYTE-FOR-BYTE and are read THROUGH this clause — so do their readings of `0.5.0`, `1.0.0`, `1.0.1`, `1.1.0`, `1.2.0` and `1.3.0`; each was true of the tree it was read on.** **THE MANIFEST AT ITS OWN BYTES THIS DATE: `bindings/js/package.json`'s `version` is `"1.5.0"`, all five `optionalDependencies` pins are `1.5.0` with it, and the five `bindings/js/platforms/*/package.json` `version` fields read `1.5.0` with them — ELEVEN CELLS, ONE VERSION, moved TOGETHER in this act and never singly (§0 item 1; `PUB-DD-10`) — and `npm run build` stamps the artefact from that manifest, so `version()` answers `1.5.0` at the built artefact and at a package installed from it.** **AND THE RELEASE THIS CHAIN SKIPPED IS NAMED RATHER THAN SILENTLY ABSORBED: `1.4.0` read `1.4.0` at those same eleven cells and was cut from them — the tag `v1.4.0` names a tree whose `bindings/js/package.json` reads `"version": "1.4.0"` at its own bytes.** **SO THE SITES ARE RE-READ, NOT RE-SPELLED:** this section's version line, §2.2's five exact pins, §8.1's *"an installed `0.5.0`"* — itself already corrected to `1.0.0`, `1.0.1`, `1.1.0`, `1.2.0` and `1.3.0` — and §11's manifest table all read `1.5.0`. **AND THE TAG SET IS A RECORD OF RELEASES AND NOT A CLAIM ABOUT THIS TREE:** `git tag --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0` · `v1.3.0` · `v1.4.0`, and `git describe` reads `v1.4.0-27-ga3312b7` — **so this clause states the version and NOT whether it is cut, because the cut-state is not a document's to state** (`D-57`; the clause above).
75
+
74
76
  **AND ONE THING A READER OF THE INSTALLED PACKAGE SHOULD KNOW BEFORE THE CITATIONS: WHEN THIS DOCUMENT IS AT
75
77
  `node_modules/provident-storeroom/README.guide.md`, IT IS THIS GUIDE.** **Its ONE authored home is
76
78
  `docs/guides/package-use.md` in the repository, and the release's assembly stages it byte-for-byte at the packaging
@@ -465,6 +467,12 @@ guide's constraint story that is not yet observable.
465
467
 
466
468
  **⟶ AND THE ONE SENTENCE THAT WAS MISSING, DECLARED HERE IN THE TERMS YOUR OWN REVIEW ASKED FOR, 2026-10-28 — `D-55` · `DEF-AN`, THE ARCHITECT, VERBATIM: *"A constraint-refused edit rolls back to the previous safe state, with all edits in the commit undone. Specify this."*** `RCA-8(g)` ANNOTATE-BESIDE: **every clause of §5.4 above and below stands BYTE-FOR-BYTE and is read THROUGH this one; no rank, no status, no member and no promise moves — what this clause adds is the statement of WHAT THE ROLLBACK COVERS.** **THE RULE, IN ONE SENTENCE: a refused edit rolls the commit back to the state it opened at — every edit the commit made is undone, including writes that succeeded before the refusal.** **THE REASON, STATED SO YOU CAN REASON WITH IT: the restore names the mark the commit cached at its OUTERMOST OPENING** (§5.4's closing clause above), **and a commit is one unit of work, so the mark is not the refused op's own — it is where the WHOLE commit began.** **A write, a repair or a delete that landed EARLIER IN THE SAME COMMIT is undone WITH the refusal**, because the commit that carried it is undone; **that is WHY the mark is the outermost opening's and not the nearest one.** **WHAT STILL STANDS: a refused edit moves no state and mints no code beyond the one declared refusal; an edit in a DIFFERENT commit is not touched** — a listener body's own write opens its own commit (`D-53`), so it is a unit of its own and is not undone by yours. **MEASURED ON THIS CHECKOUT, 2026-10-28:** a write that succeeds inside a commit whose listener then reverses and is refused leaves the store at the state the commit opened at — the successful landing gone with the reversal — and the pair is asked at that state (`tests/e2e/discard-witness.mjs`'s `DW-10.5`).
467
469
 
470
+ **⟶ AND THAT ONE SENTENCE IS CORRECTED, 2026-10-28 — `D-63`: A REFUSED EDIT ROLLS BACK TO THE LAST VALIDATED STATE, NOT TO THE STATE THE COMMIT OPENED AT.** `RCA-8(g)` ANNOTATE-BESIDE: **the whole paragraph above stands BYTE-FOR-BYTE and is read THROUGH this clause; no rank, no status, no member and no promise moves — what moves is the STATE a refusal restores, and the sentence that names it.** **THE RULING, THE ARCHITECT, VERBATIM:** *"After the constraint sweep ends in a valid state, bump the restore mark. The passing constraint state marks the new next valid state."*
471
+
472
+ - **OLD → NEW, SO YOU CAN TELL WHICH BEHAVIOUR YOUR VERSION HAS.** **OLD:** *"a refused edit rolls the commit back to the state it opened at — every edit the commit made is undone, including writes that succeeded before the refusal."* **NEW:** *"a refused edit rolls the commit back to THE LAST VALIDATED STATE — every edit the commit made AFTER the last constraint sweep that passed is undone, and every edit that sweep APPROVED stands."* **THE RESTORE IS TOLD A POSITION AND THE POSITION MOVES FORWARD**: it starts where the commit opened and it moves to the store's own journal position at every constraint sweep that ends valid, **before the listeners are delivered.** **So `"the state it opened at"` is now the answer to exactly one case — a commit whose constraint sweep never passed — and it is today's behaviour there and stays.**
473
+ - **WHAT YOU WILL SEE, IN THE THREE SHAPES THAT MATTER TO A CONSUMER.** **(1) An edit that PASSED its checks STANDS even if a later step in the same commit is refused** — you asked for it, the constraints approved it, and the refusal is about what came after. **(2) A REPAIR'S WRITE GOES WITH THE WRITE**: a repair runs *during* the check, so if the check then refuses, the repair's edit is undone with yours. **(3) A LISTENER'S WRITE SURVIVES YOUR REFUSAL**: a listener is delivered *after* every constraint has passed, so its write is a later, discrete act and the restore of yours does not reach it — it is still there afterwards, and you should not treat a refusal as having undone it.
474
+ - **AND THE `DEF-AN` MEASUREMENT ABOVE STILL STANDS, FOR THE REASON IT STANDS.** That drive's pair refuses on the FIRST check, so that commit never reaches a passing sweep, nothing moves the mark, and the store returns to the state the commit opened at — **which is why the reading is unchanged and the rule that produced it is not.** The `D-63` arms are driven beside it in `tests/e2e/discard-witness.mjs` section `W12` (`DW-12.1`–`DW-12.4`), and `tests/e2e/in-commit-restart.test.mjs`, `tests/e2e/direct-pass-restart.test.mjs`, `tests/e2e/downstream-claims.test.mjs` and `tests/e2e/def-ae-restore-mark.test.mjs` carry the re-derived readings.
475
+
468
476
  **⟶ AND WHAT THE STORE HOLDS AFTER A REFUSED REVERSAL, DECLARED HERE BECAUSE `1.2.0`'s ONE BEHAVIOUR CHANGE IS THIS AND NO SHIPPED DOCUMENT SAID IT UNTIL NOW.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause of §5.4 above stands BYTE-FOR-BYTE and is read THROUGH this one; this clause adds the declaration the release owed and moves no promise it prints.**
469
477
 
470
478
  - **THE FACT: WHEN A REVERSAL IS REFUSED, THE COMPENSATING ACT PUTS THE STORE BACK AT THE MARK THE COMMIT CACHED WHEN IT OPENED — the journal's LAST VALID POSITION as it stood when that commit began (an op id, or the FLOOR where the journal held no entry then) — and never at whatever the journal's head happens to be when the refusal is built.** **Every address the reversal MOVED is read again afterwards and counted as restored only where it stands exactly as it stood before the reversal — the same value at the same tier, or absent where it was absent — and the refusal's one log entry says so address by address**, naming each address that could not be put back with what stands there instead and what it was owed (§8.1 row `20`; `js/contract.md §2.6`'s clause of 2026-10-27). **A reversal taken AT REST makes the two marks describe the same state** — it appends no journal entry — **so this is where the store stands either way at the surface.**
@@ -559,6 +567,23 @@ instance and not a function you hand to the store.**
559
567
  2. **`triggered` membership is decided by address and by nothing else:** a handle appears exactly where **its
560
568
  listener's address is a PREFIX of the triggering address** (`surface.md §2.3` item 5). **So a listener bound at
561
569
  a strict descendant of a deleted address does NOT fire.**
570
+
571
+ **⟶ AND THE SECOND ARM IS `TOUCHED`, 2026-10-29 — `D-66` AND `D-67`, AND THE SENTENCE ABOVE IS READ THROUGH
572
+ THIS ONE.** `RCA-8(g)` ANNOTATE-BESIDE: **that sentence was the build's rule until this date, and the
573
+ architect measured what it costs** — verbatim: *"Does the listener get fired when the value is purged by a
574
+ higher-persistence write that doesn't include it? Because that's the actual problem"* (`strata/decisions.md`
575
+ · `D-67`). **THE ANSWER WAS NO, AND THAT WAS THE DEFECT.** **So a handle now appears where its address is a
576
+ PREFIX of the triggering address (`D-56`, unmoved) OR WHERE THE ACT TOUCHED IT (`D-66`)** — the touched set
577
+ being the paths the act's value contains together with the whole subtree of every version that act PURGED,
578
+ **a purge at a higher persistence included, which is the case the prefix rule could not reach.** **A LISTENER
579
+ BOUND AT A STRICT DESCENDANT OF A DELETED ADDRESS DOES FIRE**: the cascade removed its node, so the value a
580
+ read there returns changed. **AND A CONSTRAINT IS REACHED BY THE SAME ONE PREDICATE** (`D-69`: a registration
581
+ is a handle and a body, and a pair has both), **so `triggered` names both kinds in one list and the kernel
582
+ filters it — an element that is a constraint's `id` is ASKED, a listener's is DELIVERED.** **MEASURED
583
+ 2026-10-29 on this checkout** (`tests/e2e/discard-witness.mjs`'s `DW-14.1`/`DW-14.2`/`DW-14.3`): a listener at
584
+ `['a','b','c']` fires once for a write at `['a','b']` that writes `c`; a `file`-tier write that purges a node
585
+ with a `mem` shadow fires the listener bound at the purged path **and** asks the constraint bound there, while
586
+ the pair at an address neither value names is asked nothing.
562
587
  3. **A registration made during a firing window is not invoked during that window.** A delivery's recipient set
563
588
  is read from the array as it stands when the window opens (`surface.md §2.4`, the delivery-window clause).
564
589
  4. **One invocation per distinct handle.** A handle bound at two addresses that both match fires ONCE
@@ -571,6 +596,11 @@ BOUND at, never the address the write targeted**, and the two are told apart: **
571
596
  the write's address** (`index.d.ts`, `TriggerPair`; `held-listener/contract.md §2.4` items 1 and 7; `PAR-HL-19`–`PAR-HL-21`).
572
597
  **There is no parallel `triggeredAddresses` array and none may be added.**
573
598
 
599
+ **★ ⟶ AND WHAT THAT ONE ARGUMENT DOES NOT CARRY, STATED BESIDE IT 2026-10-29: it names the ACT's address and
600
+ never what MOVED under it — so a container listener that must know which position moved diffs the collection
601
+ itself** (§7.9's item 4, where the reason is given: the act's address is the store's own datum, and which
602
+ position moved is the caller's question).
603
+
574
604
  - **`write` answers `{op, watched, triggered}`** (`index.d.ts`, `WriteRecord`). **`op` is the store's own journal
575
605
  record and not a number** — `{opId, kind, address, tier, before, after, seq, compacted}` — and **the op's
576
606
  `opId` is a string** and is the token `rollback` accepts (`index.d.ts`, `JournalOp`). **`watched` carries
@@ -586,10 +616,206 @@ the write's address** (`index.d.ts`, `TriggerPair`; `held-listener/contract.md
586
616
  - **The kernel's own `pending` list carries the same pair element as `triggered`**, because `pending` is seeded as
587
617
  a clone of the store's returned set (`index.d.ts`, `CommitRecord`; `held-listener/contract.md §2.4` item 3).
588
618
 
619
+ **⟶ AND THAT BULLET IS THE ONE THAT MOVED, 2026-10-29 — `D-56`: A PASSING WRITE NOW EMPTIES `pending`.** `RCA-8(g)`
620
+ ANNOTATE-BESIDE: **every clause above stands BYTE-FOR-BYTE and is read THROUGH this one; the record's four members,
621
+ the seeding rule and the by-identity check-off do not move — what moves is HOW MUCH of the seeded set the pass takes
622
+ out of it.** **THE MECHANISM, IN ONE SENTENCE: `pending` is seeded whole from the store's `triggered` set and every
623
+ handle the pass EVALUATES is checked off by identity, so when the pass's set and the store's set are the SAME SET the
624
+ residue is EMPTY.** **`AT `1.4.0`'s PREDECESSOR** the pass selected only the pairs standing at the act's EXACT
625
+ address, the store's `triggered` set was already the wider PREFIX set, and the difference was the residue you saw: a
626
+ pair at `['window','tabs']` fired for a write at `['window','tabs','landingPage']` (a listener, `§6.4`) and was
627
+ never asked by the pass — so its handle stayed in `pending` and the delivery ran it. **NOW the pass's set IS the
628
+ `triggered` set** (`§7.6`'s clause of 2026-10-29, `D-56`), **so on a PASSING write every handle in the returned set is
629
+ checked off, `record.pending` reads `[]`, and the delivery's residue is empty.** **MEASURED `1` → `0` on a passing
630
+ write.** **WHAT THAT MEANS FOR YOU, SAID PLAINLY: `pending` IS NO LONGER A LIST OF "WHAT I STILL OWE A DELIVERY TO" —
631
+ IT IS THE LIST OF HANDLES THE PASS DID NOT EVALUATE, and on a passing write there are none.** **A non-empty `pending`
632
+ therefore means one of two things and only two**: the write FAILED (the record's `pending` is then the whole returned
633
+ set, because a failing arm checks nothing off), or a handle stands in `triggered` that stands at none of the pass's
634
+ addresses — **which, from this date, is the DESCENDANT direction `D-56` does not cover.** **Read `triggered` for what
635
+ fired and `pending` for what the pass left; on a passing write they are no longer the same list, and `pending` is the
636
+ shorter one.** (`D-56`; `index.d.ts`'s `CommitRecord`; §7.6's prefix-set clause; §7.8's ancestor clause.)
637
+
638
+ **⟶ AND THE SENTENCE THAT SAYS A PASSING WRITE EMPTIES `pending` IS RE-MEASURED ONE ARM FURTHER, 2026-10-29 — THE PASS CHECKS OFF WHAT IT ASKED, AND A LISTENER'S HANDLE IS THE DELIVERY'S.** `RCA-8(g)` ANNOTATE-BESIDE: **the clause above stands BYTE-FOR-BYTE and is read THROUGH this one — so does its *"on a PASSING write every handle in the returned set is checked off, `record.pending` reads `[]`"*, which is exactly true of a fired set made of CONSTRAINTS and is not true of a fired set that also carries a LISTENER.** **MEASURED 2026-10-29 ON THIS CHECKOUT, THROUGH THE PUBLISHED ENTRY, BOTH ARMS PRINTED:** a pair at `['anc']` with a passing write at `['anc','child']` — `K-2`'s record carries `['anc-pair']` and after the pass it carries `[]` ✓ **the `1 → 0` the clause above measured**; the same write with a listener also bound at `['anc','child']` — `K-2`'s record carries `['anc-pair','watch-child']` and **after the pass it carries `['watch-child']`**, because **the pass evaluates CONSTRAINT ROWS and a listener's handle is the DELIVERY's work and never the pass's.** **SO READ IT PRECISELY: ON A PASSING WRITE `pending` HOLDS EXACTLY THE HANDLES THE PASS DID NOT EVALUATE — NO CONSTRAINT AT AN ADDRESS IT ASKED, AND EVERY LISTENER THE DELIVERY WILL FIRE** — **and `[]` is that member's value when nothing but constraints was fired.** **NO MEMBER MOVES AND NO FIGURE OF THE CLAUSE ABOVE IS WITHDRAWN: this is its reading, one arm wider.** (`D-56`; `D-69`; `tests/e2e/discard-witness.mjs`'s `DW-14.4`; §7.6's prefix-set clause.)
639
+
640
+ **⟶ AND THE COMPOSITION IS NOW MEASURED, 2026-10-29 — `D-69`, AND EVERY SENTENCE ABOVE STANDS BYTE-FOR-BYTE.**
641
+ `RCA-8(g)` ANNOTATE-BESIDE: **the clause above reasons about the member's SIZE; this one states what the member now
642
+ CARRIES, because `D-69` moved the store's set as well as the pass's.** **THE STORE NOW NAMES A CONSTRAINT STANDING AT
643
+ A TOUCHED DESCENDANT** — `D-66`'s criterion, computed where the per-tier versions live (`D-67`) — **so `pending` is
644
+ seeded with that `id` where it was not before, and the pass then ASKS it and CHECKS IT OFF like any other element.**
645
+ **MEASURED, BEFORE → AFTER, on one drive** (`tests/e2e/discard-witness.mjs`'s `DW-14.4`): a write whose pair stands at a
646
+ TOUCHED DESCENDANT and whose listener stands at an ancestor — at `K-2`'s return the member carries **2** elements
647
+ (the constraint's `id` AND the listener's handle) where the prefix-only composition carried **1**, and after the pass
648
+ it carries **1** (the listener's handle, which is the DELIVERY's work and never the pass's) — **so the composition
649
+ moves AT `K-2` and the delivered residue is unmoved.** **WHAT THAT MEANS FOR YOU, SAID PLAINLY: a `pending` entry is
650
+ either a listener the delivery still owes (the residue) or a constraint the pass has not reached (the failing arm's
651
+ whole set) — and on a passing write the pass asks EVERY element the store named that IT HOLDS A ROW FOR, so the
652
+ residue's only remaining constraint is one it holds no row for.** **THAT ONE STATE IS REACHABLE AND MEASURED**
653
+ (`tests/e2e/discard-witness.mjs`'s `DW-14.3`): **a registration whose own constraint REFUSED it at the registration
654
+ instant** — `ConstraintRefusedAtRegistration`, state `2` of `contract.md §7.3` (b) — **leaves the store-side entry
655
+ standing and NO row in the kernel's registry**, so the store's `triggered` names that handle, the pass asks nothing
656
+ for it, and it stays in the residue; **it fires NOTHING, silently, and its body's one run is the registration's own
657
+ evaluation** (`surface.md §2.4` rule 1). (`D-69`; `D-66`; `D-67`; `kernel-surface.md §2.1` item 2's `A112` reading.)
658
+
589
659
  **And one store behaviour that shows up in the records if you use integer addresses: a delete of an indexed
590
660
  version of an array container RENUMBERS the surviving anchors in container order from `0`, each keeping its tier
591
661
  and its node** (`write-and-read.md §4.4`'s renumbering clause).
592
662
 
663
+ **★ AND WHICH KIND YOU ARE IS THE QUESTION THIS SURFACE LEAVES YOU, 2026-10-29 — `D-70`: IF YOUR CALLBACK CHANGES
664
+ THE STORE IT IS A CONSTRAINT OR A REPAIR (§7), AND IF IT TELLS THE WORLD IT IS A LISTENER.** **§7.9 states the three
665
+ rules, each with its reason, and they govern what you register and where — because this surface's other kind is one
666
+ section away and the two are NOT interchangeable: a listener at a derived index is a registration on a value the
667
+ store never wrote, and a listener that writes has no loop guard to bound it.** (`D-70`; §7.9.)
668
+
669
+ ### §6.5 ★ A LISTENER'S OUTCOME IS NOT YOURS — its own commit, and its refusal cannot fail your write
670
+
671
+ **★ THE RULING, IN THE ARCHITECT'S OWN SENTENCE** (`strata/decisions.md` · `D-71`, verbatim): *"A listener is
672
+ independent of the commit record of the triggering caller. The caller does not need to know about the outcome of
673
+ the listeners."* **AND THE CONSEQUENCES, STATED BECAUSE EACH IS SOMETHING YOU WILL OTHERWISE GUESS AT:**
674
+
675
+ 1. **A LISTENER RUNS IN ITS OWN COMMIT** (`D-45`), **AND ITS OUTCOME — PASSED OR REFUSED — IS THAT COMMIT'S**, not
676
+ yours.
677
+ 2. **THE TRIGGERING CALLER RECEIVES ITS OWN OUTCOME AND NOTHING ABOUT THE LISTENER'S.** **Your record is your
678
+ write's** — `op`, `watched`, `triggered` (`§6.4`) — **and it carries no member for what a listener's own
679
+ commit did.**
680
+ 3. **A LISTENER'S REFUSAL DOES NOT FAIL THE WRITE THAT FIRED IT.** **A listener is a SIDE EFFECT for external
681
+ code, and a side effect's failure is the side effect's** — your write already passed every constraint and
682
+ already answered before the delivery ran.
683
+ 4. **AND BECAUSE OF THAT, THE ONLY THING A CHAIN OF LISTENER WRITES EXPOSES UPWARD IS ITS COST** — depth, and
684
+ whatever the listener itself does with what its own call returns. **Which is why the missing loop guard is the
685
+ asymmetry that matters** (`§7.9` item 2): **nothing else about the chain is observable, so nothing else can be
686
+ bounded.**
687
+
688
+ **MEASURED 2026-10-29 ON THIS CHECKOUT, THROUGH THE PUBLISHED ENTRY — AND THE MEASUREMENT IS THE POINT, BECAUSE
689
+ THIS IS A CLAIM ABOUT WHAT CROSSES AND IT MUST BE PRINTED RATHER THAN ASSUMED.** One store: a listener at `['a']`
690
+ whose body writes `['b'] = 'bad'`, and a constraint at `['b']` that refuses `'bad'` with
691
+ `{message: 'b may not be bad'}`. **WHAT THE DRIVE PRINTED, RAW:**
692
+
693
+ - **THE CALLER'S `store.write(['a'], 'mem', 1)` ANSWERED NORMALLY** — `{op: {opId: 'op-1', kind: 'write', address:
694
+ ['a'], tier: 'mem', before: {present: false}, after: {present: true, value: 1}, seq: 1, compacted: false},
695
+ watched: [['a']], triggered: [{handle: 'watch-a', address: ['a']}]}` — **no refusal, no status and no `log`
696
+ member: nothing of the listener's outcome crossed.**
697
+ - **THE LISTENER'S OWN WRITE WAS REFUSED, INSIDE THE LISTENER** — caught there as
698
+ `status: 'ConstraintPassRefused'`, `message: 'b may not be bad'`, own members `['status', 'message', 'log']`
699
+ — **and that refusal was the listener's to catch; the call above never saw it.**
700
+ - **THE STORE AFTER THE CALL: `['a']` reads `1`, AND `['b']` READS ABSENT (`AddressNotFound`)** — the listener's
701
+ own commit restored itself to where it opened (`§5.4`), and the caller's landing stands.
702
+ - **THE CONTROL, WHICH IS WHAT MAKES THE MEASUREMENT MEAN ANYTHING: the same caller writing `['b'] = 'bad'
703
+ DIRECTLY is REFUSED, same `ConstraintPassRefused`, same message.** **So the constraint was armed throughout,
704
+ and what differs is only WHAT CROSSES — a caller's own refusal crosses, and a listener's does not.**
705
+
706
+ **WHAT THAT MEANS FOR YOU, SAID PLAINLY: YOU CANNOT READ A LISTENER'S SUCCESS FROM ANY RETURN VALUE.** **No
707
+ member, no log entry and no status on your record says a listener's own write landed; the only way your code
708
+ learns it is if the listener body tells you out of band.** **That is the design and not a gap, and it is the
709
+ reason the next subsection's chain is bounded by cost alone.** (`D-71`; `D-45`; `§6.4`'s record members; `§7.9`.)
710
+
711
+ **AND THE ONE THING INDEPENDENCE DOES NOT COVER, MEASURED SO IT IS NOT INFERRED: A LISTENER THAT THROWS IS NOT A
712
+ LISTENER THAT IS REFUSED, AND ITS THROW CROSSES ALL THE WAY UP.** **MEASURED 2026-10-29, on this checkout, through
713
+ the published entry:** with `hA` at `['a']` writing `['x']` and `hN` at `['x']` throwing
714
+ `new Error('boom-in-nested-listener')`, the run printed `["A", "nested throws", "A caught Error"]` **and the OUTER
715
+ `store.write(['a'], 'mem', 1)` THREW that `Error`** — the delivery's own rule that *"a throwing listener body is
716
+ not caught, not retried and not reported"* (`docs/specs/storeroom-js/contract.md §2.7` item 4) **read through the
717
+ nesting's synchronous stack.** **SO THE INDEPENDENCE IS THE COMMIT'S: a refusal is the nested commit's and cannot
718
+ cross, while a raw throw is not a commit outcome and does cross, because the call is on the same stack and nothing
719
+ catches it on the way up — and the caller's write is then never answered at all.** **If you want a listener's
720
+ failure to stay the listener's, catch it in the listener's own body.**
721
+
722
+ ### §6.5a ★ THE ASYMMETRY IS THE DESIGN — a refusal is CONTAINED, a throw is NOT, and the reason is whose code failed
723
+
724
+ **★ THE RULING, THE ARCHITECT, VERBATIM** (`strata/decisions.md` · `D-73`): *"Keep the throw so that the client can
725
+ log errors cleanly"* — **and it completes `§6.5`: the independence stands, and the THROW is the one thing it does not
726
+ cover.** **STATE THE TWO HALVES AS A PAIR, BECAUSE THE ASYMMETRY IS THE POINT:**
727
+
728
+ - **A LISTENER'S REFUSAL IS CONTAINED.** **Its own commit is refused, YOUR write answers its own record, and the
729
+ refused value never lands** — **because a refusal is a JUDGEMENT ABOUT DATA, and the data had its chance.**
730
+ - **★ A LISTENER'S THROW PROPAGATES TO YOU.** **YOUR write throws the listener's error** — **because a throw is an
731
+ ERROR IN THE CLIENT'S CODE, and code that swallows errors cannot be debugged.** **A CONTAINED THROW IS AN ERROR
732
+ NOBODY CAN LOG.**
733
+
734
+ **AND THE REASON IS WHERE THE CODE RUNS: a listener is where YOUR handler runs** — **the screen update, the render,
735
+ the external call** — **so when that code fails, the failure belongs to you, at the point you can see it.**
736
+ **CONTAINMENT WOULD PRODUCE THE OPPOSITE: "your write succeeded and nothing happened" — the least debuggable outcome
737
+ a library can produce.**
738
+
739
+ **★ AND THE CONSEQUENCE, STATED SO IT IS NOT A SURPRISE: A LISTENER THAT THROWS LEAVES YOUR WRITE UNANSWERED.** **You
740
+ see the listener's error instead of your own record, and that is your signal to log and decide.** **MEASURED
741
+ 2026-10-29 ON THIS CHECKOUT, THROUGH THE PUBLISHED ENTRY, BOTH HALVES PRINTED RAW:**
742
+
743
+ - **THE THROW.** One listener at `['a']` throwing `new Error('boom-in-listener')`. **`store.write(['a'], 'mem', 1)`
744
+ THREW**, and what it threw **IS the listener's own `Error` — identity `===` true**, `{name: 'Error', message:
745
+ 'boom-in-listener'}` — **and the write ANSWERED NOTHING** (`undefined`; no record was produced). **The data had
746
+ already landed (`read(['a'])` answered `1`), because the commit resolved before its delivery ran; what the throw
747
+ takes away is the ANSWER, not the write.**
748
+ - **THE REFUSAL, as the control.** One listener at `['a']` whose body writes `['b'] = 'bad'`, against a constraint
749
+ at `['b']` refusing `'bad'`. **The listener's own write was refused INSIDE the listener** — `{status:
750
+ 'ConstraintPassRefused', message: 'b may not be bad', log: […] }`, own members `["status","message","log"]` —
751
+ **`store.write(['a'], 'mem', 1)` RETURNED ITS OWN RECORD** with **no status and no `log`**, and `['b']` read
752
+ **ABSENT**. **The same caller writing `['b'] = 'bad'` directly WAS refused with the same status — so the
753
+ constraint was armed throughout, and the difference is only WHAT CROSSES.**
754
+
755
+ **WHAT THAT MEANS FOR YOU, AND IT IS THE SHAPE TO WRITE: A LISTENER BODY LOGS ITS OWN ERRORS AND DECIDES WHETHER TO
756
+ RETHROW.** **YOUR WRITE IS THE ONE PLACE THE LISTENER'S FAILURE SURFACES.** **Catch in the body to keep a failure
757
+ inside the listener** (`§6.5`'s closing sentence) **— and let it out to hand the error to the caller that can log
758
+ it.** **There is no middle arm: nothing in your record reports a listener's throw afterwards, because after a throw
759
+ there is no record — only the error.** (`D-73`; `D-71`; `D-45`; `docs/specs/storeroom-js/contract.md §2.7`'s clause
760
+ of the same date; `§6.6`'s item 5, where a DEPTH-TWO throw's destination is measured.)
761
+
762
+ **★ AND THE PRACTICAL HAZARD THIS ASYMMETRY MAKES REAL, WRITTEN HERE SO YOU MEET IT IN A TEST RATHER THAN IN PRODUCTION: THE WRITE'S DATA LANDED AND ITS ANSWER DID NOT — SO A BLIND RETRY RE-APPLIES A WRITE THAT ALREADY SUCCEEDED.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause of §6.5a above stands BYTE-FOR-BYTE and is read THROUGH this one; no ruling, no measurement and no member moves — what this clause adds is the one consequence of the measured arm that a caller's ERROR HANDLER will otherwise get wrong.** **IT FOLLOWS FROM THE MEASUREMENT ABOVE AND NEEDS NO NEW ONE:** *"the data had already landed (`read(['a'])` answered `1`), because the commit resolved before its delivery ran; what the throw takes away is the ANSWER, not the write"* — **so `try { store.write(...) } catch { retry() }` runs that write a SECOND time, and the store has no way to tell the two apart: there is no commit identity on your side, no idempotency key and no record, because after a throw there is no record** (`§6.5a`'s closing sentence). **AND THE ERROR IS YOURS AND NOT THE PACKAGE'S SHAPE:** it carries **no depth, no handle, no address** (`§6.6` item 5) — a throw at depth two arrives as the same `Error` object a depth-one throw would — **so a retry policy cannot key on where the chain broke, and a listener body's own `catch` is the only containment arm there is.** **WHAT TO WRITE INSTEAD: catch in the body, decide whether to rethrow, and make the write your retry re-issues one whose landing you can recognise** — an `op` you kept from an earlier answer, a value you wrote, or a read before you write. (`D-73`; `D-71`; the `§6.5a` measurement; `§6.6` item 5; `docs/specs/storeroom-js/contract.md §2.7` item 4.)
763
+
764
+ ### §6.6 ★ DELIVERY NESTS — every window is a synchronous call on one thread, and the stack is the only place its order exists
765
+
766
+ **★ THE SHAPE, IN ONE STACK** (`strata/decisions.md` · `D-72`). **A commit resolves and its delivery begins; a
767
+ listener that writes opens a commit of its own (`D-45`), which runs its own pass and then ITS delivery — so
768
+ windows are live at once, NESTED, every level a synchronous call on one thread:**
769
+
770
+ ```text
771
+ outer write → its commit → its pass → its delivery → listener A → A's write (a NEW commit) → A's pass → A's delivery → listener B → …
772
+ ```
773
+
774
+ **SO "INTERLEAVING" IS NOT CONCURRENCY — IT IS NESTED SUSPENSION: `A`'s entire chain runs to completion before the
775
+ window that fired it invokes its next listener.** **The outer loop is suspended, not interleaved.**
776
+
777
+ **FOUR PROPERTIES ARE REAL, AND NOT ONE OF THEM IS DECLARED ANYWHERE UP THE STACK — so each is stated here:**
778
+
779
+ 1. **DEPTH IS UNBOUNDED** — no counter, no cap and no instrument (`D-70`'s absence; `§7.9` item 2). **The stack
780
+ grows until your code stops calling.**
781
+ 2. **★ THE CROSS-WINDOW ORDER IS REAL AND UNDECLARED.** **Within one window the order is unspecified and the list
782
+ is a set** (`DD-37`; `§6.4`) — **but across windows the nesting imposes one: a nested chain precedes the
783
+ window's next listener.** **The machine provides that guarantee and no clause promises it — so a consumer
784
+ relying on the opposite relies on nothing.** **MEASURED 2026-10-29, on this checkout, through the published
785
+ entry:** listeners `hA` and `hB` at `['a']` and `hC` at `['x']`, where `hA`'s body writes `['x']`, printed
786
+ `["A", "C (nested commit)", "A-end", "B"]` — **the whole nested chain ran inside `A`'s own call, before `B` was
787
+ invoked, and `A`'s code resumed after it.**
788
+ 3. **★ RE-ENTRANCY IS UNAVOIDABLY OPEN.** **A listener that writes at the address it was delivered for fires
789
+ itself again**, because the store's trigger set is computed per act. **Nothing detects it, and nothing is
790
+ meant to** — that is the loop the missing guard leaves open, and the concrete shape of *"no instrument you can
791
+ read"* (`D-70`).
792
+ 4. **AND NOTHING ABOVE SEES BELOW** (`D-71`; `§6.5`). **A chain that fails at depth three is indistinguishable, to
793
+ the original caller, from one that never ran:** the original record is its own, and the depth-three refusal is
794
+ that nested commit's.
795
+
796
+ 5. **★ AND A THROW AT DEPTH TWO REACHES THE ORIGINAL CALLER — THE PROPERTY THIS NESTING LEFT UNDECLARED, NOW MEASURED
797
+ AND DECIDED.** **A FIFTH PROPERTY JOINS THE FOUR ABOVE.** (`RCA-8(g)` ANNOTATE-BESIDE: **the four stand
798
+ BYTE-FOR-BYTE as the reading of their own date, and item 4's *"nothing above sees below"* is unmoved for
799
+ OUTCOMES; what this item decides is the THROW's destination, which `D-73` alone rules.**) **THE REASON IS THE
800
+ STACK'S: a throw is not a commit outcome, so no nested commit contains it, and every level of this chain is a
801
+ synchronous call with nothing catching in between** (`§6.5a`). **MEASURED 2026-10-29 ON THIS CHECKOUT, THROUGH
802
+ THE PUBLISHED ENTRY:** `hA` at `['a']` whose body writes `['x']`, and `hN` at `['x']` throwing
803
+ `new Error('boom-in-nested-listener')`. **THE TRACE WAS `["A enters", "N throws", "A: its own write THREW
804
+ Error{name:'Error',message:'boom-in-nested-listener'} (=== nested error: true)", "A leaves"]`, AND THE ORIGINAL
805
+ `store.write(['a'], 'mem', 1)` THREW THE SAME `Error` — identity `===` true — AND ANSWERED NOTHING.** **SO WHERE
806
+ IT SURFACES IS: FIRST AT `A`'s OWN `write(['x'], …)` INSIDE THE LISTENER, THEN — `A` NOT HAVING CAUGHT IT — OUT
807
+ THROUGH THE OUTER DELIVERY INTO THE ORIGINAL CALLER.** **YES: A DEPTH-TWO THROW REACHES THE ORIGINAL CALLER, AS
808
+ THE SAME ERROR OBJECT AT EVERY HOP, AND LEAVES THE ORIGINAL WRITE UNANSWERED.** **AND THE STOP IS YOURS TO PLACE:
809
+ with `A`'s body catching instead, the measured trace was `["A enters", "N throws", "A caught Error{…} (===
810
+ nested error: true)", "A leaves"]` and the original write ANSWERED ITS OWN RECORD with `threw: false`** — **so
811
+ the DEPTH is invisible in the error unless the listener adds it, and a caller that must know where a chain failed
812
+ annotates the throw itself.** (`D-73`; `D-72`; `§6.5a`; `docs/specs/storeroom-js/contract.md §2.7`'s clause of
813
+ the same date.)
814
+
815
+ **WHAT THAT MEANS FOR YOU, IN ONE SENTENCE: if you write a listener that writes, you have moved the order of your
816
+ own effects out of the record and into the call stack, and the only thing you can still hold is the depth you
817
+ yourself refuse to exceed.** (`D-72`; `D-71`; `D-70`; `D-45`; `DD-37`; `§7.9`.)
818
+
593
819
  ---
594
820
 
595
821
  ## §7 · Constraining: the pair, the handle, and the two routes
@@ -758,6 +984,10 @@ body.**
758
984
 
759
985
  **⟶ AND THE PASS'S SET IS NOW A PREFIX SET, 2026-10-29 — `D-56`, WHICH SUPERSEDES THE CLAUSE ABOVE.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE as the rule of the build that printed it, and it is READ THROUGH this one.** **THE ARCHITECT, VERBATIM** (`strata/decisions.md` · `D-56`): *"A listener/constraint should fire when the descendants of its targeted address node change, because the descendants become part of the object that is read from that address"*. **SO A PAIR AT `['tabs']` IS ASKED FOR A DELETE AT `['tabs','landingPage']`** — the value read at `['tabs']` CONTAINS the subtree the delete moved, so your pair judges an object that moved — **and a pair at `['tabs','landingPage']` is still asked for that same delete.** **WHAT IS STILL NOT ASKED IS THE OTHER DIRECTION**, which the ruling does not cover: a delete at `['tabs']` does not ask the pair at `['tabs','landingPage']`, and the object that pair judges then reads as ABSENT. **THE MEMBERSHIP RULE, STATED ONCE: your pair is asked when THE ACT'S ADDRESS IS AT OR BELOW YOUR PAIR'S ADDRESS.** **AND WHAT YOUR PAIR IS HANDED DID NOT MOVE**: the context carries THE ACT'S `address`, `tier` and `value` — so a pair standing at an ancestor is handed the value that landed AT THE ACT'S ADDRESS (absence, for a delete), **not** the object at its own. **A PAIR THAT JUDGES ITS OWN ADDRESS READS IT** (`§7.6`'s `read()` rule, which `D-56` leaves standing — it is no longer NECESSARY for an ancestor's interest in a descendant, and it is still correct for the pair's own object). **MEASURED 2026-10-29, on this checkout, through the published entry** (`tests/e2e/discard-witness.mjs`'s `DW-10.13`/`DW-10.15`/`DW-10.16`): a pair at `['window','tabs']` and a delete at `['window','tabs','landingPage']` — **the pair IS asked (2 asks: its registration's and the pass's), its refusal crosses, and the delete rolls back** (`window.tabs` reads `{"landingPage":{"active":true},"settings":{"active":false}}` again); a pair AT the act's own address is asked once by the pass, unchanged; a pair at the act's DESCENDANT is asked `0` times and its address reads ABSENT afterwards.
760
986
 
987
+ **⟶ AND THE DESCENDANT DIRECTION IS RULED TOO, 2026-10-29 — `D-66`, AND THE TWO CLAUSES ABOVE STAND BYTE-FOR-BYTE AND ARE READ THROUGH THIS ONE.** `RCA-8(g)` ANNOTATE-BESIDE: **this clause completes the membership rule; it moves no clause above it and no figure of this section.** **THE ARCHITECT, VERBATIM** (`strata/decisions.md` · `D-66`): *"A pair at a descendant should only be asked if the change also affects that descendant, ex. write(['a', 'b'], {'c': "foo", 'd': "bar"} should trigger at ['a'], ['a', 'b'], ['a', 'b', 'c'], and ['a', 'b', 'd'], but not ['a', 'b', 'e']"*. **SO THE MEMBERSHIP RULE IS NOW: your pair is asked when THE ACT CHANGES THE VALUE AT YOUR PAIR'S ADDRESS — which means the act's address is at or below yours (`D-56`, unmoved), OR your pair's address is one the act TOUCHED.** **WHAT "TOUCHED" MEANS, IN THE TWO VERBS YOU DRIVE:** **a `write` touches exactly the paths its value contains** — write `{c:'foo', d:'bar'}` at `['a','b']` and the pairs at `['a','b','c']` and `['a','b','d']` ARE asked, while the pair at `['a','b','e']` is NOT, **because the write did not touch `e`** (it stands neither before nor after the act) — and a value with a nested object touches its own sub-paths by the same rule one level down, an array its own indices, a scalar nothing below itself; **a `delete` touches the WHOLE SUBTREE at its address**, because a descendant of a deleted node is ABSENT after the act and was not before, **which is a change to what a read there returns** — so a delete at `['window','tabs']` DOES ask a pair standing at `['window','tabs','settings']`. **AND WHAT YOUR PAIR IS STILL NOT ASKED FOR IS A DESCENDANT THE ACT DID NOT TOUCH**, which is the whole of the distinction: it is not "descendant", it is "touched". **ONE THING YOUR PAIR IS HANDED, ON EVERY ARM**: the context carries THE ACT'S `address`, `tier` and `value` — so a pair standing at a touched descendant is handed the value the act landed AT THE ACT'S ADDRESS (absence, for a delete), **not** the object at its own; **a pair that judges its own address READS it** (`§7.6`'s own rule, which stands). **MEASURED 2026-10-29, on this checkout, through the published entry** (`tests/e2e/discard-witness.mjs`'s `DW-13.1`/`DW-13.2`/`DW-13.3` and `DW-10.16`): the ruling's own drive asks `['a']`, `['a','b']`, `['a','b','c']` and `['a','b','d']` and NOT `['a','b','e']`; a nested value asks its own sub-paths and not a sibling it did not write; a delete at `['window','tabs']` asks the pair at `['window','tabs','settings']`; **and the pass's set is still ONE snapshot, FIXED WHEN THE PASS BEGINS and in ONE registration order across the ancestors, the act's own address and the touched descendants** (a pair registered during a pass enters the next one and no earlier one).
988
+
989
+ **⟶ AND A WRITE'S TOUCHED SET IS NOW BOTH VALUES', 2026-10-29 — `D-66` READ SYMMETRICALLY, AND THE CLAUSE ABOVE STANDS BYTE-FOR-BYTE AND IS READ THROUGH THIS ONE.** `RCA-8(g)` ANNOTATE-BESIDE: **the one sentence this clause supersedes is that clause's bullet *"a `write` touches exactly the paths its value contains"*, named here rather than overwritten; the `delete` bullet and every other figure of this section are unmoved.** **THE GAP, MEASURED BEFORE IT WAS CLOSED: A WRITE THAT REPLACES A NODE DROPS THE SUB-PATHS THE OLD VALUE CARRIED.** Write `{c: 1}` over `{c:{x:1}}` and the path `['a','b','c','x']` stands PRESENT before the act and ABSENT after it — **a change to what a read there returns** — **and `x` is in neither the written value's path set nor the word "descendant", so the pair standing there went unasked.** **THE CRITERION THAT CLAUSE ALREADY NAMES DECIDES IT WITHOUT A NEW RULE** — *"your pair is asked when the act changes the value at your pair's address"* — **and a path that DISAPPEARS changed as surely as a path that APPEARS.** **SO THE WRITE ARM IS SYMMETRIC: your pair is asked when the act touched the value it WROTE *or* the value it REPLACED** (`op.before.value`, the state the store's own journal carries), **and the touched set is the union of the two path sets** — a path in both being yours once, not twice. **THE `delete` ARM DOES NOT MOVE**: the whole subtree it removed, exactly as the clause above states it. **AND A FIRST WRITE AT AN ADDRESS HAS NO BEFORE VALUE AND NEEDS NONE**: `op.before` is present on every op and answers `present: false` where nothing stood, so that write's union is the written value's path set exactly and nothing throws. **`['a','b','e']` IS STILL NOT ASKED**, for the reason the clause above gives: `e` stands in neither value, so neither half of the union touches it. **MEASURED 2026-10-29, ON THIS CHECKOUT, THROUGH THE PUBLISHED ENTRY** (`tests/e2e/discard-witness.mjs`'s `DW-13.5` and `DW-13.6`, with `DW-13.1`–`DW-13.4` still green): a write of `{c:1}` over `{c:{x:1}}` at `['a','b']` now ASKS the pair at `['a','b','c','x']` and does NOT ask `['a','b','c','z']` or `['a','b','y']`, which stand in neither value; the first write at an empty `['f']` asks `['f','g']` and `['f','g','q']` and not `['f','h']`; **and the pass's set is still ONE snapshot, FIXED WHEN THE PASS BEGINS, in ONE registration order.** (`D-66`; `D-56`; §7.6's touched-set clause of the same date; `bindings/js/src/entry/kernel-foundations.mjs`'s `touchedAddresses`.)
990
+
761
991
  ### §7.7 ★ The check is BOUNDED — THREE restarts per terminal act, and past the budget it fails closed
762
992
 
763
993
  **★ THE LIMIT, DECLARED HERE BECAUSE NO CLAUSE OF THIS GUIDE SAID IT: A CONSTRAINT CHECK RESTARTS AT MOST THREE TIMES PER TERMINAL ACT.** The bound is **`RESTART_LIMIT` = `3`**, one exported constant at **`bindings/js/src/entry/constraints.mjs:1366`**. **THE BUDGET IS SPENT AND NOT RESET by an action raised inside a restart** — a body that reverses again inside a restart's own ask spends the SAME budget and not a fresh one — **AND PAST IT THE CHECK FAILS CLOSED IN THE ONE FORM:** the write throws the same plain `{status, message, log}` it throws for a refused pass (§8), with `status` **`'ConstraintPassRefused'`** and **ONE log entry** whose message says the budget was spent rather than that a pair refused a state it never judged. **The store is restored** — the request's own watch records what is owed — so the terminal act leaves no unjudged effect standing (`D-42` item `3`; `D-41` item `4`).
@@ -805,8 +1035,8 @@ store.addConstraint({ address: ['window','tabs','landingPage'], id: 'landing-pag
805
1035
 
806
1036
  store.delete(['window','tabs','landingPage']);
807
1037
  // throws { status: 'ConstraintPassRefused', message: 'the landing page is not removable', log: [ … ] }
808
- // log[0] = { seq: 1, kind: 'constraint-check', id: 'landing-page-must-stand', opId: 'op-3', state: null, … }
809
- // log[1] = { seq: 2, kind: 'outcome', id: null, opId: 'op-3', state: 'KC-3', … }
1038
+ // log[0] = { kind: 'constraint-check', id: 'landing-page-must-stand', opId: 'op-3', state: null, … }
1039
+ // log[1] = { kind: 'outcome', id: null, opId: 'op-3', state: 'KC-3', … }
810
1040
  store.read(['window','tabs','landingPage']); // { active: true } — the delete was undone
811
1041
  ```
812
1042
 
@@ -816,6 +1046,30 @@ pass** — the pass keeps the write's exact-address rule and not the trigger set
816
1046
  such a listener DOES fire for the delete (`§6.4`). **And a delete that removes nothing is not an edit**: `tiers: []`,
817
1047
  no pass, no refusal, no delivery (`§5.3`).
818
1048
 
1049
+ **⟶ AND THE SECOND OF THOSE THREE SENTENCES IS CORRECTED, 2026-10-29 — `D-56`: THE PAIR AT AN ANCESTOR IS ASKED, AND
1050
+ THE DELETE AT `['window','tabs','landingPage']` IS ASKED OF THE PAIR AT `['window','tabs']`.** `RCA-8(g)`
1051
+ ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE as the rule of the build that printed it and is read
1052
+ THROUGH this clause; the AFTER-state, the `tier`, the attempt identity, the `discarded` witness, the "removes nothing
1053
+ mints nothing" rule and the four steps above are all unmoved.** **THE ARCHITECT, VERBATIM: *"A listener/constraint
1054
+ should fire when the descendants of their targeted address node change, because the descendants become part of the
1055
+ object that is read from that address"*** (`D-56`) — **so the delete's pass asks the pairs standing at the deleted
1056
+ address AND the pairs standing at every ANCESTOR of it, because the value read at an ancestor CONTAINS the subtree the
1057
+ delete moved.** **WHAT YOU SEE, ON THE EXACT TREE `§6.4` USES:** with a pair registered at `['window','tabs']` and a
1058
+ **`delete(['window','tabs','landingPage'])`**, **the pair IS asked** — and **its refusal CROSSES and the delete ROLLS
1059
+ BACK**, so `window.tabs` reads `{"landingPage":{"active":true},"settings":{"active":false}}` again. **MEASURED
1060
+ 2026-10-29 on this checkout through the published entry** (`tests/e2e/discard-witness.mjs`'s
1061
+ `DW-10.13`/`DW-10.15`/`DW-10.16`): the ancestor pair is asked **2** times (its registration's evaluation and the
1062
+ pass's), a pair AT the deleted address is asked **once** by the pass and unchanged, **and a pair at a DESCENDANT of
1063
+ the deleted address is asked `0` times and its address reads ABSENT afterwards** — that last direction is the one
1064
+ `D-56` does not cover and this guide does not claim. **THE MEMBERSHIP RULE, ONCE: your pair is asked when THE ACT'S
1065
+ ADDRESS IS AT OR BELOW YOUR PAIR'S ADDRESS.** **AND WHAT YOUR PAIR IS HANDED DID NOT MOVE**: the ACT's `address`, the
1066
+ ACT's `tier` and the value that landed at the ACT's address (absence, for a delete) — **not** the object standing at
1067
+ its own address — so **a pair that wants its OWN object reads it** (`§7.6`'s `read()` rule, which `D-56` leaves
1068
+ standing and which is no longer NECESSARY for an ancestor's interest in a descendant). **So the "exactly one tab is
1069
+ active" constraint `§6.4` writes now judges the delete as well as the write — and a delete that would leave a state
1070
+ your pair refuses is refused at the delete.** (`D-56`; §7.6's prefix-set clause of the same date; `HL-8` item 1 and
1071
+ attempt-lifecycle `§2.4` item 5 (iv), annotated at their own homes and not rewritten.)
1072
+
819
1073
  **Why you care: a delete cannot be used to slip a state past a constraint you registered, and a listener you write
820
1074
  for the use case in `§6.4` — "exactly one tab is active" — now runs on a state the pass has already approved.**
821
1075
  **WHAT THE WITNESS STILL SPEAKS FOR** (§8's `record.discarded`): a `rollback` your listener raises inside the
@@ -828,6 +1082,136 @@ delete reads the pass's ask already taken (`1`, where it read `0`) and the after
828
1082
  refused delete leaves the store at the state it opened at; and the delete's log is the commit's ONE list with
829
1083
  `seq` `1..2` (`tests/e2e/discard-witness.mjs`'s `DW-10.8`–`DW-10.13`).
830
1084
 
1085
+ **⟶ AND TWO READINGS OF THAT MEASUREMENT SENTENCE ARE THE READINGS OF THEIR OWN DATE, 2026-10-29 — THE POSITION IS
1086
+ THE ARRAY INDEX (`D-65`) AND A REFUSED DELETE RESTS AT THE LAST VALIDATED STATE (`D-63`).** `RCA-8(g)`
1087
+ ANNOTATE-BESIDE: **every clause of §7.8 above stands BYTE-FOR-BYTE and is read THROUGH this one; the asks, the
1088
+ after-state, the witness and the four steps are unmoved — two figures and one noun move.** **(i) *"the delete's log is
1089
+ the commit's ONE list with `seq` `1..2`"* IS READ AS: the commit's ONE list, TWO entries, standing at INDEX `0` and
1090
+ `1`** — the `seq` member is gone from `LogEntry` (`D-65`; §8.0a's retirement clause below), so `log[0]` is the
1091
+ `constraint-check` entry and `log[1]` the `outcome` entry, and the position is where an entry stands in the array.
1092
+ **(ii) *"a refused delete leaves the store at the state it opened at"* IS READ AS: at THE LAST VALIDATED STATE** —
1093
+ which is the state it opened at whenever the delete's sweep never passed, and the state a passing sweep approved
1094
+ otherwise (`D-63`; §5.4's `D-63` clause). **AND THE THIRD THING THIS CLAUSE OWES, WHICH NO EARLIER CLAUSE OF §7.8
1095
+ NAMES: WHAT THE DELETE'S RECEIPT CARRIES AND WHAT FOLLOWS FROM IT.**
1096
+ - **THE RECEIPT.** `delete` still ANSWERS `{address, op, tiers, triggered}` (`index.d.ts`, `DeleteRecord`), and the
1097
+ **non-enumerable `discarded` witness** still rides it unlisted (`§8`). **⟶ AND BESIDE BOTH, FROM THIS DATE, A
1098
+ NON-ENUMERABLE `commit` MEMBER** — **the same four-member `CommitRecord` a write's `K-2` mints** (`attempt`, `op`,
1099
+ `triggered`, `pending`). **`Object.keys(receipt)` still shows the record's own members and not this one**, so a
1100
+ consumer that copies a receipt loses the commit as it loses the witness — **read it off the receipt itself.**
1101
+ - **ADOPTION.** The entry **ADOPTS** that record: it stands the delete's own receipt in the leg slot for the pass and
1102
+ **restores the enclosing leg in a `finally`**, so a refusal raised inside the delete's pass reports the DELETE's
1103
+ record and not an enclosing write's.
1104
+ - **THE `pending` RESIDUE.** The delete's `pending` is **the returned set MINUS the handles the delete's own pass
1105
+ checked off** — on a passing delete, empty (`D-56`; §6.2's clause) — **and the delivery fires THE RESIDUE**, not the
1106
+ whole returned set.
1107
+ - **`K-4` AND `K-5` BY REFERENCE.** Both readers now answer a delete's attempt **BY REFERENCE** where they refused
1108
+ `NO-REF` before — so `K.log(store, receipt.commit.attempt)` and `K.report(store, receipt.commit.attempt)`
1109
+ reach the delete's own attempt once it has passed, and not only through a refusal's `log` — and **both still
1110
+ refuse a LIVE attempt with `KC-7`** (`D-58`; §8.6's clause). **`receipt.commit` is `null` on the arm that removed
1111
+ nothing** (`D-3`), so guard it before you reach through it.
1112
+ - **THE SAVE.** The `file`-tier save is the delete's own op, on the passing arm — **§9.3's clause below is its home
1113
+ and this bullet does not restate its scope.**
1114
+ **AND NO KERNEL ITEM IS OWED FOR ANY OF IT: the verb is the surface, the kernel's set stays `K-1`…`K-6`, and a `K-7`
1115
+ `commitRemoval` would be owed only if you could drive a delete's attempt directly — you cannot** (`D-57`'s second
1116
+ half; `D-3`; `D-44`; `D-53`).
1117
+
1118
+ ### §7.9 ★ WHICH KIND — two different jobs, and why a derived value is not an address
1119
+
1120
+ **★ THIS IS WHERE THE TWO SURFACES MEET, AND IT IS THE SECTION TO READ BEFORE YOU REGISTER ANYTHING.** `§6`'s
1121
+ listener and this section's constraint stand over the SAME address domain and are named in the SAME `triggered`
1122
+ list (`§6.2`'s `D-69` clause: *an element that is a constraint's `id` is ASKED, a listener's is DELIVERED*), and
1123
+ **they are not interchangeable.** **Three rules, each with its reason.**
1124
+
1125
+ 1. **★ WHICH KIND. IF YOUR CALLBACK CHANGES THE STORE, IT IS A CONSTRAINT OR A REPAIR; IF IT TELLS THE WORLD, IT IS
1126
+ A LISTENER** — **updating external code with new data, changing the rendered information on screen.**
1127
+ **THE REASON, STATED: a constraint runs INSIDE the pass, its answer is JUDGED — a `{message}` is a refusal that
1128
+ rolls the commit back (`§5.4`) — and it HAS LOOP GUARDS**: the restart budget (`RESTART_LIMIT` `3`, `§7.7`), the
1129
+ applied-repair marker (an applied repair never runs twice, `P-SM-6`), and the per-op floor. **A listener runs
1130
+ AFTER every constraint, opens its OWN commit when it writes, and HAS NO LOOP GUARD** — nothing counts its
1131
+ writes, nothing marks its repair, and its write is a unit of its own (`D-53`) — **so a listener that writes as a
1132
+ matter of course drives a chain the machinery does not bound.** **The loop guard exists only inside the pass;
1133
+ that is the whole reason a data-changing callback belongs there.** (`D-70`, the architect, verbatim: *"Functions
1134
+ that automatically produce changes in the stored data should be written as constraint/repair, not as listeners,
1135
+ because constraint/repair has loop guards while listeners don't"* — and *"The use case for listeners is for
1136
+ updating external code with new data, ex. changing the rendered information on screen"*.)
1137
+ 2. **★ A DERIVED VALUE IS NOT AN ADDRESS. AN INDEX INSIDE A COLLECTION IS DERIVED.** **`delete(['v',0])` RENUMBERS
1138
+ the survivors in container order from `0` (`§6.4`'s closing clause), so `['v',1]` stops meaning what it meant:
1139
+ the node that stood there stands at `['v',0]` afterwards and a DIFFERENT node stands at `['v',1]`.** **So a
1140
+ registration at an index is a registration on a value the store never wrote** — it names a POSITION, and the
1141
+ store writes LOCATIONS. **THE RULE: a constraint or a listener that cares about positional membership REGISTERS
1142
+ AT THE CONTAINER — `['v']` — AND READS WHAT IT CARES ABOUT** (`D-50`'s `read()` rule, `§7.6`; `D-70`, verbatim:
1143
+ *"A constraint/listener that cares about a derived value like the vec index should listen to the vec, not the
1144
+ contained node"*).
1145
+ 3. **AND THE CONSEQUENCE A CONSUMER WILL OTHERWISE DISCOVER: A REGISTRATION AT AN INDEX WILL NOT FIRE WHEN ITS
1146
+ NEIGHBOURS MOVE — AND THAT IS NOT A DEFECT, BECAUSE NOTHING WAS WRITTEN AT THAT ADDRESS.** **`D-70`, verbatim:
1147
+ *"a listener at `['v','1']` does not hear it — correctly … A registration at a DERIVED address is a
1148
+ registration on a value the store never wrote … the `triggered` list is right to be empty, because nothing at
1149
+ `['v','1']` was written."*** **The act's address was `['v',0]`, the anchor it removed was at `['v',0]`, and no
1150
+ op of the store carries `['v',1]` as its address** — so there is no firing to owe. **The store owes you the
1151
+ CONTAINER's firing; it does not owe you a firing for a renumbering.** **And a registration at an index is not
1152
+ the only way to get this wrong — a listener whose job is to change data is the other half of rule 1.**
1153
+
1154
+ **MEASURED 2026-10-29, ON THIS CHECKOUT, THROUGH THE PUBLISHED ENTRY** (`tests/e2e/discard-witness.mjs`'s
1155
+ `DW-15.1`/`DW-15.2`/`DW-15.3`; the drive is `store.write(['v'], 'mem', [{b:1}, {b:2}, {b:3}])` and then
1156
+ `store.delete(['v',0])`, so `{b:2}` moves from `['v',1]` to `['v',0]` and `{b:3}` from `['v',2]` to `['v',1]`):
1157
+
1158
+ - **THE LISTENER AT `['v']` FIRES, ONCE**, is handed the ACT's address `['v',0]`, and **the collection it reads
1159
+ inside its body is the RENUMBERED one** — `[{"b":2},{"b":3}]`, the value it cares about, read at the address that
1160
+ is not derived; **and the record's `triggered` names its handle at `['v']`, the address it was bound at.**
1161
+ - **THE LISTENER AT `['v',1]` DOES NOT FIRE** — `0` invocations, its handle nowhere in `triggered` — **and the
1162
+ cell asserts `0` as CORRECT, citing `D-70`, not as a defect**: `['v',1]` named `{"b":2}` before the act and
1163
+ names `{"b":3}` after it, so the renumber moved a DIFFERENT node under the position it registered.
1164
+ - **THE CONSTRAINT AT `['v']` IS ASKED FOR THE SAME DELETE** — once by the pass — and it is handed **THE ACT's
1165
+ `address` (`['v',0]`), `tier` and `value`**: the value the delete left AT THE ACT'S ADDRESS, which under a
1166
+ renumbering is **the survivor that moved into index `0`, `{"b":2}`, and NOT the collection.** **The collection it
1167
+ JUDGES is the one its body reads at `['v']`** (`D-50`): the renumbered `[{"b":2},{"b":3}]`. **Its registration's
1168
+ own ask is the one with no attempt, and that ask's `value` IS the collection at `['v']`** — so a container pair
1169
+ is asked at the container and reads at the container, whichever ask it is answering. **Its `id` stands in the
1170
+ same `triggered` list as the two listener handles.**
1171
+
1172
+ **EACH CELL BITES UNDER A `/tmp` REVERT, AND THE REVERT IS THE ONE THIS RULE NAMES — THE CONTAINER REGISTRATION
1173
+ REPLACED BY AN INDEX ONE:** `['v']` → `['v',1]` at the listener turns `DW-15.1` RED (no firing, no collection read)
1174
+ and at the pair turns `DW-15.3` RED (the pass asks it `0` times); the mirror move — the index listener's `['v',1]`
1175
+ → `['v']` — turns `DW-15.2` RED (the `0` becomes a `1`). **So each arm is held by the registration's ADDRESS and by
1176
+ nothing else in the drive.**
1177
+
1178
+ **AND WHAT `D-70` DOES NOT CHANGE, SAID PLAINLY: no member, status, kernel item or bound moves.** **This section
1179
+ declares a rule of USE over a surface that was already measured — the seventh residual closes by DECLARATION, not by
1180
+ machinery** (`D-70`'s own terms; `§3.1`'s fourteen members; `§8.1`'s twenty statuses; `§7.7`'s budget).
1181
+
1182
+ **★ AND THE FOUR THINGS THIS SECTION STILL LEFT A CONSUMER TO DISCOVER, WRITTEN DOWN 2026-10-29 — `D-66` READ
1183
+ BESIDE `D-70`, AND EVERY SENTENCE ABOVE STANDS BYTE-FOR-BYTE AND IS READ THROUGH THIS CLAUSE.** `RCA-8(g)`
1184
+ ANNOTATE-BESIDE: **this clause declares no member, no status, no kernel item and no bound, and it moves no figure
1185
+ of `§3.1`, `§8.1` or `§7.7`. Each of the four is a reading this surface leaves you to DERIVE unless it is
1186
+ stated — none of them is a rule the surface lacks, and that is exactly why they have to be written.**
1187
+
1188
+ 1. **★ THE RECONCILIATION, IN ONE CLAUSE: THE REACH IS PER ADDRESS THE STORE WROTE, NOT PER POSITION.** **`D-66`'s
1189
+ sentence — *"a pair is asked when the act changes the value at its address"* — is a criterion over the
1190
+ addresses the act WROTE and the addresses it REPLACED, and `D-70`'s — *"nothing was written at `['v',1]`"* —
1191
+ is that same criterion read at an address the act never wrote.** **The two collide only ON THEIR FACE, and the
1192
+ noun reconciles them: a `VEC` renumber DOES change what a read at an index returns, but AN INDEX'S *MEANING*
1193
+ CHANGING IS NOT THE STORE *WRITING* IT.** **The store wrote `['v',0]` and replaced nothing at `['v',1]`, so it
1194
+ owes you a firing at the one address it wrote and none at the other** — which is rule 3 above, measured at
1195
+ `DW-15.1`/`DW-15.2`.
1196
+ 2. **★ THE MISSING LOOP GUARD IS AN ABSENCE, AND THIS IS WHAT IT MEANS.** **Nothing observably bounds a chain of
1197
+ listener writes: no budget, no depth, no counter and NO INSTRUMENT YOU CAN READ.** **The constraint side is
1198
+ different for one reason and not for a better one: THE GUARDS ARE THE PASS'S, and a listener does not run in a
1199
+ pass** — the restart budget (`RESTART_LIMIT` `3`), the applied-repair marker and the per-op floor all belong to
1200
+ the pass, and a listener is delivered after it. **SO YOU BOUND YOUR OWN CHAIN, in your own code, with your own
1201
+ count, because the package will not.** **And the practical shape is a sequence rather than a defect: a listener
1202
+ that writes is a listener whose writes OPEN COMMITS, whose commits RUN CONSTRAINTS, whose constraints FIRE
1203
+ LISTENERS — the machine follows that as far as your code takes it and stops only when your code stops.**
1204
+ 3. **★ A CALLBACK THAT BOTH WRITES AND RENDERS IS NOT REFUSED.** **The two kinds are A RULE OF USE, not an enforced
1205
+ classification.** **The package registers such a function, delivers it as a listener, and lets its write go
1206
+ UNGUARDED — nothing inspects a listener's body for a store call, and no refusal names the mix.** **So a consumer
1207
+ who assumes the package enforces the split will build the chain of item 2 believing it cannot happen.**
1208
+ 4. **WHAT MOVED IS NOT REPORTED.** **The delivery's one argument is the ACT's address** — `['v',0]`, the address the
1209
+ store wrote — **and not what shifted under it.** **So a container listener that must know which position moved
1210
+ DIFFS THE COLLECTION ITSELF**, inside its own body, at the container (`D-50`'s `read()` rule). **The reason is
1211
+ not an omission: the act's address is THE STORE'S OWN DATUM** — it stands on every op and on every record
1212
+ `§6.4` declares — **whereas WHICH POSITION MOVED IS THE CALLER'S QUESTION, asked against state the caller chose
1213
+ to keep.**
1214
+
831
1215
  ---
832
1216
 
833
1217
  ## §8 · Refusals
@@ -873,9 +1257,10 @@ commit does — the constraint passes that judged its value, a repair's own writ
873
1257
  and the terminal arm's `outcome` entry — **appends to ONE array**. Consequences you can rely on, each measured
874
1258
  on this checkout:
875
1259
 
876
- - **`seq` runs `1..n` CONTINUOUSLY across those steps**, because it is *the ordinal of the list it stands in*
877
- and there is one list. A repair's `commit` entry can stand in the middle of the list, between the refused
878
- pass's entries and the re-run's: **it is a real entry of the same commit, not a second log.**
1260
+ - **the entries run `0..n-1` CONTINUOUSLY across those steps**, because the position of an entry in the list
1261
+ **IS the array index** and there is one list (`D-65`; the `seq` member that used to restate it is gone). A
1262
+ repair's `commit` entry can stand in the middle of the list, between the refused pass's entries and the
1263
+ re-run's: **it is a real entry of the same commit, not a second log.**
879
1264
 
880
1265
  **⟶ AND WHAT `seq` IS TRUE OF, SAID PLAINLY, 2026-10-28 — `DEF-AI`, MEASURED.** **`seq` is the position of the
881
1266
  entry in the commit's own message log; it is not the store's journal ordinal, and the two differ by design.**
@@ -889,6 +1274,18 @@ CLAIMED: one repair write appends the five entries `constraint-check` `1` · `re
889
1274
  the repair's own joined write and the re-run** (`tests/e2e/repair-in-commit.test.mjs`'s `D-46` (1) cell, printed).
890
1275
  **No entry is ever minted from the store's journal counter**: that would be a second ordinal with no consumer.
891
1276
  (`D-53`; `D-48` · `DEF-AI`; `index.d.ts`'s `LogEntry` carries the same sentence.)
1277
+
1278
+ **⟶ AND THE MEMBER THAT SENTENCE WAS ABOUT IS GONE, 2026-10-28 — `D-65`: THE ARRAY INDEX IS THE POSITION.**
1279
+ `RCA-8(g)` ANNOTATE-BESIDE: **every byte above stands BYTE-FOR-BYTE and is read THROUGH this paragraph; what it says
1280
+ of `seq` is RETIRED, not rewritten.** **THE RULING, THE ARCHITECT, ONE WORD: *"Drop it"*** (`strata/decisions.md` ·
1281
+ `D-65`) — `seq: log.length + 1` IS the index of the entry being appended, a second copy of a fact the array already
1282
+ carries, so **the entry carries FIVE members — `kind` · `id` · `message` · `opId` · `state` — and NO `seq`.**
1283
+ **WHAT THAT MEANS FOR YOU, WITHOUT A MEMBER TO READ:** the position of an entry is **`log.indexOf(entry)`**, or
1284
+ the index of the loop you are already in; the order across a commit's attempts is the same order those bullets
1285
+ measured, read off the array; and **`JournalOp.seq` IS UNMOVED** — the store's append ordinal is a different subject
1286
+ and is now impossible to confuse with the commit's, because the commit's no longer has a member to be confused
1287
+ with. **NO OTHER MEMBER, KIND, STATUS, COUNT OR SENTENCE OF THIS GUIDE MOVES** (`bindings/js/index.d.ts`'s
1288
+ `LogEntry` carries the same retirement).
892
1289
  - **A nested write a CONSTRAINT body makes is part of the same commit**, so **its entries are in YOUR list** —
893
1290
  which is why a constraint body that performs a refused write now shows you that refusal's own
894
1291
  `constraint-check` and `outcome` entries, verbatim, before the enclosing `outcome` entry. **That is `DEF-AK`'s
@@ -917,12 +1314,16 @@ invoked at a REVERSAL's judgement has no commit record standing beside it to nam
917
1314
  makes still opens a commit of its own and its entries land in that commit's list and not in the reversal's
918
1315
  refusal (`js/contract.md §2.6`'s `D-53` clause, item `6`).
919
1316
 
920
- **⟶ AND A THROWN MESSAGE STANDS IN THAT LOG, 2026-10-28 — `D-55` ITEM 1 · `DEF-AK`, MEASURED.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause of §8.0a above stands BYTE-FOR-BYTE and is read THROUGH this one; the list's home, its six members, its one-`kind`-per-entry rule and its `seq` ordinal do not move.** **THE RULING, THE ARCHITECT, VERBATIM: *"Include a thrown message in the message log. Obviously."*** **WHAT `1.3.0` DID, MEASURED: a constraint body that threw its own `Error` crossed `ConstraintBodyThrew` whose `log` carried only the attempt's `outcome` entry — the thrown value's own literal occurred ZERO TIMES in it — while the crossed sentence said *"a constraint body's throwable crosses as this refusal"*, a carriage the log did not make.** **WHAT YOU GET NOW:**
1317
+ **⟶ AND A THROWN MESSAGE STANDS IN THAT LOG, 2026-10-28 — `D-55` ITEM 1 · `DEF-AK`, MEASURED.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause of §8.0a above stands BYTE-FOR-BYTE and is read THROUGH this one; the list's home, its one-`kind`-per-entry rule and its `seq` ordinal do not move — ⟶ and from 2026-10-28 the ordinal is the ARRAY INDEX and the member is gone (`D-65`), so *"its six members"* above is read as the FIVE-member shape this guide declares at `LogEntry`.** **THE RULING, THE ARCHITECT, VERBATIM: *"Include a thrown message in the message log. Obviously."*** **WHAT `1.3.0` DID, MEASURED: a constraint body that threw its own `Error` crossed `ConstraintBodyThrew` whose `log` carried only the attempt's `outcome` entry — the thrown value's own literal occurred ZERO TIMES in it — while the crossed sentence said *"a constraint body's throwable crosses as this refusal"*, a carriage the log did not make.** **WHAT YOU GET NOW:**
921
1318
  - **the value the body threw is PRINTED IN THE LOG**, in the ONE entry the attempt's terminal act appends (the `outcome` entry): *"the constraint `c1` threw; the attempt is closed — the value it threw was …"*. **THE FORM IS NAMED AND NOT SILENTLY STRINGIFIED**: an `Error` (or any object) reads *"an object whose own `message` member is the string "…""*, a thrown string reads *"a string whose text is "…""*, a thrown number *"a number whose value is 42"*, a thrown `void 0` *"no value at all"*, and an object with no `message` *"an object carrying no own string `message` member"*. **Nothing is read off a prototype and no caller code runs to spell it**;
922
1319
  - **and the crossed `message` stops claiming the value crosses**: after the store's generated sentence it says, in its own words, that the value the body threw does **NOT** cross as this refusal — and it names where the form it threw stands, which is that `log` entry. **THE CALLER'S OWN TEXT IS QUOTED IN THE LOG AND NEVER IN THE SENTENCE**, so a forged `{status, message}` cannot make the package speak a refusal it did not find (`DEF-A`'s protection, unmoved);
923
1320
  - **where no attempt stands there is no commit log to carry it** — a registration-time body's throw crosses with `log: []`, which is `surface.md §2.5` item 4's declared arm — **and the crossed sentence says exactly that instead of pointing at a list that would not hold the form**. (`tests/e2e/discard-witness.mjs`'s `DW-10.3`/`DW-10.4` print the readings for an `Error`, a string and an object with no `message`; both cells are RED under a revert of the terminal sentence.)
924
1321
 
925
1322
  **⟶ AND THE RECORD YOU ARE HANDED IS FINAL, 2026-10-28 — `D-55` ITEM 6 · `DEF-AO`, MEASURED.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause above stands BYTE-FOR-BYTE and is read THROUGH this one; the log's home on the commit, its entries and its identity are unmoved.** **THE RULING, THE ARCHITECT, VERBATIM: *"Attempts don't log. This is what the commits are for. The commits have their log handed off to the client and are dropped after closing out."*** **SO: a closed attempt's report and its log DO NOT MUTATE AFTER THE HANDOFF — a consumer holding a refusal is holding the record, and a record that changes after it is given out is not a record.** **WHAT THE PACKAGE DOES: at the end of the commit's own processing — the restarted check's amendment included, which is part of closing out — the report and the log it carries are `Object.freeze`d**, so a later act can neither append an entry nor re-member the report. **THE LIST IS THE SAME LIST** (`D-53`: *"the crossed report IS that list"*) — the refusal you caught and `report(store, ref)`'s `log` are ONE array, now sealed. **AND THE LIST IS SEALED WITH ITS COMMIT**, never at a nested attempt's own handoff: a constraint body's nested write is part of your commit (`D-53`), so freezing the list from inside it would stop the enclosing attempt's own `append`. (`tests/e2e/discard-witness.mjs`'s `DW-10.6` holds the crossed refusal and the closed report, drives four further acts, and prints the bytes before → after beside `Object.isFrozen` on both; RED under a revert of the seal.)
1323
+ **⟶ AND ITS SECOND HALF IS NOW DELIVERED, 2026-10-28 — `D-58` · THE DROP, AND NOTHING OF A RUNNING COMMIT.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause above stands BYTE-FOR-BYTE and is read THROUGH this one; the seal, the list's identity and the log's home on the commit are unmoved.** **THE RULING, THE ARCHITECT, VERBATIM: *"The client does not need any insight into the current state of a commit/attempt before it completes. Don't expose any of it. After a commit/attempt resolves/rejects, the store does not need to retain the message log or other client-returned data. Don't retain it."*** **WHAT THAT MEANS FOR YOU, IN TWO SENTENCES. (1) A RUNNING COMMIT HANDS YOU NOTHING**: the log reader refuses a live attempt with `KC-7` — the same refusal the report reader already answered — so an in-flight `seq` list is no longer a thing you can read; **and (2) ONCE THE COMMIT RESOLVES OR REJECTS, THE STORE KEEPS NO MESSAGE LOG**: what it goes on holding is the outcome, the ops and the reversal's record, and the list it handed you — the entries on the refusal you caught, or on `report`'s return — is the ONLY copy, sealed at the handoff. **WHAT THIS COSTS, SAID PLAINLY**: on an arm whose handoff carries no list at all — a repair body that throws, and a PASSING `write` (whose answer is `{op, watched, triggered}` and has never carried one) — the entries are no longer readable after the call. **THAT IS THE RULING'S PRICE AND NOT A DEFECT**, and it is why the seal mattered: a record you hold is the record. (`tests/e2e/discard-witness.mjs`'s `DW-11.1`–`DW-11.4` print both readers, the pass's own instant, the retained shape before → after and the single-copy proof; each RED under its own `/tmp` revert.)
1324
+
1325
+ **AND THE RECORD THAT SURVIVES THE HANDOFF HAS FOUR MEMBERS, NAMED HERE BECAUSE THE CLAUSE ABOVE SAYS WHAT IT HOLDS WITHOUT SPELLING ITS SHAPE: `{attempt, ops, outcome, rollback}`** — the attempt's identity, the ops the commit appended, the outcome it reached, and the reversal's record where one ran — **and NO message list.** **A log entry's position is its ARRAY INDEX (`D-65`), so *"an in-flight `seq` list"* above is read as an in-flight ENTRY list**: there is no `seq` member in it and no list to read while the attempt runs. (`D-58`; `D-65`; `bindings/js/src/entry/kernel-terminal.mjs`'s `dropHandoff`, which is where the closed record's four members are written; `D-55` item `6` is the seal they are frozen under.)
1326
+
926
1327
 
927
1328
  **EVERY REFUSAL NAMES ITSELF** — by a `status` from the store's own closed set, and by a **human `message` that
928
1329
  carries the address, the domain, and what was found instead.** The message is generated from the code and the
@@ -1326,6 +1727,8 @@ each is the figure its own clause already prints.** **THE FIVE, EACH WITH ITS ME
1326
1727
  5. **THE DEPTH CEILING IS `126`** — the crossing's guard reads `depth > 126` (`bindings/js/src/crossing.rs`), so a value of depth `126` is admitted and one of depth `127` is refused; the node ceiling stands at `1,000,000` beside it (`json-crossing/contract.md §4`'s clause; §10.4).
1327
1728
  **NO FIGURE MOVES BY THIS CLAUSE, AND THE ONE THING IT ADDS IS THE DATE ON WHICH ALL FIVE WERE READ AT THE SAME TREE.**
1328
1729
 
1730
+ **⟶ AND THE SIX FIGURES THIS GUIDE STATES ABOUT THE SHIPPED TREE ARE RE-MEASURED AGAIN AT THE `1.5.0` PREPARATION, 2026-10-29 — EVERY ONE OF THEM UNMOVED, AND THE PACKED SET MEASURED RATHER THAN CARRIED.** `RCA-8(g)` ANNOTATE-BESIDE: **every row, every ★ paragraph and every dated clause above stands BYTE-FOR-BYTE and is read THROUGH this one; this clause adds no rule, moves no figure and re-reads all six at one tree.** **THE SIX, EACH WITH THE READING ITS OWN BYTES GIVE THIS DATE:** **(1) THE STATUS SET IS TWENTY** — `src/error.rs`'s `CODES` is `[&str; 20]`, ranks `1`…`20` (`§8.1`'s heading, its table's `20` row). **(2) THE KERNEL'S TOKEN SET IS NINE** — `bindings/js/src/entry/kernel-foundations.mjs`'s `KC` carries `KC-1`…`KC-9` and no tenth (§8.0a's `KC-9` clause). **(3) THE INSTANCE CARRIES FOURTEEN OWN MEMBERS** (§3.1's table; `index.d.ts`'s `StoreInstance`). **(4) THE DEPTH CEILING IS `126`** — `bindings/js/src/entry/carrier.mjs`'s `ENCODER_CEILING = 126` and `bindings/js/src/crossing.rs`'s `depth > 126` are ONE figure, with `127` and beyond refused at the walk and the node ceiling at `1,000,000` beside it (`§10.3`). **(5) THE ALLOWLIST IS SEVEN ROWS** — `index.mjs` · `README.md` · `README.guide.md` · `RELEASE-NOTES.md` · `index.d.ts` · `src/entry/` · `src/constraint-kernel.mjs`, `7 = 5 + 2` ✓ (the clause of 2026-10-28 above). **(6) THE PACKED MEMBER SET IS `20` BARE AND `21` ASSEMBLED** — measured with `npm pack --dry-run --json` at `bindings/js` this date: `1` `package.json` + `5` root files + `13` entry modules + `1` kernel `= 20` ✓, and the assembled artefact adds the release's `LICENSE` for `21` (the clause above). **AND THE VERSION IS `1.5.0` AT ELEVEN CELLS** (§0's clause of this date). **NO FIGURE MOVED BETWEEN THE `1.4.0` PREPARATION AND THIS ONE**, and the reason is named rather than left to inference: **the twenty-seven commits past `v1.4.0` add no member, no status, no token, no ceiling, no packed byte and no allowlist row** — they declare the reach, the two kinds, the derived address, the listener's independence, the delivery's nesting and the throw (`D-66` … `D-73`), and those are clauses of use rather than rows of this section. (`D-66`–`D-73`; §0's clause of this date; `scripts/publish.sh --figures`.)
1731
+
1329
1732
  **★ THE `exports` MAP HAS ONE ARM, AND THAT IS A PROMISE ABOUT WHAT IS REACHABLE:** **the addon is NOT reachable
1330
1733
  as a subpath and neither is the constraint kernel.** **There is no wildcard export, no deep import to the addon
1331
1734
  and no CJS arm** (`bindings/js/README.md`; `docs/specs/storeroom-publish/contract.md §1.3`;
@@ -1529,6 +1932,8 @@ tree sharing no mutable member with the store or with another crossing**, which
1529
1932
 
1530
1933
  **Neither window is new and neither is a defect**: both are places **a pass does not begin**, not places a judgement was skipped mid-flight.
1531
1934
 
1935
+ **⟶ AND ONE CLAUSE OF ITEM 1 ABOVE IS CORRECTED AT ITS OWN SITE, 2026-10-29 — `D-55` ITEM 3 AND `D-57`: A `delete` DOES MINT AN ATTEMPT NOW, AND THE WINDOW'S REAL REASON IS THE DELIVERY'S POSITION.** `RCA-8(g)` ANNOTATE-BESIDE: **item 1's operative claim — a listener invoked by a `delete`'s delivery runs no constraint pass, and a `rollback` raised there is unjudged and its effect stands — is UNMOVED; what is false of this tree is its given reason, *"there is no attempt for a pass to run over."*** **THE TREE AT `1.4.0`: a `delete` opens its own commit, its own attempt and its own pass, and its receipt carries the four-member `CommitRecord`** (`§7.8`'s clause; `D-57`'s second half; `D-55` item 3). **SO THE ATTEMPT EXISTS — IT HAS ALREADY CLOSED** — **and the window stays passless for the ruling's own reason: the delivery runs AFTER the pass, and after a pass nothing re-enters on that work** (`D-64`; `§7.8`'s four steps). **NOTHING ELSE OF ITEM 1, OF ITEM 2, OF THE EXITS OR OF THE WITNESS MOVES.** (`D-55` item 3; `D-57`; `D-64`; §7.8; §12.6's clause above.)
1936
+
1532
1937
  **⟶ AND THE SENTENCE THAT STOOD HERE IS WITHDRAWN AS FALSE, 2026-10-28 — `D-54`, MEASURED, AND IT IS WITHDRAWN RATHER THAN NARROWED. THE BYTES WERE: *"And every pass that DOES run drains its own restart request — so the fail-state is bounded by the two acts that run none."* THE CONSUMER MEASURED THREE HOSTS WHERE NEITHER HALF HOLDS — a repair body, a delete's pass, and a reentrant reversal-then-write — AND IN EACH ONE A PASS RAN, THE REVERSAL WAS LEFT UNJUDGED, AND ITS EFFECT STOOD (zero judge invocations; the refused `5` still there). What follows replaces them and is true of the code after that fix.**
1533
1938
 
1534
1939
  **THE RULE NOW, IN ONE SENTENCE: NO PASS CONSUMES A RESTART REQUEST IT DID NOT RAISE, AND A REQUEST RAISED INSIDE A PASS IS CARRIED TO THAT PASS'S OWN TERMINAL STATE AND JUDGED THERE — ONCE, AS `D-38` DECLARES, AND NEVER PER STEP.** The budget, its three asks, the failing-closed arm and `D-42` are exactly as they were; what changed is where the request is carried.