provident-storeroom 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.guide.md +212 -5
- package/README.md +36 -11
- package/RELEASE-NOTES.md +610 -0
- package/index.d.ts +77 -6
- package/index.mjs +120 -34
- package/package.json +7 -6
- package/src/entry/constraints.mjs +662 -73
- package/src/entry/delivery.mjs +19 -5
- package/src/entry/kernel-attempt.mjs +181 -23
- package/src/entry/kernel-commit.mjs +191 -2
- package/src/entry/kernel-foundations.mjs +266 -24
- package/src/entry/kernel-registration.mjs +81 -27
- package/src/entry/kernel-terminal.mjs +18 -5
- package/src/entry/state.mjs +47 -4
|
@@ -38,12 +38,23 @@
|
|
|
38
38
|
// ---------------------------------------------------------------------------------------------
|
|
39
39
|
// `fail-surface.md §2` — THE KERNEL'S OWN CLOSED STATE SET, `8` MEMBERS AND NO NINTH.
|
|
40
40
|
// ---------------------------------------------------------------------------------------------
|
|
41
|
+
// **⟶ AND THE SET OPENS TO `9` ON 2026-10-28 — `D-53`'s THIRD RULING, THE ARCHITECT'S WORD: *"Open the token
|
|
42
|
+
// set"*** (`strata/decisions.md` · `D-53`; `D-52`'s rule 3 is its measurement: **`KC-8` CROSSED AS TWO
|
|
43
|
+
// STATUSES** — a constraint refusal whose composition met the floor, and a failed save — **so neither arm was
|
|
44
|
+
// derivable from the log's terminal state**). **THE SENTENCE ABOVE STANDS BYTE-FOR-BYTE AND IS READ THROUGH
|
|
45
|
+
// THIS ONE: `9` MEMBERS AND NO TENTH, ON `14` SITES.** **THE APPENDED MEMBER IS `KC-9`, THE SAVE ARM'S OWN —
|
|
46
|
+
// `ConstraintSaveFailed`** — so a save failure and a constraint refusal cross with DIFFERENT statuses AND each
|
|
47
|
+
// is derivable from the log's terminal state: the save arm's ONE `outcome` entry carries `KC-9` and a constraint
|
|
48
|
+
// refusal's carries `KC-3`/`KC-5`/`KC-6`/`KC-8` (`KC-9`'s own row, `kernel-attempt.mjs`'s save arm, and
|
|
49
|
+
// `kernel-terminal.mjs`'s precedence clause: **the FLOOR DOES NOT OVERWRITE THIS TOKEN, which is what keeps the
|
|
50
|
+
// two arms apart where the save's own composition meets a floor code**).
|
|
41
51
|
// `fail-surface.md §1.1` ITEM 1 (a) — THE ONE SPELLING, AND IT IS THE TOKEN: a refusal's `status` carries
|
|
42
|
-
// `KC-1`…`KC-
|
|
52
|
+
// `KC-1`…`KC-9` and NOTHING ELSE. The full names (`ConstraintViolated` …) are LABELS: they keep exactly
|
|
43
53
|
// one declared use — the `name` column of `§2`'s table, and a citation beside a token — and NO clause
|
|
44
54
|
// spells a member's VALUE as a name. `status` and `LogEntry.state` therefore read THE SAME TOKEN STRING,
|
|
45
|
-
// related by IDENTITY (`§1.1` item 1 (c)). THE CENSUS
|
|
46
|
-
// on `13` sites (`1 + 4 + 4 + 3 + 1
|
|
55
|
+
// related by IDENTITY (`§1.1` item 1 (c)). THE CENSUS MOVES BY THE RULING AND BY NOTHING ELSE:
|
|
56
|
+
// `8 → 9` members (`2 + 2 + 2 + 1 + 1 + 1`) on `13 → 14` sites (`1 + 4 + 4 + 3 + 1 + 1`, the last being the
|
|
57
|
+
// save arm's own, `kernel-attempt.mjs`).
|
|
47
58
|
export const KC = {
|
|
48
59
|
address: 'KC-1', // ConstraintAddressRefused
|
|
49
60
|
arg: 'KC-2', // ConstraintArgRefused
|
|
@@ -53,9 +64,10 @@ export const KC = {
|
|
|
53
64
|
repeat: 'KC-6', // ConstraintRepeat
|
|
54
65
|
attemptOpen: 'KC-7', // ConstraintAttemptOpen
|
|
55
66
|
rollbackFloor: 'KC-8', // ConstraintRollbackFloor
|
|
67
|
+
saveFailed: 'KC-9', // ConstraintSaveFailed
|
|
56
68
|
};
|
|
57
69
|
|
|
58
|
-
/** The
|
|
70
|
+
/** The nine tokens above, as the ONE list a member's own value is checked against — the kernel's own
|
|
59
71
|
* token is NEVER named as a store code (`fail-surface.md §1.1` item 1 (a); `§2`'s `KC-4` row). */
|
|
60
72
|
export const KC_TOKENS = Object.values(KC);
|
|
61
73
|
|
|
@@ -217,6 +229,61 @@ export function markBodyThrow(thrown, address, log) {
|
|
|
217
229
|
}
|
|
218
230
|
}
|
|
219
231
|
|
|
232
|
+
/// **⟶ ADDED 2026-10-28 — `D-55` ITEM 1, THE ARCHITECT, VERBATIM: *"Include a thrown message in the message
|
|
233
|
+
/// log. Obviously."*** **THE MEASURED DEFECT (`DEF-AK`):** a constraint body that threw its own `Error`
|
|
234
|
+
/// crossed as the rank-`18` `ConstraintBodyThrew` whose `log` carried **only the attempt's `outcome` entry** —
|
|
235
|
+
/// the thrown value's own literal occurred **zero times** in it — while the crossed sentence said *"a
|
|
236
|
+
/// constraint body's throwable crosses as this refusal"*. **The commit's log now carries the throwable's own
|
|
237
|
+
/// form, written into the ONE `outcome` entry the terminal act appends at the frame that caught the body —
|
|
238
|
+
/// before the attempt is disposed of and before the record is handed off** (`kernel-attempt.mjs`'s `evaluate`;
|
|
239
|
+
/// no second entry and no fifth `kind` is minted).
|
|
240
|
+
///
|
|
241
|
+
/// **WHAT THE FORM IS, AND WHY IT NAMES WHAT IT READ RATHER THAN A CLASS.** The value is the CALLER'S OWN —
|
|
242
|
+
/// it may be an `Error`, a string, a number, an object with no `message`, a `Proxy` — so the spelling is
|
|
243
|
+
/// built from **own data members only** (`ownMember`, `[[GetOwnProperty]]`, `D-35`'s read half) and from the
|
|
244
|
+
/// language's own `typeof`. **NO PROTOTYPE IS CONSULTED**: `instanceof`, `constructor.name` and
|
|
245
|
+
/// `Object.prototype.toString` all walk a chain a caller owns, and a `Proxy`'s trap would RUN here, on a
|
|
246
|
+
/// refusal path. **AND A CLASS IS NEVER CLAIMED**: *"an object whose own `message` member is the string …"*
|
|
247
|
+
/// is true of an `Error` and of a plain object alike, which is what the reading supports.
|
|
248
|
+
///
|
|
249
|
+
/// **THE FORM IS NAMED AND NOT SILENTLY STRINGIFIED**: a thrown string is *"a string whose text is …"*, a
|
|
250
|
+
/// number *"a number whose value is …"*, a thrown `void 0` *"no value at all"*, an object without a `message`
|
|
251
|
+
/// *"an object carrying no own string `message` member"*. A consumer therefore reads WHAT KIND of value the
|
|
252
|
+
/// body threw beside whatever text it carried.
|
|
253
|
+
///
|
|
254
|
+
/// **IT IS TOTAL, AND THE ONLY READ THAT COULD RUN CALLER CODE IS THE GUARDED ONE**: this frame invokes
|
|
255
|
+
/// nothing of the caller's — `ownMember` is `[[GetOwnProperty]]` and consults no chain — and the one trap it
|
|
256
|
+
/// can trip (a `Proxy`'s `getOwnPropertyDescriptor`) is inside a `try`, whose arm past it answers a sentence of
|
|
257
|
+
/// this frame's own. **NO `undefined` IS EVER PRINTED** (`native/contract.md §8.2` property (c); the `DEF-Q`
|
|
258
|
+
/// sweep reads every entry's message for it): a thrown `void 0` says *"no value at all"* and a missing member
|
|
259
|
+
/// is named as absent rather than spelled.
|
|
260
|
+
export function throwableForm(thrown) {
|
|
261
|
+
if (thrown === null) return '`null`';
|
|
262
|
+
const kind = typeof thrown;
|
|
263
|
+
if (kind === 'undefined') return 'no value at all (the body threw `void 0`)';
|
|
264
|
+
if (kind === 'string') return `a string whose text is ${JSON.stringify(thrown)}`;
|
|
265
|
+
if (kind === 'number') return `a number whose value is ${String(thrown)}`;
|
|
266
|
+
if (kind === 'boolean') return `a boolean whose value is ${String(thrown)}`;
|
|
267
|
+
if (kind === 'bigint') return `a bigint whose value is ${String(thrown)}`;
|
|
268
|
+
if (kind === 'symbol') return 'a symbol, which carries no text a log can print';
|
|
269
|
+
if (kind === 'function') return 'a function, which carries no message';
|
|
270
|
+
let message;
|
|
271
|
+
let name;
|
|
272
|
+
try {
|
|
273
|
+
message = ownMember(thrown, 'message');
|
|
274
|
+
name = ownMember(thrown, 'name');
|
|
275
|
+
} catch {
|
|
276
|
+
// A `Proxy` whose `getOwnPropertyDescriptor` trap throws cannot be read at all: this frame says so and
|
|
277
|
+
// runs nothing further (`D-35`: the refusal path invokes no caller code it was not already handed).
|
|
278
|
+
return 'an object this frame could not read, so its form is not printed';
|
|
279
|
+
}
|
|
280
|
+
const named = typeof name === 'string' && name.length > 0 ? ` named ${JSON.stringify(name)}` : '';
|
|
281
|
+
if (typeof message === 'string') {
|
|
282
|
+
return `an object${named} whose own \`message\` member is the string ${JSON.stringify(message)}`;
|
|
283
|
+
}
|
|
284
|
+
return `an object${named} carrying no own string \`message\` member`;
|
|
285
|
+
}
|
|
286
|
+
|
|
220
287
|
/// **WHETHER A VALUE IS A REFUSAL THIS KERNEL BUILT** — the entry's crossing and this kernel's own repair
|
|
221
288
|
/// arm both ask this and nothing else.
|
|
222
289
|
///
|
|
@@ -385,6 +452,37 @@ export function sameAddress(left, right) {
|
|
|
385
452
|
return true;
|
|
386
453
|
}
|
|
387
454
|
|
|
455
|
+
/**
|
|
456
|
+
* **⟶ ADDED 2026-10-29 — `isAddressPrefix`: THE PASS'S OWN MEMBERSHIP TEST, AND IT IS `D-56`'S SENTENCE IN
|
|
457
|
+
* ONE FUNCTION.** The architect, verbatim: *"A listener/constraint should fire when the descendants of its
|
|
458
|
+
* targeted address node change, because the descendants become part of the object that is read from that
|
|
459
|
+
* address"* (`strata/decisions.md` · `D-56`). **THE GROUND IS SEMANTIC AND NOT A PREFERENCE: the value read at
|
|
460
|
+
* a prefix CONTAINS its subtree, so a change at a descendant CHANGES what a read at the ancestor returns** —
|
|
461
|
+
* and a pair standing at the ancestor therefore **judges an object that moved.**
|
|
462
|
+
*
|
|
463
|
+
* **THE SET, STATED ONCE: a pair is asked when THE ACT'S ADDRESS IS AT OR BELOW THE PAIR'S ADDRESS** — *"the
|
|
464
|
+
* pair's address is a prefix of the act's address (equality included)"* (`D-56`). **So `isAddressPrefix(standing,
|
|
465
|
+
* act)` is `true` exactly where the pair stands AT the act's address OR AT ONE OF ITS ANCESTORS**, and `false`
|
|
466
|
+
* for a pair standing at a DESCENDANT — the unruled direction, which `D-56` requires to be MEASURED rather than
|
|
467
|
+
* implemented, and which this predicate therefore does not reach.
|
|
468
|
+
*
|
|
469
|
+
* **IT IS STRUCTURAL AND SEGMENT-WISE, WITH `string` AND `number` DISTINGUISHED, EXACTLY AS `sameAddress` IS**
|
|
470
|
+
* (`P: docs/pending.md · (M-3)` item (iv)): a pair at `['a', 0]` is NOT asked by an act at `['a', '0']`, so the
|
|
471
|
+
* widening changes WHICH DEPTHS are members and NOT how a segment is compared. **A SEGMENT COUNT OF ZERO IS A
|
|
472
|
+
* PREFIX OF EVERY ADDRESS** — the root pair's own reading, and the same one the trigger set's prefix rule gives.
|
|
473
|
+
*/
|
|
474
|
+
export function isAddressPrefix(prefix, address) {
|
|
475
|
+
if (!Array.isArray(prefix) || !Array.isArray(address)) return false;
|
|
476
|
+
if (prefix.length > address.length) return false;
|
|
477
|
+
for (let i = 0; i < prefix.length; i += 1) {
|
|
478
|
+
const a = prefix[i];
|
|
479
|
+
const b = address[i];
|
|
480
|
+
if (typeof a !== typeof b) return false;
|
|
481
|
+
if (a !== b) return false;
|
|
482
|
+
}
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
|
|
388
486
|
// ---------------------------------------------------------------------------------------------
|
|
389
487
|
// THE KERNEL'S OWN CALLER-SIDE STATE — **THE INSTANCE OWNS IT, IN A SLOT ON THE INSTANCE ITSELF**, so
|
|
390
488
|
// two stores never share a registry, this module retains no store of its own, and NOTHING STANDS AT
|
|
@@ -484,6 +582,11 @@ export function kernelFor(store) {
|
|
|
484
582
|
live: new Map(),
|
|
485
583
|
closed: new Map(),
|
|
486
584
|
attempts: 0,
|
|
585
|
+
// **⟶ AND THE COMMIT'S FRAME, 2026-10-28 (`D-53`)**: the stack of attempts whose commit the kernel is, at
|
|
586
|
+
// this instant, invoking caller code inside. `K-2` reads its top and joins that attempt's list; a write
|
|
587
|
+
// reached with no frame standing OPENS a commit and starts its own list. It is the instance's own, exactly
|
|
588
|
+
// as `live`/`closed` are (`D-30`), so no two stores share a frame and no module-level stack exists.
|
|
589
|
+
frames: [],
|
|
487
590
|
store,
|
|
488
591
|
};
|
|
489
592
|
// **THE SLOT IS DEFINED AND THE RECORD IS PUBLISHED IN THE SAME ACT** (`Object.defineProperty`, exactly as
|
|
@@ -613,16 +716,129 @@ export function ownMember(value, name) {
|
|
|
613
716
|
return descriptor.value;
|
|
614
717
|
}
|
|
615
718
|
|
|
719
|
+
// ---------------------------------------------------------------------------------------------
|
|
720
|
+
// **⟶ THE MESSAGE LOG BELONGS TO THE COMMIT, NOT TO THE ATTEMPT — `D-53`, 2026-10-28.**
|
|
721
|
+
//
|
|
722
|
+
// **THE ARCHITECT, VERBATIM: *"If it's part of the same commit, then it uses the same message log. If it opens a
|
|
723
|
+
// new commit, it uses the new commit's message log. Constraints/Repairs should always use the same commit.
|
|
724
|
+
// Listeners should open a new commit, because the triggering commit already passed constraints"***
|
|
725
|
+
// (`strata/decisions.md` · `D-53`). **A COMMIT IS THE UNIT OF WORK AND AN ATTEMPT IS THE CONSTRAINT-JUDGED WRITE
|
|
726
|
+
// INSIDE IT**, so a commit that holds several attempts — a check, its repair, the repair's own write, the re-run
|
|
727
|
+
// — holds ONE list, and every one of those attempts appends to it: **`attempt.log` IS the commit's list, carried
|
|
728
|
+
// by reference, and it is not a copy of anybody's.**
|
|
729
|
+
//
|
|
730
|
+
// **WHAT THAT DISSOLVES, SAID BECAUSE IT WAS ASKED AS A QUESTION.** `D-52`'s rule 2 asked where a nested
|
|
731
|
+
// attempt's report is merged into its host's, and how a merged entry keeps *"its own attempt identity"* when
|
|
732
|
+
// `seq` is *"the ordinal of the list it stands in"* and the six declared members leave no room for a seventh.
|
|
733
|
+
// **THERE WAS NEVER A MERGE TO PERFORM: a constraint body's write is part of the same commit, so its entries
|
|
734
|
+
// ARE this list's entries, the crossed report IS this list, no entry is renumbered and `seq` keeps its
|
|
735
|
+
// declaration because there is ONE list.** `DEF-AK`'s *"one inner refusal, two hosts"* is the measurement of it.
|
|
736
|
+
//
|
|
737
|
+
// **THE KEY IS A `Symbol.for` SPELLING ON THE COMMIT'S OWN RECORD, AND BOTH SIDES SPELL IT** (`A117` (D6)): the
|
|
738
|
+
// entry's terminal arm attaches this list to a failed save's crossing, and it holds the `CommitRecord` and
|
|
739
|
+
// nothing else — so the list travels ON the record under a symbol key that `Object.keys` and
|
|
740
|
+
// `Object.getOwnPropertyNames` read past, and the record keeps its FOUR declared members.
|
|
741
|
+
export const COMMIT_LOG = Symbol.for('provident-storeroom.commit-log');
|
|
742
|
+
|
|
743
|
+
// ---------------------------------------------------------------------------------------------
|
|
744
|
+
// **⟶ THE HANDOFF'S OWN SEAL — `D-55` ITEM 6, `DEF-AO`, ADDED 2026-10-28.** The architect, verbatim:
|
|
745
|
+
// *"Attempts don't log. This is what the commits are for. The commits have their log handed off to the client
|
|
746
|
+
// and are dropped after closing out."* **SO THE RECORD IS HANDED OFF ONCE, AT THE END OF THE COMMIT'S OWN
|
|
747
|
+
// PROCESSING, AND A RECORD THAT CHANGES AFTER THE HANDOFF IS NOT A RECORD.**
|
|
748
|
+
//
|
|
749
|
+
// **WHAT WAS MEASURED BEFORE THIS ACT EXISTED.** The drain amends the REPORT a pass already closed — it sets
|
|
750
|
+
// `outcome` and appends the refusal's entry to the report's list — and the list it appends to is THE COMMIT'S
|
|
751
|
+
// OWN, held by reference by every attempt of the commit, the crossed refusals included. A consumer that took
|
|
752
|
+
// the closed report (or a refusal carrying that list) before the drain therefore held a record that moved
|
|
753
|
+
// under it. **FREEZING AT THE SEAL MAKES THE HANDED-OFF RECORD FINAL**: the drain's amendment happens BEFORE
|
|
754
|
+
// this call (it is part of closing out), and nothing after it can append, renumber or re-member the list.
|
|
755
|
+
//
|
|
756
|
+
// **WHAT IT FREEZES, AND WHY THE LOG'S SEAL IS THE COMMIT'S.** `D-53` makes the message log THE COMMIT'S: an
|
|
757
|
+
// attempt's `log` is that one list, carried by reference, and every attempt of the commit appends to it — a
|
|
758
|
+
// constraint body's nested write, a repair's write, the re-run. **SO THE REPORT IS SEALED AT EVERY ATTEMPT'S
|
|
759
|
+
// HANDOFF AND THE LIST IS SEALED AT THE HANDOFF OF THE ATTEMPT WHOSE SCOPE OWNS IT** (the one whose commit is
|
|
760
|
+
// not an enclosing invocation's list, read off `commitLogInFlight`): freezing the list at a NESTED attempt's
|
|
761
|
+
// handoff would stop the enclosing attempt's own `append` and turn a lawful write into a raw host `TypeError`
|
|
762
|
+
// — measured, and the reason the `shared` argument exists. **THE LIST IS SEALED WITH ITS COMMIT**, which is
|
|
763
|
+
// what *"the commits have their log handed off to the client and are dropped after closing out"* says.
|
|
764
|
+
//
|
|
765
|
+
// **IT FREEZES TWO THINGS AND ONLY TWO**: the report's `log` array (where this attempt's scope owns it) and
|
|
766
|
+
// the report itself. **NO MEMBER MOVES, NO MEMBER IS ADDED, AND THE LIST'S IDENTITY IS UNCHANGED** — `D-53`'s
|
|
767
|
+
// *"the crossed report IS that list"* is a statement about WHICH array crosses, and the same array crosses
|
|
768
|
+
// (frozen): `K-5`, `K-4` and every refusal built from it read the same entries at the same `seq` ordinals.
|
|
769
|
+
// **A PASSING ATTEMPT'S REPORT IS SEALED TOO** — its log is handed off exactly once and drops with the commit.
|
|
770
|
+
export function sealHandoff(report, shared) {
|
|
771
|
+
if (report === null || typeof report !== 'object') return report;
|
|
772
|
+
// THE REPORT'S OWN `log` MEMBER, READ AS A MEMBER OF THE OBJECT THIS FRAME BUILT (`kernel-terminal.mjs`
|
|
773
|
+
// places the commit's list there and nothing else): an absent or non-array member is not this act's, and
|
|
774
|
+
// `refusalLog`'s own rule (`surface.md §2.5` item 4) is that a `log` is a list on every arm.
|
|
775
|
+
const log = report.log;
|
|
776
|
+
if (shared !== true && Array.isArray(log) === true) Object.freeze(log);
|
|
777
|
+
Object.freeze(report);
|
|
778
|
+
return report;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// **THE COMMIT'S FRAME — THE ONE STRUCTURE THAT MAKES "THE SAME COMMIT" A FACT RATHER THAN A CONVENTION.** It is
|
|
782
|
+
// a per-instance stack on the kernel record (`kernel.frames`, created by `kernelFor`), pushed by the kernel
|
|
783
|
+
// around each invocation IT makes of caller code that belongs to an attempt — a constraint body at a landing,
|
|
784
|
+
// at a registration's evaluation, at its re-run; a repair body — and popped in a `finally`.
|
|
785
|
+
//
|
|
786
|
+
// **`K-2` READS IT AND NOTHING ELSE DECIDES THE LOG**: a write the kernel reaches from inside such an
|
|
787
|
+
// invocation JOINS the innermost frame's list; a write reached from anywhere else — a caller's own top-level
|
|
788
|
+
// write, and A LISTENER BODY'S WRITE, which the ENTRY invokes at the terminal arm with no frame of this
|
|
789
|
+
// kernel's standing — OPENS a commit and therefore starts a list of its own (`D-53`: *"Listeners should open a new
|
|
790
|
+
// commit, because the triggering commit already passed constraints"* — what the listener saw was already
|
|
791
|
+
// approved, so what it does now is a NEW QUESTION and must not inherit the old verdict).
|
|
792
|
+
export function enterCommitFrame(kernel, log) {
|
|
793
|
+
appendOwn(kernel.frames, { log });
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/** The pop, and it is a local index loop for the reason every other list surgery here is (`contract.md §2.1`'s
|
|
797
|
+
* clause of 2026-10-24 on `F7-1`): no `Array.prototype.pop` is read on a path a caller's prototype can reach. */
|
|
798
|
+
export function leaveCommitFrame(kernel) {
|
|
799
|
+
const kept = [];
|
|
800
|
+
for (let i = 0; i + 1 < kernel.frames.length; i += 1) appendOwn(kept, kernel.frames[i]);
|
|
801
|
+
kernel.frames = kept;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/** **THE LOG OF THE COMMIT THE KERNEL IS INSIDE, OR `null` WHERE IT IS INSIDE NONE** — the one read `K-2` takes
|
|
805
|
+
* to decide whether this write joins a commit or opens one. */
|
|
806
|
+
export function commitLogInFlight(kernel) {
|
|
807
|
+
return kernel.frames.length === 0 ? null : kernel.frames[kernel.frames.length - 1].log;
|
|
808
|
+
}
|
|
809
|
+
|
|
616
810
|
// ---------------------------------------------------------------------------------------------
|
|
617
811
|
// THE MESSAGE LOG (`kernel-surface.md §2.5` item 1; `PAR-C-4`). SIX MEMBERS, `seq` ASCENDING FROM
|
|
618
812
|
// `1`, ONE KIND PER ENTRY: `constraint-check` | `repair-run` | `commit` | `outcome`.
|
|
619
|
-
//
|
|
620
|
-
|
|
813
|
+
//
|
|
814
|
+
// **⟶ AND THE ENTRY IS NAMED BY AN ITERATION AND NOT BY TWO LOOSE IDENTITIES — 2026-10-28, `D-53`'s FIRST
|
|
815
|
+
// RULING: *"Both combined to identify which constraint iteration it is on"*.** **THE ARCHITECT'S ANSWER TO
|
|
816
|
+
// `D-52`'s rule 1, read with `D-53`'s own gloss: *"an entry carries the PAIR identity and the OP identity
|
|
817
|
+
// together, and the PAIR identifies WHICH CONSTRAINT of that pair's evaluations is being spoken about … The two
|
|
818
|
+
// columns are not alternatives — they are one identity"*.** **THE SUBJECT OF AN ENTRY IS THE ITERATION, AND AN
|
|
819
|
+
// ITERATION IS A PAIR AT AN OP** — which is why no single acted-upon object could supply both, and why the old
|
|
820
|
+
// `(attempt, kind, id, opId, message, state)` signature (two loose strings in two adjacent positions) could be
|
|
821
|
+
// fed one value where the other belonged.
|
|
822
|
+
//
|
|
823
|
+
// **SO THE SIGNATURE TAKES THE ITERATION AS ONE OBJECT AT ONE POSITION, and reads its two members as its OWN
|
|
824
|
+
// data members** (`D-35`'s read half: `[[GetOwnProperty]]` and never a `[[Get]]` that walks a caller's chain):
|
|
825
|
+
// * `iteration.pair` — the registry row (`{ addresses, id, constraint }`) the entry speaks about, or `null`
|
|
826
|
+
// where the kind names none (the `commit` entry names no pair, and the `outcome` entry names one only where
|
|
827
|
+
// the arm has one);
|
|
828
|
+
// * `iteration.op` — the journal op the iteration is judged at, or `null` where the kind names none.
|
|
829
|
+
// **`id` IS READ OFF THE PAIR AND `opId` OFF THE OP**: a caller cannot put an id in the op's place, because
|
|
830
|
+
// there is no place for one.
|
|
831
|
+
export function append(attempt, kind, iteration, message, state) {
|
|
832
|
+
const held = iteration !== null && typeof iteration === 'object' ? iteration : null;
|
|
833
|
+
const pair = held === null ? undefined : ownMember(held, 'pair');
|
|
834
|
+
const op = held === null ? undefined : ownMember(held, 'op');
|
|
835
|
+
const id = pair === undefined || pair === null || typeof pair.id !== 'string' ? null : pair.id;
|
|
836
|
+
const opId = op === undefined || op === null || typeof op.opId !== 'string' ? null : op.opId;
|
|
621
837
|
appendOwn(attempt.log, {
|
|
622
838
|
seq: attempt.log.length + 1,
|
|
623
839
|
kind,
|
|
624
|
-
id
|
|
625
|
-
opId
|
|
840
|
+
id,
|
|
841
|
+
opId,
|
|
626
842
|
message,
|
|
627
843
|
state: state === undefined ? null : state,
|
|
628
844
|
});
|
|
@@ -759,31 +975,57 @@ function opSpelling(value) {
|
|
|
759
975
|
* replacement for `byAddress`'s index, declared at `contract.md §2.8` item 6 (`HL-DD-6`) and
|
|
760
976
|
* `kernel-selection.md §3` item 1.
|
|
761
977
|
*
|
|
762
|
-
*
|
|
763
|
-
*
|
|
978
|
+
* **⟶ THE PREDICATE IS WIDENED FROM EXACT ADDRESS TO PREFIX, 2026-10-29 — `D-56`, AND THE CLAUSE BELOW STANDS
|
|
979
|
+
* BYTE-FOR-BYTE AS THE RULE THIS ONE SUPERSEDES.** `RCA-8(g)` ANNOTATE-BESIDE: **the paragraph that stood here
|
|
980
|
+
* read** *"THE SET IS THE PAIRS WHOSE OWN ADDRESS IS THE ATTEMPT'S — selected by an EXACT-ADDRESS match and NEVER
|
|
981
|
+
* widened to `triggered`'s prefix set"* (`P: docs/pending.md · (AA-1)`, verbatim: *"the pass selects the rows
|
|
764
982
|
* whose address IS the triggering address, which PRESERVES the EXACT-ADDRESS RULE rather than widening it to
|
|
765
|
-
* `triggered`'s prefix set"*; `contract.md §2.8` item 1)
|
|
983
|
+
* `triggered`'s prefix set"*; `contract.md §2.8` item 1), **and the architect has superseded it**, verbatim:
|
|
984
|
+
* *"A listener/constraint should fire when the descendants of its targeted address node change, because the
|
|
985
|
+
* descendants become part of the object that is read from that address"* (`strata/decisions.md` · `D-56`).
|
|
986
|
+
* **THE TWO CLAUSES `D-56` NAMES BY NUMBER ARE `HL-8` ITEM 1'S OWN SENTENCE AND
|
|
987
|
+
* `attempt-lifecycle.md §2.4` ITEM 5 (iv)'s EXACT-ADDRESS RULE — both superseded, both annotated in place, and
|
|
988
|
+
* neither rewritten.**
|
|
989
|
+
*
|
|
990
|
+
* **THE SET IS NOW THE PAIRS WHOSE OWN ADDRESS IS A PREFIX OF THE ATTEMPT'S — equality included — WHICH IS
|
|
991
|
+
* `isAddressPrefix(standing, address)` AND IS `D-56`'s ONE SENTENCE**: a pair at `['tabs']` IS asked for a
|
|
992
|
+
* delete at `['tabs','landingPage']`, a pair at `['tabs','landingPage']` IS asked for that same delete, and a
|
|
993
|
+
* pair at `['tabs','landingPage','x']` is NOT asked because the act did not change it (**the unruled direction,
|
|
994
|
+
* measured and not implemented** — `D-56`'s own terms). **THE REASON IS THE READ:** the value read at a prefix
|
|
995
|
+
* contains its subtree, so a descendant's change changes what the ancestor's read returns, and the ancestor pair
|
|
996
|
+
* **judges an object that moved.**
|
|
766
997
|
*
|
|
767
|
-
* **IT IS A SCAN, AND THE COST IS PRICED AND ACCEPTED** (`P: docs/pending.md · (AA-1)`, verbatim:
|
|
768
|
-
* rows by address is a scan over `kernel.pairs` … THAT GROUND WAS WRONG AND IS WITHDRAWN: the store
|
|
769
|
-
* ADDRESS, and the kernel selects"*)
|
|
998
|
+
* **IT IS STILL A SCAN, AND THE COST IS STILL PRICED AND ACCEPTED** (`P: docs/pending.md · (AA-1)`, verbatim:
|
|
999
|
+
* *"selecting rows by address is a scan over `kernel.pairs` … THAT GROUND WAS WRONG AND IS WITHDRAWN: the store
|
|
1000
|
+
* names the ADDRESS, and the kernel selects"*) — **and `D-56` re-prices it not at all**: the scan reads one
|
|
1001
|
+
* prefix test per standing address instead of one equality test per standing address, on the same rows.
|
|
770
1002
|
*
|
|
771
|
-
* **AND THE RESULT IS MATERIALISED ONCE, WHICH IS WHAT IMPLEMENTS `CX-12`'s *"the pass's evaluated set is
|
|
772
|
-
* FIXED WHEN THE PASS BEGINS"*** (`P: docs/pending.md · R-B3`'s snapshot clause; `contract.md §2.8` item 6
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
* (`kernel-selection.md §3` item 5).
|
|
1003
|
+
* **AND THE RESULT IS STILL MATERIALISED ONCE, WHICH IS WHAT IMPLEMENTS `CX-12`'s *"the pass's evaluated set is
|
|
1004
|
+
* FIXED WHEN THE PASS BEGINS"*** (`P: docs/pending.md · R-B3`'s snapshot clause; `contract.md §2.8` item 6;
|
|
1005
|
+
* `D-56`'s third deferrer, which changes WHAT is materialised and not WHEN): the returned list is a fresh array,
|
|
1006
|
+
* so a `K-1` that returns DURING the pass enters the NEXT pass's set and no earlier one, and a pair PURGED
|
|
1007
|
+
* mid-pass is still evaluated by the pass that began with it (`kernel-selection.md §3` item 5). **THE PASS READS
|
|
1008
|
+
* THIS LIST AND NEVER THE REGISTRY**, and **`D-56` says nothing that moves that**: the ancestors are members of
|
|
1009
|
+
* the SAME one snapshot, taken at the SAME instant.
|
|
776
1010
|
*
|
|
777
|
-
* **THE ORDER IS THE PAIR'S FIRST-REGISTRATION ORDER
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
1011
|
+
* **THE ORDER IS STILL THE PAIR'S FIRST-REGISTRATION ORDER — `HL-8` ITEM 6's RULE SURVIVES `D-56` — AND THE
|
|
1012
|
+
* ANCESTORS INTERLEAVE INTO THAT ONE ORDER RATHER THAN FORMING A SECOND.** `attempt-lifecycle.md:193`'s *"clause
|
|
1013
|
+
* (ii)'s first-registration order"* **is supplied by `kernel.pairs`' own `Map` iteration**, which is the order
|
|
1014
|
+
* the ruling says is preserved *"by the store's own returned order, not by an index's append order"*
|
|
1015
|
+
* (`P: docs/pending.md · M-3`, its closing sentence; `contract.md §2.8` item 6's `HL-DD-6`). **THE WIDENING ADDS
|
|
1016
|
+
* NO ITERATION AND NO SORT**: `D-39`'s registration sequence is the `Map`'s insertion order over the pair rows,
|
|
1017
|
+
* the one loop below walks it once, and **a row is admitted or not by its own `addresses` member** — so an
|
|
1018
|
+
* ancestor registered FIRST is asked FIRST, an ancestor registered THIRD is asked THIRD, **interleaved with the
|
|
1019
|
+
* act's own pairs by the one sequence both stand in.** There is no "ancestors first", no "ancestors last", and
|
|
1020
|
+
* no second list: **one order, one list, one snapshot.** **EACH ELEMENT IS EVALUATED AT MOST ONCE** — the `break`
|
|
1021
|
+
* below is that rule, so a pair standing at N addresses of which two are prefixes of the act is reached once
|
|
1022
|
+
* (`contract.md §2.6` item 5).
|
|
781
1023
|
*/
|
|
782
1024
|
export function pairsAtAddress(kernel, address) {
|
|
783
1025
|
const out = [];
|
|
784
1026
|
for (const [key, pair] of kernel.pairs) {
|
|
785
1027
|
for (const standing of pair.addresses) {
|
|
786
|
-
if (
|
|
1028
|
+
if (isAddressPrefix(standing, address)) {
|
|
787
1029
|
appendOwn(out, key);
|
|
788
1030
|
break;
|
|
789
1031
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// `D-13` (`docs/L1/kernel-subdivision.md` §1 part `9b`) — the registration act, its evaluation, and the registry's removal: bytes moved from `bindings/js/src/constraint-kernel.mjs`; no logic changed.
|
|
2
|
-
import { KC, KERNEL_REFUSAL, markBodyThrow, refuse, inDomainAddress, inDomainId, pairRowAt, sameAddress, kernelFor, append, appendOwn, landedOp, pairsAtAddress,
|
|
2
|
+
import { KC, KERNEL_REFUSAL, markBodyThrow, refuse, inDomainAddress, inDomainId, pairRowAt, sameAddress, kernelFor, append, appendOwn, landedOp, pairsAtAddress, enterCommitFrame, leaveCommitFrame } from './kernel-foundations.mjs';
|
|
3
3
|
|
|
4
4
|
/// **⟶ ADDED 2026-10-27 — `D-46`'s NAME ON A REPAIR INVOCATION'S OWN ENTRY, SPELLED HERE AS
|
|
5
5
|
/// `kernel-attempt.mjs` SPELLS IT.** **THE RULING, THE ARCHITECT, VERBATIM: *"A constraint's repair needs to stay
|
|
@@ -31,6 +31,19 @@ function repairInCommit(store, commit, run) {
|
|
|
31
31
|
if (typeof channel === 'function') return channel(run, commit);
|
|
32
32
|
return run();
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
/// **⟶ AND THE CONSTRAINT BODY'S INVOCATION AT THE REGISTRATION INSTANT NAMES THE REGISTRATION'S OWN COMMIT —
|
|
36
|
+
/// `D-53`, 2026-10-28: *"Constraints/Repairs should always use the same commit"*.** `D-46` named the commit for
|
|
37
|
+
/// the repair alone; **`D-53` states the invariant both kinds of caller-authored body obey, and a CONSTRAINT BODY
|
|
38
|
+
/// IS A CHECK: the commit the registering verb opened (`addConstraint`'s bracket, `docs/specs/storeroom-js/
|
|
39
|
+
/// surface.md §4.1`) is the commit it is asked inside, so a verb it calls JOINS that window and never opens a
|
|
40
|
+
/// second.** **A LISTENER BODY STILL NAMES NOTHING**: the entry invokes it at the terminal arm, where *"the
|
|
41
|
+
/// triggering commit already passed constraints"*, so what it does is a new question (`D-53`).
|
|
42
|
+
function constraintInCommit(store, commit, run) {
|
|
43
|
+
const channel = store !== null && typeof store === 'object' ? store[EXTERNAL_CALL] : undefined;
|
|
44
|
+
if (typeof channel === 'function') return channel(run, commit);
|
|
45
|
+
return run();
|
|
46
|
+
}
|
|
34
47
|
// ---------------------------------------------------------------------------------------------
|
|
35
48
|
// `K-1` `register(store, address, id, constraint) -> Handle`
|
|
36
49
|
// ---------------------------------------------------------------------------------------------
|
|
@@ -247,6 +260,13 @@ function withdrawRegistration(kernel, address, id, fresh, home) {
|
|
|
247
260
|
* invocation below is NOT wrapped — a throwing body reaches the caller as the very value it threw.
|
|
248
261
|
*/
|
|
249
262
|
function registrationEvaluation(kernel, store, address, id, constraint) {
|
|
263
|
+
// **⟶ THE REGISTRATION'S OWN COMMIT AND ITS OWN ONE LIST — `D-53`, 2026-10-28.** A registration is a commit
|
|
264
|
+
// (`addConstraint`'s and `constraintOn`'s brackets open one, and `3-bis` (a) already declares *"the
|
|
265
|
+
// `CommitRecord` of the registration act"*), so the record is built FIRST and the list beside it: **a verb the
|
|
266
|
+
// body calls is part of this commit, its entries are this list's entries, and the synthetic attempt a repair
|
|
267
|
+
// needs (state `3`) is an attempt of this same commit** — it appends to this list and mints no second one.
|
|
268
|
+
const commitRecord = { attempt: null, op: null, triggered: [], pending: [] };
|
|
269
|
+
const commitLog = [];
|
|
250
270
|
// **⟶ AMENDED 2026-10-26 (`DEF-S`; the architect's ruling, verbatim: *"Expand the returned error set for
|
|
251
271
|
// both S/N"*): THE BODY'S THROW IS MARKED AT THE FRAME THAT CAUGHT IT, and no attempt stands at this
|
|
252
272
|
// instant (`null`), so the mark carries the `[]` its clause declares. **THE THROWABLE'S IDENTITY IS
|
|
@@ -255,16 +275,23 @@ function registrationEvaluation(kernel, store, address, id, constraint) {
|
|
|
255
275
|
// unmarked throw is still the caller's own (`markBodyThrow`, `kernel-foundations.mjs`).
|
|
256
276
|
let outcome;
|
|
257
277
|
const context = registrationContext(store, address, null);
|
|
278
|
+
// **⟶ AND THE BODY IS INVOKED WITH THE REGISTRATION'S COMMIT NAMED — `D-53`, 2026-10-28.** The clause this
|
|
279
|
+
// replaces read *"the body is invoked with nothing named … so a verb it calls OPENS ITS OWN COMMIT"*
|
|
280
|
+
// (`D-45`, `D-46` item `1`), and **`D-53`'s invariant reverses it for constraints: *"Constraints/Repairs should
|
|
281
|
+
// always use the same commit"*** — a constraint body is asked, and the check it is asked by is this commit.
|
|
282
|
+
// **THE FRAME IS PUSHED FOR EXACTLY THE INVOCATION AND POPPED IN A `finally`**, so a nested write appends to this
|
|
283
|
+
// registration's list and a throwable leaves no frame standing.
|
|
284
|
+
// **THE CONTEXT IS BUILT ABOVE THE INVOCATION** (`kernel-surface.md §2.3` item 1), so the store read the context
|
|
285
|
+
// owes is this verb's own act and not the body's.
|
|
286
|
+
enterCommitFrame(kernel, commitLog);
|
|
258
287
|
try {
|
|
259
|
-
|
|
260
|
-
// is EXTERNALLY-SUPPLIED FUNCTION code entering the surface **and it has no commit in hand to name** — its
|
|
261
|
-
// five-member context carries none (`kernel-surface.md §2.3` item 1) — so **a verb it calls OPENS ITS OWN
|
|
262
|
-
// COMMIT** rather than joining the registering verb's (*"It should be opening a new commit by default of
|
|
263
|
-
// entering at the surface"*). **THE CONTEXT IS BUILT ABOVE THE INVOCATION**, so the store read the context
|
|
264
|
-
// owes is this verb's own act and not the body's.
|
|
265
|
-
outcome = externalCall(store, () => constraint(context));
|
|
288
|
+
outcome = constraintInCommit(store, commitRecord, () => constraint(context));
|
|
266
289
|
} catch (body) {
|
|
267
|
-
|
|
290
|
+
// **AND THE MARK CARRIES THIS COMMIT'S LIST** (`markBodyThrow`'s second slot): a registration-time body that
|
|
291
|
+
// threw after its own verbs appended carries those entries to the crossing, where `[]` used to be.
|
|
292
|
+
throw markBodyThrow(body, address, commitLog);
|
|
293
|
+
} finally {
|
|
294
|
+
leaveCommitFrame(kernel);
|
|
268
295
|
}
|
|
269
296
|
// THE OUTCOME IS `PAR-C-5`'S CLOSED THREE-ARM SET, read as the landing pass reads it: `true` is the pass
|
|
270
297
|
// arm; an object carrying `message` is the violation arm (its `repair`, where present, the repair the
|
|
@@ -277,9 +304,10 @@ function registrationEvaluation(kernel, store, address, id, constraint) {
|
|
|
277
304
|
: null;
|
|
278
305
|
// STATE 2 — THE STATE VIOLATES IT AND NO REPAIR IS REGISTERED. Nothing is attempted and no attempt is
|
|
279
306
|
// opened; the refusal carries the store's code and the row's own slots.
|
|
280
|
-
if (repair === null) return registrationRefusal(address, id,
|
|
281
|
-
// STATE 3 — THE REPAIR IS ATTEMPTED, on the synthetic attempt `3-bis` (a) declares
|
|
282
|
-
|
|
307
|
+
if (repair === null) return registrationRefusal(address, id, commitLog);
|
|
308
|
+
// STATE 3 — THE REPAIR IS ATTEMPTED, on the synthetic attempt `3-bis` (a) declares — **the attempt of THIS
|
|
309
|
+
// commit, holding THIS list by reference** (`D-53`).
|
|
310
|
+
return registrationAttempt(kernel, store, { address, id, repair, log: commitLog, commit: commitRecord });
|
|
283
311
|
}
|
|
284
312
|
|
|
285
313
|
/// **THE FIVE-MEMBER EVALUATION CONTEXT** (`kernel-surface.md §2.3` item 1's clause of 2026-10-17), built
|
|
@@ -392,11 +420,14 @@ function registrationAttempt(kernel, store, pair) {
|
|
|
392
420
|
tier: null,
|
|
393
421
|
value: undefined,
|
|
394
422
|
// `commit` — THE REGISTRATION ACT'S OWN `CommitRecord` (`3-bis` (a)): this kernel's four members, with
|
|
395
|
-
// no write's op and no write's triggered set, because a registration lands no `K-2` of its own.
|
|
396
|
-
|
|
423
|
+
// no write's op and no write's triggered set, because a registration lands no `K-2` of its own. **⟶ IT IS THE
|
|
424
|
+
// RECORD THE EVALUATION ALREADY BUILT AND NAMED (`D-53`), not a second one**, so the commit the constraint
|
|
425
|
+
// body was asked inside and the commit its repair joins are ONE.
|
|
426
|
+
commit: pair.commit,
|
|
397
427
|
write: null,
|
|
398
428
|
ops: [],
|
|
399
|
-
|
|
429
|
+
// **AND THE LIST IS THAT COMMIT'S OWN, BY REFERENCE** (`D-53`).
|
|
430
|
+
log: pair.log,
|
|
400
431
|
ran: [],
|
|
401
432
|
appliedRepairs: [],
|
|
402
433
|
rollback: [],
|
|
@@ -411,9 +442,12 @@ function registrationAttempt(kernel, store, pair) {
|
|
|
411
442
|
// pair is appended to BOTH `ran` and `appliedRepairs` (`3-bis` (b): the pair JOINS both members — of the
|
|
412
443
|
// SYNTHETIC attempt, and of no other). **THE PAIR ENTERS `ran` BEFORE THE REPAIR RUNS**, which is that
|
|
413
444
|
// arm's own ordering and is what makes the repeat arms reachable at the re-run below.
|
|
414
|
-
|
|
445
|
+
// **⟶ AND THE TWO ENTRIES ARE NAMED BY THE ITERATION — `D-53`'s first ruling.** This arm names no OP (`3-bis`
|
|
446
|
+
// (a)'s synthetic attempt has landed nothing when these are appended): the pair stands, the op is the declared
|
|
447
|
+
// `null` absence, and the `repair-run` entry's `opId` is rewritten below where the repair lands one.
|
|
448
|
+
append(attempt, 'constraint-check', { pair, op: null }, `the evaluation of ${pair.id}`);
|
|
415
449
|
appendOwn(attempt.ran, key);
|
|
416
|
-
append(attempt, 'repair-run', pair
|
|
450
|
+
append(attempt, 'repair-run', { pair, op: null }, 'the pair\'s repair was attempted at registration');
|
|
417
451
|
|
|
418
452
|
let result;
|
|
419
453
|
const repairContext = registrationRepairContext(store, address, pair.id, attempt.commit);
|
|
@@ -428,6 +462,8 @@ function registrationAttempt(kernel, store, pair) {
|
|
|
428
462
|
// that context at `write`'s fourth position names the same commit by its own hand, and the two spellings
|
|
429
463
|
// cannot disagree (the entry's position wins where it is supplied, and the invocation's name is the fallback
|
|
430
464
|
// where it is not — `state.mjs`'s `openCommit`).
|
|
465
|
+
// **AND THE FRAME STANDS FOR THIS INVOCATION TOO (`D-53`)**: the repair's verbs append to this commit's list.
|
|
466
|
+
enterCommitFrame(kernel, attempt.log);
|
|
431
467
|
result = repairInCommit(store, attempt.commit, () => pair.repair(repairContext));
|
|
432
468
|
} catch (body) {
|
|
433
469
|
// A REPAIR WHOSE BODY THROWS IS A FAILED REPAIR AND THE REGISTRATION IS REFUSED — the caller's act is
|
|
@@ -437,6 +473,8 @@ function registrationAttempt(kernel, store, pair) {
|
|
|
437
473
|
// that expected the body's own value out of `addConstraint` has read a route no clause declares.
|
|
438
474
|
closeRegistrationAttempt(kernel, attempt);
|
|
439
475
|
return registrationRefusal(address, pair.id, attempt.log);
|
|
476
|
+
} finally {
|
|
477
|
+
leaveCommitFrame(kernel);
|
|
440
478
|
}
|
|
441
479
|
|
|
442
480
|
const ok = result !== null && typeof result === 'object' && result.ok === true;
|
|
@@ -483,11 +521,18 @@ function registrationRerun(kernel, attempt, produced) {
|
|
|
483
521
|
// **THE ADDRESS IS IN HAND ONE FRAME ABOVE the `byAddress.get` call that stood here**, and the store→kernel
|
|
484
522
|
// channel is `record` alone (`A117` (D6) forbids a fifth member).
|
|
485
523
|
//
|
|
486
|
-
// **AND THE SELECTION IS
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
// `contract.md §2.8` item 1)
|
|
490
|
-
//
|
|
524
|
+
// **AND THE SELECTION IS A PREFIX MATCH ON A PAIR'S OWN ADDRESS, AS OF 2026-10-29 (`D-56`).** `RCA-8(g)`
|
|
525
|
+
// ANNOTATE-BESIDE: **the sentence that stood here read** *"the pass's set is the pairs WHOSE OWN ADDRESS IS THE
|
|
526
|
+
// ATTEMPT'S, which preserves `attempt-lifecycle.md §2.4` item 5 (iv)'s exact-address rule rather than widening
|
|
527
|
+
// it to the store's prefix-selected `triggered`"* (`P: docs/pending.md · (AA-1)`; `contract.md §2.8` item 1) —
|
|
528
|
+
// **and `D-56` supersedes that rule**: *"A listener/constraint should fire when the descendants of its targeted
|
|
529
|
+
// address node change, because the descendants become part of the object that is read from that address"*.
|
|
530
|
+
// **SO THE SET HERE IS `pairsAtAddress`'s AND MOVES WITH IT** — the pairs whose own address is a PREFIX of the
|
|
531
|
+
// attempt's, equality included — because a registration's re-run is not a second kind of pass and mints no
|
|
532
|
+
// second membership rule. **THE WIDENING IS THE FUNCTION'S AND NOT THIS MODULE'S**: the call below is byte-for-
|
|
533
|
+
// byte what it was, and the registration instant inherits `D-56` by CALLING the one selection function.
|
|
534
|
+
// **EACH ELEMENT IS EVALUATED AT MOST ONCE**, so a pair standing at N addresses whose two addresses are both
|
|
535
|
+
// prefixes of the act is reached once (`contract.md §2.6` item 5).
|
|
491
536
|
const list = pairsAtAddress(kernel, attempt.address);
|
|
492
537
|
for (const key of list) {
|
|
493
538
|
const pair = kernel.pairs.get(key);
|
|
@@ -500,17 +545,26 @@ function registrationRerun(kernel, attempt, produced) {
|
|
|
500
545
|
attempt: attempt.ref,
|
|
501
546
|
op: produced,
|
|
502
547
|
};
|
|
548
|
+
// **⟶ AND THE RE-RUN'S BODIES ARE OF THIS COMMIT TOO — `D-53`.** The clause this replaces read *"this body is
|
|
549
|
+
// invoked with nothing named too … the third of the three that invoke a caller-authored constraint body"*
|
|
550
|
+
// (`D-45`): **the three frames name the attempt's commit now, and the registration's re-run names the same
|
|
551
|
+
// one its repair joined.** The context is built ABOVE the invocation.
|
|
552
|
+
enterCommitFrame(kernel, attempt.log);
|
|
503
553
|
try {
|
|
504
|
-
|
|
505
|
-
// re-run's frame is the third of the three that invoke a caller-authored constraint body, and it names no
|
|
506
|
-
// commit exactly as the registration evaluation and the landing's pass do. The context is built ABOVE the
|
|
507
|
-
// invocation.
|
|
508
|
-
outcome = externalCall(attempt.store, () => pair.constraint(context));
|
|
554
|
+
outcome = constraintInCommit(attempt.store, attempt.commit, () => pair.constraint(context));
|
|
509
555
|
} catch (body) {
|
|
510
556
|
// **⟶ ADDED 2026-10-26 (`DEF-S`, the same ruling): a body thrown at the synthetic attempt's re-run is
|
|
511
557
|
// marked at this frame too — the mark carries the attempt's own log and address, and the entry's
|
|
512
558
|
// crossing converts a marked value only** (`markBodyThrow`, `kernel-foundations.mjs`).
|
|
559
|
+
// **⟶ AND NEITHER THIS FRAME NOR THE REGISTRATION-TIME EVALUATION ABOVE APPENDS A THROWABLE ENTRY, 2026-10-28
|
|
560
|
+
// — `DEF-AK`'s RECORDED ARM IS THE LANDING'S.** The re-run appends no `constraint-check` entry for the
|
|
561
|
+
// evaluation it threw in (the pair's own function ran at the registration instant), and no `outcome`
|
|
562
|
+
// entry stands because this throwable propagates before any terminal act — so there is no entry of the
|
|
563
|
+
// closed four this frame could honestly extend, and no fifth `kind` is minted for it. The registration
|
|
564
|
+
// instant's `log` is `surface.md §2.5` item 4's declared `[]` and stays it (`DEF-S`'s own cell reads it).
|
|
513
565
|
throw markBodyThrow(body, attempt.address, attempt.log);
|
|
566
|
+
} finally {
|
|
567
|
+
leaveCommitFrame(kernel);
|
|
514
568
|
}
|
|
515
569
|
if (outcome === true) continue;
|
|
516
570
|
attempt.terminalArm = attempt.appliedRepairs.includes(key) ? 'KC-5' : 'KC-6';
|
|
@@ -49,14 +49,27 @@ export function terminal(kernel, attempt, status, message) {
|
|
|
49
49
|
// THE COMPOSITION'S OWN FLOOR, TAKEN OFF THE MEMBER IT WAS DECIDED ON (`composition-and-states.md
|
|
50
50
|
// §2.6` item 5 (b)): a still-owed op's call meeting either floor code makes the arm `KC-8` WHATEVER
|
|
51
51
|
// the pass's own arm was, and nothing is restored (item 6 (a), (c)).
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
//
|
|
53
|
+
// **⟶ AND THE SAVE ARM'S OWN TOKEN IS NOT OVERWRITTEN BY IT — `D-53`'s THIRD RULING, 2026-10-28.** **THE FLOOR
|
|
54
|
+
// BELONGS TO THE COMPOSITION AND `KC-8` KEEPS ITS DECLARED MEANING; what it may not do is make a SAVE FAILURE
|
|
55
|
+
// and a CONSTRAINT REFUSAL end at the same token**, which is the contradiction `D-52` measured (*"`KC-8` crosses
|
|
56
|
+
// as both statuses"*). **SO THE PRECEDENCE IS ONE SENTENCE: THE FLOOR GOVERNS EVERY ARM BUT THE SAVE'S, and the
|
|
57
|
+
// save's arm keeps `KC-9`, its own message, and the floor's own sentence beside it** — so the caller can still
|
|
58
|
+
// read, from the ONE `outcome` entry, both what failed and what the composition then met.
|
|
59
|
+
const floorGoverns = floor !== null && status !== KC.saveFailed;
|
|
60
|
+
const finalStatus = floorGoverns ? KC.rollbackFloor : status;
|
|
61
|
+
const finalMessage = floorGoverns
|
|
62
|
+
? `the per-op rollback met the store's own ${floor.code} at ${floor.opId}`
|
|
63
|
+
: floor === null
|
|
64
|
+
? message
|
|
65
|
+
: `${message} — the per-op rollback then met the store's own ${floor.code} at ${floor.opId}`;
|
|
56
66
|
// THE `outcome` ENTRY — appended ONCE, and `state` is THE ARM'S ONE TOKEN: the floor is answered IN THIS
|
|
57
67
|
// SAME ENTRY where the attempt would also have had a failure arm, and NO SECOND ENTRY IS APPENDED
|
|
58
68
|
// (`kernel-surface.md §2.5` item 1's kind table; `§2.6` item 6 (a), (b)).
|
|
59
|
-
|
|
69
|
+
// **⟶ AND ITS ITERATION NAMES NO PAIR AND THE ATTEMPT'S LAST OP — `D-53`'s first ruling**, so the two columns
|
|
70
|
+
// travel as one identity wherever an op exists and read `null` where one does not ("an `outcome` names them
|
|
71
|
+
// where they exist").
|
|
72
|
+
append(attempt, 'outcome', { pair: null, op: attempt.ops[attempt.ops.length - 1] }, finalMessage, finalStatus);
|
|
60
73
|
// THE DISCARD RULE, AT ITS ONE OBSERVABLE (`attempt-lifecycle.md §2.4` item 8 (i) (5), read with
|
|
61
74
|
// `kernel-surface.md §2.1` item 2's discarded-set clause; `A: docs/decisions.md` · `A112`): where the
|
|
62
75
|
// attempt's own write FAILED the registered constraints at its landing and could not be repaired, its
|