provident-storeroom 1.2.0 → 1.3.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 +122 -3
- package/README.md +24 -8
- package/RELEASE-NOTES.md +584 -0
- package/index.d.ts +38 -2
- package/index.mjs +11 -3
- package/package.json +7 -6
- package/src/entry/constraints.mjs +402 -69
- package/src/entry/delivery.mjs +8 -2
- package/src/entry/kernel-attempt.mjs +136 -19
- package/src/entry/kernel-commit.mjs +26 -2
- package/src/entry/kernel-foundations.mjs +100 -8
- package/src/entry/kernel-registration.mjs +63 -22
- package/src/entry/kernel-terminal.mjs +18 -5
- package/src/entry/state.mjs +47 -4
package/README.guide.md
CHANGED
|
@@ -21,6 +21,18 @@ WAS DRIVEN AGAINST A PUBLISHED TARBALL:** every behavioural claim below is eithe
|
|
|
21
21
|
measurement taken on this repository's checkout and named as one. **No `npm install` was run by the pass that
|
|
22
22
|
wrote this file against the registry, so a registry-installed `0.5.0` is described here and not witnessed.**
|
|
23
23
|
|
|
24
|
+
**⟶ AND THE TWO FIGURES THIS GUIDE CANNOT AFFORD TO HAND-WRITE ARE GENERATED AND ASSERTED FROM 2026-10-28 — `DEF-AC` (b), AND THE ASSERTION IS THE DELIVERABLE.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph above stands
|
|
25
|
+
BYTE-FOR-BYTE and is read THROUGH this clause.** **THE DEFECT: the version line and the cut-state sentence below
|
|
26
|
+
were written BY HAND, which is how this guide came to deny the release it travels in** — a figure copied by hand
|
|
27
|
+
goes stale the moment the manifest or the tag set moves, and for eight dated paragraphs nothing reddened. **SO
|
|
28
|
+
`scripts/publish.sh` GENERATES BOTH from `bindings/js/package.json`'s `version` and `git tag --list`, and its
|
|
29
|
+
preflight REFUSES when these two lines do not read what it computed** (`scripts/publish.sh --figures` runs that
|
|
30
|
+
one check, read-only). **THE TWO LINES ARE THIS GUIDE'S OPERATIVE FIGURES; every dated paragraph below is the
|
|
31
|
+
reading of its own date and is read through them.**
|
|
32
|
+
|
|
33
|
+
PUBLISH-GUIDE-VERSION-LINE: THE VERSION THIS GUIDE DESCRIBES IS `1.3.0`.
|
|
34
|
+
PUBLISH-GUIDE-CUT-STATE: THE TAGS THIS TREE CARRIES ARE `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0`; `v1.3.0` DOES NOT EXIST, SO THE RELEASE THIS GUIDE DESCRIBES IS NOT CUT.
|
|
35
|
+
|
|
24
36
|
**⟶ CORRECTED 2026-10-26 — THE VERSION THIS GUIDE DESCRIBES IS `1.0.0`, NOT `0.5.0`, AND THE SENTENCE ABOVE STANDS
|
|
25
37
|
BYTE-FOR-BYTE AS THE READING OF THE DAY THIS FILE WAS WRITTEN AND IS READ THROUGH THIS CLAUSE** (`RCA-8(g)`
|
|
26
38
|
ANNOTATE-BESIDE; `DEF-2026-10-02`: no whole-file rewrite). **`bindings/js/package.json`'s `version` field read at its
|
|
@@ -49,7 +61,13 @@ measurements on a locally packed, installed artefact, and is still not witnessed
|
|
|
49
61
|
|
|
50
62
|
**⟶ AND THE RELEASE IN PREPARATION IS NOT THIS GUIDE'S VERSION, 2026-10-28 — THE MANIFEST IS `1.1.0`, AND THIS GUIDE CLAIMS NO `1.2.0`.** `RCA-8(g)` ANNOTATE-BESIDE: **the four dated paragraphs above stand BYTE-FOR-BYTE and are read THROUGH this clause; this clause re-reads one figure and adds one pointer, and moves no other claim of this file.** **THE FIGURE, AT ITS OWN BYTES, READ THIS DATE: `bindings/js/package.json`'s `version` is `"1.1.0"` and all five `optionalDependencies` pins are `1.1.0` with it** — the six figures move together and never singly (§0 item 1; `PUB-DD-10`) — **so `1.1.0` is the version this guide DESCRIBES, and it is the version an installed tree answers to.** **A RELEASE IS IN PREPARATION AND IT HAS NOT BEEN CUT: what it adds is listed in `RELEASE-NOTES.md` at the repository root, under a `1.2.0` heading MARKED UNRELEASED, and nothing in that section is a version this guide claims or a behaviour this guide measured as shipped.** **AND THAT FILE SHIPS NOWHERE:** it stands at the repository root and no tarball carries it (§11's `files` allowlist, six rows), so a consumer reading `node_modules/provident-storeroom` has this guide and the six figures of `1.1.0`, and the `1.2.0` list is a CHECKOUT reader's document. **The rule, in one line: this guide describes what was cut (`1.1.0`); `RELEASE-NOTES.md` describes what is being prepared (`1.2.0`, UNRELEASED); neither claims the other's figure.** (`D-41` item `1`; §11's manifest table reads the same six figures; `docs/specs/storeroom-publish/contract.md §2.3` item `3`.)
|
|
51
63
|
|
|
52
|
-
**⟶ AND THE FIGURES MOVE TO THE PREPARED RELEASE, 2026-10-28 — THE SIX FIGURES THIS GUIDE POINTS AT READ `1.2.0`, AND `1.2.0` IS PREPARED, NOT CUT.** `RCA-8(g)` ANNOTATE-BESIDE: **the five 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` and `1.1.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.2.0"` and all five `optionalDependencies` pins are `1.2.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.2.0` with them, which is eleven sites and one rebuild.** **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.2.0`; **every `0.5.0`, `1.0.0`, `1.0.1` and `1.1.0` this guide prints is the figure of its writing date and reads `1.2.0` from here on.** **AND WHAT THIS CLAUSE DOES NOT CLAIM, SAID FIRST BECAUSE IT IS THE EASIER THING TO GET WRONG: `1.2.0` IS PREPARED AT THOSE SIX FIGURES AND THE TAG IS NOT CUT — `git tag --list` carries `v1.0.0` · `v1.0.1` · `v1.1.0` and no `v1.2.0`, so nothing here says the release is cut, and the tag is not cut until the architect cuts it.**
|
|
64
|
+
**⟶ AND THE FIGURES MOVE TO THE PREPARED RELEASE, 2026-10-28 — THE SIX FIGURES THIS GUIDE POINTS AT READ `1.2.0`, AND `1.2.0` IS PREPARED, NOT CUT.** `RCA-8(g)` ANNOTATE-BESIDE: **the five 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` and `1.1.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.2.0"` and all five `optionalDependencies` pins are `1.2.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.2.0` with them, which is eleven sites and one rebuild.** **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.2.0`; **every `0.5.0`, `1.0.0`, `1.0.1` and `1.1.0` this guide prints is the figure of its writing date and reads `1.2.0` from here on.** **AND WHAT THIS CLAUSE DOES NOT CLAIM, SAID FIRST BECAUSE IT IS THE EASIER THING TO GET WRONG: `1.2.0` IS PREPARED AT THOSE SIX FIGURES AND THE TAG IS NOT CUT — `git tag --list` carries `v1.0.0` · `v1.0.1` · `v1.1.0` and no `v1.2.0`, so nothing here says the release is cut, and the tag is not cut until the architect cuts it.**
|
|
65
|
+
|
|
66
|
+
**⟶ AND THE TAG THAT CLAUSE SAID WAS ABSENT IS CUT, 2026-10-28 — `v1.2.0` EXISTS, AND IT IS THE RELEASE THIS GUIDE TRAVELS IN.** `RCA-8(g)` ANNOTATE-BESIDE: **the six dated paragraphs above stand BYTE-FOR-BYTE and are read THROUGH this clause — so does the sentence *"`1.2.0` IS PREPARED AT THOSE SIX FIGURES AND THE TAG IS NOT CUT … the tag is not cut until the architect cuts it"*; it was true of the tree it was written on.** **THE TAG AT ITS OWN NAME THIS DATE: `git tag --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0`; the tag `v1.2.0` names a tree whose `bindings/js/package.json` reads `"version": "1.2.0"` at its own bytes and whose five `optionalDependencies` pins read `1.2.0` with it; and `git describe` reads `v1.2.0-1-ge7c211f`.** **SO `1.2.0` IS CUT AND THIS GUIDE DESCRIBES IT — the text you are reading travels inside the `1.2.0` tarball, and a guide that told you its own release did not exist would be the denial this clause closes.** **`RELEASE-NOTES.md` at the repository root still heads its `1.2.0` section `UNRELEASED` and still says no `v1.2.0` tag exists; that file ships nowhere (§11's `files` allowlist, six rows) and its heading is behind the tag — this guide states what was cut, and what was cut is `1.2.0`.** **NO OTHER CLAIM OF THIS GUIDE MOVES: the `files` allowlist's six rows (§11), the packed set's nineteen-bare/twenty-assembled (§11), the twenty-status set (§11) and the fourteen own members all stand exactly as they stood.** (§0's figure rule; `docs/specs/storeroom-publish/contract.md §2.3` item `3` — the byte-for-byte guide stage this correction travels by.) **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.2.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 six rows (§11's dated re-read clause (i)), the packed set's nineteen-bare/twenty-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`; `D-48` · `DEF-AC`; `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 the tag coupling `release.md §2.5` puts AFTER them.)
|
|
67
|
+
|
|
68
|
+
**⟶ AND THE TREE THIS TEXT DESCRIBES IS NINE COMMITS PAST THE TARBALL IT TRAVELS IN, 2026-10-28 — THE MANIFEST IS `1.2.0`, `1.2.0` IS CUT AND PUBLISHED, AND `main` CARRIES BEHAVIOUR THAT IS NOT IN THAT TARBALL.** `RCA-8(g)` ANNOTATE-BESIDE: **the seven dated paragraphs above stand BYTE-FOR-BYTE and are read THROUGH this clause; this clause adds the one distinction none of them draws and corrects two sentences of the paragraph immediately above, and it moves no figure and no other claim of theirs.** **THE SIX FIGURES AND THE TAG, AT THEIR OWN BYTES THIS DATE:** `bindings/js/package.json`'s `version` is `"1.2.0"`, all five `optionalDependencies` pins are `1.2.0` with it, the five platform manifests' `version` fields read `1.2.0` with them — eleven sites, one rebuild — and `git tag --list` carries `v1.2.0`, **so the version line above is generated from exactly those two facts and it states that the release this guide travels in is CUT.** **AND THE TREE IS NINE COMMITS PAST THAT TAG:** `git describe` reads `v1.2.0-9-g989c216`, no version bump is in any of the nine commits, and **two of them change behaviour: `§8.0a`'s claim that the `log` belongs to the COMMIT — and that `seq` is the position in that list and not the store's journal ordinal — and `§12.6b`'s carry rule, that a reversal raised inside a pass is judged at that pass's terminal state, describe THIS TREE'S BEHAVIOUR AND NOT THE BEHAVIOUR OF THE `1.2.0` TARBALL** — `1.2.0` ships the per-attempt list and the sentence the carry rule withdraws. **So read this guide for what it is: it is the tree's text, and where it describes the two changes that are not in `1.2.0`, the change list at `node_modules/provident-storeroom/RELEASE-NOTES.md` is what tells you which release carries them — and until the next release is cut, nothing a consumer installs has them.** **AND THE TWO SENTENCES OF THE PARAGRAPH ABOVE THIS ONE THAT THIS CLAUSE CORRECTS:** *"that file ships nowhere (§11's `files` allowlist, six rows)"* is **false from 2026-10-28** — the change list is the allowlist's SEVENTH row and the release's assembly stages it byte-for-byte at the packaging root, so it ships (§11's `2026-10-28` clause (i)) — and *"its heading is behind the tag"* is **withdrawn at that file's own head**, where the `1.2.0` section is now marked **CUT AND PUBLISHED**. **THE VERSION LINE ABOVE IS NOT MOVED BY THIS CLAUSE AND MUST NOT BE: the manifest is `1.2.0` and `v1.2.0` exists, so the figure the preflight generates is the figure written there.** (`D-53`; `D-54`; `DEF-AI`; `DEF-AM`; `DEF-AJ`; the change list's `§MAIN`.)
|
|
69
|
+
|
|
70
|
+
**⟶ 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.)
|
|
53
71
|
|
|
54
72
|
**AND ONE THING A READER OF THE INSTALLED PACKAGE SHOULD KNOW BEFORE THE CITATIONS: WHEN THIS DOCUMENT IS AT
|
|
55
73
|
`node_modules/provident-storeroom/README.guide.md`, IT IS THIS GUIDE.** **Its ONE authored home is
|
|
@@ -439,9 +457,14 @@ guide's constraint story that is not yet observable.
|
|
|
439
457
|
1. **A reversal INSIDE an open commit is NOT judged.** If you reverse from inside a constraint body, a repair, a listener, or the kernel's own failing-attempt floor call, the state the reversal leaves is not the state that stands (the open window moves it again, and the caller sees nothing yet) — **and judging it would invoke your constraint bodies MID-ATTEMPT and break `D-40`'s promise that a failed attempt leaves the store as it found it.** **The judgement is the AT-REST reversal's: your own `rollback` at the surface, where the state it leaves is the state you then read.**
|
|
440
458
|
2. **A DISABLED pair is NOT judged.** A pair you `constraintOff`'d still appears in `constraints()`, but the judgement asks only pairs that are enabled — **because a disabled pair cannot fire, so nothing it would refuse can have run.** Re-enable it and it is asked again at the next reversal.
|
|
441
459
|
3. **A pair registered STRAIGHT THROUGH THE KERNEL'S `K-1` is NOT judged at a reversal.** The judgement reads the package's own registry, which the package's declared registration routes write — `cfg.constraints` at construction and `addConstraint` after it — while a pair placed by a kernel-direct call is evaluated at writes but is **not** in the state the judgement reads (and `constraints()` does not list it either). **Register through the package's routes and the promise covers you.**
|
|
442
|
-
4. **WHEN IT REFUSES AND NO ATTEMPT STANDS, `log` IS ONE `constraint-check` ENTRY — NOT `[]`.** The `log` member is normally *"the attempt's own message log"*, and `[]` is its value where a failure's cause has no attempt; **a reversal's judgement is one of those causes, and here the refusal AUTHORS ITS OWN RECORD instead of reporting an absence:** `log.length === 1`, `log[0].kind === 'constraint-check'`, `log[0].id` the refusing pair's own id, `log[0].state` `null`, `log[0].opId` the reversal's own op id or `null`. **So do not read an empty array as *"nothing failed"* at this arm, and do not read this one entry as an attempt's history — it is the refusal's.**
|
|
460
|
+
4. **WHEN IT REFUSES AND NO ATTEMPT STANDS, `log` IS ONE `constraint-check` ENTRY — NOT `[]`.** The `log` member is normally *"the attempt's own message log"*, and `[]` is its value where a failure's cause has no attempt; **a reversal's judgement is one of those causes, and here the refusal AUTHORS ITS OWN RECORD instead of reporting an absence:** `log.length === 1`, `log[0].kind === 'constraint-check'`, `log[0].id` the refusing pair's own id, `log[0].state` `null`, `log[0].opId` the reversal's own op id or `null`. **So do not read an empty array as *"nothing failed"* at this arm, and do not read this one entry as an attempt's history — it is the refusal's.** **⟶ AND FROM 2026-10-28 *"the attempt's own message log"* IS READ THROUGH `D-53` AS THE COMMIT'S OWN LIST** (§8.0a above): at this arm no attempt and no commit stands, which is what makes `[]` the wrong value here and one authored entry the right one.
|
|
443
461
|
**AND ONE THING ABOUT A FAILING REPAIR, WHICH IS THE SAME SHAPE AND IS DECLARED RATHER THAN DISCOVERED: THE FLOOR CALL RESTORES THE ADDRESS THE ATTEMPT WROTE; AN ADDRESS A REPAIR LANDED AT BESIDE IT IS NOT RESTORED.** `D-40`'s sentence — *"a failed attempt leaves the store exactly as it found it"* — is measured true of the attempt's own address and false of a beside address: the store's rollback scope is the addressed subtree at or after the named op's own position, so a repair that writes elsewhere leaves THAT value standing after the failed attempt. **If you need the beside address's pre-attempt value, keep it yourself: the store's own floor call does not put it back** (`docs/specs/storeroom-js/contract.md §2.6`'s clause of 2026-10-26, which is where the four narrowings, the `log` arm and this spatial scope are declared; `E2E-C-9` cell 6 in `tests/e2e/blind-constraints-v2.mjs` is the measured reach).
|
|
444
462
|
|
|
463
|
+
**⟶ 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.**
|
|
464
|
+
|
|
465
|
+
- **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.**
|
|
466
|
+
- **WHAT `1.2.0` CHANGED, IN ONE SENTENCE, SO YOU KNOW WHICH BEHAVIOUR YOUR VERSION HAS: BEFORE `1.2.0` THE RESTORE NAMED THE JOURNAL'S HEAD; FROM `1.2.0` IT NAMES THE OPENING MARK.** **Why the head was wrong is the measurement the ruling was taken on (`DEF-AE`):** *"a reversal appends no journal entry, so the head describes the state that stood before the action"* is true of a reversal **you** take at rest and **false of one taken inside a write's own commit** — there the ENCLOSING WRITE'S OWN OP stands at the head when a listener body's reversal runs, so the old compensation restored the write's LANDING and **a write that reported a refusal had left its own value standing** (measured: `9` stayed `9` where the refused write should have restored `7`). **In `1.2.0` a write that reports a refusal leaves the store where the ATTEMPT found it, not where the refusal's own op landed.** **A LAWFUL reversal is unchanged** (same `{opId, undoneOps, restoredTo}`, no throw), **and a lawful write still answers its record with its value standing.** **MEASURED ON THIS CHECKOUT, 2026-10-28:** a refused write restores the pre-attempt value at its own tier, and the reversal's own refusal restores the pre-reversal standing tier for tier (`tests/e2e/def-ae-restore-mark.test.mjs` cells `1`–`2`; `tests/e2e/refused-reversal-restore.test.mjs`'s shadow, higher-tier/parent and absent arms). **So the store after a refused reversal holds exactly the state the act FOUND — not a later landing that the refusal's own sentence has already told you was undone.**
|
|
467
|
+
|
|
445
468
|
---
|
|
446
469
|
|
|
447
470
|
## §6 · Watching for changes: the listener surface
|
|
@@ -732,6 +755,11 @@ body.**
|
|
|
732
755
|
|
|
733
756
|
**★ 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`).
|
|
734
757
|
|
|
758
|
+
**⟶ AND THE ARM PAST THE BUDGET NAMES THE PAIR THAT WAS BEING ASKED, AND SAYS WHAT IT IS, 2026-10-28 — `DEF-AL`, MEASURED AND CLOSED HERE.** `RCA-8(g)` ANNOTATE-BESIDE: **the two clauses above stand BYTE-FOR-BYTE and are read THROUGH this one; this clause re-reads what the refusal NAMES and what its `message` SAYS, and moves no status, no form and no bound.** **WHAT WAS MEASURED:** the arm named the FIRST WATCHED ADDRESS rather than the one the budget was spent at, **so registration order decided the accusation — the pair it named had answered `true` on every ask it received**, and the crossed `message` was **byte-identical to a genuine refusal's**, so a consumer reading only the message could not tell a pair refusing from a budget running out. **WHAT IT DOES NOW:**
|
|
759
|
+
- **the one `log` entry names the pair that was BEING ASKED when the budget ran out, and the address it was being asked at** — not the first watched address — **and its sentence says that pair refused nothing and that the check could not settle**;
|
|
760
|
+
- **the crossed `message` keeps the store's generated sentence for `ConstraintPassRefused` and then says, in its own words, that this is a RESTART BUDGET EXHAUSTION and NOT a constraint pair refusing a state** — no pair refused the state the check was asking it for, a pair body acted inside the check at every restart, and the budget is spent. **A GENUINE refusal never carries that clause**, so the two are distinguishable by the message alone.
|
|
761
|
+
**`status` stays `ConstraintPassRefused`, the form stays `{status, message, log}`, ONE log entry stands, and the store is still restored by the refusal's own compensating act.** (`D-42`; `D-41` item `4`; §7.7's bound above.) **MEASURED 2026-10-28, on this checkout, with a passing pair registered FIRST: the entry named the passing pair and the passing pair's address before this clause, and names the pair the check was asking and its own address after it; the crossed message said `'t5' was refused by a constraint pass, the state this act would leave is not one the registered constraints admit` before and carries the budget's own clause after — beside a control in which a genuine refusal still reads as its refusing pair's own sentence.**
|
|
762
|
+
|
|
735
763
|
**MEASURED 2026-10-28, ON THIS CHECKOUT, THROUGH THE PUBLISHED ENTRY — AND THE MEASUREMENT IS THE POINT: THE RESIDUAL IS THE BUDGET, NOT THE STATE AND NOT THE JOURNAL.** A pair whose body raises ONE FRESH REVERSAL on every ask the restart makes, **with every ask passing**, was driven twice: **with `60` fresh reversals available it rests at exactly `3` restart asks** (the listener's own action plus one per ask — `4` actions in all), **and with `40` available it answers identically, `3`.** **The body had `57` and `37` reversals it never got to spend, and nothing structural stopped it: every ask it made passed.** The terminal write then refused `ConstraintPassRefused` with its log entry saying the budget was spent.
|
|
736
764
|
|
|
737
765
|
**AND WHY THE BOUND EXISTS, SAID PLAINLY: NO STRUCTURAL STATE DISTINGUISHES A BODY THAT KEEPS REVERSING FROM ONE THAT MEANS TO.** The machinery cannot tell a loop from a caller with more work to do, so the restarts are COUNTED and the check fails closed instead of spinning.
|
|
@@ -769,6 +797,64 @@ attempt at all, and every failure whose attempt exists carries that attempt's ow
|
|
|
769
797
|
`unlisten`, `register` and `removeListener`: every one was an `Object` whose `Object.keys` was
|
|
770
798
|
`["status","message","log"]`, whose `log` was `[]`, and which was not an `Error` instance.**
|
|
771
799
|
|
|
800
|
+
### §8.0a What the `log` IS: one list per COMMIT — and what that buys you
|
|
801
|
+
|
|
802
|
+
**⟶ ADDED 2026-10-28. THIS SUBSECTION IS THE ONE THING TO KNOW ABOUT `log`, AND IT CHANGES WHAT YOU WILL SEE
|
|
803
|
+
IN IT.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE and is read THROUGH this
|
|
804
|
+
subsection.** **The architect, verbatim: *"If it's part of the same commit, then it uses the same message log.
|
|
805
|
+
If it opens a new commit, it uses the new commit's message log. Constraints/Repairs should always use the same
|
|
806
|
+
commit. Listeners should open a new commit, because the triggering commit already passed constraints"***
|
|
807
|
+
(`strata/decisions.md` · `D-53`).
|
|
808
|
+
|
|
809
|
+
**SO THE LIST BELONGS TO THE COMMIT AND NOT TO THE ATTEMPT.** One write is one commit, and everything that
|
|
810
|
+
commit does — the constraint passes that judged its value, a repair's own write, the re-run after that repair,
|
|
811
|
+
and the terminal arm's `outcome` entry — **appends to ONE array**. Consequences you can rely on, each measured
|
|
812
|
+
on this checkout:
|
|
813
|
+
|
|
814
|
+
- **`seq` runs `1..n` CONTINUOUSLY across those steps**, because it is *the ordinal of the list it stands in*
|
|
815
|
+
and there is one list. A repair's `commit` entry can stand in the middle of the list, between the refused
|
|
816
|
+
pass's entries and the re-run's: **it is a real entry of the same commit, not a second log.**
|
|
817
|
+
|
|
818
|
+
**⟶ AND WHAT `seq` IS TRUE OF, SAID PLAINLY, 2026-10-28 — `DEF-AI`, MEASURED.** **`seq` is the position of the
|
|
819
|
+
entry in the commit's own message log; it is not the store's journal ordinal, and the two differ by design.**
|
|
820
|
+
`RCA-8(g)` ANNOTATE-BESIDE: **the bullets above stand BYTE-FOR-BYTE and are read THROUGH this paragraph.** **THE
|
|
821
|
+
MEASUREMENT THAT OWES IT: a refusal's entry carried `seq` `1` while the store's own journal counter read `41`, and a
|
|
822
|
+
consumer read the two as one ordinal.** They are two ordinals with two homes — **`JournalOp.seq`, the store's
|
|
823
|
+
append ordinal that orders the store's record, and this `seq`, the kernel's append ordinal on the COMMIT's one
|
|
824
|
+
list** — and neither equals the other by construction. **AND THE ORDER ACROSS A COMMIT'S ATTEMPTS IS MEASURED, NOT
|
|
825
|
+
CLAIMED: one repair write appends the five entries `constraint-check` `1` · `repair-run` `2` · `commit` `3` ·
|
|
826
|
+
`constraint-check` `4` · `commit` `5` — strictly increasing in array order, continuous from `1`, across the pass,
|
|
827
|
+
the repair's own joined write and the re-run** (`tests/e2e/repair-in-commit.test.mjs`'s `D-46` (1) cell, printed).
|
|
828
|
+
**No entry is ever minted from the store's journal counter**: that would be a second ordinal with no consumer.
|
|
829
|
+
(`D-53`; `D-48` · `DEF-AI`; `index.d.ts`'s `LogEntry` carries the same sentence.)
|
|
830
|
+
- **A nested write a CONSTRAINT body makes is part of the same commit**, so **its entries are in YOUR list** —
|
|
831
|
+
which is why a constraint body that performs a refused write now shows you that refusal's own
|
|
832
|
+
`constraint-check` and `outcome` entries, verbatim, before the enclosing `outcome` entry. **That is `DEF-AK`'s
|
|
833
|
+
`constraint` host.** (Its `listener` host is unchanged, and the difference is the next bullet.)
|
|
834
|
+
- **A LISTENER's write OPENS A COMMIT OF ITS OWN**, so **its entries are NOT in the list of the commit that
|
|
835
|
+
triggered it**: *the triggering commit already passed constraints, so what the listener does is a new
|
|
836
|
+
question.* If you need to know what the listener's own write decided, catch the refusal the listener body
|
|
837
|
+
lets out — it carries **its own** `log`, and so does a refusal you throw out of a listener.
|
|
838
|
+
- **A failed `file`-tier SAVE now crosses WITH THE COMMIT'S ENTRIES — its `log` is no longer `[]`.** The save is
|
|
839
|
+
the write's LAST constraint: when it fails, the one `outcome` entry that ends your list carries **`KC-9`**,
|
|
840
|
+
and the entries before it are everything the commit did. **So a consumer can tell the two failing arms apart
|
|
841
|
+
from the log alone: `ConstraintPassRefused` ends at `KC-3`/`KC-5`/`KC-6`/`KC-8`, `FileCommitFailed` ends at
|
|
842
|
+
`KC-9`.** (See `§8.1`'s token line below — the kernel's set is `KC-1`…`KC-9` from this date, and the store's
|
|
843
|
+
closed status set has not moved.)
|
|
844
|
+
- **A refusal that names no attempt still carries `[]`** — a `listen` refusal, a construction refusal, a
|
|
845
|
+
detached member's — and a `TypeError` from a constraint method carries `[]` too. **The list is the COMMIT's
|
|
846
|
+
and there is no commit there.**
|
|
847
|
+
|
|
848
|
+
**READ THIS BEFORE YOU LOG-COUNT.** `log.length` is **not** *"how many constraints were evaluated"* and not
|
|
849
|
+
*"how many attempts this write made"*: it is **every entry of the commit**, in append order, from every attempt
|
|
850
|
+
the commit held. Count entries by `kind` and `id` (and by `opId` where you need the iteration) rather than
|
|
851
|
+
assuming a shape, because **a repair or a body's own write legitimately adds entries to the list you caught.**
|
|
852
|
+
|
|
853
|
+
**AND THE ONE PLACE THE INVARIANT IS NOT REACHED, SAID PLAINLY RATHER THAN LEFT TO A MEASUREMENT: a pair body
|
|
854
|
+
invoked at a REVERSAL's judgement has no commit record standing beside it to name**, so a write such a body
|
|
855
|
+
makes still opens a commit of its own and its entries land in that commit's list and not in the reversal's
|
|
856
|
+
refusal (`js/contract.md §2.6`'s `D-53` clause, item `6`).
|
|
857
|
+
|
|
772
858
|
**EVERY REFUSAL NAMES ITSELF** — by a `status` from the store's own closed set, and by a **human `message` that
|
|
773
859
|
carries the address, the domain, and what was found instead.** The message is generated from the code and the
|
|
774
860
|
failing trigger's arguments and never hand-authored at a call site
|
|
@@ -791,6 +877,17 @@ answers it again**, and the status stops naming a layer that did not fail. The a
|
|
|
791
877
|
own date and is read THROUGH this clause** (the guide's figures move with the set's own membership, which is
|
|
792
878
|
this section's own rule).
|
|
793
879
|
|
|
880
|
+
**★ AND THE KERNEL'S OWN TOKEN SET — the one that rides `log[].state` — GREW BY ONE ON 2026-10-28, WHILE THIS
|
|
881
|
+
SECTION'S SET DID NOT MOVE AT ALL.** **The architect, verbatim: *"Open the token set"*** (`strata/decisions.md` ·
|
|
882
|
+
`D-53`). **The kernel's states are `KC-1`…`KC-9` from this date; the appended member is the SAVE ARM's own,
|
|
883
|
+
`KC-9`, and `KC-8` keeps its declared meaning (the composition's floor) unmoved.** **WHY IT WAS OWED: a save
|
|
884
|
+
failure and a constraint refusal both ended at `KC-8` on the arm where the failed save's compensation met a
|
|
885
|
+
floor code, so `KC-8` crossed as two statuses and neither arm was derivable from the log's terminal state.** **So
|
|
886
|
+
now: a constraint's refusal ends at `KC-3`/`KC-5`/`KC-6`/`KC-8`, a failed save ends at `KC-9`, and the two are
|
|
887
|
+
told apart by the list you caught.** **NO MEMBER OF THE STORE'S CLOSED STATUS SET MOVES AND NO RANK OF IT
|
|
888
|
+
MOVES**: `KC-9` rides `log[].state` exactly as every other token does, and `status` still never carries a `KC`
|
|
889
|
+
spelling at all — the paragraph above's own law (`A120` (2)), unmoved.
|
|
890
|
+
|
|
794
891
|
**⟶ RE-DERIVED 2026-10-26 TO THE ARCHITECT'S RULING AND NOT TO THE BYTES** (`DEF-S` and `DEF-N`; the architect,
|
|
795
892
|
verbatim: *"Expand the returned error set for both S/N"*). **`StoreStatus` carries NINETEEN members, plus the open
|
|
796
893
|
escape arm `(string & {})`** — ranks `1`…`17` stand exactly as the paragraph below prints them, and the two
|
|
@@ -828,6 +925,13 @@ whose union stopped at `17` would mistype both.** **So: do
|
|
|
828
925
|
not `switch` on these without a `default`, and NEVER treat an unknown `status` as success.** The set is the
|
|
829
926
|
store's to close; **the package mints no member, widens no set and renames none.**
|
|
830
927
|
|
|
928
|
+
**⟶ AND AN INNER REFUSAL A CONSTRAINT BODY THREW NOW CROSSES BESIDE THE CROSSED ONE, 2026-10-28 — `DEF-AK`, MEASURED AND DECLARED.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE and is read THROUGH this one; no rank moves and no member is minted.** **WHAT WAS MEASURED: a LISTENER body propagates an inner refusal VERBATIM — same `status`, same `message`, same two-entry `log` — while a CONSTRAINT body making the IDENTICAL write had it REPLACED by a generated `ConstraintBodyThrew` whose single log entry was the OUTER attempt's, with the inner refusal's own literal occurring ZERO TIMES anywhere. WHICH HOST YOU WERE INSIDE DECIDED WHAT YOU WERE TOLD.**
|
|
929
|
+
- **`ConstraintBodyThrew` is still the `status` that crosses** — the body did throw, and rank `18` says so — **but the inner refusal is now REACHABLE from what you catch, under `Symbol.for('provident-storeroom.inner-refusal')`:** a non-enumerable own member carrying the value the body threw, so **its own `status`, its own `message` and its own `log` are all there to read.** `Object.keys(caught)` still reads `["status","message","log"]` — three members in the form's own order — and the form is unmoved.
|
|
930
|
+
- **AND THE CROSSED SENTENCE STOPS CLAIMING MORE THAN IT DELIVERS.** Its own bytes — *"a constraint body's throwable crosses as this refusal"* — now stand followed by **the package's own clause saying the value the body threw does NOT cross as this refusal, naming the inner `status` and quoting the inner `message`, and saying where the inner refusal crosses instead.** A body that threw something that is **not** a refusal (**a `TypeError`, a string**) has **nothing carried beside the crossed form**; there is no inner refusal to name, and the generated sentence names the CODE rather than promising a value.
|
|
931
|
+
- **A FORGED THREE-MEMBER OBJECT IS STILL NOT QUOTED.** The inner refusal is recognised by **a mark this package sets on the forms IT builds** — never by the shape a caller can spell — so a body throwing `{status, message, log}` of its own gets the generated sentence and nothing of its text is repeated back as though the package had found a refusal there (`DEF-A`'s protection, extended one layer in).
|
|
932
|
+
- **THE LISTENER ARM IS UNCHANGED, AND THAT IS THE CONTROL:** nothing marks a listener's throw, so it still crosses **as itself**, by identity — `caught === thrown`, its own `status`, `message` and `log`. **A `rollback` whose judgement a pair's body threw** crosses `ConstraintBodyThrew` at rank `18` and carries any inner refusal the same way (`§5.4`).
|
|
933
|
+
- **⟶ AND THE CONSTRAINT HOST'S LIST IS NOW THE COMMIT'S, WHICH IS THE DEEPER HALF OF THE SAME RULING (2026-10-28, `D-53`).** The inner refusal's own two entries are **IN the crossed report** — the `constraint-check` entry naming the inner pair and the `outcome` entry carrying `KC-3` — on the same array the enclosing attempt appends to, at a continuous `seq`; **`carriedInner.log` and `caught.log` are ONE array, not two.** **READ §8.0a ABOVE BEFORE COUNTING ENTRIES**: the listener's list is still its own, because the listener's write opens its own commit, and that difference between the two hosts is now the difference the ruling draws rather than an asymmetry nobody declared.
|
|
934
|
+
|
|
831
935
|
**AND `ValueRefusedAtBoundary` IS THE ONE YOU WILL MEET ON THE VALUE ROUTE:** the package's own walk decides a
|
|
832
936
|
value's class **before any store verb is called** and answers this member with the failing target's spelling
|
|
833
937
|
(§10). **`ValueNotAdmitted` stays at rank `14` and is the STORE's own answer on the native route — a pass that
|
|
@@ -1170,6 +1274,8 @@ a change of licence.**
|
|
|
1170
1274
|
|
|
1171
1275
|
**⟶ AND FOUR FIGURES OF THIS SECTION ARE RE-READ AT THE SHIPPED TREE, 2026-10-26, EACH AT ITS OWN SITE, SO THE ALLOWLIST IS NOT LEFT AT A COUNT THE MANIFEST NO LONGER CARRIES.** `RCA-8(g)` ANNOTATE-BESIDE: **every table row, every ★ paragraph and every figure above stands BYTE-FOR-BYTE and is read THROUGH this clause; THIS clause re-reads four figures and moves no rule of theirs — the reachability rule, the licence reading's ground and the `engines` floor all stand whole.** **(i) THE `files` ROW READS SIX ROWS, NOT FIVE** — `bindings/js/package.json`'s `files` array, read at its own bytes: `index.mjs` · `README.md` · `README.guide.md` · `index.d.ts` · `src/entry/` · `src/constraint-kernel.mjs` — **`6 = 4 + 2` ✓, the four root files plus the entry directory and the kernel** — and **the sixth row is the consumer guide's landed copy, `README.guide.md`, staged byte-for-byte from `docs/guides/package-use.md` by the release's assembly and imported by nothing** (`scripts/publish.sh`'s guide stage; `distribution.md §4.2` item 3's documented-text class). **THE TWO *"FIVE"* READINGS ABOVE — the table's own *"five rows"* and the ★ paragraph's *"THE FIVE ROWS ABOVE"* — are the reading of their own date and are read THROUGH this clause; and so is the licence paragraph's *"the five allowlist rows"*, whose subject is UNMOVED: NONE of the SIX rows is a `LICENSE` row, and none will be unless `D-8`'s evidence condition is met.** **THE RULE THE COUNT CARRIES IS UNMOVED EITHER WAY: whatever the entry requires by path must ship, and the count is a fact of this tree and not a contract.** **(ii) THE PACKED SET READS NINETEEN MEMBERS BARE AND TWENTY ASSEMBLED** — measured at the shipped packers: **the bare tarball carries `19` files** (`1` `package.json` + `4` root files + `13` entry modules + `1` kernel, `1 + 4 + 13 + 1 = 19` ✓, the guide standing among the four root files), **and the assembled artefact carries `20`, the nineteen plus `LICENSE`, which lands only in the assembled tree** — so a consumer comparing a bare `npm pack` tree with the release's artefact should expect exactly one member's difference and it is the licence. **(iii) AND THE GUIDE ITSELF NOW SHIPS:** **this document's canonical text reaches `node_modules/provident-storeroom/README.guide.md` in an installed package, beside `README.md`** — so a reader of the installed tree holds the document this file is, at that one path, and the landing adds no code, no export and no import. **(iv) THE STATUS SET IS TWENTY** — the figure `§8.1`'s heading and table print, and the one `§8.1`'s own dated clause and `§12.3`'s entry still spell `nineteen`: **each is read through the correction of this date at its own site, and the crate's own `CODES` is `[&str; 20]` at its bytes**, so the declaration of record and the crate agree at twenty.**
|
|
1172
1276
|
|
|
1277
|
+
**⟶ AND THE CHANGE LIST NOW SHIPS AND THE ALLOWLIST NAMES SEVEN ROWS, 2026-10-28 — `DEF-AC` (a), MEASURED.** `RCA-8(g)` ANNOTATE-BESIDE: **every row and every dated clause above stands BYTE-FOR-BYTE and is read THROUGH this clause; THIS clause re-reads three figures of this section and adds one document, and it moves no rule of theirs.** **(i) THE `files` ROW READS SEVEN ROWS, NOT SIX** — `bindings/js/package.json`'s `files` array, read at its own bytes: `index.mjs` · `README.md` · `README.guide.md` · `RELEASE-NOTES.md` · `index.d.ts` · `src/entry/` · `src/constraint-kernel.mjs` — **`7 = 5 + 2` ✓, the five root files plus the entry directory and the kernel** — and **the seventh row is the CHANGE LIST's landed copy, `RELEASE-NOTES.md`, staged byte-for-byte from the repository root by the release's assembly and imported by nothing**, the same mechanism and the same declared non-code class as `README.guide.md`. **NONE OF THE SEVEN IS A `LICENSE` ROW**, and none will be unless `D-8`'s evidence condition is met. **(ii) THE PACKED SET READS TWENTY MEMBERS BARE AND TWENTY-ONE ASSEMBLED** — **the bare tarball carries `20` files** (`1` `package.json` + `5` root files + `13` entry modules + `1` kernel, `1 + 5 + 13 + 1 = 20` ✓, the guide and the change list standing among the five root files), **and the assembled artefact carries `21`, the twenty plus `LICENSE`** — so a consumer comparing a bare `npm pack` tree with the release's artefact still expects exactly one member's difference and it is still the licence. **(iii) AND THE CHANGE LIST IS ON DISK IN AN INSTALLED PACKAGE**: `node_modules/provident-storeroom/RELEASE-NOTES.md` is **the declaration of `1.2.0`'s one behaviour change** — *"a refused reversal now restores to the commit's opening mark, not the journal's head"* — and **that is the row's own subject: a consumer receives the behaviour change WITH a shipped declaration of it, not a root document it can only reach by reading the repository** (`scripts/publish.sh`'s notes stage; the preflight REFUSES a drifted landing and refuses an allowlist that does not name it). **THE RULE THE COUNT CARRIES IS UNMOVED EITHER WAY: whatever the entry requires by path must ship, and the count is a fact of this tree and not a contract.**
|
|
1278
|
+
|
|
1173
1279
|
**AND THE `engines` FLOOR IS ONE DECLARATION WITH ONE READER — YOURS.** `>=18.0.0` is what the artefact loads on
|
|
1174
1280
|
and it is honest rather than provisional: the addon's highest-referenced Node-API class is the `napi_*` pair at
|
|
1175
1281
|
**Node-API version 6** (`Node 12.17.0` / `10.20.0`), read at `bindings/js/build.rs:35`–`:36`, and the ESM entry uses
|
|
@@ -1336,7 +1442,20 @@ tree sharing no mutable member with the store or with another crossing**, which
|
|
|
1336
1442
|
|
|
1337
1443
|
**THE SECOND EXIT — REGENERATE THE STORE.** Construct a new instance and replay your writes; **a judged state by construction.**
|
|
1338
1444
|
|
|
1339
|
-
**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.
|
|
1445
|
+
**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.
|
|
1446
|
+
|
|
1447
|
+
**⟶ 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.**
|
|
1448
|
+
|
|
1449
|
+
**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.
|
|
1450
|
+
|
|
1451
|
+
- **A PASS THAT RUNS TO ITS PASSING ARM** drains the request its bodies raised after the pass and before its commit closes — unchanged, and the arm this section always described.
|
|
1452
|
+
- **A PASS THAT ENDS BY THROWING** reaches the SAME judgement: a repair body that reversed and then broke the attempt's re-run, or a pair that refused after its delivery's act, is judged at the TERMINAL state the pass left, inside the same window, before you meet the pass's answer. **A pass's own refusal is superseded by the verdict of the check it invalidated — the state that pass left**; a constraint body's own throwable and a store's own refusal still cross as themselves, so no caller's value is re-shaped.
|
|
1453
|
+
- **A NESTED PASS NO LONGER DROPS AN ENCLOSING WINDOW'S REQUEST.** The restart's consumer compares window identities; where they differ it ASKS NOTHING AND TAKES NOTHING. The request stands for the act that raised it (`D-42` item `3`), and the enclosing pass's own check is the one that judges it. **A request no pass ever matches still dies with its window**, and the two passless windows below have their own answers.
|
|
1454
|
+
- **AND THE PACKAGE'S OWN COMPENSATING ROLLBACK IS NOT AN ACTION OF YOURS.** The kernel's terminal act composes the attempt's rollback through the `rollback` member; while it does, it carries a flag and neither raises a request nor is judged as a step — `D-42`: *"a restart is only ever raised by a consumer's own `rollback` member call."*
|
|
1455
|
+
|
|
1456
|
+
**SO THE FAIL-STATE OF PASS-HOSTED REVERSALS IS EMPTY, AND WHAT GUARANTEES IT IS ONE CONSUMER: the drain in the pass's own commit scope, reached on BOTH arms, matching the window that raised the request, and judging at the pass's terminal state.** The exits below are now owed to the two passless windows alone.
|
|
1457
|
+
|
|
1458
|
+
**YOUR `delete` QUESTION, ANSWERED HERE, AND IT IS A THIRD CASE AND NOT THE DECLARED ONE.** A `delete` runs **no constraint pass of its own** (`D-1-bis`); the window declared above is its LISTENER DELIVERY, which runs no pass and is UNCHANGED — the `discarded` witness still reports the discard and the reversal's effect still stands. **Where a `delete` is performed INSIDE a pass — the case the consumer measured — the delete's window IS that pass's window**, and a reversal raised by the listener its delivery fires is a DIFFERENT ACT AT A DIFFERENT INSTANT from the declared window: **a THIRD case, and it is now judged** — the request lands in the pass's window and that pass's terminal check asks the pairs at the state the reversal left. **A registration's own evaluation remains the second passless window, silent and identity-only** (`D-49`), and both exits below still leave it honestly.
|
|
1340
1459
|
|
|
1341
1460
|
**⟶ ADDED 2026-10-28 — `D-49`: THE DISCARD IS NOW OBSERVABLE ON THE `delete`'S OWN ANSWER, AND THE OTHER
|
|
1342
1461
|
WINDOW STILL CARRIES NOTHING. READ THIS BEFORE YOU RELY ON EITHER FAIL-STATE.**
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ reached INTERNALLY by the package's own resolution step and is not an entry poin
|
|
|
54
54
|
| `read(address, tier?)` | a leaf's literal, a branch's assembled value, or the empty address's whole register |
|
|
55
55
|
| `readLiteral(address, tier?)` | the same, narrowed to a leaf (`ReadTargetIsBranch` on a branch) |
|
|
56
56
|
| `write(address, tier, value, commit?)` | `{op, watched, triggered}` — **four positions, `commit` the fourth and optional** |
|
|
57
|
-
| `delete(address, tier?)` | `{address, tiers, triggered}` |
|
|
57
|
+
| `delete(address, tier?)` | `{address, op, tiers, triggered}`, plus a non-enumerable `discarded` witness |
|
|
58
58
|
| `rollback(opId)` | `{opId, undoneOps, restoredTo}` |
|
|
59
59
|
| `listen(handle, addresses)` | **the handle it watches under** (`Handle`) — **you spell it**, and position `2` is a SET |
|
|
60
60
|
| `unlisten(handle)` | `undefined` — the withdrawal: the store-side entry and this package's registry entry |
|
|
@@ -115,6 +115,17 @@ records, with the `outcome` entry's `state` carrying the `KC` token where the co
|
|
|
115
115
|
(`index.d.ts`, `LogEntry`; `surface.md §2.5` items 3–4). **The `message` is generated from the code and the
|
|
116
116
|
failing trigger's arguments**, never hand-authored at a call site.
|
|
117
117
|
|
|
118
|
+
**★ AND TWO THINGS ABOUT THAT LIST THAT A CONSUMER COUNTING IT NEEDS — DECLARED HERE BECAUSE THE SURFACE DOES NOT
|
|
119
|
+
TELL YOU EITHER BY ITSELF.** **ONE: THE LIST BELONGS TO THE COMMIT, NOT TO THE ATTEMPT.** One write is one commit,
|
|
120
|
+
and everything the commit does — the passes that judged its value, a repair's own write, the re-run after that
|
|
121
|
+
repair, the terminal arm's `outcome` entry — appends to **one** array, **so a crossed report carries the entries of
|
|
122
|
+
EVERY attempt in the commit, including a write a constraint body makes** (a listener's write opens a commit of its
|
|
123
|
+
own, so its entries are that new commit's). **`log.length` is therefore every entry of the commit and not "how many
|
|
124
|
+
constraints were evaluated".** **TWO: AN ENTRY'S `seq` IS THE POSITION OF THE ENTRY IN THAT LIST — NOT THE STORE'S
|
|
125
|
+
JOURNAL ORDINAL.** `JournalOp.seq` orders the store's own record; this `seq` orders the commit's message log, and
|
|
126
|
+
the two differ by design (a refusal's entry can carry `seq` `1` while the store's journal counter reads `41`). **The
|
|
127
|
+
kernel's `state` token set is `KC-1`…`KC-9`, `KC-9` being the save arm's own; the store's status set has not moved.**
|
|
128
|
+
|
|
118
129
|
## The status set is TWENTY, and open by design
|
|
119
130
|
|
|
120
131
|
**`StoreStatus` carries TWENTY members, ranked `1`…`20`, plus the open escape arm `(string & {})`** — the union
|
|
@@ -178,8 +189,9 @@ is REJECTED in both directions** — a listener and a constraint do not share on
|
|
|
178
189
|
constraint arm is declared, and none is owed.
|
|
179
190
|
|
|
180
191
|
**What a refusal costs you:** a write whose registered constraint refuses it **throws
|
|
181
|
-
`{status: 'ConstraintPassRefused', message, log}`** — rank `20` — with the failure's `log` carrying the
|
|
182
|
-
|
|
192
|
+
`{status: 'ConstraintPassRefused', message, log}`** — rank `20` — with the failure's `log` carrying the entries of
|
|
193
|
+
the write's whole commit (the attempt's own among them, and every attempt the commit held) and the kernel's `KC`
|
|
194
|
+
token on the `outcome` entry's `state`. **The value is not written
|
|
183
195
|
and a failed attempt leaves the store exactly as it found it**, whether the constraint refused outright or its
|
|
184
196
|
repair failed on the re-run (`D-40`).
|
|
185
197
|
|
|
@@ -268,8 +280,12 @@ empirically by `delivery` together with the e2e/install instruments. **No declar
|
|
|
268
280
|
exclusivity binds the allowlist** — a hand-maintained count in its place would re-create the constraint those
|
|
269
281
|
rulings lifted. **ONE DOCUMENTATION ROW IS ADDITIVE AND DECLARED AS SUCH:** `README.guide.md` names no module and
|
|
270
282
|
imports nothing, so it travels in the reachability rule's own declared non-code class (`README*` at the package
|
|
271
|
-
root) and no limb of that rule moves for it. **
|
|
272
|
-
|
|
283
|
+
root) and no limb of that rule moves for it. **AND A SECOND: `RELEASE-NOTES.md` is the change list, staged
|
|
284
|
+
byte-for-byte at the packaging root by the release's assembly, names no module and imports nothing, and is likewise
|
|
285
|
+
admitted and declared** — so the manifest's `files` allowlist reads **seven rows** and the packed set reads **`20`
|
|
286
|
+
members bare / `21` assembled** (`1` manifest + `5` root files + `13` entry modules + `1` kernel `= 20`, plus the
|
|
287
|
+
licence at assembly). **The prohibitions are unmoved:** no `.node`, no `build/Release` path and no `postinstall`
|
|
288
|
+
route in this package's own tarball, and no `LICENSE` row.
|
|
273
289
|
|
|
274
290
|
## Tests — a REPOSITORY instruction, not a consumer one
|
|
275
291
|
|
|
@@ -279,12 +295,12 @@ nothing by them. **A consumer's own tests are the consumer's.**
|
|
|
279
295
|
|
|
280
296
|
```sh
|
|
281
297
|
cargo test --manifest-path tests/Cargo.toml -p storeroom-tests --no-fail-fast # THE BATTERY'S LEG — 235 cells, 0 fail
|
|
282
|
-
cargo test --offline -p storeroom-native # THE STORE'S LEG —
|
|
283
|
-
cargo test # BOTH —
|
|
298
|
+
cargo test --offline -p storeroom-native # THE STORE'S LEG — 434 cells, 0 fail
|
|
299
|
+
cargo test # BOTH — 669 cells, 0 fail
|
|
284
300
|
```
|
|
285
301
|
|
|
286
302
|
**AND THE THIRD COMMAND IS NOT A FOURTH LEG:** a bare `cargo test` runs `default-members = [".", "tests"]`, so
|
|
287
|
-
it is EXACTLY the store's `
|
|
303
|
+
it is EXACTLY the store's `434` plus the battery's `235` — `434 + 235 = 669` ✓ — in one run (`D-34`: one
|
|
288
304
|
workspace at the repository root, `members = [".", "bindings/js", "tests"]`). **`-p` IS NOT DECORATION ON THE
|
|
289
305
|
BUILD SIDE EITHER:** the store's leg keeps `--offline`, and a workspace-root `cargo build --offline` would pull
|
|
290
306
|
this crate's `napi` crates and `--offline` would refuse them.
|