provident-storeroom 1.2.0 → 1.4.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.
@@ -0,0 +1,610 @@
1
+ # Release notes — `provident-storeroom` `1.1.0`
2
+
3
+ **⟶ THE FILE'S OPERATIVE READING, 2026-10-28 — THE HEAD IS CORRECTED HERE, AND THE DEFECT WAS ONE LEVEL IN: A DOCUMENT
4
+ DENYING THE STATE IT DESCRIBED.** `RCA-8(g)` ANNOTATE-BESIDE: **the title line above and every dated paragraph below
5
+ stand BYTE-FOR-BYTE as the reading of their own date; THIS clause and the `§MAIN` section beneath it are the operative
6
+ readings of the two things the head got wrong.** **(i) `1.2.0` IS NOT UNRELEASED.** `git tag --list` answers `v1.0.0` ·
7
+ `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"`
8
+ at its own bytes; and the registry carries `1.2.0`. **So the section that stood under *"UNRELEASED"* is the change list
9
+ of a CUT release, its *"no `v1.2.0` tag exists"* sentence and its *"what is installed today is still `1.1.0`"* sentence
10
+ are the reading of the date they were written, and its heading is corrected at its own line** — the withdrawn bytes are
11
+ recorded there, because a heading that denies its own tag is exactly the class of defect this project calls `DEF-AC`.
12
+ **(ii) THE PUBLISHED FIGURE IS `1.2.0`, NOT `1.1.0`, AND THE TREE READ HERE IS NINE COMMITS PAST THAT RELEASE WITH NO
13
+ TAG ON IT.** **So this file now carries a section for the tree that is not cut (`§MAIN`, prepared and marked so) beside
14
+ the section for the release that is (`§1.2.0`).** **No version is bumped, no manifest moves, and nothing in `§MAIN`
15
+ claims to be installable.**
16
+
17
+ **⟶ AND THE CUT-STATE IS DROPPED FROM THIS FILE, 2026-10-28 — `D-57`, THE ARCHITECT VERBATIM: *"Drop the cut-state."*** `RCA-8(g)` ANNOTATE-BESIDE: **the title line and every dated paragraph of this file stand BYTE-FOR-BYTE as the reading of their own date, THIS clause is the one that reads them, and not one byte is deleted.** **THE REASON IS STRUCTURAL AND IT WAS MEASURED THREE TIMES: 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 this file's own head was stale within minutes of the tag that falsified it. **SO EVERY SENTENCE BELOW THAT CLAIMS WHETHER SOME VERSION IS OR IS NOT CUT — *"PREPARED — NOT CUT"*, *"no `v1.3.0`"*, *"nothing in this section is cut"*, *"the release is not cut"*, *"what is installed today is still `1.1.0`"*, and each reading printed beside them — IS READ THROUGH THIS CLAUSE: the cut-state is not a document's to state.** **WHAT SURVIVES IS THE ONE FIGURE A SHIPPED DOCUMENT CAN BE RIGHT ABOUT, AND IT IS GENERATED FROM THE MANIFEST AND ASSERTED BY THE PREFLIGHT:**
18
+
19
+ PUBLISH-NOTES-VERSION-LINE: THE VERSION THIS CHANGE LIST DESCRIBES IS `1.4.0`.
20
+
21
+ **AND THE TAG SET SURVIVES AS A RECORD OF RELEASES — PAST TENSE, A LIST OF WHAT HAS BEEN CUT, NEVER A CLAIM ABOUT THE CURRENT ONE** (the record stands in `§1.4.0` below — the section this file's head called `§main` until it was re-cut to name the version it prepares, 2026-10-28 — beside the section for the tree this file describes). (`D-57`; `DEF-AC` (b) — `scripts/publish.sh --figures` generates that line from `bindings/js/package.json`'s `version` and refuses on any disagreement, in this file, in `bindings/js/README.md` and in the shipped guide: three documents, three version lines, one generator, one assertion.)
22
+
23
+ **THE ONE THING THIS DOCUMENT IS FOR: `1.1.0` IS A MINOR, AND THIS IS WHERE ITS BREAKING CHANGES ARE
24
+ DECLARED.** `1.0.1` was published as a PATCH and it carried behaviour changes a patch may not carry. The
25
+ architect ruled the remedy a MINOR — *"the next release is `1.1.0`"* (`strata/decisions.md` · `D-42` item `1`)
26
+ — so **`1.0.1` stands as published with a disclosed breach, and `1.1.0` carries the declaration.** This file
27
+ is that declaration. **It is not a changelog of everything that happened; it is the list of things that can
28
+ break you, each with what it did before and what it does now.**
29
+
30
+ **WHERE IT BELONGS, AND WHY IT IS AT THE REPOSITORY ROOT.** This note is at the packaging root's PARENT, not
31
+ inside `bindings/js/`: the main manifest's `files` allowlist does not name it and must not, so **it ships in NO
32
+ tarball.** It addresses a consumer deciding whether to move off `1.0.1`, so it must be readable BEFORE an
33
+ install and must cover the six packages at once — the main package and the five platform packages share one
34
+ version and one decision.
35
+
36
+ **⟶ AND THE PARAGRAPH ABOVE IS SUPERSEDED BY MEASUREMENT, 2026-10-28 — `DEF-AC`, AND THIS FILE NOW SHIPS.** `RCA-8(g)`
37
+ ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE and is the reading of its own date (the `1.1.0` cut, when
38
+ it did ship nowhere); it is read THROUGH this clause.** **THE DEFECT THE DOWNSTREAM FILED: the ONE behaviour change
39
+ `1.2.0` makes — a refused reversal's restore to the commit's OPENING mark — was declared in THIS FILE and in no
40
+ shipped document, so a consumer installing `1.2.0` received a behaviour change with no shipped declaration of it.**
41
+ **SO THE FILE IS LANDED THE WAY THE GUIDE IS LANDED**: `RELEASE-NOTES.md` at the repository root is the ONE authored
42
+ home, the release's assembly stages it **BYTE-FOR-BYTE** at the packaging root as `bindings/js/RELEASE-NOTES.md`,
43
+ and the main manifest's `files` allowlist **names it** — one additive documentation row beside `README.guide.md`,
44
+ staged by the same assembly step and admitted by the reachability rule's own declared non-code class. **A BARE
45
+ `npm pack` STILL WORKS** because the landed copy is a TRACKED, GENERATED file like `README.guide.md`: it is present
46
+ whether or not the assembly has run. **AND WHAT SHIPS IS THE CHANGE LIST, at `node_modules/provident-storeroom/
47
+ RELEASE-NOTES.md`.**
48
+
49
+ **THE VERSION THIS RELEASE DECLARES IS `1.1.0` AT ELEVEN SITES, MOVING TOGETHER** — the main manifest's
50
+ `version`, its FIVE exact `optionalDependencies` pins, and the FIVE `platforms/*/package.json` versions. **The
51
+ artefact is stamped from the manifest by `bindings/js/build.rs`, so `version()` answers `1.1.0`** and that is
52
+ the value to assert against, not the crate's own `Cargo.toml` version.
53
+
54
+ ---
55
+
56
+ ## §1.4.0 · **PREPARED** — what `1.4.0` carries: the seven commits on `main` past `v1.3.0`, and the one figure this section states
57
+
58
+ **⟶ THIS SECTION IS RE-CUT FROM THE HEADING IT STOOD UNDER, 2026-10-28, AND ITS FIGURES MOVED WITH THE ELEVEN CELLS.** `RCA-8(g)` ANNOTATE-BESIDE: **the heading that stood here was *"`## §main · **PREPARED** — the seven commits on `main` past `v1.3.0`, and the one figure this section states`"*, the withdrawn bytes are quoted there, and the four numbered items below stand BYTE-FOR-BYTE as the reading of their own date and are read THROUGH this clause.** **THE HEADING NOW NAMES THE VERSION THIS SECTION PREPARES — `1.4.0` — because the section below it, `§1.3.0`, is the change list of a release that IS cut, and a prepared section must say which version it prepares.** **AND IT STILL STATES THE VERSION AND NOT THE CUT-STATE, BECAUSE THE SECOND IS NOT A DOCUMENT'S TO STATE (`D-57`).**
59
+
60
+ **THE VERSION THIS TREE CARRIES IS `1.3.0` AT ELEVEN SITES** — `bindings/js/package.json`'s `version`, its five `optionalDependencies` pins, and the five `bindings/js/platforms/*/package.json` `version` fields — **the artefact is stamped from that manifest by `bindings/js/build.rs`, so `version()` answers `1.3.0`, and no version bump is in any of the commits listed here.** **THE RECORD OF RELEASES, PAST TENSE — the tags this repository has cut, and nothing about the tree you are reading:** `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0` · `v1.3.0`.
61
+
62
+ **⟶ AND THE PARAGRAPH ABOVE IS CORRECTED AT THIS LINE, 2026-10-28 — ITS FIGURE WAS `1.3.0` AND IS NOW `1.4.0`.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE as the reading of its own date (`v1.3.0`'s tag) and is read THROUGH this clause; not one byte of it is deleted.** **`bindings/js/package.json`'s `version` now reads `1.4.0`, its five `optionalDependencies` pins read `1.4.0` five times, and the five `bindings/js/platforms/*/package.json` `version` fields read `1.4.0` — ELEVEN CELLS, ONE VERSION, moved TOGETHER in this act — and `npm run build` stamps the artefact from that manifest, so `version()` answers `1.4.0` at the built artefact and at a package installed from it.** **AND THE TREE NOW STANDS NINE COMMITS PAST `v1.3.0`** — `git describe` reads `v1.3.0-9-gf579a5a` — **of which the two beyond the seven below change no behaviour**: `23ac519` regenerates the guide's cut-state sentence and `f579a5a` DROPS the cut-state from the shipped face, because `D-57` drops it. **THE TAG SET IS NOT TOUCHED BY THIS ACT AND REMAINS A RECORD OF RELEASES, PAST TENSE:** `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0` · `v1.3.0`. **AND NOTHING IN THIS SECTION CLAIMS WHETHER `1.4.0` IS CUT: the cut-state is not a document's to state, and `D-57` is why.** **AND THE PARAGRAPH BELOW — *"THE TREE STANDS EIGHT COMMITS PAST THAT TAG"* — STANDS AS THE READING OF ITS OWN DATE AND IS READ THROUGH THIS CLAUSE TOO: the count is NINE, and the two beyond the seven are `23ac519` and `f579a5a`.**
63
+
64
+ **THE TREE STANDS EIGHT COMMITS PAST THAT TAG** — `git describe` reads `v1.3.0-8-g8c0e671` — **and SEVEN of them change what this package does or what it declares.** **The eighth is `23ac519`'s regeneration of the guide's cut-state sentence, which is the sentence `D-57` drops and the reason it is dropped.** **THE SEVEN, DERIVED FROM THE TREE THEY LANDED ON, EACH STATED FOR A CONSUMER:**
65
+
66
+ **1 · ★ A PAIR IS ASKED FOR ACTS BELOW IT — THE PASS'S SET WIDENED TO THE ACT'S ANCESTORS (`D-56`), BECAUSE THE VALUE READ AT A PREFIX CONTAINS ITS SUBTREE.** **The architect, verbatim: *"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."*** **WHAT A CONSUMER SEES: a pair standing at `['tabs']` is now asked for a `delete` at `['tabs','landingPage']`** — it is handed the ACT's `address`, `tier` and `value`, so a refusal crosses as it would at its own address and the commit rolls back — **and the membership rule reads once: your pair is asked when THE ACT'S ADDRESS IS AT OR BELOW YOUR PAIR'S ADDRESS.** **A pair at a DESCENDANT of the act is still NOT asked, and its address then reads as absent.** **AND THE CONSEQUENCE THAT IS UNMISTAKABLE: a passing write now EMPTIES `pending`** — the pass's set now EQUALS the store's `triggered` set, which is exactly what the earlier exact-address rule refused to allow — **measured `1` → `0` on a passing write.** (`D-56`; `HL-8` item 1 and attempt-lifecycle `§2.4` item 5 (iv) are annotated beside in the guide, not rewritten.)
67
+
68
+ **2 · A `delete` IS AN EDITING VERB — ITS OWN ATTEMPT KIND, ITS OWN PASS, AND A DELIVERY AFTER THE JUDGEMENT.** **WHAT A CONSUMER SEES:** the `delete`'s receipt now carries a **non-enumerable `commit` member** — the same four-member `CommitRecord` a write's `K-2` mints (`attempt`, `op`, `triggered`, `pending`) — **so a delete can be read back through `K-4` and `K-5`, which now answer BY REFERENCE where they refused `NO-REF` before**; the record is **ADOPTED** by the entry, which stands the delete's own receipt in the leg slot for the pass and restores the enclosing leg in a `finally`; the **`pending` residue is one entry** (the returned set minus the handles the delete's own pass checked off), and the delivery fires **THE RESIDUE** rather than the whole returned set; and a `file`-tier delete **SAVES** — the terminal arm saves the delete's own op, so a fresh boot answers `AddressNotFound` where the bytes used to stand. **A DELETE THAT REMOVES NOTHING MINTS NOTHING** (`D-3`), **and a `rollback` keeps no attempt**, because a reversal appends no journal op and a fabricated ref would be a lie. **THE COMMIT IS A SCOPE, A LOG'S HOME, A SAFE-STATE UNIT AND A RECORD — NOT A KERNEL ITEM** (`D-57`'s second half: the kernel's surface stays `K-1`…`K-6`, and `K-7` `commitRemoval` is owed only if a consumer must drive a delete's attempt directly, which none can). (`D-57`; `D-3`; `D-44`; `D-53`; `DEF-AN`.)
69
+
70
+ **3 · FIVE SMALLER ITEMS, EACH A THING A CONSUMER SEES.** **A THROWN MESSAGE'S FORM IS IN THE LOG** (`D-55` item 1 · `DEF-AK`): the value a pair threw is PRINTED in the attempt's one `outcome` entry, named rather than silently stringified, and the crossed `message` stops claiming the value crosses. **AN ENTRY IS NEVER SHIPPED WITH AN EMPTY ADDRESS LIST** (`D-55` item 2 · `DEF-AH`). **A CLOSED RECORD IS SEALED AT HANDOFF** (`D-55` item 6 · `DEF-AO`): what a consumer holds is final. **THE DRAIN JUDGES THE STANDING STATE** (`D-55` item 6 · `DEF-AP`, and `D-54`'s withdrawn sentence): where two of your listeners each reverse inside one commit, the check judges the state the commit STANDS AT — both raises — and a pass that ends by throwing reaches the same judgement at the state the pass left. **AND A REFUSED EDIT UNDOES THE WHOLE COMMIT** (`D-55` · `DEF-AN`): a constraint-refused edit rolls back to the previous safe state with ALL edits in the commit undone — including a delete's. (`D-55`'s six clarifications; the four rows `dfa9fc7` settled; `strata/decisions.md` `D-55`.)
71
+
72
+ **4 · AND A SHIPPED SENTENCE WAS FALSIFIED BY ALL OF IT, AND IS CORRECTED AT ITS OWN HOME.** **The package's `README.md` said a `delete` and a `rollback` both perform no file I/O at any tier scope.** **A `delete` SAVES NOW** — a `file`-tier delete left the bytes standing and a fresh boot read the old value; the terminal arm saves the delete's own op, and a failed save is the write's arm with `KC-9`. **A `rollback` still performs no file I/O, because it has no op of its own to save at** — and that half of the sentence was never in doubt. (`1090e1e`; `bindings/js/README.md`'s own 2026-10-28 clause.)
73
+
74
+ ## §1.3.0 · **CUT AND PUBLISHED — tag `v1.3.0`** — what that release carries, ten commits past `v1.2.0`
75
+
76
+ **⟶ THE HEADING THAT STOOD HERE WAS *"`## §1.3.0 · **PREPARED — NOT CUT** — what `1.3.0` carries, ten commits past `v1.2.0``"*, AND IT IS CORRECTED AT ITS OWN LINE RATHER THAN ANNOTATED AROUND, 2026-10-28.** `RCA-8(g)` ANNOTATE-BESIDE: **the withdrawn bytes are quoted above, the section's body below stands BYTE-FOR-BYTE as the reading of its own date, and every reading in it that says the release is not cut is read THROUGH the head clause.** **THE DEFECT: the heading denied the release the tag names — `git tag --list` answers `v1.3.0`, the tag names a tree whose `bindings/js/package.json` reads `"version": "1.3.0"` at its own bytes, and the registry carries `1.3.0` — so a reader opening this file met *"PREPARED — NOT CUT"* over a published version.** **That is the `DEF-AC` class one level in, and it is the third iteration of the same class; `D-57` is the ruling that ends the recurrence.** (`D-57`; the head clause above.)
77
+
78
+ **★ THIS SECTION DESCRIBES A TREE NOTHING CAN INSTALL, AND IT IS MARKED BEFORE IT SAYS ANYTHING ELSE, BECAUSE A MARK
79
+ ADDED AFTERWARDS IS THE DEFECT THIS FILE JUST CORRECTED ONE SECTION DOWN.** **THE PUBLISHED RELEASE IS `1.2.0`**: `git
80
+ tag --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0`, the tag `v1.2.0` names a tree whose
81
+ `bindings/js/package.json` reads `"version": "1.2.0"` at its own bytes, and the registry carries that release. **THE TREE
82
+ THIS SECTION IS DERIVED FROM IS NINE COMMITS PAST IT** — `git describe` reads `v1.2.0-9-g989c216`, `git rev-list --count
83
+ v1.2.0..HEAD` reads `9`, and **no version bump is in any of those nine commits: the manifest still reads `1.2.0` at
84
+ eleven sites and no tag names this tree.** **SO THE HONEST READING IS THIS: A CONSUMER INSTALLING `1.2.0` GETS `1.2.0`'S
85
+ BYTES AND `1.2.0`'S CHANGE LIST (the section below); WHAT THIS SECTION DECLARES IS PREPARED AND NOT CUT, and a prepared
86
+ change is not a shipped one.** **No consumer can install any of it yet, and every figure this section prints is a
87
+ figure of the TREE and not of a tarball.**
88
+
89
+ **⟶ AND THE VERSION THIS SECTION DECLARES IS `1.3.0` AT ELEVEN SITES, PREPARED AND NOT CUT, 2026-10-28.** `RCA-8(g)` ANNOTATE-BESIDE: **the ★ paragraph above stands BYTE-FOR-BYTE as the reading of its own date and is read THROUGH this clause; the two sentences of it that the bump supersedes are named here rather than overwritten.** **THE MANIFEST AT ITS OWN BYTES THIS DATE: `bindings/js/package.json`'s `version` is `"1.3.0"`, all five `optionalDependencies` pins are `1.3.0` with it, and the five `bindings/js/platforms/*/package.json` `version` fields read `1.3.0` with them — ELEVEN SITES, ONE REBUILD — and the rebuilt artefact is stamped from that manifest, so `version()` answers `1.3.0`.** **SO *"no version bump is in any of those nine commits: the manifest still reads `1.2.0` at eleven sites"* IS THE READING OF ITS OWN DATE, AND THE BUMP IS THIS PREPARATION'S (a working-tree change, not a commit): the tree is `10` commits past `v1.2.0` — `git describe` reads `v1.2.0-10-g14787b5` and `git rev-list --count v1.2.0..HEAD` reads `10` — and the eleven sites read `1.3.0`.** **AND WHAT THIS SECTION IS AND IS NOT, SAID PLAINLY BECAUSE THE EASIER THING TO GET WRONG IS THAT A BUMP IS A RELEASE: `1.3.0` IS THE PREPARED VERSION — at the eleven sites and in the rebuilt artefact — and it is NOT A RELEASE. `git tag --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0` and no `v1.3.0`, the registry carries no `1.3.0`, and no consumer can install any of this until the architect cuts the tag.** **The published release remains `1.2.0`, and the section below remains its change list, unchanged and still marked CUT AND PUBLISHED.** (The shipped guide's two generated figures — `scripts/publish.sh --figures` — agree with this clause: the version line reads `1.3.0` and the cut-state sentence reads *"`v1.3.0` DOES NOT EXIST, SO THE RELEASE THIS GUIDE DESCRIBES IS NOT CUT"*.)
90
+
91
+ **IT DECLARES TWO BEHAVIOUR CHANGES A CONSUMER WILL FEEL, AND THEN FOUR SMALLER ITEMS. THE TWO COME FIRST BECAUSE THEY
92
+ ARE THE CONTENT.**
93
+
94
+ **1 · ★ THE MESSAGE LOG BELONGS TO THE COMMIT NOW — SO A CROSSED REPORT CARRIES MORE ENTRIES THAN `1.2.0`'S DID.**
95
+ **`AT `1.2.0`:** the `log` was the **ATTEMPT's** own list — the constraint-judged write inside a commit carried the
96
+ entries its own pass appended, and where an attempt was **nested** inside another (a write a constraint body makes, a
97
+ repair's own write) the enclosing report carried the **enclosing** attempt's list: the nested refusal's entries were not
98
+ in it, and on the arm the downstream filed (`DEF-AK`) the inner refusal's own entry was **REPLACED** rather than joined.
99
+ **NOW:** the list belongs to the **COMMIT** — it is taken once per commit off the kernel's frame stack, defined on the
100
+ `CommitRecord` under a symbol, and **every attempt in that commit holds a reference to it** — so **a crossed report
101
+ carries the entries of EVERY attempt in the commit**, including a nested write made by a constraint body, whose refusal
102
+ now shows its own `constraint-check` and `outcome` entries verbatim before the enclosing `outcome` entry. **A CONSUMER
103
+ DIFFING `1.2.0` AGAINST THIS RELEASE SEES A REPORT CARRY MORE ENTRIES** — and that is the whole change: what is refused,
104
+ what is restored, and which status crosses have not moved with it. **The one declared reach that is still a new list: a
105
+ listener's write opens a commit of its own** (*"the triggering commit already passed constraints"*), so its entries are
106
+ not in the triggering commit's list; and a pair body asked at a reversal's judgement names no commit, so a write that
107
+ body makes opens one.
108
+ **AND THE ENTRY'S `seq` IS THE POSITION IN THAT LIST — NOT THE STORE'S JOURNAL ORDINAL.** **`1.2.0`'s declaration said
109
+ *"the ordinal of the list it stands in"* and that sentence was read as the journal's** (`DEF-AI`, measured): a refusal's
110
+ entry carried `seq` `1` while the store's own journal counter read `41`. **They are two ordinals with two homes:
111
+ `JournalOp.seq` is the store's append ordinal that orders the store's record, and this `seq` orders the COMMIT's message
112
+ log and nothing else; neither equals the other by design.** **One repair write appends five entries in one list at `seq`
113
+ `1..5`, strictly increasing in array order** — the pass's `constraint-check`, the repair's `repair-run`, the repair's
114
+ `commit`, the re-run's `constraint-check`, and the terminal `commit`/`outcome` — **and no entry is ever minted from the
115
+ store's journal counter.** **Say it to yourself before you count: `log.length` is every entry of the COMMIT, not "how
116
+ many constraints were evaluated" and not "how many attempts this write made".**
117
+
118
+ **2 · ★ A REVERSAL RAISED INSIDE A PASS IS NOW JUDGED — THREE HOSTS CHANGED FROM "A PASS RAN AND THE REVERSAL'S EFFECT
119
+ STOOD" TO "REFUSED AND RESTORED".** **`AT `1.2.0`:** a reversal raised where a pass was running could be **left unjudged
120
+ with its effect standing**, and the shipped guide said so falsely: *"And every pass that DOES run drains its own restart
121
+ request — so the fail-state is bounded by the two acts that run none."* **That sentence is WITHDRAWN AS FALSE** (`D-54`;
122
+ measured by the downstream): **a pass no longer consumes a request it did not raise, and the request is carried to the
123
+ pass's own terminal state.** **The rule, quoted from the shipped guide:** ***"no pass consumes a restart request it did
124
+ not raise, and a request raised inside a pass is carried to that pass's own terminal state and judged there — once,
125
+ never per step."*** **THE THREE HOSTS, EACH MEASURED, BEFORE → AFTER:**
126
+ - **A REPAIR BODY'S REVERSAL** — the judge was asked the pairs `[9,7]` and never `[5]`, with `0` judge invocations and the
127
+ refused `5` standing; **now the pairs asked are `[9,7,5]`, the invocation count is `1`, the write crosses
128
+ `ConstraintPassRefused`, and the store reads `9`** — the refused value does not stand.
129
+ - **A REVERSAL INSIDE A `delete`'S CONSTRAINT PASS** — the same `[9,7]`/`0`/standing-`5` reading, and **now the same
130
+ `[9,7,5]`/`1`/`9`**, with the delete's own `discarded` witness reading `[]` because nothing was discarded.
131
+ - **A REENTRANT REVERSAL-THEN-WRITE** — the write used to answer with the reversal's effect standing at `5`; **now it
132
+ REFUSES and the store reads `9`.**
133
+ **AND THE TWO DECLARED PASSLESS WINDOWS STILL RUN NO PASS, WITH THEIR EXITS UNCHANGED: a `delete`'s LISTENER DELIVERY
134
+ (a listener invoked by a delete's delivery runs no constraint pass, so a reversal raised inside it is unjudged and its
135
+ effect stands, and the `discarded` witness reports the discard) and a REGISTRATION'S OWN EVALUATION (`addConstraint`'s
136
+ and `constraintRegister`'s evaluation of a supplied body runs no pass, so an action raised there is unjudged and its
137
+ effect stands).** **Their exits are the two the guide declares and they are unchanged: RELOAD THE FILE — a restore that
138
+ moved a `file`-tier version saves the restored image, so a fresh boot over that path returns to judged bytes — or
139
+ REGENERATE THE STORE, replaying your writes.** **A reversal raised by the listener a `delete`'s delivery fires INSIDE a
140
+ pass is a THIRD case and not the declared window: that pass's terminal check now asks the pairs at the state the
141
+ reversal left.** `D-42`, `D-38`'s once-per-terminal-state rule, the restart budget (`3`), its spend-and-never-reset rule
142
+ and its failing-closed arm are **untouched**; what changed is where the request is carried and who may consume it.
143
+
144
+ **3 · THE RESTORE NO LONGER REPORTS A SUCCEEDED WHOLE-COMMIT UNDO AS A FAILURE (`DEF-AJ`).** **`AT `1.2.0`:** a message
145
+ could say *"0 of the 1 address it moved stand again"* when **every** address stood: the restore verified each moved
146
+ address against the watch's **pre-reversal capture** while the store returned it to the **journal mark the commit cached
147
+ at its OPENING**, and on the restart arm the commit had already landed `7` before the reversal ran, so the mark's `9`
148
+ did not equal the capture's `7` and a complete whole-commit undo read as a failure. **NOW:** a successful restore counts
149
+ every measured address restored to the mark, a standing **past** the capture is recorded as a `wholeCommit` and spoken as
150
+ such with the baseline named, and **only a refused mark, a cacheless window or an unrestored address say NOT undone.**
151
+ The message's meaning is the thing that moved; nothing about what a refusal restores moved with it.
152
+
153
+ **4 · THE `discarded` WITNESS NAMES WHAT MOVED, NOT THE WHOLE WATCHED REGISTRY (`DEF-AM`).** A delete's `discarded`
154
+ carries `addresses` — the addresses the discarded check would have been asked at — and **those are now the addresses the
155
+ reversal actually MOVED, measured once against the standing the store holds, and not every address the registry
156
+ watches.** **Measured: two pairs in the registry, one moved, and the witness names one.** **The witness is still a
157
+ WITNESS and not a repair** — the delete answers what it answered, throws nothing, and the reversal's effect still
158
+ stands in that declared window — and it is still **non-enumerable** (`Object.keys` never shows it; a spread copy loses
159
+ it).
160
+
161
+ **5 · THE CHANGE LIST ITSELF NOW SHIPS IN THE TARBALL (`DEF-AC` (a)).** **`RELEASE-NOTES.md` is the SEVENTH row of the
162
+ main manifest's `files` allowlist**, staged **byte-for-byte** from this repository-root home to the packaging root as
163
+ `bindings/js/RELEASE-NOTES.md` by the release's assembly — the same mechanism that lands `README.guide.md` and the
164
+ `LICENSE` copy — and the preflight REFUSES a drifted landing. **So a consumer installing the next release has this
165
+ change list at `node_modules/provident-storeroom/RELEASE-NOTES.md`**, and the packed member set reads **`20` bare / `21`
166
+ assembled** (`1` manifest + `5` root files + `13` entry modules + `1` kernel = `20`, plus the licence at assembly).
167
+ **This is the half of `DEF-AC` that is already cut in `1.2.0` and it stays cut in this tree.**
168
+
169
+ **6 · THE PREFLIGHT GENERATES AND ASSERTS THE SHIPPED GUIDE'S VERSION LINE AND CUT-STATE (`DEF-AC` (b)).** **The
170
+ guide's version line and cut-state sentence used to be HAND-WRITTEN, which is how the guide came to deny the release it
171
+ travelled in.** **Now `scripts/publish.sh` GENERATES both from `bindings/js/package.json`'s `version` and `git tag
172
+ --list`, and its preflight REFUSES when the shipped guide's two marked lines disagree** — a hand-written *"IS NOT CUT"*
173
+ beside a generated *"IS CUT"* fails, and the generated line passes; `--figures` runs that one check read-only. **A
174
+ hand-written line that contradicts the manifest can no longer travel.**
175
+
176
+ **NOTHING IN THIS SECTION IS CUT, NO TAG NAMES IT, NO VERSION BUMP IS PROPOSED, AND THE ELEVEN VERSION SITES STAY AT
177
+ `1.2.0`.** **The two behaviour changes are declared here because a consumer must be able to read them BEFORE the cut and
178
+ must not be told they are in a tarball that does not carry them** — the same honesty the corrected head above owes.
179
+
180
+ **⟶ AND WHAT THE PARAGRAPH ABOVE SAYS ABOUT THE FIGURES IS SUPERSEDED BY THIS PREPARATION, 2026-10-28 — WHAT IT SAYS ABOUT THE CUT IS NOT.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph above stands BYTE-FOR-BYTE as the reading of its own date and is read THROUGH this clause.** **UNMOVED: *"NOTHING IN THIS SECTION IS CUT, NO TAG NAMES IT"* — `git tag --list` carries no `v1.3.0`, the registry carries no `1.3.0`, and a consumer cannot install any of this.** **SUPERSEDED: *"NO VERSION BUMP IS PROPOSED, AND THE ELEVEN VERSION SITES STAY AT `1.2.0`"* — the bump IS this preparation's, and the eleven sites read `1.3.0`** (the clause at this section's head states the manifest, the pins, the five platform manifests and the rebuilt artefact's `version()`). **The two behaviour changes are unchanged, and they are `1.3.0`'s content: what a consumer installing `1.2.0` gets is `1.2.0`'s bytes, and this section is the change list of the version being prepared, not of a released one.**
181
+
182
+ ---
183
+
184
+ ## §1.2.0 · **CUT AND PUBLISHED — tag `v1.2.0`** — what that release adds, derived from the tree
185
+
186
+ **⟶ THE HEADING THAT STOOD HERE WAS *"`## §1.2.0 · **UNRELEASED** — what the release in preparation adds, derived from
187
+ the tree`"*, AND IT IS CORRECTED RATHER THAN ANNOTATED AROUND, 2026-10-28.** `RCA-8(g)` ANNOTATE-BESIDE: **the withdrawn
188
+ bytes are quoted above and the section's body below stands BYTE-FOR-BYTE as the reading of its own date; every reading
189
+ in it that says the release is not cut is read THROUGH the head clause and the clause of 2026-10-28 at the end of this
190
+ section's opening paragraphs.** **THE DEFECT: a heading denying the release it describes is the `DEF-AC` class one level
191
+ in, and a reader opening this file met *"UNRELEASED"* over a version the registry carries.** **The tag is cut — `git tag
192
+ --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0` — and the release this section describes is published.**
193
+
194
+ **★ THIS SECTION DESCRIBES A RELEASE THAT HAS NOT BEEN CUT, AND IT IS MARKED SO IT CAN NEVER BE MISTAKEN FOR A
195
+ DECLARATION OF SHIPPED BYTES.** `bindings/js/package.json`'s `version` reads **`1.2.0`** at its own bytes this
196
+ date, all five `optionalDependencies` pins read `1.2.0` with it, the five platform manifests' `version` fields read
197
+ `1.2.0` with them — **eleven sites, one rebuild, and the artefact the manifest stamps answers `version()` =
198
+ `1.2.0`** — **and no `v1.2.0` tag exists: `git tag --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` and nothing else.**
199
+ **SO THE HONEST READING IS THIS: THE MANIFEST IS PREPARED AT `1.2.0` AND THE RELEASE IS NOT CUT — a prepared version
200
+ is not a released one, the tag is not cut until the architect cuts it, and no consumer can install any of this
201
+ yet.** **What `1.1.0` describes is still what is cut and published; what this section describes is the preparation,
202
+ derived from the tree on 2026-10-28, and the figure a reader checks against the registry today is still `1.1.0`.**
203
+
204
+ **AND WHAT SHIPS NOWHERE, SAID FIRST BECAUSE IT IS THE EASIEST THING TO GET WRONG: THIS FILE IS AT THE
205
+ REPOSITORY ROOT AND NO TARBALL CARRIES IT.** The main manifest's `files` allowlist names six rows — `index.mjs` ·
206
+ `README.md` · `README.guide.md` · `index.d.ts` · `src/entry/` · `src/constraint-kernel.mjs` — **and this document
207
+ is not one of them and must not be.** So a `npm install provident-storeroom` puts **no `RELEASE-NOTES.md`** on
208
+ disk: a consumer holding only `node_modules` has the package's own bytes and the shipped guide
209
+ (`README.guide.md`), and reaches this file only by reading the repository. **The same was already true of the
210
+ `1.1.0` declaration above and it is true of the `1.2.0` list below.**
211
+
212
+ **⟶ AND BOTH PARAGRAPHS ABOVE ARE RE-READ, 2026-10-28 — `DEF-AC`: THIS FILE SHIPS, AND IT IS THE CHANGE LIST A
213
+ CONSUMER OF `1.2.0` RECEIVES.** `RCA-8(g)` ANNOTATE-BESIDE: **the two paragraphs stand BYTE-FOR-BYTE as the reading
214
+ of their own date; THIS clause is the operative reading of BOTH the heading and the allowlist.** **(i) THE TAG IS
215
+ CUT:** `git tag --list` answers `v1.0.0` · `v1.0.1` · `v1.1.0` · `v1.2.0`, so **the `1.2.0` section's *"UNRELEASED"*
216
+ heading and its *"no `v1.2.0` tag exists"* sentence are the reading of the date they were written and are read
217
+ THROUGH this clause; the release is CUT, and this text travels in its tarball.** **(ii) THE ALLOWLIST NAMES SEVEN
218
+ ROWS, THIS FILE AMONG THEM:** `index.mjs` · `README.md` · `README.guide.md` · `RELEASE-NOTES.md` · `index.d.ts` ·
219
+ `src/entry/` · `src/constraint-kernel.mjs` — **the landed copy of this document is a TRACKED, GENERATED file at
220
+ `bindings/js/RELEASE-NOTES.md`, staged byte-for-byte from this authored home by the release's assembly, exactly as
221
+ `README.guide.md` is staged from `docs/guides/package-use.md`** (`scripts/publish.sh`'s notes stage; the preflight
222
+ REFUSES a drifted landing). **SO THE SENTENCE *"NO TARBALL CARRIES IT"* IS UNTRUE FROM THIS DATE AND IS READ THROUGH
223
+ THIS CLAUSE: a consumer installing `1.2.0` has this change list at `node_modules/provident-storeroom/
224
+ RELEASE-NOTES.md`.**
225
+
226
+ **WHAT HAS CHANGED SINCE `1.1.0`, IN FOUR ITEMS — ONE OF THEM A BEHAVIOUR CHANGE AND THREE OF THEM NOT.**
227
+
228
+ 1. **`DeleteRecord` GAINED `discarded` (ADDITIVE).** A delete's record carries a fifth own member beside
229
+ `address`, `op`, `tiers` and `triggered`: **`discarded`**, a list `0` or `1` long of `{ opId, addresses }` —
230
+ the reversal a delivery raised and the engine threw away, with the addresses the discarded check owed.
231
+ `discarded.length === 0` means the delivery discarded nothing. **It is a WITNESS and not a repair:** the
232
+ delete still answers everything it answered, throws nothing, mints no status, and the reversal's effect still
233
+ stands. **AND ITS ENUMERABILITY CONSEQUENCE IS PART OF THE DECLARATION, NOT A FOOTNOTE: `discarded` is
234
+ DECLARED as a member in `index.d.ts` and is NON-ENUMERABLE at runtime.** Measured on this checkout
235
+ 2026-10-28: a delete's record answers `Object.keys` as `['address','op','tiers','triggered']` — **four** —
236
+ while `Object.getOwnPropertyNames` answers **five**, `discarded`'s own descriptor being
237
+ `{enumerable: false, configurable: true, writable: false}`. **So `Object.keys` never shows it, and a spread or
238
+ `Object.assign` copy of a receipt LOSES it:** both were driven and neither copy carried the member. **Read the
239
+ witness off the record itself** — a consumer that copies a receipt loses the witness, and nothing throws when
240
+ it does.
241
+
242
+ 2. **THE ONE BEHAVIOUR CHANGE: A REFUSED REVERSAL NOW RESTORES TO THE COMMIT'S OPENING MARK, NOT THE JOURNAL'S
243
+ HEAD.** `restoreReversal` used to restore the journal's head, on the reasoning that *"a reversal appends no
244
+ journal entry, so that head describes the state that stood BEFORE the action"*. **That reasoning fails on the
245
+ restart arm**: the enclosing write's own op stands at the head when a listener's reversal runs, so the
246
+ compensation restored the write's LANDING and **a write that reported a refusal had left its own value
247
+ standing** (`DEF-AE`: `9` stayed `9` where the refused write should have restored `7`). **Now the opening
248
+ caches its mark — the journal's last valid op id, or the floor where the journal holds no entry — and the
249
+ restore hands that cached mark back.** Measured: the refusing arm leaves the store where the ATTEMPT found it
250
+ (`tests/e2e/def-ae-restore-mark.test.mjs`, cells `1`–`2`, and the seven refusing arms swept around them).
251
+ **A lawful reversal is unchanged**, and a lawful write still answers its record with its value standing.
252
+
253
+ 3. **`context.value`'S RESPONSIBILITY IS NOW DECLARED (NO BEHAVIOUR CHANGE).** `D-50`, the architect, verbatim:
254
+ *"If a constraint needs to look for the data at a given location, it can read()"*. **`context.value` is the
255
+ value the write verb returned** — a repair that lands elsewhere hands your body the value that op landed — **so
256
+ a constraint that cares about any other location reads it itself.** Nothing about the machinery moved; the
257
+ guide's `§7.6` now says it, and the same section now names the exact-address consequence beside it: **a pass
258
+ judges the pairs standing at the address it writes, so a pair at another address is not asked** (measured: a
259
+ pair at `['b']` asked `0` times by a write at `['a']`).
260
+
261
+ 4. **THE PASS'S STATE MACHINE IS PINNED BY CELLS (NO BEHAVIOUR CHANGE).** The architect's state machine — one
262
+ action, the checks in order, **a repair restarting the checks from `#1` because a repair can break a check
263
+ already passed**, and termination being structural rather than counted — is now measured property by property
264
+ through the entry (`tests/e2e/repair-restart-state-machine.test.mjs`, whose cells also print that a pass
265
+ evaluates exactly the pairs at the attempt's own address). **The behaviour is the behaviour `1.1.0` already
266
+ ships; what is new is that it is pinned, so a later move meets a red instead of a reader.**
267
+
268
+ **AND ONE NUMBER A CONSUMER MIGHT WANT, WITH ITS WARNING: THE RESTART BUDGET IS `3` AND IT NOW SAYS SO IN THE
269
+ GUIDE.** `RESTART_LIMIT = 3` at `bindings/js/src/entry/constraints.mjs:1366` has been the behaviour since
270
+ `1.1.0`; the shipped guide declared it nowhere, and the guide's `§7.7` now does. **This is a DECLARATION and not
271
+ a change** — the bound, its spend-and-never-reset rule and its fail-closed arm stand exactly as they shipped.
272
+
273
+ **NOTHING ELSE IN THIS LIST IS A BREAKING CHANGE, AND NOTHING IN IT IS CUT.** Items `1` and `2` are the two a
274
+ consumer can feel; `3` and `4` are declarations and pins. **When `1.2.0` is cut, this section is the declaration
275
+ it carries — and until then the six figures a reader checks are PREPARED at `1.2.0` and the tag is NOT CUT, so what
276
+ is installed today is still `1.1.0`.**
277
+
278
+ ---
279
+
280
+ ## §0 · What to do if you are on `1.0.1`
281
+
282
+ 1. **Re-read your refusal mapper.** Read §2 items `B-1`, `B-2` and `B-5` before you upgrade. **A status you
283
+ branch on has changed meaning and one has changed value.** If your mapper treats `FileCommitFailed` as "a
284
+ constraint refused my write", it is now WRONG: that code is the SAVE's alone.
285
+ 2. **Wrap `rollback` in your throw path.** It throws now (§2 `B-3`) where a total function was declared.
286
+ 3. **Stop assuming a refused attempt leaves the refused value.** It leaves the state before the attempt
287
+ (§2 `B-4`).
288
+ 4. **Add `op` to anything that reads a delete's record** (§2 `B-7`). The record grew a fourth member; a
289
+ delete's reversal is now reachable by that member's id.
290
+ 5. **Do not carry a handle, an address object or a store instance across the recovery exits in §3.** Those
291
+ exits are the consumer's act, and the package does not perform them.
292
+ 6. **If you pinned `<1.0.1`** — the answer to `1.0.1`'s breach — **`1.1.0` is the version that supersedes it.**
293
+ Pin `1.1.0`, not `1.0.1`: the four items `B-1`…`B-4` reached `1.0.1`'s bytes UNDECLARED, and you get them
294
+ either way.
295
+
296
+ **A NOTE ON `B-1`…`B-4` AND THE WORD "AT `1.0.1`".** Those four were already in `1.0.1`'s shipped bytes —
297
+ `src/error.rs`'s `CODES` reads `[&str; 20]` at the `v1.0.1` tag, not `17`. **So for each of them this file
298
+ gives the reading at `1.0.0` (what moved), the fact that `1.0.1` shipped the move UNDECLARED, and the
299
+ reading at `1.1.0` (which is the same behaviour, now declared).** A consumer already on `1.0.1` has absorbed
300
+ them; **`B-5` onward are what `1.1.0` changes under them.**
301
+
302
+ ---
303
+
304
+ ## §1 · The shape of the list, and where it exceeded the ruling's count
305
+
306
+ `D-42` item `1` named **FOUR** breaking changes. **Derived from the tree rather than from the ruling's count,
307
+ the list is ELEVEN.** Four were shipped in `1.0.1` (`B-1`…`B-4`); seven more land in `1.1.0` (`B-5`…`B-11`).
308
+ **The list exceeded `D-42`'s four at `B-5`**, and every addition below was measured at its own site — the
309
+ commits named beside each item are the ones that made the change.
310
+
311
+ | # | the change | shipped in |
312
+ |---|---|---|
313
+ | `B-1` | the emitted vocabulary `17 → 20` | `1.0.1` (undeclared) |
314
+ | `B-2` | a constraint-refused write's status is no longer `FileCommitFailed` | `1.0.1` (undeclared) |
315
+ | `B-3` | `rollback` went from total to partial: **it throws** | `1.0.1` (undeclared) |
316
+ | `B-4` | a failing attempt leaves the pre-attempt state (`9 → 5`) | `1.0.1` (undeclared) |
317
+ | `B-5` | a refused reversal is RESTORED, and its restore WRITES the file | `1.1.0` |
318
+ | `B-6` | a constraint check always runs inside an open commit | `1.1.0` |
319
+ | `B-7` | `DeleteRecord` gained `op` — a record's shape grew | `1.1.0` |
320
+ | `B-8` | a delete's journal before-state was captured at the wrong home | `1.1.0` |
321
+ | `B-9` | an external callback's call opens its OWN commit | `1.1.0` |
322
+ | `B-10` | an action inside an open commit RESTARTS the constraint check | `1.1.0` |
323
+ | `B-11` | a directly driven pass reports a restart as a REPORT, not a throw | `1.1.0` |
324
+
325
+ ---
326
+
327
+ ## §2 · The breaking changes, one line of "before" and one of "now"
328
+
329
+ ### `B-1` · The emitted status vocabulary grew `17 → 20`
330
+
331
+ **AT `1.0.0`:** `CODES` was `[&str; 17]` — ranks `1`…`17`, the last being `ValueRefusedAtBoundary`.
332
+ **`1.0.1` SHIPPED THREE MEMBERS UNDER A PATCH WITHOUT SAYING SO.**
333
+ **AT `1.1.0`:** the set is **`[&str; 20]`**, ranks `1`…`20`, and the three appended members are:
334
+
335
+ - **rank `18` `ConstraintBodyThrew`** — a constraint BODY threw, where the package's crossing used to answer
336
+ the store's own code for a body that failed;
337
+ - **rank `19` `ConstraintRefusedAtRegistration`** — the store refused a pair AT REGISTRATION;
338
+ - **rank `20` `ConstraintPassRefused`** — the ONE status a constraint's refusal of a `write` answers, and of
339
+ a `rollback` whose terminal state a pair refuses.
340
+
341
+ **WHAT BREAKS YOU:** a mapper with a closed `switch` over the seventeen old members now meets three values it
342
+ has no arm for, and `errorMessage(code, args)` resolves a clause for each. **NO RANK OF `1`…`17` MOVED**, so
343
+ an ordinal you already stored is still that member (`FileCommitFailed` is still rank `15`).
344
+ **ONE MEMBER IS NOT A CONSUMER'S TO SEE:** `ConstraintRefusedAtRegistration` is the store's and crosses only
345
+ where the store mints it.
346
+
347
+ ### `B-2` · A constraint-refused write's status is `ConstraintPassRefused`, not `FileCommitFailed`
348
+
349
+ **AT `1.0.0` (and under `1.0.1`'s undeclared change, before it):** a write a constraint refused crossed as
350
+ `FileCommitFailed` — **which is the STORE'S SAVE CODE, rank `15`** — so the status named a layer the failure
351
+ did not happen at.
352
+ **AT `1.1.0`:** the refusal crosses as **`ConstraintPassRefused`, rank `20`**, the pass's own member.
353
+ **`FileCommitFailed` STAYS the save's code and is produced by save failures ONLY.**
354
+ **WHAT BREAKS YOU:** the most likely break in this release. **A consumer who treated `FileCommitFailed` as
355
+ "a constraint said no" now reads a save failure as a constraint refusal.** The refusal's own `KC` token still
356
+ rides `log[].state`; it is one status for all eight tokens, not one per token.
357
+
358
+ ### `B-3` · `rollback` went from total to partial, and it THROWS
359
+
360
+ **AT `1.0.1`'s DECLARATION:** `rollback(opId): RollbackRecord` — **a total function that answers a record and
361
+ fails never.** It was already untrue of `1.0.1`'s code; **this file declares it against the code, which is
362
+ where the truth is.**
363
+ **AT `1.1.0`:** a reversal is JUDGED. **A `rollback` whose TERMINAL state a registered pair refuses THROWS
364
+ `{status: 'ConstraintPassRefused', message, log}` at rank `20`.** A LAWFUL reversal is unchanged — same
365
+ `{opId, undoneOps, restoredTo}`, three members, no throw, no new member. **The judgement is of the state the
366
+ reversal LEFT, never a per-step approval** — an unwinding composition passes through intermediate states no
367
+ constraint would approve.
368
+ **WHAT BREAKS YOU:** a call you could not fail now throws a plain object literal (never an `Error` subclass).
369
+ **AND THE THROW IS NOT THE WHOLE OF IT — SEE `B-5`: THE REVERSAL IS ALSO UNDONE.**
370
+ **THE JUDGEMENT IS NOT A WALK AND NOT FREE:** it takes a pre-reversal standing of every enabled pair's every
371
+ address before the store call and asks the terminal state after it. A store that registered no constraint
372
+ reaches no read at all, and the member is what it was.
373
+
374
+ ### `B-4` · A failing attempt leaves the PRE-ATTEMPT state, not the refused value
375
+
376
+ **AT `1.0.0`:** seed `5`, refused write `9`, repair `1` — **the store was left holding `9`, the value the
377
+ constraint REFUSED.** A per-op walk over the repair's op reversed it AND marked it compacted, so the second
378
+ call over the write's op was answered `RollbackCompacted` and undid nothing. **The floor law made the walk
379
+ unsound and the violation stood.**
380
+ **AT `1.1.0`:** the failing arm leaves **`5`** — the state before the attempt. **A plain rejection still
381
+ leaves it, a repair answering `{ok: false}` still leaves it, and a PASSING repaired write still lands its
382
+ repaired value and composes nothing.**
383
+ **WHAT BREAKS YOU:** if you compensated for the old residue in your own layer, **your compensation now
384
+ unwinds a state that is already unwound.** The composition reports one step per address it issued a call at,
385
+ and `report.rollback` carries what actually happened.
386
+
387
+ ### `B-5` · A refused reversal is RESTORED, and its restore WRITES THE FILE
388
+
389
+ **AT `1.0.1`:** the compensating undo cleared every tier and rewrote at `mem` — **so a `file`-tier value was
390
+ DESTROYED by a refusal that then told you every address stood again at its pre-reversal state** (measured by
391
+ the downstream at 200 of 200), **and the restore was in memory only, so a re-boot read bytes describing the
392
+ PRE-restore state.** *(Commits `00f90df`, `9e16c0e`, `bd0fd8c`.)*
393
+ **AT `1.1.0`:** the restore puts back **exactly the per-tier standing it captured** — a present capture writes
394
+ each tier at its own tier, most persistent first, so a shadow reconstructs; an absent capture becomes ONE
395
+ untiered delete, where `AddressNotFound` **is** the owed state; **no tier that stood is ever cleared.** It
396
+ **verifies the result and counts an address restored only if it is exact**, so the message cannot claim what
397
+ did not happen — where it fails it names the address, what stands, what was owed, and how many of the
398
+ addresses it moved stand again. It restores **from the store's own journal** (`restoreMark`), not from a JS
399
+ capture, so a mixed-depth shadow and a higher tier whose parent the reversal moved below it are now reachable.
400
+ **AND `bd0fd8c` MAKES THE FILE AGREEMENT REAL:** the restore takes a `file`-tier snapshot before and after the
401
+ replay, and **where a version standing at `Tier::File` moved it SAVES the restored image** with the store's one
402
+ writer — so a re-boot returns to JUDGED bytes.
403
+ **WHAT BREAKS YOU — TWO THINGS, BOTH NEW BEHAVIOUR:**
404
+ - **THE BYTES AT `cfg.filePath` ARE NO LONGER "the last successful `file`-tier write's and no other state".**
405
+ A refused reversal's restore is now a SECOND producer of them. **A consumer who diffs those bytes, hashes the
406
+ file, or watches its inode/mtime will see it move on a path that used to write nothing** — and where no
407
+ file-tier version moved, **no byte is touched and the inode and mtime stay put.**
408
+ - **THE ASYMMETRY, SAID PLAINLY RATHER THAN LEFT TO BE DISCOVERED: a SUCCESSFUL `rollback` persists NOTHING.**
409
+ Measured: `file` `a=1`, `file` `a=2`, rollback the second — memory reads `1`, the bytes still say `{"a":2}`,
410
+ and a fresh boot reads `2`. **A reversal writes no bytes; a restore now does.**
411
+ **AND A SAVE THAT CANNOT LAND IS REPORTED, NOT SWALLOWED.** `FileCommitFailed` propagates after the replay and
412
+ the refusal says the store restored its state IN MEMORY while its FILE WAS NOT UPDATED. **The status stays
413
+ `ConstraintPassRefused`; nothing is minted for it.** **A constraint BODY that throws at the judgement now fails
414
+ closed**: the reversal is restored and the log names the throwing pair, with the body's own rank-`18` status
415
+ crossing — the code says what happened, the treatment is the violation's.
416
+ **STILL NOT RESTORABLE, NAMED SO IT IS NOT ASSUMED:** mixed-depth shadows *(reached by `restoreMark` now)*; an
417
+ address whose parent the journal never resolved *(reported as residue rather than guessed)*; state changed by
418
+ an act the store does not journal; an entry a failed file-save removed.
419
+
420
+ ### `B-6` · No constraint check without an open commit — a check always runs inside one
421
+
422
+ **AT `1.0.1`:** a CHECK could run where NO commit was open. That one state was every remaining window on this
423
+ branch's list — a listener body's write at a descendant, a pass driven by hand (`open=0`/`live=1`), and the
424
+ restart's dependence on the write path being the consumer. *(Commit `846f5ea`.)*
425
+ **AT `1.1.0`:** **an open commit is the PRECONDITION of the check**, enforced **where the check runs, not where
426
+ it is called from** — a seam a driver can bypass is not an invariant. `runAttempt` wraps its whole pass in the
427
+ store's own commit scope: **the scope opens one if none is open, joins the one that is, and closes only what it
428
+ opened.**
429
+ **WHAT BREAKS YOU:** **a store that carries no such channel is REFUSED, not run uncommitted** — the invariant
430
+ fails closed before status moves, before an entry, before any body, and without minting a token. **So a
431
+ consumer or a harness that hand-drives a pass over a store lacking that seam now gets a refusal where it used
432
+ to run.** **MEASURED: the production write's nesting is UNCHANGED** — the count during the pass is one at the
433
+ body's ask and one after its nested write. **A pass you drive directly now carries `open 1` where it carried
434
+ `0`**, opening exactly one commit itself and returning to zero.
435
+
436
+ ### `B-7` · `DeleteRecord` gained `op` — a record's shape grew
437
+
438
+ **AT `1.0.1`:** `delete` answered **`{address, tiers, triggered}`** — three members, **and no identity.** The
439
+ act was already journalled and `rollback` already accepted its id, **but no caller could NAME the act, so no
440
+ caller could reverse it**: an act that cannot be named cannot be reversed. *(Commit `c25765c`.)*
441
+ **AT `1.1.0`:** `delete` answers **`{address, tiers, triggered, op}`** — `op` is the store's own `JournalOp`,
442
+ **the same member, at the same name and the same type, that `WriteRecord` carries**, so `rollback(record.op.opId)`
443
+ is the one route to reversing a delete.
444
+ **`op` IS `null` ON THE ARM THAT REMOVED NOTHING** (`tiers: []`): that arm appends no journal entry, so it names
445
+ no op — **`null` is the truth rather than a minted id no reversal could find.**
446
+ **WHAT BREAKS YOU:** an object-shape assertion (`Object.keys(...).length === 3`, a strict deep-equal, a
447
+ serializer with a closed schema) breaks. **And `null` does not fold to `undefined`** — it crosses as `null`
448
+ unchanged.
449
+
450
+ ### `B-8` · A delete's journal before-state was captured at the wrong home
451
+
452
+ **AT `1.0.1`:** the entry's before-state was captured at the WRONG HOME — `pair_home` resolved the first
453
+ standing version's link — **so a STRUCTURED target journalled an EMPTY before-state and its reversal restored
454
+ NOTHING AT ALL.** Scalars looked healthy, which is why it went unseen; an EMPTY-ADDRESS delete had the same
455
+ fate. *(Commit `c25765c`, the defect the `B-7` exposure had been hiding.)*
456
+ **AT `1.1.0`:** the capture is at the correct home, and **an empty-address delete captures the register and
457
+ reverses too.**
458
+ **WHAT BREAKS YOU:** **code that worked around the old behaviour** — a manual re-write after reversing a
459
+ subtree delete — now restores over a correction that already happened. The reversal restores the values AND
460
+ their tiers, scalar and subtree alike. **A SECOND reversal of the same op answers `RollbackCompacted`**, which
461
+ is the existing floor and not a new rule.
462
+
463
+ ### `B-9` · An external callback's call opens its OWN commit
464
+
465
+ **AT `1.0.1`:** the join rule said a nested call *"JOINS the extant commit rather than opening a second"* — it
466
+ was written to keep ONE ACT's machinery from double-counting itself, **and it conflated INTERNAL NESTING (the
467
+ package's machinery inside its own verb) with EXTERNAL RE-ENTRY (your function, which the package invoked,
468
+ calling back in).** A listener body's write reused the outer verb's commit, so a listener's write at a
469
+ DESCENDANT address left the ancestor pair unasked and the violating effect stood. *(Commits `98cb3ac`,
470
+ `835f09f`; rulings `D-45`, `D-46`.)*
471
+ **AT `1.1.0`:** **a listener body — and every one of the caller-code invocation sites — OPENS A NEW COMMIT**,
472
+ because that is what entering at the package surface means. **The discriminator is the COMMIT ID a call NAMES,
473
+ not an authorship the package infers:** a call that supplies a commit id **JOINS** that commit; **a call that
474
+ supplies none OPENS a new one.** `write`'s FOURTH position already carries the commit, so **the surface did not
475
+ grow a member — it grew a rule about one it has.**
476
+ **A REPAIR JOINS** — a repair is not a separate act at the surface, it is PART OF THE ATTEMPT BEING TRACKED, so
477
+ it stays inside the attempt's own commit and the commit's record still describes the repair it performed.
478
+ **WHAT BREAKS YOU — THE OBSERVABLE COUNTS MOVE:** a listener body's write now **opens a second commit**, so an
479
+ attempt-opened observer **fires TWICE where it fired once**, and the descendant address is now asked by the
480
+ listener's OWN attempt rather than the outer write's. **The outer commit's count is unchanged across the call
481
+ and the outer write's record is untouched.** An ordinary write with a pair body and a listener body inside it
482
+ still opens ONE commit. **ONE EXTERNAL FUNCTION STILL INHERITS, named rather than hidden: the attempt-opened
483
+ observer itself**, which is called inside the opening before it returns — marking it would let a self-writing
484
+ observer open a commit at every notification, unbounded.
485
+
486
+ ### `B-10` · An action inside an open commit RESTARTS the constraint check
487
+
488
+ **AT `1.0.1`:** a reversal issued INSIDE an open commit — from a listener body, from a constraint body — was
489
+ **UNJUDGED**, so its violating effect STOOD, **while the identical call one frame out was refused and
490
+ restored.** The conservative direction had become the permissive one. *(Commit `fd11eff`.)*
491
+ **AT `1.1.0`:** **an action performed inside an open commit STARTS THE CONSTRAINT CHECK OVER AGAIN** — the
492
+ check the action invalidated is **re-run from its FIRST pair against the state the action left**, so no
493
+ violating effect can stand unjudged and no body is invoked mid-unwind either, because the restart is a fresh
494
+ pass and not a judgement of a partial composition. **The step itself is still not judged at its instant**
495
+ (`D-40`'s gate stands: the watch keeps answering empty and no body runs there).
496
+ **WHAT BREAKS YOU:** **a violating reversal inside an open commit is now REFUSED and restored, where it used to
497
+ stand.** Measured: a listener body asked `[9,7,5]` and the write was REFUSED, store at `7`; a constraint body
498
+ the same; a LAWFUL act asked `[9,7,5]` with NO refusal and its effect stands. **TERMINATION IS BOUNDED RATHER
499
+ THAN ASSUMED: three restarts per terminal act**, the budget spent and not reset by actions raised inside a
500
+ restart, **and past it the check FAILS CLOSED in the same form.** **So a consumer whose body writes and
501
+ reverses in a loop now meets a refusal at the third restart instead of an unbounded pass.**
502
+
503
+ ### `B-11` · A directly driven pass LEARNS a restart from the REPORT, not from a throw
504
+
505
+ **AT `1.0.1`:** the restart's request was consumed by the WRITE's frame, **so a body's `rollback` inside a
506
+ directly driven pass was neither judged at its instant nor restarted, and the request died with its window.**
507
+ *(Commit `0ade6b3`.)*
508
+ **AT `1.1.0`:** the request is a store-side fact and **its consumer is the store's own commit scope** — one
509
+ mechanism, not two. `runAttempt` drains it after its pass answers, inside the same scope. **And a directly
510
+ driven pass learns it from the REPORT rather than a throw: the outcome becomes `failed` and the refusal's own
511
+ constraint-check entry joins the attempt's log with its REAL ordinal**, so `K-3` does not throw while `K-5`
512
+ answers the same object.
513
+ **WHAT BREAKS YOU:** **a harness that drove a pass by hand and expected a THROW now gets none** — it must read
514
+ `report.outcome` and `report.log`. **The refusal's compensating restore runs before the report is amended**, so
515
+ your store stands restored; what you must READ is the report, never a throw.
516
+
517
+ ---
518
+
519
+ ## §3 · The two known fail-states, and their exits
520
+
521
+ **These are DECLARED, not fixed.** `D-43` item `2`, the architect, verbatim: *"Known fail-state, file reloads /
522
+ client regenerates store to return to valid state."* **A known fail-state with a documented recovery is a
523
+ specification; an unreachable window with no exit is a defect.** **The declaration of record is
524
+ `docs/specs/storeroom-js/contract.md`'s clause of 2026-10-27 and it is restated here because a consumer of the
525
+ tarball reads this file.**
526
+
527
+ **THE TWO WINDOWS.** Each holds a commit and **runs NO PASS**, so a request raised inside it has no consumer
528
+ and dies with that window:
529
+ 1. **A `delete`'s listener delivery** — a delete consults no constraint, so the delivery runs with an open
530
+ commit and no check; a `rollback` a listener body issues there is a step whose check never runs.
531
+ 2. **A REGISTRATION's own evaluation** — `addConstraint`/`register` asks a pair's body inside the registering
532
+ verb's own commit window, at an instant no `K-2`/`K-3` attempt stands at, so a `rollback` a registration
533
+ body issues dies the same way.
534
+
535
+ **NEITHER WINDOW IS NEW, NEITHER IS A DEFECT, AND NEITHER IS AN UNREACHED CASE OF THE RESTART.**
536
+ **WHAT IS TRUE OF BOTH, SAID BEFORE THE EXIT: the reversal's own effect STANDS in the live instance — so the
537
+ absence of a refusal there is NOT an approval and must not be read as one.**
538
+
539
+ **EXIT 1 — RELOAD THE FILE.** **Construct a fresh instance over the same `cfg.filePath`.** The boot reads the
540
+ bytes at the path and nothing else. **AND SINCE `1.1.0` THIS RETURNS TO JUDGED BYTES RATHER THAN TO BYTES
541
+ DESCRIBING AN UNJUDGED STATE**: a restore that moved a version standing at `Tier::File` now SAVES the restored
542
+ image (§2 `B-5`). **What it does not carry:** the boot reads the last successful save and no other state — no
543
+ journal, no registration, no `mem` or `temp` version — and a reversal that moved only `mem`/`temp` nodes does
544
+ not save, so a reload does not carry it. **This exit is the store's declared boot semantics, not a general
545
+ undo.**
546
+
547
+ **EXIT 2 — REGENERATE THE STORE.** **Discard the instance and construct the store again from the same
548
+ configuration** — a `mem` register with no `filePath`, or a `file` register over the same path, which is exit
549
+ `1` as well. **The new instance is a judged state by construction**: no attempt, no open commit, no window
550
+ carried over.
551
+
552
+ **THE CONSUMER'S OBLIGATION IS THE SAME ON BOTH EXITS, AND IT IS THE POINT: the recovery is YOUR act; the
553
+ package neither performs it nor pretends to.**
554
+
555
+ ---
556
+
557
+ ## §4 · What did NOT break — so the reading is not taken wider than it is
558
+
559
+ - **THE FOURTEEN OWN MEMBERS ARE UNMOVED** — `{ read, readLiteral, write, delete, rollback, listen, unlisten,
560
+ addConstraint, constraintOn, constraintOff, register, constraints, removeListener, removeConstraint }`.
561
+ **No member was added and none was removed.** The module namespace keeps its ONE name, `storeCreate`.
562
+ - **NO POSITION, ARITY OR CLASS TEST MOVED.** `write`'s fourth position was READ for a new purpose and its
563
+ class domain is unmoved: it accepts the commit RECORD and refuses everything else in the one `TypeError`.
564
+ - **THE THROWN FORM IS THE SAME ONE FORM** — a plain object literal `{status, message, log}`, never an `Error`
565
+ subclass — and `ConstraintPassRefused` is a member of the SAME set, not a new shape.
566
+ - **REGISTRATION ORDER IS A GUARANTEE, NOT A LUCK.** `constraints()` emits by a MONOTONE REGISTRATION
567
+ SEQUENCE, kept through overwrite, toggle and restore, so five snapshots are element-wise equal and equal to
568
+ registration order. **This is new in `1.0.1` and it is a GUARANTEE, NOT A BREAK** — before it, *"no order is
569
+ promised"* and a toggle could perturb it. It is declared here because a consumer diffing snapshots relies on
570
+ it and because a later change would be a break.
571
+ - **NO TABLE ROW, RANK OR TRIGGER MOVED** inside ranks `1`…`17`.
572
+ - **THE CRATE'S VERSION IS NOT THE RELEASE VERSION.** `bindings/js/Cargo.toml` reads the crate's own `0.1.0`
573
+ and `version()` answers the RELEASE's. They are deliberately distinct.
574
+
575
+ ---
576
+
577
+ ## §5 · Where the authority lives
578
+
579
+ - **The declaration of record** is the tree under `docs/specs/` — chiefly `storeroom-js/contract.md` (the
580
+ package surface), `storeroom-native/contract.md` (the store), and `storeroom-publish/contract.md` (the six
581
+ packages' coupling). **This note is a CONSUMER SUMMARY of them and yields to them.**
582
+ - **The rulings** are `strata/decisions.md` — `D-42` (the minor, the four, the restart), `D-43` (a listener's
583
+ own commit, the known fail-state, a journaled and reversible delete), `D-44` (no check without an open
584
+ commit), `D-45`/`D-46` (a callback opens, a repair joins, the commit id decides), `D-41`/`D-40` (the
585
+ attempt's footprint and the step's gate).
586
+ - **The shipped guide** is `README.guide.md` INSIDE the main package — the assembly stages
587
+ `docs/guides/package-use.md` there BYTE-FOR-BYTE, so when you read it from `node_modules/provident-storeroom/`
588
+ it IS that document.
589
+
590
+ **THE SIX PACKAGES, ONE VERSION, ONE DECISION:** `provident-storeroom` and the five
591
+ `@auspicion/provident-storeroom-js-{linux-x64-gnu, linux-arm64-gnu, darwin-x64, darwin-arm64, win32-x64-msvc}`
592
+ all read **`1.1.0`**, and the main manifest's five `optionalDependencies` pins are EXACT `1.1.0` — no caret, no
593
+ tilde, no range. **A manifest that reads anything else anywhere is the wrong package.**
594
+
595
+ **STATUS OF THIS RELEASE'S OWN REHEARSAL:** the six tarballs were packed, a `1.1.0` install was driven in a
596
+ `/tmp` consumer with no repository in its ancestry, and `version()` answered `1.1.0` at the rebuilt artefact and
597
+ at the installed package. **No tag was cut, nothing was pushed, nothing was published, and no registry install
598
+ was witnessed** — a registry-installed `1.1.0` is described here from the manifest and from a locally packed,
599
+ installed artefact, and is still not witnessed as a registry download.
600
+
601
+ **⟶ AND THE TWO PARAGRAPHS ABOVE ARE `1.1.0`'S OWN READING AND ARE READ THROUGH THIS CLAUSE, 2026-10-28: AT THIS
602
+ TREE THE SIX FIGURES READ `1.2.0`, AND `1.2.0` IS PREPARED AND NOT CUT.** `RCA-8(g)` ANNOTATE-BESIDE: **both stand
603
+ BYTE-FOR-BYTE; what each says of `1.1.0` was true of the tree it was read on.** **THE SIX FIGURES, RE-READ AT THEIR
604
+ OWN BYTES THIS DATE: the main manifest's `version` is `"1.2.0"`, its five `optionalDependencies` pins are exact
605
+ `1.2.0` with it, and the five platform manifests' `version` fields are `1.2.0` with them — eleven sites, moving
606
+ together and never singly** (`PUB-DD-10`) — **so the rule the paragraph above teaches is UNMOVED and its figure is
607
+ `1.2.0`: a manifest that reads anything else anywhere is the wrong package.** **THE CUT, AND WHAT THIS FILE STILL
608
+ DOES NOT CLAIM:** `git tag --list` carries `v1.0.0` · `v1.0.1` · `v1.1.0` and no `v1.2.0`, so **`1.2.0` is PREPARED
609
+ at those eleven figures and the tag is not cut until the architect cuts it**; the bytes a registry install yields
610
+ today are `1.1.0`'s, and nothing here says otherwise.