provident-storeroom 1.1.0 → 1.2.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 +80 -0
- package/index.d.ts +35 -0
- package/index.mjs +48 -6
- package/package.json +6 -6
- package/src/entry/constraints.mjs +205 -53
- package/src/entry/delivery.mjs +3 -2
- package/src/entry/frame.mjs +2 -1
- package/src/entry/kernel-attempt.mjs +7 -7
- package/src/entry/kernel-commit.mjs +2 -2
- package/src/entry/kernel-foundations.mjs +27 -3
- package/src/entry/state.mjs +69 -5
package/README.guide.md
CHANGED
|
@@ -45,6 +45,12 @@ date and reads `1.0.1` from here on.** **AND THE ONE THING NO PASS WITNESSED IS
|
|
|
45
45
|
run against the registry, so a registry-installed `1.0.1` is described here from the manifest and from
|
|
46
46
|
measurements on a locally packed, installed artefact, and is still not witnessed as a registry download.**
|
|
47
47
|
|
|
48
|
+
**⟶ AND THE FIGURE THE PARAGRAPH ABOVE CARRIES IS ITSELF ONE RELEASE BEHIND THE TARBALL IT DESCRIBES, 2026-10-28 — THE VERSION THIS GUIDE DESCRIBES IS `1.1.0`, `1.1.0` HAS BEEN CUT, AND EVERY `1.0.1` THIS GUIDE PRINTS READS `1.1.0` FROM HERE ON.** `RCA-8(g)` ANNOTATE-BESIDE: **the three dated paragraphs above stand BYTE-FOR-BYTE and are read THROUGH this clause — so do their readings of `0.5.0`, of `1.0.0` and of `1.0.1`; each was true of the tree it was read on and each is one release behind the shipped tree from this date.** **THE PARAGRAPH THAT OWES THIS IS QUOTED AT ITS OWN BYTES, because a guide that denies its own tarball is the defect this clause closes — `D-48` · `DEF-AC`: *"THE VERSION THIS GUIDE DESCRIBES IS `1.0.1`, AND EVERY `1.0.0` THIS GUIDE PRINTS READS `1.0.1` FROM HERE ON … the tags the tree carries are `v1.0.0` and `v1.0.1`, with `main` sixteen commits past `v1.0.1` and no version bump in any of them (`git describe` at this date reads `v1.0.1-16-gdf3ef88`; `D-41` item `1`'s semver ruling names the next release `1.1.0`, and that release has not been cut)."*** **THE TARBALL DENIES EVERY FIGURE OF THAT SENTENCE, AND IT IS THE FILE THE GUIDE TELLS YOU TO READ: `bindings/js/package.json`'s `version` is `"1.1.0"` at its own bytes, all five `optionalDependencies` pins are `1.1.0` with it, the tags the tree carries are `v1.0.0` · `v1.0.1` and `v1.1.0`, `git describe` reads `v1.1.0-1-gcbc3f8a`, and `D-41` item `1`'s minor has been RELEASED rather than awaited.** **SO THE SITES ARE RE-READ, NOT RE-SPELLED:** §0's two paragraphs above, §2.2's five exact pins, §8.1's *"an installed `0.5.0`"* — itself already corrected to `1.0.0` and then to `1.0.1` — and §11's manifest table all read `1.1.0`; **every `0.5.0`, `1.0.0` and `1.0.1` this guide prints is the figure of its writing date and reads `1.1.0` from here on**, and the six figures — the main `version` and the five pins — move together and never singly (§0 item 1; `PUB-DD-10`). **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.1.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.** (`strata/decisions.md` · `D-48` · `DEF-AC`; `D-41` item `1`; `D-42` item `1`; `D-38`; `docs/specs/storeroom-publish/contract.md §2.3` item `3` — the byte-for-byte guide stage this correction travels by.)
|
|
49
|
+
|
|
50
|
+
**⟶ 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
|
+
|
|
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.** **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.)
|
|
53
|
+
|
|
48
54
|
**AND ONE THING A READER OF THE INSTALLED PACKAGE SHOULD KNOW BEFORE THE CITATIONS: WHEN THIS DOCUMENT IS AT
|
|
49
55
|
`node_modules/provident-storeroom/README.guide.md`, IT IS THIS GUIDE.** **Its ONE authored home is
|
|
50
56
|
`docs/guides/package-use.md` in the repository, and the release's assembly stages it byte-for-byte at the packaging
|
|
@@ -688,6 +694,50 @@ filter nothing on one.** **There is no read-side enforcement arm, none is declar
|
|
|
688
694
|
writes and on nothing else** — and **reads consult no constraint's verdict, filter nothing on one, and refuse
|
|
689
695
|
nothing because of one.**
|
|
690
696
|
|
|
697
|
+
### §7.6 ★ `context.value` is what the write verb returned — read anything else yourself
|
|
698
|
+
|
|
699
|
+
**★ THE ONE SENTENCE TO CARRY AWAY: `context.value` is the value the write verb returned; a constraint that
|
|
700
|
+
cares about another location reads it.** (`D-50`, the architect, verbatim: *"If a constraint needs to look for
|
|
701
|
+
the data at a given location, it can read()"*.)
|
|
702
|
+
|
|
703
|
+
**AND THE CASE THAT MAKES IT MATTER IS A REPAIR THAT LANDS SOMEWHERE ELSE.** A constraint that refuses `2` at
|
|
704
|
+
its own address `['a']` returns a repair that writes `11` at a *different* address `['b']`. **The repair's op is
|
|
705
|
+
the attempt's last op, so the re-run hands your body the value that op landed — `11` — while the address your
|
|
706
|
+
pair judges still stands at `2`.** **That is not a machinery defect: it is the value the write verb returned, and
|
|
707
|
+
the package cannot be wrong about a value it was told to hand over — it can only be wrong about what it stored.**
|
|
708
|
+
**If your constraint cares about the state at any other location — the address it judges, the address its repair
|
|
709
|
+
landed at, or anywhere else — IT READS THAT LOCATION.** The body is your code, it closes over the store handle
|
|
710
|
+
you already hold, and `store.read(address)` is a published verb. **Measured 2026-10-28**
|
|
711
|
+
(`tests/e2e/discard-witness.mjs`, the `W8` cell): the re-run handed the pair `11` while its own address read
|
|
712
|
+
`2`; **the same body with `store.read(['b'])` refused on what it read** — the write failed and the store was
|
|
713
|
+
restored — **and the same body without the read passed, answering its record with its own value still standing at
|
|
714
|
+
its address.** **The read is the whole difference.**
|
|
715
|
+
|
|
716
|
+
**★ AND THE CONSEQUENCE A READER GETS WRONG, IN `D-50`'S OWN WORDS: *"a constraint that reads inside its body is
|
|
717
|
+
caller code entering the surface, so by `D-45` that read opens its own commit"* — **⟶ MEASURED 2026-10-28, AND THAT CLAUSE IS WRONG: A READ BRACKETS NO COMMIT AT ALL.** `read`, `readLiteral` and `constraints` are the surface's **NON-BRACKETING** calls — the count during a constraint body's read is the attempt's own and is left undisturbed, `attempt-opened` does not fire for it, and the same `attempt` is in force. **So the accurate consequence is the shorter one: a read inside a body runs INSIDE the attempt's window, opens nothing, and disturbs nothing.** (The `D-45` quote above is kept as the reading of its own date; this sentence governs.) — AND A READ RUNS NO CHECK, SO
|
|
718
|
+
NOTHING IS JUDGED BY IT.** **No constraint is asked on the value it returns, no pass runs, and the value you
|
|
719
|
+
read back is never a verdict.** **AND THE COUNT'S OWN RULE IS WHERE THE ACT'S SHAPE IS VISIBLE — MEASURED
|
|
720
|
+
2026-10-28 AT THE `W8` CELL, ON BOTH SIDES OF THE READ: `read`, `readLiteral` and `constraints` are the surface's
|
|
721
|
+
NON-BRACKETING calls — no commit is bracketed for them — so the count during your read is the attempt's own
|
|
722
|
+
(`open` `1`, `live` `1`) and it is left undisturbed (`open` `1`, the same attempt).** **THE DECLARED SENTENCE IS
|
|
723
|
+
THE AUTHORSHIP — the read is not the write's act — and the count shows what that authorship costs: nothing is
|
|
724
|
+
opened and nothing is judged for it.** **So the load-bearing half for you is the authorship and the absence of a
|
|
725
|
+
check: your read is your own act at the surface, it carries no judgement, and it neither re-asks a constraint nor
|
|
726
|
+
re-runs the pass. A read is data, never a verdict — if you want a state judged, read it and judge it in your
|
|
727
|
+
body.**
|
|
728
|
+
|
|
729
|
+
**⟶ AND THE PASS ASKS EXACTLY THE PAIRS STANDING AT THE ADDRESS IT WRITES, 2026-10-28 — `D-50`'S CONSEQUENCE, WHICH NO CLAUSE ABOVE SPELLS OUT.** `RCA-8(g)` ANNOTATE-BESIDE: **every clause of §7.6 above stands BYTE-FOR-BYTE and is read THROUGH this one; this clause adds one declaration and moves nothing it prints.** **THE RULE: A WRITE'S CONSTRAINT PASS JUDGES THE PAIRS STANDING AT THE ADDRESS IT WRITES — the kernel's own `pairsAtAddress` reads the pair record at that one address — SO A PAIR AT A DIFFERENT ADDRESS IS NOT ASKED.** **If a constraint cares about another location it READS it** (`D-50`, the architect, verbatim: *"If a constraint needs to look for the data at a given location, it can read()"*). **MEASURED 2026-10-28, on this checkout, through the published entry, in a two-address drive:** a pair `b1` registered at `['b']`; **a write at `['a']` asked `b1` `0` times**; **the same write at `['b']` asked it once**, and the value the body was handed was the one that write returned. **So an action one address away is INVISIBLE to your pair** — it was never asked at the address the action moved — **and the body's own `store.read` is the only thing that makes it visible.** **That is the whole reason this section tells you to read what you care about: the pass will not ask a pair that does not stand where you wrote.** (`held-listener/contract.md §2.8` item `1`, `HL-8`: *"the pass selects the rows whose address IS the triggering address"*, preserving the EXACT-ADDRESS rule rather than widening it; `D-50`; §7.1–§7.5's declarations; the pass's own scan at `bindings/js/src/entry/kernel-foundations.mjs:782`.)
|
|
730
|
+
|
|
731
|
+
### §7.7 ★ The check is BOUNDED — THREE restarts per terminal act, and past the budget it fails closed
|
|
732
|
+
|
|
733
|
+
**★ 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
|
+
|
|
735
|
+
**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
|
+
|
|
737
|
+
**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.
|
|
738
|
+
|
|
739
|
+
**WHAT DOES NOT SPEND THE BUDGET**, so a lawful in-commit action costs at most one round and no more: **a request whose watch shows no moved address is consumed and asks nothing** — it can neither loop nor exhaust the budget — and **the count belongs to the PASS's own scope**, so a nested pass (a listener body's own write) has a scope and a budget of its own, exactly as it has its own commit (`js/contract.md §2.6`'s clause of 2026-10-27, item `4`).
|
|
740
|
+
|
|
691
741
|
---
|
|
692
742
|
|
|
693
743
|
## §8 · Refusals
|
|
@@ -1288,6 +1338,34 @@ tree sharing no mutable member with the store or with another crossing**, which
|
|
|
1288
1338
|
|
|
1289
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. **And every pass that DOES run drains its own restart request** — so the fail-state is bounded by the two acts that run none.
|
|
1290
1340
|
|
|
1341
|
+
**⟶ ADDED 2026-10-28 — `D-49`: THE DISCARD IS NOW OBSERVABLE ON THE `delete`'S OWN ANSWER, AND THE OTHER
|
|
1342
|
+
WINDOW STILL CARRIES NOTHING. READ THIS BEFORE YOU RELY ON EITHER FAIL-STATE.**
|
|
1343
|
+
|
|
1344
|
+
**THE USE CASE THAT MADE IT A DEFECT, IN YOUR TERMS.** Your `window.tabs` is one object; **a listener you
|
|
1345
|
+
installed at `window.tabs` DOES fire when you delete `window.tabs.landingPage`** — the triggered set's rule is the
|
|
1346
|
+
address prefix, and the invocation's one argument is the deleted address. That is exactly where you would check
|
|
1347
|
+
your own invariant — *"exactly one tab is active"* — **and that check IS the kind of act the delete-delivery
|
|
1348
|
+
window throws away**: if it fails and you raise a `rollback`, **the request dies with the window** (`DEF-AH`).
|
|
1349
|
+
|
|
1350
|
+
- **WHAT YOU CAN NOW SEE.** **A `delete`'s record carries `discarded` beside its four members** — a list, `0` or
|
|
1351
|
+
`1` long, of `{ opId, addresses }`: **`opId` is the id the reversal you raised named**, and **`addresses` are
|
|
1352
|
+
the addresses the discarded check would have been asked at**. **`record.discarded.length === 0` means this
|
|
1353
|
+
act's delivery discarded nothing.** **This is a WITNESS, not a repair** — the delete still answers everything
|
|
1354
|
+
it answered, **throws nothing**, mints no new status, and the reversal's effect **still stands**; the
|
|
1355
|
+
fail-state, the exits below and the behaviour of both windows are unchanged.
|
|
1356
|
+
- **READ IT BY ITS NAME, AND EXPECT IT NOT TO BE ENUMERABLE.** `record.discarded` works; **`Object.keys(record)`
|
|
1357
|
+
still prints the four members you already know**, and **a spread or `Object.assign` copy of a receipt does not
|
|
1358
|
+
carry the witness** — read `discarded` off the record itself.
|
|
1359
|
+
- **WHAT IT CANNOT SHOW, SAID PLAINLY.** **A registration's answer (`addConstraint`) is an opaque identity and
|
|
1360
|
+
carries NO witness** — an action raised inside that evaluation is still unobservable, and no member was
|
|
1361
|
+
invented for it. **And the machinery holds ONE pending request per instance**: a second in-flight action
|
|
1362
|
+
overwrites the first, so the witness reports the **last** request a delivery raised, and earlier ones were
|
|
1363
|
+
never recorded. **Neither limit is a defect; both are the declared shape.**
|
|
1364
|
+
|
|
1365
|
+
**THE EXITS ARE STILL YOURS AND ARE UNCHANGED: reload the file, or regenerate the store.** What changed is that
|
|
1366
|
+
**the `delete` now tells you the discard happened** — *"a fail-state is honest only if the consumer learns it
|
|
1367
|
+
happened"* (`D-49`).
|
|
1368
|
+
|
|
1291
1369
|
### §12.7 A skip is not a green, and your own throws are not refusals
|
|
1292
1370
|
|
|
1293
1371
|
**WHAT BREAKS:** **a `skipped` cell is a cell that DID NOT RUN** — *"a skip is not a green"*, in the authority
|
|
@@ -1335,3 +1413,5 @@ quietly.**
|
|
|
1335
1413
|
document, not a test report:** the declared documents are the instrument for questions of semantics, and a
|
|
1336
1414
|
driven run is the instrument for questions of behaviour. **This guide tries to say which is which, and it is not
|
|
1337
1415
|
the instrument that decides between them.**
|
|
1416
|
+
|
|
1417
|
+
**⟶ CORRECTED 2026-10-28 — THE BULLET ABOVE'S *"the two of 2026-10-26"* NO LONGER COUNTS THIS FILE, AND THE FIGURE IS MOVED RATHER THAN THE RULE.** `RCA-8(g)` ANNOTATE-BESIDE: **the bullet above stands BYTE-FOR-BYTE and is read THROUGH this clause.** **This file now names FOUR measurements of its own — the two of 2026-10-26 the bullet carries, §7.6's two-address `b1` drive and §7.7's 60/40-reversal restart-budget drive, both taken 2026-10-28 on this checkout through the published entry — and each is named where it stands rather than gathered here.** **WHAT DOES NOT MOVE IS THE BULLET'S RULE AND THE DOCUMENT'S OWN STANDING: this guide is a consumer document and not a test report; a figure it states is either declared and cited or measured and marked; and the declared documents and the driven batteries remain the instruments for questions of semantics and of behaviour respectively.** **A reader who wants the measurements re-run finds their drives named at their sites, and no figure of this file is offered as a green.**
|
package/index.d.ts
CHANGED
|
@@ -485,6 +485,41 @@ export interface DeleteRecord {
|
|
|
485
485
|
* journal entry, so there is no op to carry: **nothing is named because nothing was destroyed.**
|
|
486
486
|
*/
|
|
487
487
|
readonly op: JournalOp | null;
|
|
488
|
+
/**
|
|
489
|
+
* **THE DISCARD'S WITNESS — THE REVERSALS THIS ACT'S OWN DELIVERY RAISED AND THE PACKAGE THREW AWAY**
|
|
490
|
+
* (`strata/decisions.md` · `D-49`, the architect, verbatim: *"Make discard observable"*; `DEF-AH`).
|
|
491
|
+
*
|
|
492
|
+
* **WHY THIS MEMBER EXISTS.** A `delete`'s listener delivery **runs no constraint pass** — there is no attempt
|
|
493
|
+
* for one to run over — so a `rollback` a listener body issues inside it raises a **restart request with no
|
|
494
|
+
* consumer**, and the fail-state is honest only if the caller learns it happened (`D-43` item 2's fail-state
|
|
495
|
+
* and both exits stand; `D-49` owes the witness and nothing else). **A listener at `window.tabs` fires for a
|
|
496
|
+
* delete at `window.tabs.landingPage`** — the triggered set's membership rule is the address prefix — **and the
|
|
497
|
+
* check it runs there is exactly the act the window discards**; this member is where that caller reads it.
|
|
498
|
+
*
|
|
499
|
+
* **ITS SHAPE, AND IT IS A LIST SO THE MEMBER CAN CARRY ONE TODAY AND MORE WITHOUT A SECOND SPELLING.** The
|
|
500
|
+
* restart machinery holds **one** pending request per instance (a second in-flight action overwrites the
|
|
501
|
+
* first — a declared limit, not a claim of this member), so the array is **`0` or `1` long**:
|
|
502
|
+
* * `opId` — **the store's own echo of the id the discarded reversal named**, or `null` where the reversal's
|
|
503
|
+
* call answered no id;
|
|
504
|
+
* * `addresses` — **the addresses the discarded check would have been asked at** (the watch's own addresses,
|
|
505
|
+
* each a fresh segment list), so a caller can re-run its own check at exactly those addresses.
|
|
506
|
+
*
|
|
507
|
+
* **A WITNESS IS NOT A REFUSAL.** The `delete` still answers what it answered — this record's other members
|
|
508
|
+
* are unmoved, the act **throws nothing**, **no member of the closed status set is minted**, and the reversed
|
|
509
|
+
* effect **still stands** (the request is reported, not re-run). **AND THIS MEMBER IS A NON-ENUMERABLE OWN
|
|
510
|
+
* PROPERTY**: `Object.keys(record)` and every deep-equality over the record read the same four members they
|
|
511
|
+
* read before, while a caller reads the witness **by its name**. A spread or `Object.assign` copy of the record
|
|
512
|
+
* does not carry it — read the member off the record itself.
|
|
513
|
+
*
|
|
514
|
+
* **WHAT IT CANNOT CARRY, SAID HERE RATHER THAN LEFT TO BE DISCOVERED.** The other passless window — a
|
|
515
|
+
* registration's own evaluation (`addConstraint`) — answers an **opaque identity** and carries **no witness**:
|
|
516
|
+
* an identity is not a record and no member of it is declared, so the action raised there remains unobservable
|
|
517
|
+
* without a new surface (`D-49`'s own instruction: say so rather than invent a member).
|
|
518
|
+
*/
|
|
519
|
+
readonly discarded: readonly {
|
|
520
|
+
readonly opId: string | null;
|
|
521
|
+
readonly addresses: readonly Address[];
|
|
522
|
+
}[];
|
|
488
523
|
}
|
|
489
524
|
|
|
490
525
|
/**
|
package/index.mjs
CHANGED
|
@@ -87,9 +87,10 @@ import { withAddon, boundaryReject, adoptModuleContext } from './src/entry/artef
|
|
|
87
87
|
import { VALUE_ARGUMENT_POSITION, accessorOrSymbolArm, arrayClass, classSpelling, extendedPath, hasLoneSurrogate, inDomainAddress, isAdmittedArray, isLawfulListenerElement, isPlainObjectValue, protoClass, shapeArmClass, targetSpelling, valueReject, valueTargetSpelling } from './src/entry/class-decision.mjs';
|
|
88
88
|
import { encodeAddress, encodeFilePath, encodeJournalLength, encodeOpId, encodeTier, encodeValue, handleWire, inDomainHandle } from './src/entry/carrier.mjs';
|
|
89
89
|
import { admittedConstraintBatch, constraintAddress, decodeBaseState, decodeJournalOp, decodeSegments, decodeValue, encodeConfig, spellConstraintAddress } from './src/entry/frame.mjs';
|
|
90
|
-
import {
|
|
90
|
+
import { addressSpelling } from './src/entry/kernel-foundations.mjs';
|
|
91
|
+
import { FORGET_PAIR, INSTANCES, STORE_INDEX, STORE_RETIREMENT, TERMINAL_ARM, carryRefusal, closeCommit, crossTriggered, currentWindow, entryOf, homeAddressKey, installAttemptSeam, isStoreReceiver, openCommit, writeRefusal } from './src/entry/state.mjs';
|
|
91
92
|
import { commitPositionRefusal, constraintOverwrittenByListen, deliver, listenerStandingAt, registerOn, terminalArm } from './src/entry/delivery.mjs';
|
|
92
|
-
import { ARGUMENT_POSITION_FIRST, addressSetKey, carryConstraint, constraintDetached, constraintPairKey, constraintRefuse, constraintSite, constraintUncarried, constraintWrite, constraintsKernel, enumerateConstraints, judgeReversal, registrationCrossing, restoreHeldPair, reversalWatch, unionAddressSets, withEmptyLog, withdrawStanding } from './src/entry/constraints.mjs';
|
|
93
|
+
import { ARGUMENT_POSITION_FIRST, addressSetKey, carryConstraint, constraintDetached, constraintPairKey, constraintRefuse, constraintSite, constraintUncarried, constraintWrite, constraintsKernel, enumerateConstraints, judgeReversal, registrationCrossing, restoreHeldPair, reversalWatch, unionAddressSets, withEmptyLog, witnessDiscardedReversal, withdrawStanding } from './src/entry/constraints.mjs';
|
|
93
94
|
const require_ = createRequire(import.meta.url);
|
|
94
95
|
const ADDON_PATH = join(dirOf(fileURLToPath(import.meta.url)), 'build', 'Release', 'storeroom_js_binding.node');
|
|
95
96
|
|
|
@@ -470,9 +471,38 @@ export function storeCreate(cfg) {
|
|
|
470
471
|
/// `DeleteRecord.op`): the member `write`'s record carries, at the same name, so `rollback(record.op.opId)`
|
|
471
472
|
/// reverses the delete. `null` is the `D-3` arm that removed nothing — it appended no entry, so it names
|
|
472
473
|
/// no op — and it crosses unchanged rather than folding to `undefined` (`crossing.md §1.3`).
|
|
474
|
+
///
|
|
475
|
+
/// **⟶ AND IT CARRIES THE DISCARD'S WITNESS FROM 2026-10-28 — `D-49`, `strata/decisions.md`, THE ARCHITECT,
|
|
476
|
+
/// VERBATIM: *"Make discard observable"*** (`index.d.ts` `DeleteRecord.discarded`; the use case's own
|
|
477
|
+
/// foundation is the prefix rule the delivery already obeys: **a listener at `window.tabs` FIRES for a
|
|
478
|
+
/// delete at `window.tabs.landingPage`, and the check it runs there is exactly the kind of act the
|
|
479
|
+
/// `delete`-delivery window throws away**).
|
|
480
|
+
///
|
|
481
|
+
/// **`delete` IS THE ONE ACT WHOSE DELIVERY RUNS NO PASS AND WHOSE ANSWER SURVIVES TO TELL** (`D-43` item
|
|
482
|
+
/// 2's other window is a registration, whose answer is an opaque identity and carries nothing). So the
|
|
483
|
+
/// request a listener body raises inside THIS window — a `rollback`, stamped with this commit's identity by
|
|
484
|
+
/// `reversalWatch` — is read at the end of the delivery and reported **BESIDE** the record's four members, by
|
|
485
|
+
/// the one rule `D-49` sets: **the act still answers what it answered, no status is minted, and the witness
|
|
486
|
+
/// is not a refusal.**
|
|
487
|
+
///
|
|
488
|
+
/// **THE MEMBER IS A NON-ENUMERABLE OWN `data` PROPERTY, AND THE CHOICE IS DECLARED.** It is **visible to the
|
|
489
|
+
/// caller by its name** (`record.discarded`) and declared in `index.d.ts`, while the record's **enumerable
|
|
490
|
+
/// member set stays the four its declaration and its cells assert** — `Object.keys`, every deep-equality over
|
|
491
|
+
/// a receipt and every census of a record's members read exactly what they read before. **A witness added by
|
|
492
|
+
/// moving the record's own declared ENUMERABLE shape would make the cells that assert that set's readings
|
|
493
|
+
/// false to buy nothing a caller needs**; a `Symbol.for` key would be the family's other device (`A117` (D6))
|
|
494
|
+
/// but is not declarable as a member of `DeleteRecord`, and `D-49` asks for the member to be declared.
|
|
495
|
+
///
|
|
496
|
+
/// **THE VALUE IS `[]` WHERE NOTHING WAS DISCARDED AND ONE `{ opId, addresses }` ENTRY WHERE A REQUEST WAS**
|
|
497
|
+
/// — the id the reversal named (the store's own echo) and the addresses the discarded check would have been
|
|
498
|
+
/// asked at. **NO PASS RUNS, NO BODY IS INVOKED, NO JUDGEMENT IS TAKEN AND THE BEHAVIOUR OF THE WINDOW IS
|
|
499
|
+
/// UNMOVED**: the request is consumed (reported) and its effect still stands.
|
|
473
500
|
delete(address, tier) {
|
|
474
501
|
// **⟶ `§4.1`: `delete` OPENS ONE.**
|
|
475
502
|
const opened = openCommit(instance);
|
|
503
|
+
// **THE WINDOW THIS ACT OWNS, TAKEN AT ITS OPENING** — the identity `reversalWatch` stamps a request with,
|
|
504
|
+
// so that what the witness reads is the request THIS delivery raised and never another window's.
|
|
505
|
+
const window = currentWindow(instance);
|
|
476
506
|
try {
|
|
477
507
|
const args = arguments.length >= 1 ? [encodeAddress(address, undefined, 'first argument')] : [];
|
|
478
508
|
// `delete`'s tier is read as a VALUE and not by an arity fold: an ABSENT position is the whole-target
|
|
@@ -488,6 +518,18 @@ export function storeCreate(cfg) {
|
|
|
488
518
|
};
|
|
489
519
|
// `A43`: a delete FIRES its own triggered set, on the same window as a write (`docs/specs/storeroom-js/surface.md §2.7` item 2).
|
|
490
520
|
deliver(state, receipt.triggered, answer.triggeringAddress);
|
|
521
|
+
// **⟶ `D-49`: THE WITNESS, READ AFTER THE DELIVERY AND REPORTED BESIDE THE RECORD** — the delivery is
|
|
522
|
+
// the only body-invoking instant this act has, so a request standing after it is one this window raised.
|
|
523
|
+
// **ONLY A DELETE THAT OPENED ITS OWN WINDOW REPORTS**: a call that joined an enclosing commit has no
|
|
524
|
+
// window of its own to witness, and any request under that identity belongs to the act that opened it
|
|
525
|
+
// (`witnessDiscardedReversal` clears a request of the window handed in and of no other).
|
|
526
|
+
const discarded = opened === true ? witnessDiscardedReversal(instance, window) : null;
|
|
527
|
+
Object.defineProperty(receipt, 'discarded', {
|
|
528
|
+
value: discarded === null ? [] : [discarded],
|
|
529
|
+
enumerable: false,
|
|
530
|
+
writable: false,
|
|
531
|
+
configurable: true,
|
|
532
|
+
});
|
|
491
533
|
return receipt;
|
|
492
534
|
} finally {
|
|
493
535
|
closeCommit(instance, opened);
|
|
@@ -631,8 +673,8 @@ export function storeCreate(cfg) {
|
|
|
631
673
|
if (overwritten !== null) {
|
|
632
674
|
boundaryReject(
|
|
633
675
|
'AddressMalformed',
|
|
634
|
-
|
|
635
|
-
`the listener '${handle}' cannot be installed at ${
|
|
676
|
+
addressSpelling(overwritten.address),
|
|
677
|
+
`the listener '${handle}' cannot be installed at ${addressSpelling(overwritten.address)}: the constraint `
|
|
636
678
|
+ `'${overwritten.id}' stands there, and a listener and a constraint do not share one`,
|
|
637
679
|
);
|
|
638
680
|
}
|
|
@@ -821,9 +863,9 @@ export function storeCreate(cfg) {
|
|
|
821
863
|
if (collided !== null) {
|
|
822
864
|
boundaryReject(
|
|
823
865
|
'AddressMalformed',
|
|
824
|
-
|
|
866
|
+
addressSpelling(collided.address),
|
|
825
867
|
`the listener '${site.id}' cannot share its handle with the constraint '${site.id}' at `
|
|
826
|
-
+ `${
|
|
868
|
+
+ `${addressSpelling(collided.address)}: a listener and a constraint do not share one`,
|
|
827
869
|
);
|
|
828
870
|
}
|
|
829
871
|
const held = site.state.constraints.get(constraintPairKey(site.addresses, site.id));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "provident-storeroom",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "U-STOREROOM-PUBLISH: the published Node ESM binding for the native Rust store of Provident-Storeroom — the entry resolves the scoped per-target platform package first, the checkout's own module-relative addon second, and answers the store's single declared absent-addon form when neither loads",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"src/constraint-kernel.mjs"
|
|
41
41
|
],
|
|
42
42
|
"optionalDependencies": {
|
|
43
|
-
"@auspicion/provident-storeroom-js-linux-x64-gnu": "1.
|
|
44
|
-
"@auspicion/provident-storeroom-js-linux-arm64-gnu": "1.
|
|
45
|
-
"@auspicion/provident-storeroom-js-darwin-x64": "1.
|
|
46
|
-
"@auspicion/provident-storeroom-js-darwin-arm64": "1.
|
|
47
|
-
"@auspicion/provident-storeroom-js-win32-x64-msvc": "1.
|
|
43
|
+
"@auspicion/provident-storeroom-js-linux-x64-gnu": "1.2.0",
|
|
44
|
+
"@auspicion/provident-storeroom-js-linux-arm64-gnu": "1.2.0",
|
|
45
|
+
"@auspicion/provident-storeroom-js-darwin-x64": "1.2.0",
|
|
46
|
+
"@auspicion/provident-storeroom-js-darwin-arm64": "1.2.0",
|
|
47
|
+
"@auspicion/provident-storeroom-js-win32-x64-msvc": "1.2.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -4,7 +4,7 @@ import { appendOwn, fail, refusalLog } from './refusal.mjs';
|
|
|
4
4
|
import { withAddon, require_ } from './artefact.mjs';
|
|
5
5
|
import { classSpelling, isAdmittedArray, isPlainObjectValue } from './class-decision.mjs';
|
|
6
6
|
import { constraintAddress } from './frame.mjs';
|
|
7
|
-
import { currentWindow, homeAddressKey, installRestartConsumer, isStoreReceiver, openCommits } from './state.mjs';
|
|
7
|
+
import { currentWindow, homeAddressKey, installRestartConsumer, isStoreReceiver, openCommits, closeCommit, openCommit, windowMark } from './state.mjs';
|
|
8
8
|
// **THE KERNEL'S OWN RECORD, FOR ONE FIELD AND ONE ONLY** (`D-46`/`D-30`): `kernelFor(store)` answers the
|
|
9
9
|
// instance's kernel record — the same accessor every kernel act takes the instance through — and
|
|
10
10
|
// `reversalAtRest` below reads that record's own `live` map for the count of OPEN ATTEMPTS. `kernel-foundations`
|
|
@@ -1464,6 +1464,79 @@ export function drainRestartRequests(instance, report) {
|
|
|
1464
1464
|
}
|
|
1465
1465
|
}
|
|
1466
1466
|
|
|
1467
|
+
/// **⟶ ADDED 2026-10-28 — `D-49`: THE DISCARD'S WITNESS, AND IT IS READ BY THE ACT WHOSE WINDOW DISCARDED THE
|
|
1468
|
+
/// REQUEST.**
|
|
1469
|
+
///
|
|
1470
|
+
/// **THE RULING, THE ARCHITECT, VERBATIM: *"Make discard observable"*** (`strata/decisions.md` · `D-49`), and
|
|
1471
|
+
/// **`DEF-AH` is the defect it answers**: a restart request raised inside one of the two windows that run **no
|
|
1472
|
+
/// pass** — a `delete`'s listener delivery, and a registration's own evaluation — **died with its window and the
|
|
1473
|
+
/// caller could not learn that it did.** **The fail-state stands** (`D-43` item 2, both exits) — **what was
|
|
1474
|
+
/// missing was the WITNESS.**
|
|
1475
|
+
///
|
|
1476
|
+
/// **WHAT THIS FUNCTION IS, AND WHAT IT IS NOT.**
|
|
1477
|
+
/// * **IT RUNS NO PASS, NO BODY AND NO JUDGEMENT.** It reads the instance's own restart record — the record
|
|
1478
|
+
/// `reversalWatch` raised the request in — and answers a fresh copy of the two facts a consumer needs: the
|
|
1479
|
+
/// id the reversal named (`reversalId`, the store's own echo) and the addresses the discarded check would
|
|
1480
|
+
/// have been asked at (`the watch's addresses`, deduplicated by spelling and copied segment for segment).
|
|
1481
|
+
/// **THE STORE IS NOT TOUCHED, NO CODE IS MINTED, NO LOG ENTRY IS APPENDED AND NO MEMBER OF ANY RECORD IS
|
|
1482
|
+
/// MOVED** — the `D-49` bar: *"a witness is not a refusal: the act still answers what it answered, the
|
|
1483
|
+
/// discard is reported beside it, and nothing new is minted in the closed status set."*
|
|
1484
|
+
/// * **IT CONSUMES THE REQUEST IT REPORTS.** A request whose window is the caller's has no consumer that could
|
|
1485
|
+
/// ever run it (the window's act ran no pass, and a later pass compares the identity and drops it — the
|
|
1486
|
+
/// drain's own arm), so clearing the slot here moves no behaviour: it is the same clearing the drain would
|
|
1487
|
+
/// perform on a mismatched window and the at-rest watch performs on a new reversal. **IT ONLY EVER CLEARS A
|
|
1488
|
+
/// REQUEST OF THE WINDOW HANDED IN** — a request raised in another window is left exactly where it stands,
|
|
1489
|
+
/// so an enclosing act's own consumer is never robbed of it.
|
|
1490
|
+
/// * **IT IS NOT THE DRAIN.** `drainRestartRequests` is the consumer of a pass's own window and RUNS the
|
|
1491
|
+
/// restarted check; this function is the consumer of a window that has none and only REPORTS it. **Two
|
|
1492
|
+
/// consumers, two windows, and neither takes the other's request** (`D-44`: *"every request has a
|
|
1493
|
+
/// consumer"* — for the two passless windows the consumer is the caller's own record).
|
|
1494
|
+
///
|
|
1495
|
+
/// **THE BOUND, STATED SO THE WITNESS IS NOT READ AS MORE THAN IT IS.** The restart record holds **ONE** pending
|
|
1496
|
+
/// request (a second in-flight action overwrites the first — the record's own declared shape, UNMOVED by this
|
|
1497
|
+
/// pass), so the witness reports the LAST request the window raised and no list of earlier ones exists to report.
|
|
1498
|
+
/// **The registration window is the other named window and it has no such reader**: its answer is an identity, and
|
|
1499
|
+
/// the identity is opaque by declaration, so nothing this function could answer would reach it without a new
|
|
1500
|
+
/// surface — `D-49`'s own instruction is to say so rather than to invent one.
|
|
1501
|
+
export function witnessDiscardedReversal(instance, window) {
|
|
1502
|
+
const record = RESTARTS.get(instance);
|
|
1503
|
+
// NO ACTION WAS EVER TAKEN ON THIS INSTANCE, OR THE LAST ONE WAS ALREADY CONSUMED: nothing stands to report.
|
|
1504
|
+
if (record === undefined || record.pending === null) return null;
|
|
1505
|
+
const request = record.pending;
|
|
1506
|
+
// **A REQUEST BELONGS TO THE ACT THAT RAISED IT** (`D-42` item 3, measured by the `window` stamp of
|
|
1507
|
+
// 2026-10-27): a request standing from another window is that window's and is left where it stands.
|
|
1508
|
+
if (request.window !== window) return null;
|
|
1509
|
+
record.pending = null;
|
|
1510
|
+
const addresses = [];
|
|
1511
|
+
const spellings = [];
|
|
1512
|
+
for (let index = 0; index < request.watched.length; index += 1) {
|
|
1513
|
+
const address = request.watched[index].address;
|
|
1514
|
+
const spelling = homeAddressKey(address);
|
|
1515
|
+
let seen = false;
|
|
1516
|
+
for (let known = 0; known < spellings.length; known += 1) {
|
|
1517
|
+
if (spellings[known] === spelling) {
|
|
1518
|
+
seen = true;
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
// ONE ADDRESS ONCE: two pairs over one address (or one pair naming it twice) are one address the check owed,
|
|
1523
|
+
// and the witness reports the subject and not the walk.
|
|
1524
|
+
if (seen) continue;
|
|
1525
|
+
appendOwn(spellings, spelling);
|
|
1526
|
+
// **A FRESH SEGMENT LIST PER ADDRESS** (`crossing.md §1.1`'s copy-out discipline): the pair's own array is
|
|
1527
|
+
// the registry's and is never handed to a caller.
|
|
1528
|
+
const copy = [];
|
|
1529
|
+
for (let segment = 0; segment < address.length; segment += 1) appendOwn(copy, address[segment]);
|
|
1530
|
+
appendOwn(addresses, copy);
|
|
1531
|
+
}
|
|
1532
|
+
// THE STORE'S OWN ECHO OF THE ID THE REVERSAL NAMED — `null` where the reversal's call answered no id (the
|
|
1533
|
+
// request stands and the act's answer did not reach the echo, which is a real arm a caller can see).
|
|
1534
|
+
return {
|
|
1535
|
+
opId: typeof request.reversalId === 'string' ? request.reversalId : null,
|
|
1536
|
+
addresses,
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1467
1540
|
/// **⟶ THE REFUSAL'S ONE CARRIER TO WHICHEVER DRIVER ASKED — ADDED 2026-10-27.**
|
|
1468
1541
|
///
|
|
1469
1542
|
/// **THE REPORT IS AMENDED IN TWO PLAIN MEMBERS AND CARRIES THE REFUSAL WHOLE UNDER A THIRD, SYMBOL-KEYED
|
|
@@ -1691,46 +1764,63 @@ export function judgeReversal(instance, watched, reversalId) {
|
|
|
1691
1764
|
}
|
|
1692
1765
|
return undefined;
|
|
1693
1766
|
}
|
|
1694
|
-
// THE
|
|
1695
|
-
//
|
|
1696
|
-
//
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1767
|
+
// **⟶ AND THE AT-REST JUDGEMENT RUNS INSIDE A COMMIT, 2026-10-27 — `D-44`'s INVARIANT AND `DEF-AE`'S CACHE.**
|
|
1768
|
+
// `D-44`: *"There should be no state where a constraint is being checked without an open commit. Any action that
|
|
1769
|
+
// would cause a constraint check should open a commit before beginning."* **THE AT-REST JUDGEMENT WAS THE ONE
|
|
1770
|
+
// CHECK THAT RAN OUTSIDE ONE** — `reversalWatch` had already decided `reversalAtRest` on the count this call
|
|
1771
|
+
// found (`open` `0`, `live` `0`), so the discriminator's reading is unmoved by the opening that follows it —
|
|
1772
|
+
// **and the window it opens is what carries the mark the restore owes back** (`state.mjs`'s `openCommit` caches
|
|
1773
|
+
// the journal's last valid position at the opening; `windowMark` answers it). **A REVERSAL APPENDS NO ENTRY**, so
|
|
1774
|
+
// the mark taken here is still the PRE-REVERSAL state — which is why the at-rest control restores exactly what
|
|
1775
|
+
// it restored before. **ON THE RESTART ARM THIS CALL JOINS** the pass's window (the drain runs inside the pass's
|
|
1776
|
+
// own scope, `kernel-attempt.mjs`) and re-caches nothing, so the mark in flight stays the OUTERMOST opening's:
|
|
1777
|
+
// the position the attempt found. **THE `finally` RELEASES THE WINDOW ON EVERY ARM, INCLUDING THE THROWING ONE**,
|
|
1778
|
+
// because a refusal that leaves a commit standing is the count this package's own cells measure.
|
|
1779
|
+
const opened = openCommit(instance);
|
|
1780
|
+
try {
|
|
1781
|
+
// THE MOVED SET IS TAKEN FIRST, ONCE: the judgement's subject is the CHANGE the reversal made and nothing
|
|
1782
|
+
// wider, and the same list is what a refusal has to put back — with the tier capture the watch took, so a
|
|
1783
|
+
// restore knows WHERE each value stood and not merely what it was.
|
|
1784
|
+
const moved = [];
|
|
1785
|
+
for (let index = 0; index < watched.length; index += 1) {
|
|
1786
|
+
const one = watched[index];
|
|
1787
|
+
// THE ADDRESS IS READ AGAIN, AT THE STATE THE REVERSAL LEFT. **A STANDING THIS REVERSAL DID NOT MOVE IS
|
|
1788
|
+
// NOT A STANDING IT LEFT**, so the pair is not asked and cannot refuse the reversal for a state the
|
|
1789
|
+
// reversal found.
|
|
1790
|
+
const after = standingAt(instance, one.address);
|
|
1791
|
+
if (sameStanding(one.before, after) === true) continue;
|
|
1792
|
+
appendOwn(moved, {
|
|
1793
|
+
entry: one.entry,
|
|
1794
|
+
address: one.address,
|
|
1795
|
+
before: one.before,
|
|
1796
|
+
beforeTier: one.beforeTier,
|
|
1797
|
+
beforeTiers: one.beforeTiers,
|
|
1798
|
+
after,
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
for (let index = 0; index < moved.length; index += 1) {
|
|
1802
|
+
const one = moved[index];
|
|
1803
|
+
// **THE BODY'S THROW IS THE JUDGEMENT'S OWN CATCH AND NOT A PROPAGATING VALUE** — `reversalOutcome` converts
|
|
1804
|
+
// a body's throwable to the surface's rank-`18` form and re-throws anything unmarked as itself, and BOTH
|
|
1805
|
+
// arrive here: the reversal has run, so a judgement that cannot complete restores and refuses (below).
|
|
1806
|
+
let outcome;
|
|
1807
|
+
try {
|
|
1808
|
+
outcome = reversalOutcome(instance, one.entry, one.address, one.after);
|
|
1809
|
+
} catch (thrown) {
|
|
1810
|
+
const undo = restoreReversal(instance, moved);
|
|
1811
|
+
throw reversalRefusal(one, one.after, null, reversalId, undo, thrown);
|
|
1812
|
+
}
|
|
1813
|
+
if (outcome === true) continue;
|
|
1814
|
+
// **THE FIRST VIOLATING PAIR DECIDES AND THE SECOND IS NOT EVALUATED** (`attempt-lifecycle.md §2.4` item 5
|
|
1815
|
+
// (ii)–(iii), at the reversal's own instant) — and BEFORE the refusal is built, EVERY address the reversal
|
|
1816
|
+
// moved is put back, so the store the consumer meets holds no state this refusal refused.
|
|
1723
1817
|
const undo = restoreReversal(instance, moved);
|
|
1724
|
-
throw reversalRefusal(one, one.after,
|
|
1818
|
+
throw reversalRefusal(one, one.after, reversalSaid(outcome), reversalId, undo, null);
|
|
1725
1819
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
// moved is put back, so the store the consumer meets holds no state this refusal refused.
|
|
1730
|
-
const undo = restoreReversal(instance, moved);
|
|
1731
|
-
throw reversalRefusal(one, one.after, reversalSaid(outcome), reversalId, undo, null);
|
|
1820
|
+
return undefined;
|
|
1821
|
+
} finally {
|
|
1822
|
+
closeCommit(instance, opened);
|
|
1732
1823
|
}
|
|
1733
|
-
return undefined;
|
|
1734
1824
|
}
|
|
1735
1825
|
|
|
1736
1826
|
/// **THE REFUSAL'S OWN UNDOING — THE STORE RETURNS ITS OWN STATE TO ITS JOURNAL MARK, AND THE WATCH SAYS WHAT
|
|
@@ -1757,6 +1847,34 @@ export function judgeReversal(instance, watched, reversalId) {
|
|
|
1757
1847
|
/// boundary's own codec folds to the carrier's ABSENT arm (`crossing.md §1.3`): the store's own spelling for
|
|
1758
1848
|
/// *"the head"*.
|
|
1759
1849
|
///
|
|
1850
|
+
/// **⟶ AND THE TWO PARAGRAPHS ABOVE ARE READ THROUGH THEIR MARK, 2026-10-27 — THE ARCHITECT'S RULING, VERBATIM:
|
|
1851
|
+
/// *"Cache the restoreMark when opening a commit, based on the last valid state/op of the journal."*** `RCA-8(g)`
|
|
1852
|
+
/// ANNOTATE-BESIDE: **every byte above stands and this clause is the operative statement of WHICH mark the act
|
|
1853
|
+
/// names.** **THE HEAD IS NO LONGER TRUSTED, AND THE REASON IS THE MEASUREMENT `DEF-AE` FILED:** *"a reversal
|
|
1854
|
+
/// appends no journal entry, so the head describes the state that stood before the action"* is TRUE OF A REVERSAL
|
|
1855
|
+
/// TAKEN AT REST and FALSE OF ONE TAKEN INSIDE A WRITE'S COMMIT — **in the restart arm the enclosing write's own op
|
|
1856
|
+
/// stands at the head when the listener's reversal runs**, so the head described the WRITE'S LANDING and the
|
|
1857
|
+
/// compensation restored the refusal's own value: **the store stood at `7` where the attempt found `9`, and the
|
|
1858
|
+
/// write that reported the refusal had landed its value.** **SO THE ACT NAMES THE MARK ITS COMMIT CACHED AT ITS
|
|
1859
|
+
/// OPENING** — `state.mjs`'s `openCommit` reads the store's own `journalMark` (`src/store.rs`: the last VALID
|
|
1860
|
+
/// mark, which is the head at that instant and is named as a VALUE) and stands it on the window; `windowMark`
|
|
1861
|
+
/// answers it here, and the store's `restoreMark` replays to it. **THE INSTANT IS THE WHOLE FIX**: the opening
|
|
1862
|
+
/// precedes anything the commit lands, so the cached position is the state the attempt FOUND — the pre-attempt
|
|
1863
|
+
/// state, which is what a failed attempt owes back. **A JOIN RE-CACHES NOTHING** (`D-45`/`D-46` decide which
|
|
1864
|
+
/// openings are outermost: a repair's write and a pass's scope join, so they take the outermost mark and not a
|
|
1865
|
+
/// later one), and **a callback's own commit is its own opening with its own cache** (a listener body's call names
|
|
1866
|
+
/// nothing and opens, so the mark it restores to is where ITS window opened). **THE MARK IS OPAQUE HERE**: the
|
|
1867
|
+
/// store answered a carrier — `{k:'s', v:<op id>}`, or `{k:'F'}` for the FLOOR, the state the store was born with
|
|
1868
|
+
/// when the journal held no entry at the opening — and this act hands the very same carrier back. **NEITHER THE
|
|
1869
|
+
/// PACKAGE NOR THIS FUNCTION COMPOSES A POSITION.**
|
|
1870
|
+
///
|
|
1871
|
+
/// **AND A WINDOW WITH NO CACHE IS A WINDOW THAT NEVER OPENED: THIS ACT REFUSES RATHER THAN FALLING BACK TO THE
|
|
1872
|
+
/// HEAD** — the head is the value this ruling exists to stop trusting, and a silent fall-back would restore it
|
|
1873
|
+
/// while a consumer was told the reversal was undone. **THE REFUSAL IS THE ACT'S, NOT THE CALL'S**: no store verb
|
|
1874
|
+
/// is invoked, no status is minted (`DD-40`), every address the reversal moved is reported as NOT restored with
|
|
1875
|
+
/// what stands there instead, and the log entry says the window carried no cached mark — so the crossed form, its
|
|
1876
|
+
/// `status` and its member set are unmoved and the consumer is never told a restoration happened that did not.
|
|
1877
|
+
///
|
|
1760
1878
|
/// **WHAT THE CAPTURE SURVIVES AS, AND WHY IT IS NOT A FALLBACK.** `reversalWatch`'s per-tier capture is still
|
|
1761
1879
|
/// taken, and it is the ONLY record of **what was owed** — it is the DEBT'S RECORD and the VERIFICATION
|
|
1762
1880
|
/// BASELINE, not a write plan. Every address the reversal moved is read again after the store's act
|
|
@@ -1786,14 +1904,25 @@ export function judgeReversal(instance, watched, reversalId) {
|
|
|
1786
1904
|
/// NO SECOND SAVE IS ATTEMPTED** — the store's answer is the whole report.
|
|
1787
1905
|
function restoreReversal(instance, moved) {
|
|
1788
1906
|
const addon_ = withAddon();
|
|
1789
|
-
// THE ONE ACT:
|
|
1790
|
-
//
|
|
1791
|
-
//
|
|
1907
|
+
// **THE ONE ACT: THE STORE RETURNS ITS OWN STATE TO THE MARK ITS COMMIT CACHED AT ITS OPENING** (`windowMark`,
|
|
1908
|
+
// `state.mjs`) — NOT to the journal's head, which is the write's own landing on the restart arm. **THE CARRIER
|
|
1909
|
+
// IS THE STORE'S OWN ANSWER, HANDED BACK VERBATIM**: `{k:'s', v:<op id>}` names an entry and `{k:'F'}` names the
|
|
1910
|
+
// FLOOR (the state the store was born with, where the journal held no entry when the commit opened). **NOTHING
|
|
1911
|
+
// IS COMPOSED HERE**, so the mark has one spelling and it lives at the store's edge.
|
|
1792
1912
|
let refused = null;
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1913
|
+
let cacheless = false;
|
|
1914
|
+
const mark = windowMark(instance);
|
|
1915
|
+
if (mark === undefined) {
|
|
1916
|
+
// **A WINDOW WITH NO CACHE IS A WINDOW THAT NEVER OPENED, AND THIS REFUSES RATHER THAN FALLING BACK TO THE
|
|
1917
|
+
// HEAD.** No store verb is invoked, so the store holds the state it held — and the count below claims NO
|
|
1918
|
+
// address restored, so the sentence that reaches the consumer says the reversal was not undone.
|
|
1919
|
+
cacheless = true;
|
|
1920
|
+
} else {
|
|
1921
|
+
try {
|
|
1922
|
+
Reflect.apply(addon_.restoreMark, instance, [mark]);
|
|
1923
|
+
} catch (why) {
|
|
1924
|
+
refused = why;
|
|
1925
|
+
}
|
|
1797
1926
|
}
|
|
1798
1927
|
// **THE STORE'S ANSWER IS CLASSIFIED BEFORE ANY ADDRESS IS COUNTED — 2026-10-27, THE FILE-SAVE RULING.** A
|
|
1799
1928
|
// REFUSED MARK leaves the store as it was, so no address may be claimed restored. **A FAILED SAVE does not**:
|
|
@@ -1801,9 +1930,10 @@ function restoreReversal(instance, moved) {
|
|
|
1801
1930
|
// exactly as it is on the passing arm, and the file's own half is recorded beside the count (`unsaved`) for
|
|
1802
1931
|
// the ONE sentence that names it. **THIS IS THE VERIFICATION EXTENDED TO THE FILE**: the restore already
|
|
1803
1932
|
// counts the addresses it put back; the count is not narrowed by a failure that did not affect them, and the
|
|
1804
|
-
// bytes are reported as the thing that did fail.
|
|
1933
|
+
// bytes are reported as the thing that did fail. **AND THE CACHELESS ARM IS A THIRD, WHICH NEVER RESTORES**:
|
|
1934
|
+
// no mark was supplied, so no address may be counted.
|
|
1805
1935
|
const unsaved = saveRefused(refused);
|
|
1806
|
-
const stateRestored = refused === null || unsaved !== null;
|
|
1936
|
+
const stateRestored = cacheless === false && (refused === null || unsaved !== null);
|
|
1807
1937
|
let restored = 0;
|
|
1808
1938
|
const failed = [];
|
|
1809
1939
|
// ONE VERIFICATION PER ADDRESS: two pairs over one address (or one pair naming it twice) must not be counted
|
|
@@ -1833,7 +1963,7 @@ function restoreReversal(instance, moved) {
|
|
|
1833
1963
|
tiers: verdict.tiers,
|
|
1834
1964
|
});
|
|
1835
1965
|
}
|
|
1836
|
-
return { restored, total: measured.length, failed, refused, unsaved };
|
|
1966
|
+
return { restored, total: measured.length, failed, refused, unsaved, cacheless };
|
|
1837
1967
|
}
|
|
1838
1968
|
|
|
1839
1969
|
/// **WHETHER A LOCAL LIST OF SPELLINGS ALREADY HOLDS ONE** — a local index loop and not `Array.prototype.includes`.
|
|
@@ -1890,7 +2020,14 @@ function undoSpelling(undo) {
|
|
|
1890
2020
|
// store's own (`restoreReversal`), so a refusal it answered is the FIRST thing a consumer must hear — its
|
|
1891
2021
|
// status and its own generated message (`DD-52`) — and it is never spoken for by a claim about the state.
|
|
1892
2022
|
let refusal = '';
|
|
1893
|
-
if (undo.
|
|
2023
|
+
if (undo.cacheless === true) {
|
|
2024
|
+
// **⟶ AND THE CACHELESS ARM OPENS THE SENTENCE, 2026-10-27** (`restoreReversal` above): **a window with no
|
|
2025
|
+
// cached journal mark is a window that never opened, and the act refused rather than falling back to the
|
|
2026
|
+
// head.** No status is named — no store verb was reached and none refused — and the one fact a consumer must
|
|
2027
|
+
// hear is that nothing was restored, which is what the count below then spells address by address.
|
|
2028
|
+
refusal = 'the commit window this reversal ran in carries NO CACHED JOURNAL MARK, so the store was NOT asked '
|
|
2029
|
+
+ 'to restore it and holds the state the reversal left; ';
|
|
2030
|
+
} else if (undo.unsaved !== null && undo.unsaved !== undefined) {
|
|
1894
2031
|
// THE SAVE'S ARM: read as own data members and off no chain (`D-35`'s read half), exactly as the refused
|
|
1895
2032
|
// mark's status and sentence are read below.
|
|
1896
2033
|
const carried = typeof undo.unsaved === 'object';
|
|
@@ -1917,7 +2054,7 @@ function undoSpelling(undo) {
|
|
|
1917
2054
|
for (let index = 0; index < undo.failed.length; index += 1) {
|
|
1918
2055
|
const one = undo.failed[index];
|
|
1919
2056
|
named += index === 0 ? '' : '; ';
|
|
1920
|
-
named += `${
|
|
2057
|
+
named += `${addressSpelling(one.address)} could not be restored and stands `
|
|
1921
2058
|
+ `${standingDescription(one.standing, one.tiers)} where it stood `
|
|
1922
2059
|
+ `${capturedDescription(one)} before the reversal`;
|
|
1923
2060
|
}
|
|
@@ -2147,21 +2284,36 @@ function reversalRefusal(one, after, said, reversalId, undo, thrown, unsettled =
|
|
|
2147
2284
|
let spelled;
|
|
2148
2285
|
if (unsettled === true) {
|
|
2149
2286
|
spelled = `the constraint ${one.entry.id} could not be asked a state that would settle at `
|
|
2150
|
-
+ `${
|
|
2287
|
+
+ `${addressSpelling(one.address)}: the value there is ${standingSpelling(after)} — the check was `
|
|
2151
2288
|
+ `restarted ${RESTART_LIMIT} times and a pair body acted inside the check at every restart, so the `
|
|
2152
2289
|
+ `restart budget is spent and the check does not pass — ${undoSpelling(undo)}`;
|
|
2153
2290
|
} else if (thrown === null) {
|
|
2154
2291
|
spelled = `the constraint ${one.entry.id} refused the state the reversal left at `
|
|
2155
|
-
+ `${
|
|
2292
|
+
+ `${addressSpelling(one.address)}: the value there is ${standingSpelling(after)}`
|
|
2156
2293
|
+ (said === null ? '' : ` — ${said}`)
|
|
2157
2294
|
+ ` — ${undoSpelling(undo)}`;
|
|
2158
2295
|
} else {
|
|
2159
2296
|
spelled = `the constraint ${one.entry.id} THREW at the judgement of the state the reversal left at `
|
|
2160
|
-
+ `${
|
|
2297
|
+
+ `${addressSpelling(one.address)}: the value there is ${standingSpelling(after)}`
|
|
2161
2298
|
+ ` — ${undoSpelling(undo)}`;
|
|
2162
2299
|
}
|
|
2163
2300
|
const entry = {
|
|
2301
|
+
// **⟶ AND THE `seq` STANDS, 2026-10-28 — `DEF-AI`: THE ENTRY'S DECLARED SHAPE IS THE KERNEL'S CLOSED SIX
|
|
2302
|
+
// AND THIS ONE CARRIED FIVE.** The 2026-10-27 clause below withdrew the `1` as FABRICATED, on the reading
|
|
2303
|
+
// that `seq` is *"the ordinal within an ATTEMPT's own log"* and that no attempt stands at a reversal's
|
|
2304
|
+
// judgement. **THE READING IS RIGHT ABOUT THE ATTEMPT AND WRONG ABOUT THE MEMBER.** `seq`'s DECLARED
|
|
2305
|
+
// DOMAIN is *"the append ordinal, strictly increasing from `1` in array order"*
|
|
2306
|
+
// (`docs/specs/storeroom-constraints/kernel-surface.md §2.5` item 1), and the array this entry stands in is
|
|
2307
|
+
// THIS REFUSAL'S OWN ONE-ENTRY LIST: its first element's ordinal is `1` BY THAT RULE, not by invention —
|
|
2308
|
+
// the same arithmetic the kernel's own `append` performs (`log.length + 1`, read off the list the entry
|
|
2309
|
+
// stands in). **AND THE TWO COPIES OF THIS VERY ENTRY ALREADY DISAGREED**: `carryRestartRefusal` re-appends
|
|
2310
|
+
// it into the attempt's log through `append`, where it carries `seq` `1`, while the list that crosses to
|
|
2311
|
+
// the caller carried none — one entry, two shapes, which is this branch's `DEF-AI` class exactly. **`log`
|
|
2312
|
+
// IS DECLARED `LogEntry[]`** (`bindings/js/index.d.ts`), so a consumer typing it read `undefined` where
|
|
2313
|
+
// `number` is declared. **THE DECLARATION IS NOT WEAKENED TO MATCH THE ENTRY: THE ENTRY CARRIES THE
|
|
2314
|
+
// MEMBER.** No other member, no second entry and no sentence moves.
|
|
2164
2315
|
kind: 'constraint-check',
|
|
2316
|
+
seq: 1,
|
|
2165
2317
|
id: one.entry.id,
|
|
2166
2318
|
// **⟶ AND THE ENTRY SAYS WHAT THE ACT DID, 2026-10-26 (`DEF-W`'s `(a)`) and 2026-10-27 (`D-41` item `2`)** —
|
|
2167
2319
|
// the refusal's own record, beside the state it refused, so a consumer that catches it knows whether the
|
package/src/entry/delivery.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { withAddon, boundaryReject } from './artefact.mjs';
|
|
|
5
5
|
import { arrayClass, classSpelling, hasLoneSurrogate, isPlainObjectValue, targetSpelling } from './class-decision.mjs';
|
|
6
6
|
import { encodeAddress, encodeOpId, handleWire, inDomainHandle } from './carrier.mjs';
|
|
7
7
|
import { decodeSegments, spellConstraintAddress } from './frame.mjs';
|
|
8
|
+
import { addressSpelling } from './kernel-foundations.mjs';
|
|
8
9
|
import { entryOf, carryRefusal, commitFile, homeAddressKey, externalCall, SETTLED_ON_THE_PASSING_ARM, SAVE_FAILED_AT_THE_TERMINAL_ARM } from './state.mjs';
|
|
9
10
|
|
|
10
11
|
/// `PAR-JS-13`: the returned record is `{op, watched, triggered}` — fresh on every call, never a view.
|
|
@@ -305,8 +306,8 @@ export function registerOn(state, handle, listener) {
|
|
|
305
306
|
if (conflicted !== null) {
|
|
306
307
|
boundaryReject(
|
|
307
308
|
'AddressMalformed',
|
|
308
|
-
|
|
309
|
-
`the listener '${handle}' cannot be registered at ${
|
|
309
|
+
addressSpelling(conflicted.address),
|
|
310
|
+
`the listener '${handle}' cannot be registered at ${addressSpelling(conflicted.address)}: the constraint `
|
|
310
311
|
+ `'${conflicted.id}' stands at that address, and a listener and a constraint do not share one`,
|
|
311
312
|
);
|
|
312
313
|
}
|
package/src/entry/frame.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { types } from 'node:util';
|
|
3
3
|
import { boundaryReject } from './artefact.mjs';
|
|
4
4
|
import { appendOwn } from './refusal.mjs';
|
|
5
|
+
import { addressSpelling } from './kernel-foundations.mjs';
|
|
5
6
|
import { arrayClass, classSpelling, hasLoneSurrogate, isAdmittedArray, isLawfulListenerElement, isPlainObjectValue, valueTargetSpelling } from './class-decision.mjs';
|
|
6
7
|
import { encodeAddress, encodeFilePath, encodeJournalLength } from './carrier.mjs';
|
|
7
8
|
|
|
@@ -309,7 +310,7 @@ export function admittedConstraintBatch(cfg) {
|
|
|
309
310
|
'ConstraintListInvalid',
|
|
310
311
|
segment,
|
|
311
312
|
`the batch element at position ${position} names the handle '${element.id}', and this construction `
|
|
312
|
-
+ `adopts a listener under that handle at ${
|
|
313
|
+
+ `adopts a listener under that handle at ${addressSpelling(adoptedAddresses[adoptedAt])}: a listener `
|
|
313
314
|
+ 'and a constraint do not share one',
|
|
314
315
|
['constraints'],
|
|
315
316
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// `D-13` (`docs/L1/kernel-subdivision.md` §1 part `9d`) — the pass: bytes moved from `bindings/js/src/constraint-kernel.mjs`; no logic changed.
|
|
2
|
-
import { KC, KC_TOKENS, SETTLED_ON_THE_PASSING_ARM, SAVE_FAILED_AT_THE_TERMINAL_ARM, TERMINAL_ARM, markBodyThrow, refuse, isKernelRefusal, pairSpelling, sameAddress, kernelFor, append, appendOwn, ownMember, withdraw, landedOp, landedOpDefect, pairsAtAddress, externalCall } from './kernel-foundations.mjs';
|
|
2
|
+
import { KC, KC_TOKENS, SETTLED_ON_THE_PASSING_ARM, SAVE_FAILED_AT_THE_TERMINAL_ARM, TERMINAL_ARM, markBodyThrow, refuse, isKernelRefusal, pairSpelling, addressSpelling, sameAddress, kernelFor, append, appendOwn, ownMember, withdraw, landedOp, landedOpDefect, pairsAtAddress, externalCall } from './kernel-foundations.mjs';
|
|
3
3
|
import { commitAttemptIdOf, terminal, close } from './kernel-terminal.mjs';
|
|
4
4
|
// ---------------------------------------------------------------------------------------------
|
|
5
5
|
// `K-3` `runAttempt(store, commit) -> AttemptReport`
|
|
@@ -144,7 +144,7 @@ function passInCommitScope(store, commitRecord) {
|
|
|
144
144
|
if (attempt.status === 'running') {
|
|
145
145
|
// THE RE-ENTRANT `K-3`, refused by the SAME `KC-7` member a live address answers with.
|
|
146
146
|
refuse(KC.attemptOpen,
|
|
147
|
-
`the constraint attempt at ${
|
|
147
|
+
`the constraint attempt at ${addressSpelling(attempt.address)} is already running`, []);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
attempt.status = 'running';
|
|
@@ -242,7 +242,7 @@ function passInCommitScope(store, commitRecord) {
|
|
|
242
242
|
terminal(kernel, attempt, KC.violated,
|
|
243
243
|
typeof saveFailure.message === 'string'
|
|
244
244
|
? saveFailure.message
|
|
245
|
-
: `the attempt's own save at ${
|
|
245
|
+
: `the attempt's own save at ${addressSpelling(attempt.address)} failed`);
|
|
246
246
|
throw saveFailure;
|
|
247
247
|
}
|
|
248
248
|
// **THE `commit` ENTRY: THE ATTEMPT'S SUCCESS ARM, APPENDED ONCE, ON THIS ARM ALONE**
|
|
@@ -258,7 +258,7 @@ function passInCommitScope(store, commitRecord) {
|
|
|
258
258
|
// before this line and reach this attempt's log by no act (`§2.7` item 6), the record this attempt's
|
|
259
259
|
// report carries being the same list this line closes.
|
|
260
260
|
append(attempt, 'commit', null, attempt.ops[attempt.ops.length - 1].opId,
|
|
261
|
-
`every constraint registered at ${
|
|
261
|
+
`every constraint registered at ${addressSpelling(attempt.address)} passed; the commit stands`);
|
|
262
262
|
return closed;
|
|
263
263
|
}
|
|
264
264
|
|
|
@@ -423,7 +423,7 @@ function evaluate(kernel, attempt, landing) {
|
|
|
423
423
|
let text;
|
|
424
424
|
let repair = null;
|
|
425
425
|
if (outcome === true) {
|
|
426
|
-
text = `the constraint ${pair.id} passed at ${
|
|
426
|
+
text = `the constraint ${pair.id} passed at ${addressSpelling(attempt.address)}`;
|
|
427
427
|
} else if (outcome !== null && typeof outcome === 'object' && Object.hasOwn(outcome, 'message')) {
|
|
428
428
|
const outcomeMessage = ownMember(outcome, 'message');
|
|
429
429
|
text = typeof outcomeMessage === 'string' && outcomeMessage.length > 0
|
|
@@ -612,7 +612,7 @@ function evaluate(kernel, attempt, landing) {
|
|
|
612
612
|
: okMember === false
|
|
613
613
|
&& typeof messageMember === 'string' && messageMember.length > 0
|
|
614
614
|
? messageMember
|
|
615
|
-
: `the repair ${pair.id} produced no op at ${
|
|
615
|
+
: `the repair ${pair.id} produced no op at ${addressSpelling(attempt.address)}`;
|
|
616
616
|
entry.message = carried;
|
|
617
617
|
return { terminal: { status: KC.repairFailed, message: carried }, rerun: false };
|
|
618
618
|
}
|
|
@@ -757,6 +757,6 @@ function publishCheckedOff(attempt) {
|
|
|
757
757
|
* read off a member the row really holds, and no member of the sentence moves. */
|
|
758
758
|
function unrecognized(pair) {
|
|
759
759
|
return `the constraint ${pair.id} returned a value outside the three declared outcome arms at `
|
|
760
|
-
+ `${
|
|
760
|
+
+ `${addressSpelling(pair.addresses[0])}`;
|
|
761
761
|
}
|
|
762
762
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// `D-13` (`docs/L1/kernel-subdivision.md` §1 part `9c`) — the commit act: bytes moved from `bindings/js/src/constraint-kernel.mjs`; no logic changed.
|
|
2
|
-
import { KC, refuse, inDomainAddress, kernelFor, attemptHeldAt, appendOwn } from './kernel-foundations.mjs';
|
|
2
|
+
import { KC, refuse, inDomainAddress, kernelFor, attemptHeldAt, appendOwn, addressSpelling } from './kernel-foundations.mjs';
|
|
3
3
|
// ---------------------------------------------------------------------------------------------
|
|
4
4
|
// `K-2` `commit(store, address, tier, value) -> CommitRecord`
|
|
5
5
|
// ---------------------------------------------------------------------------------------------
|
|
@@ -20,7 +20,7 @@ export function commit(store, address, tier, value) {
|
|
|
20
20
|
// HELD address WITHIN the instance is refused exactly as it stood. **THE ADDRESS COMPARISON ITSELF IS UNMOVED.**
|
|
21
21
|
if (held && attemptHeldAt(kernel, address)) {
|
|
22
22
|
refuse(KC.attemptOpen,
|
|
23
|
-
`a constraint attempt is already open at ${
|
|
23
|
+
`a constraint attempt is already open at ${addressSpelling(address)}; it is disposed of by its own `
|
|
24
24
|
+ 'K-3 and by no other act',
|
|
25
25
|
[]);
|
|
26
26
|
}
|
|
@@ -316,8 +316,32 @@ export function inDomainId(id) {
|
|
|
316
316
|
* being the tuple.
|
|
317
317
|
*/
|
|
318
318
|
export function pairSpelling(pair, address) {
|
|
319
|
-
return `${(address === undefined ? pair.addresses[0] : address).
|
|
320
|
-
|
|
319
|
+
return `${addressSpelling(address === undefined ? pair.addresses[0] : address)}#${pair.id}`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* **THE ADDRESS, SPELLED FOR THE KERNEL'S OWN SENTENCES — ONE RENDERING, DECLARED ONCE, AND THIS IS IT.**
|
|
324
|
+
*
|
|
325
|
+
* **`D-48`'s `DEF-AB` ROW IS THE MEASUREMENT THIS FUNCTION CLOSES: THE SAME ADDRESS WAS PRINTED TWO WAYS
|
|
326
|
+
* ACROSS TWO MESSAGES OF ONE RECORD.** `pairSpelling` above spells an address's segments joined by `/`
|
|
327
|
+
* (`a/b#x`); every other sentence the kernel built spelled the very same address through
|
|
328
|
+
* `JSON.stringify(address)` — `["a"]` — so one attempt's log carried *"the constraint `x` passed at
|
|
329
|
+
* `["a"]`"* beside *"the pair `a#x` violated a re-run …"*. **THE `DEF-Q` DEFECT CLASS AT ANOTHER SITE**, and
|
|
330
|
+
* the rendering that fixes it is the one `pairSpelling` already carried: **the address's segments joined by
|
|
331
|
+
* `/`, and never a JSON array.** There is now ONE spelling, ONE home, and both readers take it here.
|
|
332
|
+
*
|
|
333
|
+
* **IT TAKES THE SEGMENTS AS THE REGISTRY ROW AND THE JOURNAL OP CARRY THEM** — strings and non-negative
|
|
334
|
+
* integers — and renders a segment through `String` alone, exactly as `pairSpelling` always has: **no
|
|
335
|
+
* quoting, no bracketing and no second escaping rule is introduced, and no member of any sentence moves.**
|
|
336
|
+
* A local index loop is used, so no `Array.prototype.map`/`join` is read off a mutable prototype on a refusal
|
|
337
|
+
* path (`contract.md §2.1`'s clause of 2026-10-24 on `F7-1`).
|
|
338
|
+
*/
|
|
339
|
+
export function addressSpelling(address) {
|
|
340
|
+
let spelled = '';
|
|
341
|
+
for (let position = 0; position < address.length; position += 1) {
|
|
342
|
+
spelled += position === 0 ? `${String(address[position])}` : `/${String(address[position])}`;
|
|
343
|
+
}
|
|
344
|
+
return spelled;
|
|
321
345
|
}
|
|
322
346
|
|
|
323
347
|
/// **⟶ DELETED 2026-10-24 (`D-29`): `pairRowCarrying` HAD NO SUBJECT LEFT.** Its doc read: *"THE ROW A PAIR
|
|
@@ -703,7 +727,7 @@ export function landedOp(attempt, returned, invokedFor) {
|
|
|
703
727
|
* — and never the attempt's address alone.
|
|
704
728
|
*/
|
|
705
729
|
export function landedOpDefect(attempt, pair, returned) {
|
|
706
|
-
const where =
|
|
730
|
+
const where = addressSpelling(attempt.address);
|
|
707
731
|
// **⟶ THE MEMBER IS READ AS THE RETURN'S OWN HERE TOO** (`D-35`'s read half): the arm that names *"carried no
|
|
708
732
|
// op"* and the arm that spells the op must agree with `landedOp`'s own answer, and a chain read would let a
|
|
709
733
|
// prototype decide which of the two sentences the caller is handed.
|
package/src/entry/state.mjs
CHANGED
|
@@ -290,10 +290,13 @@ export function externalCall(store, run) {
|
|
|
290
290
|
return run();
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
/** The per-store index: `{ open, observers, windows, windowSeq }`, keyed by the store instance and by
|
|
294
|
-
* else. **`windows` IS THE STACK OF OPEN WINDOW IDENTITIES** — one number per commit this store opened, the
|
|
293
|
+
/** The per-store index: `{ open, observers, windows, marks, windowSeq }`, keyed by the store instance and by
|
|
294
|
+
* nothing else. **`windows` IS THE STACK OF OPEN WINDOW IDENTITIES** — one number per commit this store opened, the
|
|
295
295
|
* top being the window in flight — and it exists so a restart request can name the window that raised it
|
|
296
|
-
* (`D-42`'s *"a request belongs to the act that raised it"*, made a measurement instead of an inference).
|
|
296
|
+
* (`D-42`'s *"a request belongs to the act that raised it"*, made a measurement instead of an inference).
|
|
297
|
+
* **`marks` IS THE STACK BESIDE IT AND IT IS THE SAME ONE STACK READ AS THE JOURNAL MARK** — one entry per commit
|
|
298
|
+
* that OPENED, pushed and popped in lockstep with `windows` (`openCommit`/`closeCommit`), so `windowMark` answers
|
|
299
|
+
* the outermost opening's mark and a join neither pushes nor pops. */
|
|
297
300
|
const ATTEMPT_INDEX = new WeakMap();
|
|
298
301
|
|
|
299
302
|
function attemptIndex(store) {
|
|
@@ -308,7 +311,7 @@ function attemptIndex(store) {
|
|
|
308
311
|
// refusal.** The list preserves the Set's own two facts — insertion order and uniqueness — and the copy
|
|
309
312
|
// is taken before any notification, so an observer that removes itself mid-notification still moves
|
|
310
313
|
// nothing.
|
|
311
|
-
index = { open: 0, observers: [], windows: [], externalAt: [], windowSeq: 0 };
|
|
314
|
+
index = { open: 0, observers: [], windows: [], marks: [], externalAt: [], windowSeq: 0 };
|
|
312
315
|
ATTEMPT_INDEX.set(store, index);
|
|
313
316
|
}
|
|
314
317
|
return index;
|
|
@@ -354,6 +357,54 @@ export function currentWindow(store) {
|
|
|
354
357
|
return windows.length === 0 ? 0 : windows[windows.length - 1];
|
|
355
358
|
}
|
|
356
359
|
|
|
360
|
+
/// **⟶ ADDED 2026-10-27 — THE MARK THE WINDOW IN FLIGHT CACHED AT ITS OPENING, AND `undefined` WHERE NO COMMIT
|
|
361
|
+
/// IS OPEN.**
|
|
362
|
+
///
|
|
363
|
+
/// **THE RULING IT CARRIES, THE ARCHITECT, VERBATIM: *"Cache the restoreMark when opening a commit, based on the
|
|
364
|
+
/// last valid state/op of the journal."*** **THE DEFECT IT CLOSES IS `DEF-AE`'s AND IT IS A DATA-INTEGRITY ONE:**
|
|
365
|
+
/// the refused reversal's restore named **the journal's HEAD**, on the reasoning that *"a reversal appends no
|
|
366
|
+
/// journal entry, so that head describes the state that stood BEFORE the action"* — **a reasoning that fails on
|
|
367
|
+
/// exactly one arm**. In the restart arm the ENCLOSING WRITE'S OWN OP STANDS AT THE HEAD when the listener's
|
|
368
|
+
/// reversal runs, so the compensation restored **the write's landing, not the pre-attempt state**: a write that
|
|
369
|
+
/// reported refusal left its own value standing (`9 → 7`).
|
|
370
|
+
///
|
|
371
|
+
/// **SO THE MARK IS TAKEN WHERE IT IS TRUE AND NOT WHERE IT IS NEEDED.** Every commit that OPENS reads the store's
|
|
372
|
+
/// last valid mark (`withAddon().journalMark`, the store's own `journalMark`) and stands it on the window beside
|
|
373
|
+
/// the window's identity. **THE INSTANT IS THE WHOLE POINT**: at an outermost opening nothing of the attempt has
|
|
374
|
+
/// landed yet, so the mark names the state the commit FOUND. A JOIN IS THE SAME ACT AND RE-CACHES NOTHING — a join
|
|
375
|
+
/// appends no window and no mark, so the cache in flight stays the outermost opening's — which is what makes a
|
|
376
|
+
/// repair's write (a join, `D-46`) and a pass's scope (a join on the production path, `D-44`) read the attempt's
|
|
377
|
+
/// own position rather than a later one. **A CALLBACK'S OWN COMMIT IS ITS OWN OPENING WITH ITS OWN CACHE**
|
|
378
|
+
/// (`D-45`/`D-46`: a listener body's call names nothing and opens), so the mark a listener's own attempt restores
|
|
379
|
+
/// to is where ITS window opened.
|
|
380
|
+
///
|
|
381
|
+
/// **A WINDOW WITH NO CACHE IS A WINDOW THAT NEVER OPENED, AND `undefined` IS ITS SPELLING.** The store answers
|
|
382
|
+
/// `{k:'s', v:<op id>}` where the journal holds an entry and `{k:'F'}` where it holds none (the FLOOR — the state
|
|
383
|
+
/// the store was born with); `undefined` means the read could not answer at all (a store whose artefact could not
|
|
384
|
+
/// be reached), and the refused-reversal restore REFUSES rather than falling back to the head
|
|
385
|
+
/// (`constraints.mjs`'s `restoreReversal` states that arm). **THE MARK IS OPAQUE HERE**: this file caches the
|
|
386
|
+
/// store's own carrier and never composes a position of its own.
|
|
387
|
+
export function windowMark(store) {
|
|
388
|
+
const index = attemptIndex(store);
|
|
389
|
+
if (index.windows.length === 0) return undefined;
|
|
390
|
+
return index.marks[index.marks.length - 1];
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/// **THE MARK THE OPENING TAKES** — the store's own read, once per commit that OPENS and never per join. **IT IS
|
|
394
|
+
/// TAKEN THROUGH THE ENTRY THE ADDON PUBLISHES** (`journalMark`), bound to the store object exactly as every other
|
|
395
|
+
/// addon call is (`commitFile` above is the same form). **A READ THAT THROWS IS A WINDOW WITH NO CACHE AND NOT A
|
|
396
|
+
/// REFUSED CALL**: the opening is not the act the consumer asked for, and refusing the consumer's verb because the
|
|
397
|
+
/// journal read failed would answer a form the verb does not declare — so the arm answers `undefined`, the window
|
|
398
|
+
/// stands without a cache, and the one consumer that needs the mark refuses its own restore instead.
|
|
399
|
+
function journalMarkAtOpening(store) {
|
|
400
|
+
try {
|
|
401
|
+
const addon_ = withAddon();
|
|
402
|
+
return Reflect.apply(addon_.journalMark, store, []);
|
|
403
|
+
} catch (unanswered) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
357
408
|
/** **THE INCREMENT MOMENT** (`PAR-ADA-15`): the opening of a commit. It is taken iff THIS call opens one —
|
|
358
409
|
* a call that finds the count already above zero has joined an extant commit and opens nothing.
|
|
359
410
|
*
|
|
@@ -396,6 +447,14 @@ export function openCommit(store, commit) {
|
|
|
396
447
|
// kept exact in the identity too, and no window id is ever reused.
|
|
397
448
|
index.windowSeq += 1;
|
|
398
449
|
appendOwn(index.windows, index.windowSeq);
|
|
450
|
+
// **⟶ AND THE MARK THE OPENING TAKES, 2026-10-27 — THE ARCHITECT'S RULING: *"Cache the restoreMark when opening
|
|
451
|
+
// a commit, based on the last valid state/op of the journal."*** **THE CACHE IS TAKEN HERE AND ONLY HERE**: this
|
|
452
|
+
// is the arm that OPENS (a join returned above and takes nothing), so the store's read names the journal's
|
|
453
|
+
// position at the instant the commit was entered — before anything the commit will land has landed. **IT IS
|
|
454
|
+
// TAKEN BEFORE THE OBSERVERS FIRE** (the notification below is part of the opening, and an observer that acts
|
|
455
|
+
// would open its own commit; this window's mark is the one that stood when the window itself opened). It is
|
|
456
|
+
// pushed in lockstep with `windows` so the two stacks are one stack, and `closeCommit` releases it with it.
|
|
457
|
+
appendOwn(index.marks, journalMarkAtOpening(store));
|
|
399
458
|
// **AND THE DEPTH FALLBACK'S OWN RECORD IS STOOD BESIDE IT**: the depth this commit was opened at, in lockstep
|
|
400
459
|
// with `windows`, so the next unnamed call can tell the package's own continuation from a callback's act.
|
|
401
460
|
appendOwn(index.externalAt, EXTERNAL_DEPTH);
|
|
@@ -419,15 +478,20 @@ export function closeCommit(store, opened) {
|
|
|
419
478
|
// prototype's `slice`/`pop` (`contract.md §2.1`'s clause of 2026-10-24 on `F7-1`/`F8-2`). A joining call
|
|
420
479
|
// opened nothing and releases nothing, so the enclosing window's identity stands. **AND THE DEPTH STOOD BESIDE
|
|
421
480
|
// IT GOES WITH IT, IN THE SAME LOOP AND AT THE SAME INSTANT**: the two stacks are one stack read two ways, so a
|
|
422
|
-
// commit's depth can never be left standing for a commit that has closed.
|
|
481
|
+
// commit's depth can never be left standing for a commit that has closed. **AND THE MARK THE OPENING CACHED
|
|
482
|
+
// GOES WITH IT IN THAT SAME LOOP** — `windows`, `externalAt` and `marks` are one stack read three ways, so no
|
|
483
|
+
// closed window's journal position can be answered to a later act.
|
|
423
484
|
const kept = [];
|
|
424
485
|
const keptAt = [];
|
|
486
|
+
const keptMark = [];
|
|
425
487
|
for (let i = 0; i + 1 < index.windows.length; i += 1) {
|
|
426
488
|
appendOwn(kept, index.windows[i]);
|
|
427
489
|
appendOwn(keptAt, index.externalAt[i]);
|
|
490
|
+
appendOwn(keptMark, index.marks[i]);
|
|
428
491
|
}
|
|
429
492
|
index.windows = kept;
|
|
430
493
|
index.externalAt = keptAt;
|
|
494
|
+
index.marks = keptMark;
|
|
431
495
|
}
|
|
432
496
|
|
|
433
497
|
/// **THE TWO CHANNELS, INSTALLED ONCE ON THE OBJECT `storeCreate` RETURNS** (`§4.2` item 4: *"`storeCreate`
|