provident-storeroom 1.3.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.
- package/README.guide.md +93 -5
- package/README.md +12 -3
- package/RELEASE-NOTES.md +27 -1
- package/index.d.ts +39 -4
- package/index.mjs +110 -32
- package/package.json +6 -6
- package/src/entry/constraints.mjs +264 -8
- package/src/entry/delivery.mjs +11 -3
- package/src/entry/kernel-attempt.mjs +48 -7
- package/src/entry/kernel-commit.mjs +165 -0
- package/src/entry/kernel-foundations.mjs +166 -16
- package/src/entry/kernel-registration.mjs +18 -5
|
@@ -19,7 +19,15 @@ import { currentWindow, homeAddressKey, installRestartConsumer, isStoreReceiver,
|
|
|
19
19
|
// function the pass appends with — rather than pushed here with a member set of its own; the REFUSAL's own
|
|
20
20
|
// list keeps its five members and no `seq`, because no attempt stands at the judgement that built it
|
|
21
21
|
// (`D-41` item 4). Two records, two honest forms, one append.
|
|
22
|
-
import { append, externalCall, kernelFor } from './kernel-foundations.mjs';
|
|
22
|
+
import { append, externalCall, kernelFor, throwableForm } from './kernel-foundations.mjs';
|
|
23
|
+
// **⟶ AND THE TWO KERNEL ACTS THE DELETE'S PATH OWES — `D-55` ITEM 3, 2026-10-29.** The kernel's public
|
|
24
|
+
// barrel (`src/constraint-kernel.mjs`) is untouched and keeps its five names; **these are two PART modules' own
|
|
25
|
+
// acts, reached here the way `append` and `kernelFor` above are** (`kernel-surface.md §1` item 1's empty import
|
|
26
|
+
// footprint is the kernel's side of this edge and it is unmoved: neither module imports this file or any entry
|
|
27
|
+
// module). `commitRemoval` is the commit part's remove-shaped act — a delete-shaped attempt that lands no write
|
|
28
|
+
// — and `runAttempt` is the ONE pass, taken verbatim so no second pass loop is minted for a delete.
|
|
29
|
+
import { commitRemoval } from './kernel-commit.mjs';
|
|
30
|
+
import { runAttempt } from './kernel-attempt.mjs';
|
|
23
31
|
// **⟶ AND THE CARRIERS, ADDED 2026-10-26 FOR THE REFUSAL'S OWN UNDOING (`DEF-W`'s `(a)`).** The
|
|
24
32
|
// compensating act below reaches the store's own verb at its entry, with the SAME carrier forms every member
|
|
25
33
|
// hands it (`carrier.mjs` is the boundary's one encoder for the three positions and imports nothing of this
|
|
@@ -489,7 +497,11 @@ export function registrationCrossing(refusal) {
|
|
|
489
497
|
// is the caller's own value and is answered as it was thrown.
|
|
490
498
|
const carried = bodyThrowCarried(refusal);
|
|
491
499
|
if (carried !== null) {
|
|
492
|
-
|
|
500
|
+
// **`false` — THE REGISTRATION INSTANT RECORDS NOTHING, AND THE CLAUSE SAYS SO.** No attempt stands at
|
|
501
|
+
// this evaluation, so the crossing's `log` is `surface.md §2.5` item 4's declared `[]` (`DEF-S`'s own cell
|
|
502
|
+
// reads it) and no terminal entry exists to carry the throwable's form: the crossed sentence must not
|
|
503
|
+
// point at a log that does not hold it (`DEF-AK`, 2026-10-28).
|
|
504
|
+
const converted = bodyThrowRefusal(carried, refusal, false);
|
|
493
505
|
if (converted !== null) throw converted;
|
|
494
506
|
}
|
|
495
507
|
if (isKernelBuiltRefusal(refusal) === false) throw refusal;
|
|
@@ -829,6 +841,140 @@ export function constraintWrite(state, instance, address, tier, value) {
|
|
|
829
841
|
};
|
|
830
842
|
}
|
|
831
843
|
|
|
844
|
+
/**
|
|
845
|
+
* **⟶ ADDED 2026-10-29 — THE DELETE'S OWN KERNEL-DRIVEN PATH: A DELETE-SHAPED ATTEMPT, A PASS, AND THE
|
|
846
|
+
* TERMINAL ENTRY. `D-55` ITEM 3, `DEF-X`, THE ARCHITECT, VERBATIM: *"A delete is an editing verb and must pass
|
|
847
|
+
* constraints. This includes all of the relevant commit and message logic."***
|
|
848
|
+
*
|
|
849
|
+
* **WHAT WAS MEASURED AT `1.3.0`, AND IT IS WHY THIS FUNCTION EXISTS.** `delete` opened its own commit window
|
|
850
|
+
* and called the addon's `delete` directly: **no `K-2`, no `K-3`, no log, no terminal entry** — so a delete
|
|
851
|
+
* consulted no constraint at all, and **the only pass shape the artefact had LANDS A WRITE FIRST** (`K-2`'s
|
|
852
|
+
* store leg called `write`, so the pass it ran judged a state the delete was not in; measured `storeAfter =
|
|
853
|
+
* {"c":2}`). **A delete therefore needed an attempt of its OWN KIND rather than a re-used `K-2`.**
|
|
854
|
+
*
|
|
855
|
+
* **THE THREE STAGES, IN THE ONE ORDER `constraintWrite` TAKES ITS OWN** (`surface.md §2.12` item 1):
|
|
856
|
+
* ```
|
|
857
|
+
* 1. the delete-shaped attempt `kernel.commitRemoval` — the hold, the commit's log, the delete's op
|
|
858
|
+
* named as the attempt's landing; NO WRITE IS LANDED
|
|
859
|
+
* 2. the store's own leg the thunk the entry hands: the addon's `delete`, crossed by `index.mjs`
|
|
860
|
+
* 3. the pass `kernel.runAttempt` — every pair standing at THE DELETE'S OWN ADDRESS is
|
|
861
|
+
* asked against THE STATE THE DELETE LEFT (its after-state is absence)
|
|
862
|
+
* 4. the terminal act the attempt's ONE `outcome` entry on the refusing arm, its `commit` entry
|
|
863
|
+
* on the passing arm, and on a refusal the composition that undoes the
|
|
864
|
+
* delete (`D-55` item 5's safe state)
|
|
865
|
+
* ```
|
|
866
|
+
* **THE PASS IS THE WRITE'S PASS, MEMBER FOR MEMBER** — `runAttempt`, the same evaluated set, the same `D-39`
|
|
867
|
+
* registration order, the same repair and re-run arms, the same restart drain — and **the ONLY difference is the
|
|
868
|
+
* landing it judges**: a delete's journal op, whose `after` is absence, instead of a write's op whose `after` is
|
|
869
|
+
* the value it landed. **NO SECOND PASS LOOP IS MINTED**, and a repair landed under a delete's pass re-runs the
|
|
870
|
+
* same evaluation against ITS op (`D-53`: repairs use the same commit).
|
|
871
|
+
*
|
|
872
|
+
* **⟶ AND "THE SAME EVALUATED SET" IS NOW A PREFIX SET, 2026-10-29 — `D-56`, WHICH SUPERSEDES THE CLAUSE THIS
|
|
873
|
+
* PARAGRAPH PRINTED.** `RCA-8(g)` ANNOTATE-BESIDE: **the bytes that stood here read** *"the same evaluated set
|
|
874
|
+
* (the pairs whose own address IS the attempt's, `pairsAtAddress`'s exact-address rule and never the trigger set's
|
|
875
|
+
* prefix widening)"*, **and they are read THROUGH the architect's sentence**: *"A listener/constraint should fire
|
|
876
|
+
* when the descendants of its targeted address node change, because the descendants become part of the object
|
|
877
|
+
* that is read from that address"*. **SO THE DELETE'S PASS ASKS THE PAIRS AT OR ABOVE THE DELETE'S ADDRESS** —
|
|
878
|
+
* the pairs whose own address is a PREFIX of it — **and a pair at `['tabs']` is asked for a delete at
|
|
879
|
+
* `['tabs','landingPage']`** (`strata/decisions.md` · `D-56`). **THE SET IS STILL `pairsAtAddress`'s ONE
|
|
880
|
+
* FUNCTION AND STILL ONE SNAPSHOT** (`CX-12`): `D-56` moves WHICH rows are members and nothing about WHEN the
|
|
881
|
+
* list is materialised, HOW it is ordered (`HL-8` item 6: first-registration order, ancestors interleaved into
|
|
882
|
+
* that one order) or how many times a row is asked.
|
|
883
|
+
*
|
|
884
|
+
* **A REFUSAL IS THE ORDINARY REFUSAL** (`constraintCrossing` below): the surface's one plain form
|
|
885
|
+
* `{status, message, log}`, its `status` the set's rank-`20` member `ConstraintPassRefused`, and its `log` the
|
|
886
|
+
* COMMIT'S OWN LIST — `constraint-check` for the pair that refused, then the terminal `outcome` entry whose
|
|
887
|
+
* `state` is the kernel's token — each with its `seq`. **AND THE SAFE STATE IS `D-55` ITEM 5's**: the
|
|
888
|
+
* composition the terminal act runs (`composeRollback`, one floor call per address at that address's first owed
|
|
889
|
+
* op) undoes **the delete and every edit the commit made under it**, so the caller meets a store back at the
|
|
890
|
+
* state the commit opened at. Where the refusal is a RESTARTED check's (`D-42`, a reversal raised by a body
|
|
891
|
+
* inside this pass), the compensation is the reversal's own and it restores the journal mark the commit cached
|
|
892
|
+
* at ITS OPENING (`state.mjs`'s `windowMark`) — the same safe state by the other route.
|
|
893
|
+
*
|
|
894
|
+
* **`D-3`'S NO-OP ARM IS NOT AN EDIT**: where the delete removed nothing there is no journal op, so
|
|
895
|
+
* `commitRemoval` answers `null`, **no attempt is opened, no pass runs and no entry is appended** — there is no
|
|
896
|
+
* state for a pair to refuse and nothing for the safe-state rule to undo. The record crosses as it always did.
|
|
897
|
+
*
|
|
898
|
+
* **THE DELIVERY IS THE TERMINAL ARM'S FROM 2026-10-29, AND IT IS WHY THE PASS IS HANDED THE `CommitRecord`
|
|
899
|
+
* (`D-55` item 3's third demand: a listener fired by a delete sees the JUDGED state, and a refused delete
|
|
900
|
+
* delivers nothing, its commit having been undone).** `commitRemoval` now mints the record the pass's terminal
|
|
901
|
+
* arm is keyed by, and `runAttempt` reaches that arm with it (`settleArm` → the entry's `TERMINAL_ARM`), so the
|
|
902
|
+
* residue `record.pending` — the delete's returned set MINUS the handles its own pass checked off — is
|
|
903
|
+
* delivered at the arm, after the judgement, exactly as a write's is. **A REFUSED DELETE STILL DELIVERS
|
|
904
|
+
* NOTHING**: the failing arm reaches the same seam with the residue the discard emptied (`terminal`).
|
|
905
|
+
*
|
|
906
|
+
* **AND THE RECORD IS HANDED TO THE CONSUMER ON THE RECEIPT, UNDER THE `D-49` DEVICE.** `DeleteRecord` keeps
|
|
907
|
+
* its enumerable members; `commit` is a NON-ENUMERABLE own `data` property, visible by its name and declared in
|
|
908
|
+
* `index.d.ts`, exactly as `discarded` is — so the record a delete minted can be held (`receipt.commit`) and
|
|
909
|
+
* handed back (`K-4`/`K-5` take its `attempt`; a nested `write` takes the record itself at its fourth
|
|
910
|
+
* position). **`null` IS THE `D-3` ARM'S VALUE**: no attempt was opened there, so there is no record to carry.
|
|
911
|
+
*/
|
|
912
|
+
export function constraintDelete(instance, address, tier, remove) {
|
|
913
|
+
// THE DELETE-SHAPED ATTEMPT, OPENED AROUND THE STORE'S OWN LEG: `remove` is the addon's `delete`, already
|
|
914
|
+
// crossed by the entry, and it is invoked with the hold taken and the commit's list in hand. `null` is the
|
|
915
|
+
// `D-3` arm (nothing removed) — the receipt the thunk answered stands and nothing is judged.
|
|
916
|
+
let receipt = null;
|
|
917
|
+
let attempt;
|
|
918
|
+
try {
|
|
919
|
+
attempt = commitRemoval(instance, address, tier, () => {
|
|
920
|
+
receipt = remove();
|
|
921
|
+
return receipt;
|
|
922
|
+
});
|
|
923
|
+
} catch (refusal) {
|
|
924
|
+
// THE KERNEL'S OWN `KC-7` (a held address, before the store is reached) or the store's own refusal: the
|
|
925
|
+
// ONE crossing every kernel-driven path takes, so a nested delete at a live attempt's address answers the
|
|
926
|
+
// same rank-`20` form a write does and a store refusal crosses verbatim (`§2.5` item 10 (ii)).
|
|
927
|
+
constraintCrossing(refusal);
|
|
928
|
+
}
|
|
929
|
+
// **THE `D-3` ARM CARRIES ITS `null`** — no attempt, so no record, and the member is present rather than
|
|
930
|
+
// absent (`D-21`: a member whose act did not run says so).
|
|
931
|
+
if (attempt === null) {
|
|
932
|
+
exposeCommit(receipt, null);
|
|
933
|
+
return receipt;
|
|
934
|
+
}
|
|
935
|
+
// THE PASS, INSIDE THE COMMIT THE MEMBER OPENED (`D-44`): `runAttempt` names THE RECORD `commitRemoval`
|
|
936
|
+
// minted (`attempt.record` — the same object `K-2` hands `K-3`), so its scope JOINS — the delete's window is
|
|
937
|
+
// the pass's window, and the pairs standing at THIS address are asked against the delete's own op. **THE
|
|
938
|
+
// TERMINAL ARM IS REACHED WITH THAT RECORD AND NOTHING ELSE** (`settleArm`), so the delivery and the
|
|
939
|
+
// `file`-tier save are the record's own facts. A failing pass throws the kernel's own refusal with its log
|
|
940
|
+
// and its compensating act already taken.
|
|
941
|
+
let report;
|
|
942
|
+
try {
|
|
943
|
+
report = runAttempt(instance, attempt.record);
|
|
944
|
+
} catch (refusal) {
|
|
945
|
+
constraintCrossing(refusal);
|
|
946
|
+
}
|
|
947
|
+
// **AND THE RESTART'S REFUSAL, WHERE THE PASS ITSELF PASSED** (`D-42`; `D-54` (b)): a reversal raised by a
|
|
948
|
+
// body inside this pass is drained at the pass's terminal state, and where the restarted check refused, the
|
|
949
|
+
// refusal the report carries is the one that crosses — the delete is refused with the store already restored
|
|
950
|
+
// to the mark the commit cached at its opening. THE PASSING DELETE FINDS NO CARRIED REFUSAL AND RETURNS ITS
|
|
951
|
+
// RECEIPT UNCHANGED.
|
|
952
|
+
const restarted = report !== null && typeof report === 'object' ? report[RESTART_REFUSAL] : undefined;
|
|
953
|
+
if (restarted !== undefined) {
|
|
954
|
+
constraintCrossing(restarted);
|
|
955
|
+
}
|
|
956
|
+
exposeCommit(receipt, attempt.record);
|
|
957
|
+
return receipt;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
/// **THE RECORD ON THE RECEIPT — A NON-ENUMERABLE OWN `data` PROPERTY, THE DEVICE `D-49` DECLARED.**
|
|
961
|
+
///
|
|
962
|
+
/// `Object.keys(receipt)`, every deep-equality over a receipt and every census of its ENUMERABLE members read
|
|
963
|
+
/// exactly what they read before, while a caller reads the commit **by its name** (`receipt.commit`) and
|
|
964
|
+
/// `index.d.ts` declares it. **IT IS A `data` PROPERTY AND NOT AN ACCESSOR**: a getter would run caller-side
|
|
965
|
+
/// code on a read, which is the read half `D-35` closes everywhere else. **A RECEIPT THAT ALREADY CARRIES ONE**
|
|
966
|
+
/// — the thunk answers the store's own object and this entry owns it — takes the value it was handed, and the
|
|
967
|
+
/// member is defined on every arm so its presence never depends on the arm.
|
|
968
|
+
function exposeCommit(receipt, record) {
|
|
969
|
+
if (receipt === null || typeof receipt !== 'object') return;
|
|
970
|
+
Object.defineProperty(receipt, 'commit', {
|
|
971
|
+
value: record === undefined ? null : record,
|
|
972
|
+
enumerable: false,
|
|
973
|
+
writable: false,
|
|
974
|
+
configurable: true,
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
|
|
832
978
|
/// **THE FAIL ARM'S CROSSING — `A120` (2): THE ENTRY CARRIES THE KERNEL'S TOKEN, THE THROW KEEPS THE
|
|
833
979
|
/// STORE'S — AND THE FORM CROSSES AT THREE MEMBERS FROM 2026-10-16** (`surface.md §2.5`'s clause of that
|
|
834
980
|
/// date, items 3–4 and 10 (i)–(iii); `docs/specs/storeroom-js/surface.md §2.12` item 1's mark of the same date).
|
|
@@ -1111,7 +1257,7 @@ function innerRefusalCarried(value) {
|
|
|
1111
1257
|
/// **A TREE THAT CARRIES NO USABLE GENERATOR ANSWERS `null`**, and both crossings then re-throw the marked
|
|
1112
1258
|
/// value AS ITSELF — the same safe direction `registrationCrossing` takes for a kernel refusal, and no
|
|
1113
1259
|
/// sentence is authored here.
|
|
1114
|
-
function bodyThrowRefusal(carried, thrown) {
|
|
1260
|
+
function bodyThrowRefusal(carried, thrown, recorded) {
|
|
1115
1261
|
const addon_ = withAddon();
|
|
1116
1262
|
if (typeof addon_.errorMessage !== 'function') return null;
|
|
1117
1263
|
const subject = typeof carried.address === 'string' ? carried.address : '';
|
|
@@ -1130,6 +1276,22 @@ function bodyThrowRefusal(carried, thrown) {
|
|
|
1130
1276
|
+ `ITSELF a refusal, ${JSON.stringify(innerStatus)} with the message ${JSON.stringify(innerSaid)}, and it `
|
|
1131
1277
|
+ `crosses BESIDE this one under Symbol.for('provident-storeroom.inner-refusal') with its own log — the `
|
|
1132
1278
|
+ `generated sentence above names the CODE for a body that threw and not the value the body threw`;
|
|
1279
|
+
} else {
|
|
1280
|
+
// **⟶ AND THE PLAIN THROWABLE'S SENTENCE STOPS CLAIMING A CROSSING IT DOES NOT MAKE — `D-55` ITEM 1,
|
|
1281
|
+
// `DEF-AK`, 2026-10-28.** The generated sentence's own bytes are *"a constraint body's throwable crosses
|
|
1282
|
+
// as this refusal"*, and the throwable DOES NOT: it is not carried, its members are not merged and its
|
|
1283
|
+
// identity is not handed on. **WHAT DOES CROSS IS ITS MESSAGE, IN THE COMMIT'S LOG** — the terminal arm of
|
|
1284
|
+
// the attempt that caught it put the form the value took (the string's own text, the object's own
|
|
1285
|
+
// `message` member, or the kind of value it was) in the ONE entry the arm appends. **`recorded` IS THAT
|
|
1286
|
+
// FACT, SAID BY THE CROSSING THAT CALLED THIS FRAME** (`constraintCrossing` reads the arm that records it;
|
|
1287
|
+
// `registrationCrossing` and the judgement do not), **so no arm points at a `log` that does not carry it**:
|
|
1288
|
+
// where the arm records nothing the clause says so and names the declared `[]` (`surface.md §2.5` item 4).
|
|
1289
|
+
const where = recorded === true
|
|
1290
|
+
? `the form the throwable took stands in the \`outcome\` entry of this refusal's \`log\`, which is where `
|
|
1291
|
+
+ `a throwable's own message crosses`
|
|
1292
|
+
: `no entry of this failure's \`log\` records it — \`log\` is the declared empty list where no attempt `
|
|
1293
|
+
+ `stands (surface.md §2.5 item 4) — so nothing of the value crosses`;
|
|
1294
|
+
generated = `${generated} — the value the constraint body threw does NOT cross as this refusal: ${where}`;
|
|
1133
1295
|
}
|
|
1134
1296
|
const crossed = {
|
|
1135
1297
|
status: BODY_THREW_STATUS,
|
|
@@ -1159,7 +1321,10 @@ function constraintCrossing(refusal) {
|
|
|
1159
1321
|
// `{status, message}` AND NO MARK STILL CROSSES AS ITSELF, BELOW.**
|
|
1160
1322
|
const carried = bodyThrowCarried(refusal);
|
|
1161
1323
|
if (carried !== null) {
|
|
1162
|
-
|
|
1324
|
+
// **`true` — THIS IS THE LANDING'S OWN CROSSING, AND ITS TERMINAL ARM RECORDS THE THROWABLE'S FORM**
|
|
1325
|
+
// (`kernel-attempt.mjs`'s `evaluate`: the attempt closes with ONE `outcome` entry whose sentence carries
|
|
1326
|
+
// `throwableForm(body)`), so the crossed sentence may point at it and `DEF-AK`'s log entry exists.
|
|
1327
|
+
const converted = bodyThrowRefusal(carried, refusal, true);
|
|
1163
1328
|
if (converted !== null) throw converted;
|
|
1164
1329
|
}
|
|
1165
1330
|
const isObject = refusal !== null && typeof refusal === 'object';
|
|
@@ -1494,6 +1659,23 @@ const COMPENSATING = Symbol.for('provident-storeroom.compensating-rollback');
|
|
|
1494
1659
|
/// first address, which is a fact about registration order and not about the check.
|
|
1495
1660
|
const ASKING = new WeakMap();
|
|
1496
1661
|
|
|
1662
|
+
/// **⟶ THE VALUE A BODY THREW, CARRIED FROM THE FRAME THAT CAUGHT IT TO THE ENTRY THAT MUST PRINT IT, ADDED
|
|
1663
|
+
/// 2026-10-28 — `D-55` ITEM 1, `DEF-AK`, MEASURED.**
|
|
1664
|
+
///
|
|
1665
|
+
/// **THE WINDOW IT CLOSES.** A pair body that throws at a reversal's judgement is caught by `reversalOutcome`,
|
|
1666
|
+
/// which converts it to the surface's rank-`18` form; `judgeReversal` then catches that and builds the refusal
|
|
1667
|
+
/// whose ONE log entry names the throwing pair. **NOTHING OF THE THROWABLE REACHED ANY RECORD**: the crossed
|
|
1668
|
+
/// sentence said *"a constraint body's throwable crosses as this refusal"* and the log carried only the pair's
|
|
1669
|
+
/// name. **D-55's clarification (the architect, verbatim: *"Include a thrown message in the message log.
|
|
1670
|
+
/// Obviously."*) makes the message a log entry's own business**, and no attempt log stands at this judgement —
|
|
1671
|
+
/// so the form travels here, from the catch frame to `reversalRefusal`'s entry sentence.
|
|
1672
|
+
///
|
|
1673
|
+
/// **A `WeakMap` KEYED BY THE CONVERTED FORM AND NOTHING ELSE** (`D-30`'s device, `D-46`): the form's three
|
|
1674
|
+
/// declared members are unmoved, no symbol is spelled on a value a caller holds, and the record dies with the
|
|
1675
|
+
/// value. **A TREE WITH NO USABLE GENERATOR IS NOT CONVERTED**, so its raw value reaches `reversalRefusal` and
|
|
1676
|
+
/// that frame spells the form itself (`throwableForm`) — the map answers nothing and nothing is invented.
|
|
1677
|
+
const THROWN_FORM = new WeakMap();
|
|
1678
|
+
|
|
1497
1679
|
/// **HOW MANY RESTARTS ONE PASS'S COMMIT SCOPE MAY TAKE** — the bound `drainRestartRequests` spends. Three is
|
|
1498
1680
|
/// the declared figure: two fewer than any arm of this package's own batteries drives, and enough that a lawful
|
|
1499
1681
|
/// in-commit action's single restart never meets it.
|
|
@@ -1690,6 +1872,17 @@ export function witnessDiscardedReversal(instance, window) {
|
|
|
1690
1872
|
}
|
|
1691
1873
|
// THE STORE'S OWN ECHO OF THE ID THE REVERSAL NAMED — `null` where the reversal's call answered no id (the
|
|
1692
1874
|
// request stands and the act's answer did not reach the echo, which is a real arm a caller can see).
|
|
1875
|
+
//
|
|
1876
|
+
// **⟶ AND AN ENTRY IS NEVER SHIPPED WITH AN EMPTY ADDRESS LIST — `D-55` ITEM 2, `DEF-AH`, 2026-10-28.**
|
|
1877
|
+
// The architect, verbatim: *"A witness address of [] corresponds to the register itself. This is not a legal
|
|
1878
|
+
// response for any other watched address."* **SO `[]` IS THE REGISTER (THE ROOT) AND IS AN ADDRESS, NEVER A
|
|
1879
|
+
// LIST**: a request whose reversal moved NOTHING has no discard to report — there is no legal response to
|
|
1880
|
+
// give it — so **the entry is ABSENT (`null`) rather than empty**, and the caller reads `discarded: []`
|
|
1881
|
+
// because nothing was discarded *observably*. **AND THE ROOT STAYS DISTINGUISHABLE**: an address that IS
|
|
1882
|
+
// `[]` is one element of `addresses` — `[[]]` — which is length `1` and therefore survives this test; the
|
|
1883
|
+
// distinction the ruling draws is between an ADDRESS of `[]` and a LIST of `[]`, and this is the one line
|
|
1884
|
+
// where it is measured.
|
|
1885
|
+
if (addresses.length === 0) return null;
|
|
1693
1886
|
return {
|
|
1694
1887
|
opId: typeof request.reversalId === 'string' ? request.reversalId : null,
|
|
1695
1888
|
addresses,
|
|
@@ -1823,13 +2016,55 @@ export function reversalWatch(state, instance) {
|
|
|
1823
2016
|
// judgement — a listener's own window is the measured arm), and the arm past the budget then says so
|
|
1824
2017
|
// rather than naming a pair it cannot know.
|
|
1825
2018
|
const asking = ASKING.get(instance);
|
|
1826
|
-
|
|
1827
|
-
|
|
2019
|
+
const window = currentWindow(instance);
|
|
2020
|
+
// **⟶ AND A SECOND RAISE IN THE SAME COMMIT MERGES INTO THE REQUEST RATHER THAN REPLACING IT — `D-55`
|
|
2021
|
+
// ITEM 6's SECOND HALF, `DEF-AP`, 2026-10-28, MEASURED.** **WHAT WAS MEASURED:** two listeners each
|
|
2022
|
+
// reversing inside ONE commit — two raises in one window — left only the LAST raise judged; the earlier
|
|
2023
|
+
// listener's own violation was asked **zero** times, registration order decided which raise was lost, and
|
|
2024
|
+
// when the survivor's judgement passed the write returned normally **with the violation standing**. **THE
|
|
2025
|
+
// ROW'S OWN ESCAPE — declare that an overwritten raise may leave a violation unjudged — IS UNAVAILABLE**,
|
|
2026
|
+
// because `DEF-AN`'s safe-state rule is the promise: a refused edit undoes the WHOLE commit.
|
|
2027
|
+
// **SO THE DRAIN JUDGES THE STATE THE COMMIT STANDS AT, NOT THE REQUEST THAT HAPPENED TO SURVIVE**: the
|
|
2028
|
+
// request's captures are merged to the EARLIEST reading of each address — the state the commit opened at —
|
|
2029
|
+
// so `movedStanding` at the drain sees every address the WHOLE commit moved, whichever raise named it.
|
|
2030
|
+
// **THE WALK'S ORDER AND MEMBERSHIP STAY THE REGISTRY'S** (`watchStanding`'s `D-39` order, re-read now):
|
|
2031
|
+
// an address this raise's walk carries takes the earlier capture where one exists, and an address the
|
|
2032
|
+
// earlier watch carried but the registry no longer does leaves the debt record (it is not the check's
|
|
2033
|
+
// subject now). **THE LATEST RAISE KEEPS ITS OWN ASK AND ITS `moved` IS RE-MEASURED**; the `reversalId`
|
|
2034
|
+
// stays the first echo it recorded (`judgeReversal`'s in-flight arm sets it once), so the entry a refusal
|
|
2035
|
+
// names is never re-spelled.
|
|
2036
|
+
const next = watchStanding(state, instance);
|
|
2037
|
+
const record = restartRecord(instance);
|
|
2038
|
+
const prior = record.pending;
|
|
2039
|
+
if (prior !== null && prior.window === window) {
|
|
2040
|
+
const merged = [];
|
|
2041
|
+
for (let index = 0; index < next.length; index += 1) {
|
|
2042
|
+
const one = next[index];
|
|
2043
|
+
const spelling = homeAddressKey(one.address);
|
|
2044
|
+
let earlier = null;
|
|
2045
|
+
for (let known = 0; known < prior.watched.length; known += 1) {
|
|
2046
|
+
if (homeAddressKey(prior.watched[known].address) === spelling) {
|
|
2047
|
+
earlier = prior.watched[known];
|
|
2048
|
+
break;
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
appendOwn(merged, earlier === null ? one : earlier);
|
|
2052
|
+
}
|
|
2053
|
+
prior.watched = merged;
|
|
2054
|
+
// THE MOVED SET IS RE-MEASURED AGAINST THE MERGED CAPTURES (`judgeReversal`'s in-flight arm does it at
|
|
2055
|
+
// the reversal's own instant, one frame below this call) — a set measured against the later watch would
|
|
2056
|
+
// hide the earlier raise's movement, which is the defect this merge closes.
|
|
2057
|
+
prior.moved = null;
|
|
2058
|
+
prior.asked = asking === undefined ? prior.asked : asking;
|
|
2059
|
+
return watched;
|
|
2060
|
+
}
|
|
2061
|
+
record.pending = {
|
|
2062
|
+
watched: next,
|
|
1828
2063
|
// **AND THE MOVED SET IS MEASURED BY THE JUDGEMENT, NOT BY THE WATCH** (`judgeReversal`'s in-flight arm;
|
|
1829
2064
|
// `DEF-AM`): the watch is taken BEFORE the reversal runs, so what moved is not knowable here.
|
|
1830
2065
|
moved: null,
|
|
1831
2066
|
reversalId: null,
|
|
1832
|
-
window
|
|
2067
|
+
window,
|
|
1833
2068
|
asked: asking === undefined ? null : asking,
|
|
1834
2069
|
};
|
|
1835
2070
|
return watched;
|
|
@@ -2498,7 +2733,18 @@ function reversalOutcome(instance, entry, address, value) {
|
|
|
2498
2733
|
// **⟶ AND THE BODY'S OWN VALUE IS HANDED IN, 2026-10-28 (`DEF-AK`)**: `bodyThrowRefusal` carries an inner
|
|
2499
2734
|
// refusal beside the crossed one and names it in the crossed sentence, and the value the body threw is
|
|
2500
2735
|
// the only place that refusal stands.
|
|
2501
|
-
|
|
2736
|
+
//
|
|
2737
|
+
// **⟶ AND ITS FORM IS TAKEN HERE, 2026-10-28 — `D-55` ITEM 1, `DEF-AK`.** No attempt stands at a reversal's
|
|
2738
|
+
// judgement, so there is no terminal entry for the kernel to record it in: **the judgement's own refusal
|
|
2739
|
+
// list is the log this failure crosses with**, and its ONE entry carries the form the body threw
|
|
2740
|
+
// (`reversalRefusal` reads it off this `WeakMap`). **A `WeakMap` AND NOT A MEMBER**: the converted form's
|
|
2741
|
+
// three members are unmoved and nothing is added to any record (`A117` (D6)).
|
|
2742
|
+
const form = throwableForm(body);
|
|
2743
|
+
// **`false` — NO ATTEMPT LOG STANDS AT A JUDGEMENT, AND THIS FRAME'S OWN LIST KEEPS ITS ONE ENTRY**: the
|
|
2744
|
+
// form the body threw is carried through `THROWN_FORM` and printed in that entry's sentence by
|
|
2745
|
+
// `reversalRefusal`, so the crossed sentence points at the `log` it actually carries (`DEF-AK`).
|
|
2746
|
+
const converted = bodyThrowRefusal(carried, body, false);
|
|
2747
|
+
if (converted !== null && typeof converted === 'object') THROWN_FORM.set(converted, form);
|
|
2502
2748
|
throw converted === null ? body : converted;
|
|
2503
2749
|
}
|
|
2504
2750
|
}
|
|
@@ -2615,8 +2861,18 @@ function reversalRefusal(one, after, said, reversalId, undo, thrown, unsettled =
|
|
|
2615
2861
|
+ (said === null ? '' : ` — ${said}`)
|
|
2616
2862
|
+ ` — ${undoSpelling(undo)}`;
|
|
2617
2863
|
} else {
|
|
2864
|
+
// **⟶ AND THE THROWABLE'S OWN FORM IS PRINTED IN THIS ENTRY — `D-55` ITEM 1, `DEF-AK`, 2026-10-28.** No
|
|
2865
|
+
// attempt stands at a reversal's judgement, so no commit log exists for the kernel to append to: **this
|
|
2866
|
+
// refusal's ONE entry is the log the failure crosses with**, so the value the body threw is named HERE —
|
|
2867
|
+
// the form the catch frame took (`THROWN_FORM`) where the value was converted, and the value's own form
|
|
2868
|
+
// where the tree carried no generator to convert it. **THE ENTRY'S SHAPE, KIND, `seq` AND MEMBER COUNT DO
|
|
2869
|
+
// NOT MOVE**: the form is in the sentence, not in a seventh member and not in a second entry (`D-41` item
|
|
2870
|
+
// `4`'s one-entry arm, which the restoration's cell asserts).
|
|
2871
|
+
const took = THROWN_FORM.get(thrown);
|
|
2872
|
+
const form = typeof took === 'string' ? took : throwableForm(thrown);
|
|
2618
2873
|
spelled = `the constraint ${one.entry.id} THREW at the judgement of the state the reversal left at `
|
|
2619
2874
|
+ `${addressSpelling(one.address)}: the value there is ${standingSpelling(after)}`
|
|
2875
|
+
+ ` — the value it threw was ${form}`
|
|
2620
2876
|
+ ` — ${undoSpelling(undo)}`;
|
|
2621
2877
|
}
|
|
2622
2878
|
const entry = {
|
package/src/entry/delivery.mjs
CHANGED
|
@@ -600,9 +600,17 @@ export function terminalArm(state, record) {
|
|
|
600
600
|
const triggeringAddress = answer === null || answer === undefined || answer.op === null || answer.op === undefined
|
|
601
601
|
? undefined
|
|
602
602
|
: answer.op.address;
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
|
|
603
|
+
// **⟶ AND THE ARM PERFORMS THE DELIVERY FOR A KERNEL-DRIVEN WRITE AND FOR NO OTHER ACT — 2026-10-29.** A
|
|
604
|
+
// `delete`'s delivery is its OWN MEMBER's (`D-49` declares that window the one whose check never ran, and a
|
|
605
|
+
// request raised there is the witness's and not a pass's); the record is the delete's, so this arm is
|
|
606
|
+
// reached for it — the `file`-tier save above is the arm's act on BOTH — and the residue's delivery is the
|
|
607
|
+
// member's. **THE FACT IS THE PACKAGE'S OWN STATE AND NEVER A MEMBER OF ANY RECORD**, and it is `'arm'` on
|
|
608
|
+
// every path that does not name another, so a write's delivery is exactly where it was.
|
|
609
|
+
if (state.legDelivery !== 'member') {
|
|
610
|
+
// `deliver` is THE SAME loop the post-verb window uses (`docs/specs/storeroom-js/surface.md §2.4` rules 1–3 read once, at both instants): ONE
|
|
611
|
+
// invocation per DISTINCT handle, and a handle with no registered function fires nothing silently.
|
|
612
|
+
deliver(state, triggered, triggeringAddress);
|
|
613
|
+
}
|
|
606
614
|
return undefined;
|
|
607
615
|
}
|
|
608
616
|
|
|
@@ -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, addressSpelling, sameAddress, kernelFor, append, appendOwn, ownMember, withdraw, landedOp, landedOpDefect, pairsAtAddress, enterCommitFrame, leaveCommitFrame } from './kernel-foundations.mjs';
|
|
2
|
+
import { KC, KC_TOKENS, SETTLED_ON_THE_PASSING_ARM, SAVE_FAILED_AT_THE_TERMINAL_ARM, TERMINAL_ARM, markBodyThrow, throwableForm, refuse, isKernelRefusal, pairSpelling, addressSpelling, sameAddress, kernelFor, append, appendOwn, ownMember, withdraw, landedOp, landedOpDefect, pairsAtAddress, enterCommitFrame, leaveCommitFrame, commitLogInFlight, sealHandoff } from './kernel-foundations.mjs';
|
|
3
3
|
import { commitAttemptIdOf, terminal, close } from './kernel-terminal.mjs';
|
|
4
4
|
// ---------------------------------------------------------------------------------------------
|
|
5
5
|
// `K-3` `runAttempt(store, commit) -> AttemptReport`
|
|
@@ -160,7 +160,12 @@ export function runAttempt(store, commitRecord) {
|
|
|
160
160
|
} catch (thrown) {
|
|
161
161
|
return drainFailingPass(store, commitRecord, thrown);
|
|
162
162
|
}
|
|
163
|
-
|
|
163
|
+
// **⟶ AND THE RECORD IS SEALED AT THE HANDOFF — `D-55` item 6, `DEF-AO`, 2026-10-28.** The drain above is
|
|
164
|
+
// the LAST act of closing out (it amends the report's own `outcome` and appends the refusal's entry to the
|
|
165
|
+
// report's list BEFORE this line), so what the seal freezes is the record the driver receives and no record
|
|
166
|
+
// in flight: `report.log` and the report are `Object.freeze`d, and a later act can neither append to the
|
|
167
|
+
// commit's list nor re-member the report. **A PASSING ARM IS SEALED TOO** — its list is handed off once.
|
|
168
|
+
return sealHandoff(drainRestart(store, report), commitLogInFlight(kernelFor(store)) !== null);
|
|
164
169
|
}, commitRecord);
|
|
165
170
|
}
|
|
166
171
|
|
|
@@ -182,6 +187,11 @@ function drainFailingPass(store, commitRecord, thrown) {
|
|
|
182
187
|
const closed = kernelFor(store).closed.get(commitAttemptIdOf(commitRecord));
|
|
183
188
|
if (closed === undefined) throw thrown;
|
|
184
189
|
const answered = drainRestart(store, closed);
|
|
190
|
+
// **⟶ THE FAILING ARM'S RECORD IS SEALED AT ITS OWN HANDOFF — `DEF-AO`.** The drain has already amended the
|
|
191
|
+
// closed report if the restarted check refused, so the seal stands before this arm picks which value crosses:
|
|
192
|
+
// the restarted refusal and the pass's own throwable both carry the SAME frozen list (`D-53`), and neither
|
|
193
|
+
// can be appended to after this line.
|
|
194
|
+
sealHandoff(answered, commitLogInFlight(kernelFor(store)) !== null);
|
|
185
195
|
const restarted = answered !== null && typeof answered === 'object' ? answered[RESTART_REFUSAL] : undefined;
|
|
186
196
|
if (restarted !== undefined && isKernelRefusal(thrown) === true) throw restarted;
|
|
187
197
|
throw thrown;
|
|
@@ -445,14 +455,35 @@ function evaluate(kernel, attempt, landing) {
|
|
|
445
455
|
// alike — and NOT the union of the store's prefix-selected addresses"), WHILE THE OP EVERY EVALUATION
|
|
446
456
|
// CARRIES IS THE LANDING'S OWN — the repair's op where a repair's edit landed, and the attempt's first
|
|
447
457
|
// write where the pass is the commit's own landing.
|
|
448
|
-
//
|
|
458
|
+
// **⟶ AND THE SET THAT ADDRESS MATERIALISES IS NOW A PREFIX SET, 2026-10-29 (`D-56`).** `RCA-8(g)`
|
|
459
|
+
// ANNOTATE-BESIDE: **the quotation above stands BYTE-FOR-BYTE as `attempt-lifecycle.md §2.4` item 5 (iv)'s
|
|
460
|
+
// EXACT-ADDRESS rule — the clause `D-56` names by number and SUPERSEDES**; the architect's own sentence is
|
|
461
|
+
// *"A listener/constraint should fire when the descendants of its targeted address node change, because the
|
|
462
|
+
// descendants become part of the object that is read from that address"*, and what it changes here is the
|
|
463
|
+
// PREDICATE `pairsAtAddress` applies — **the pairs whose own address is a PREFIX of the attempt's, equality
|
|
464
|
+
// included.** **NO OTHER LINE OF THIS FRAME MOVES**: the address is still the attempt's, the landing's op is
|
|
465
|
+
// still what every evaluation carries, and the set is still ONE SNAPSHOT taken at this instant.
|
|
466
|
+
// THE PASS'S OWN EVALUATED SET IS FIXED WHEN THE PASS BEGINS — a SNAPSHOT of the registry's rows AT OR ABOVE
|
|
449
467
|
// the attempt's address AT THAT INSTANT, and never a live view of the registry this pass reads again:
|
|
450
468
|
// "a PASS's evaluated set is FIXED WHEN THE PASS BEGINS — it is every pair registered at the attempt's
|
|
451
469
|
// address AT THAT INSTANT, each evaluated once in clause (ii)'s order", so "A `K-1` THAT RETURNS
|
|
452
470
|
// DURING A PASS APPENDS A PAIR TO THE REGISTRY WITHOUT APPENDING ANY ENTRY TO THAT PASS AND WITHOUT
|
|
453
471
|
// BEING EVALUATED BY IT: the new pair enters the NEXT pass's set" (`attempt-lifecycle.md §2.4` item 5
|
|
454
|
-
// (iv); `CX-12
|
|
472
|
+
// (iv); `CX-12`, which `D-56` defers to and does NOT move). **THE SNAPSHOT IS MATERIALISED ONCE PER RUN AND
|
|
473
|
+
// READ BY THE WHOLE RUN** — the loop below, the repair arm's `list` and `releasePending`'s check-off all read
|
|
474
|
+
// THIS ONE array — **and it is ALSO the set the layer (a) delivery of this run is read over.**
|
|
455
475
|
const list = pairsAtAddress(kernel, attempt.address);
|
|
476
|
+
// **⟶ AND THE COMMIT THE INVOCATIONS OF THIS RUN NAME — `D-55` ITEM 3's DELETE-SHAPED ATTEMPT, 2026-10-29.**
|
|
477
|
+
// **A WRITE'S ATTEMPT NAMES ITS `CommitRecord`** (`attempt.record`, the object `K-2` built and adopted), and
|
|
478
|
+
// every verb a body calls under it JOINS that commit (`D-46`). **A DELETE'S ATTEMPT HAS NO `CommitRecord`** —
|
|
479
|
+
// it lands no write, so there is no adoption, no residue and no save — **and it still owes the same
|
|
480
|
+
// invariant**: `D-53`'s *"Constraints/Repairs should always use the same commit"* is not a rule about records
|
|
481
|
+
// but about the COMMIT, and a body's write under a delete's pass that named nothing would OPEN a second commit
|
|
482
|
+
// and start a second list. **SO THE ATTEMPT CARRIES ITS COMMIT'S NAME** (`kernel-commit.mjs`'s
|
|
483
|
+
// `commitRemoval` sets `attempt.name` to the one member `commitAttemptIdOf` reads) **and this frame hands THE
|
|
484
|
+
// NAME where a record exists and THE RECORD where it does** — one expression, and on the write path it is the
|
|
485
|
+
// very object it always was, so no byte of the write's own invocation moves.
|
|
486
|
+
const commitName = attempt.record === undefined ? attempt.name : attempt.record;
|
|
456
487
|
// THE ATOMIC LANDING EVALUATION'S OWN ARM-TAKING IS `attempt-lifecycle.md §2.4` item 4's arms, read
|
|
457
488
|
// over THE PAIR THAT FAILED AT THAT OP (`kernel-surface.md §2.3` item 1; `§2.4`: `KC-3` where that pair
|
|
458
489
|
// is NOT in `ran` before this run and no repair is registered for it; `KC-6` where it IS in `ran` and
|
|
@@ -503,12 +534,22 @@ function evaluate(kernel, attempt, landing) {
|
|
|
503
534
|
// does.** The name is an INVOCATION's and nothing else's: it is set before the call and restored after it,
|
|
504
535
|
// on the throwing arm too, so an ordinary write still opens ONE commit and a callback's verb is still an
|
|
505
536
|
// act of its own.
|
|
506
|
-
outcome = constraintInCommit(attempt.store,
|
|
537
|
+
outcome = constraintInCommit(attempt.store, commitName, () => pair.constraint(context));
|
|
507
538
|
} catch (body) {
|
|
508
539
|
// A body that threw returned nothing, so no `constraint-check` entry stands and the attempt is
|
|
509
540
|
// closed (`PAR-C-6`; `NX-2`; `composition-and-states.md §2.7` item 13).
|
|
510
541
|
withdraw(attempt, check);
|
|
511
|
-
|
|
542
|
+
// **⟶ AND THE THROWABLE'S OWN FORM ENTERS THE COMMIT'S LOG — `D-55` ITEM 1, `DEF-AK`, 2026-10-28.**
|
|
543
|
+
// The architect, verbatim: *"Include a thrown message in the message log. Obviously."* **THE ENTRY IS
|
|
544
|
+
// THE ONE THE TERMINAL ACT ALREADY APPENDS**: this arm closes the attempt with its ONE `outcome` entry
|
|
545
|
+
// (`composition-and-states.md §2.7` item 13), and NO second entry and NO fifth `kind` is minted —
|
|
546
|
+
// `constraint-check` was WITHDRAWN above and must not come back (`fail-surface.md §1.1` item 1 (b),
|
|
547
|
+
// which the kernel-level cells assert as *"NO entry stands for the pair whose body returned nothing"*).
|
|
548
|
+
// **SO THE TERMINAL ENTRY'S SENTENCE CARRIES THE FORM** (`throwableForm`: the string's own text, the
|
|
549
|
+
// object's own `message` member, or the kind of value it was, read off own members only), and the
|
|
550
|
+
// closed report's list — the list the crossing hands the caller — holds it at that entry's `seq`.
|
|
551
|
+
terminalComposed(kernel, attempt, null, `the constraint ${pair.id} threw; the attempt is closed — the `
|
|
552
|
+
+ `value it threw was ${throwableForm(body)}`);
|
|
512
553
|
// **⟶ AND THE VALUE IS MARKED HERE, BY THE FRAME THAT CAUGHT IT FROM THE BODY — `DEF-S`, 2026-10-26,
|
|
513
554
|
// on the architect's ruling *"Expand the returned error set for both S/N"*.** The mark is what the
|
|
514
555
|
// entry's `constraintCrossing` converts on, and an UNMARKED value still crosses as itself
|
|
@@ -644,7 +685,7 @@ function evaluate(kernel, attempt, landing) {
|
|
|
644
685
|
// **⟶ AND THE FRAME STANDS FOR THIS INVOCATION TOO (`D-53`'s first invariant): the repair's own verbs
|
|
645
686
|
// append to the attempt's list, and the frame is what makes `K-2` join rather than open.**
|
|
646
687
|
enterCommitFrame(kernel, attempt.log);
|
|
647
|
-
result = repairInCommit(attempt.store,
|
|
688
|
+
result = repairInCommit(attempt.store, commitName, () => repair(repairContext));
|
|
648
689
|
} catch (body) {
|
|
649
690
|
// THE REPAIR-RUN ENTRY IS APPENDED BEFORE THE THROW, and the attempt's outcome entry carries
|
|
650
691
|
// `KC-4` (`ck_states_a_repair_body_that_throws_reaches_the_caller_unconverted`).
|