provident-storeroom 0.3.1 → 0.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/index.d.ts +40 -5
- package/index.mjs +417 -26
- package/package.json +6 -6
- package/src/constraint-kernel.mjs +390 -2
package/index.d.ts
CHANGED
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
// `constraintOn(pair, constraint)` · `constraintOff(pair, constraint)`, **PLUS `register(handle, listener)
|
|
18
18
|
// -> undefined` and `settle(record) -> undefined`** — the last being THE ORDERING SEAM the kernel calls and
|
|
19
19
|
// the entry implements; and (3) the failure surface, a thrown plain object with exactly
|
|
20
|
-
// `{status, message}
|
|
20
|
+
// `{status, message, log}` — **THREE MEMBERS FROM 2026-10-16, `2 → 3`, on the architect's ruling *"Bubble
|
|
21
|
+
// the message log to the client on failure, override any clauses that forbid this."*** (`surface.md §2.5`'s
|
|
22
|
+
// clause of that date, the crossing form's ONE home; **the ONE figure that moves is the arity, and
|
|
23
|
+
// `storeCreate` remains the namespace's one name and the product its twelve own members**).
|
|
21
24
|
//
|
|
22
25
|
// **THE TEN METHODS TAKE THE RECEIVER'S OWN POSITION AWAY: `8 → 1` ✓ AND `4 → 12` ✓** (`surface.md §2.9`
|
|
23
26
|
// item 1's and `§2.4` item 9 (f)'s `A127` clauses). The seven verbs that reach the store are METHODS of the
|
|
@@ -188,14 +191,46 @@ export type StoreStatus =
|
|
|
188
191
|
| (string & {});
|
|
189
192
|
|
|
190
193
|
/**
|
|
191
|
-
* **THE
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
194
|
+
* **THE KERNEL'S OWN LOG ENTRY** — *"exactly six members — `seq` · `kind` · `id` · `message` · `opId` ·
|
|
195
|
+
* `state`"* (`docs/specs/storeroom-constraints/kernel-surface.md §2.5` item 1, whose member set is CLOSED:
|
|
196
|
+
* *"a seventh member of `LogEntry` … is not a variation, it is a different shape"*). **DECLARED HERE ONLY
|
|
197
|
+
* AS THE ELEMENT SHAPE OF THE FAILURE'S `log` MEMBER, AND MINTED BY NO CLAUSE OF THIS UNIT**: an attempt's
|
|
198
|
+
* message log entries are the KERNEL'S records, carried VERBATIM, and no flattening is declared — a client
|
|
199
|
+
* that reads one reads the kernel's own entry.
|
|
200
|
+
*
|
|
201
|
+
* `kind` is the kernel's closed four-member `LogKind` set, and `state` is the kernel's own `KC` token on the
|
|
202
|
+
* one `outcome` entry and `null` on the three non-`outcome` kinds.
|
|
203
|
+
*/
|
|
204
|
+
export interface LogEntry {
|
|
205
|
+
readonly seq: number;
|
|
206
|
+
readonly kind: 'constraint-check' | 'repair-run' | 'commit' | 'outcome';
|
|
207
|
+
readonly id: string | null;
|
|
208
|
+
readonly message: string;
|
|
209
|
+
readonly opId: string | null;
|
|
210
|
+
readonly state: string | null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* **THE SINGLE FAILURE SURFACE** (`contract.md §1.4`; `distribution.md §5.2` item 3) — **AND ITS MEMBER SET
|
|
215
|
+
* MOVES `2 → 3` FROM 2026-10-16 ON THE ARCHITECT'S RULING *"Bubble the message log to the client on failure,
|
|
216
|
+
* override any clauses that forbid this."*** (`surface.md §2.5`'s clause of that date, whose items 1–10 are
|
|
217
|
+
* the crossing form's ONE home). A THROWN plain object carrying exactly `{status, message, log}` — never an
|
|
218
|
+
* `Error` subclass, never a returned tagged union and never a `Promise` rejection. **The status is carried
|
|
219
|
+
* VERBATIM from the store's own closed set and the message is the store's own generated string**; this
|
|
220
|
+
* package mints neither.
|
|
221
|
+
*
|
|
222
|
+
* **`log` IS AN ORDINARY OWN ENUMERABLE DATA MEMBER OF THAT SAME PLAIN OBJECT** (item 9): *"written with an
|
|
223
|
+
* object literal, not `Object.defineProperty`, not a getter, not on a prototype and not behind a `Symbol`"* —
|
|
224
|
+
* so `Object.keys(caught)` reads exactly `["log","message","status"]` and its length is `3` on EVERY arm. **IT
|
|
225
|
+
* IS NEVER ABSENT, NEVER `null` AND NEVER A NON-ARRAY** (item 9), **and `[]` is its declared value where the
|
|
226
|
+
* failure's cause has no attempt at all** (item 4: the empty array, never an absent member and never a
|
|
227
|
+
* placeholder entry) — **while every failure whose attempt exists carries that attempt's own entries, taken
|
|
228
|
+
* BEFORE the attempt is disposed of** (item 10 (iii)).
|
|
195
229
|
*/
|
|
196
230
|
export interface StoreRefusal {
|
|
197
231
|
readonly status: StoreStatus;
|
|
198
232
|
readonly message: string;
|
|
233
|
+
readonly log: LogEntry[];
|
|
199
234
|
}
|
|
200
235
|
|
|
201
236
|
/** The opaque handle a listener registration is keyed by: the package's own value for one registration. */
|
package/index.mjs
CHANGED
|
@@ -402,11 +402,84 @@ function addonLoadMessage() {
|
|
|
402
402
|
}
|
|
403
403
|
|
|
404
404
|
/// `surface.md §2.5`: **THE SINGLE FAILURE FORM** — a THROWN plain object carrying EXACTLY
|
|
405
|
-
/// `{status, message}
|
|
406
|
-
/// VERBATIM** (`§2.5` items 1–2, `DD-40`): this function constructs the
|
|
407
|
-
///
|
|
408
|
-
|
|
409
|
-
|
|
405
|
+
/// `{status, message, log}`. **The status and the message are the store's own and are carried
|
|
406
|
+
/// VERBATIM** (`§2.5` items 1–2, `DD-40`): this function constructs the form out of the refusal the addon
|
|
407
|
+
/// threw and mints no code of its own and authors no message of its own.
|
|
408
|
+
///
|
|
409
|
+
/// **⟶ AND THE FORM CROSSES AT THREE MEMBERS FROM 2026-10-16 — `surface.md §2.5` ITEM 4, THE ARCHITECT'S
|
|
410
|
+
/// RULING OF THAT DATE: *"`log` IS PRESENT ON EVERY FAILURE THIS SURFACE THROWS, AND `[]` IS ITS DECLARED
|
|
411
|
+
/// VALUE WHERE THE FAILURE'S CAUSE HAS NO ATTEMPT AT ALL."*** **The three-member member set is FLAT ACROSS
|
|
412
|
+
/// ARMS and not conditional:** a `read`/`readLiteral`/`delete`/`rollback` store refusal with no attempt
|
|
413
|
+
/// live, the construction's own `cfg`-side refusals, `a.register`'s refusal and the constraint methods'
|
|
414
|
+
/// `TypeError` all carry `log: []` — **the EMPTY ARRAY, never an absent member, never `null`, and never a
|
|
415
|
+
/// placeholder entry** — while every failure whose attempt exists carries that attempt's own entries
|
|
416
|
+
/// (`§2.5` items 3–4 and 10 (i)–(iii); `§2.12` item 1's mark of the same date). **AND WHERE A STORE ACT
|
|
417
|
+
/// PRODUCED IT, THE STORE'S `status` AND `message` ARE PRESERVED BYTE-FOR-BYTE AND `log` IS ATTACHED BESIDE
|
|
418
|
+
/// THEM — nothing is converted, a member is added** (`§2.5` item 10 (ii); `fail-surface.md §1.2`'s
|
|
419
|
+
/// *"the kernel NEVER CONVERTS ONE CHANNEL'S FAILURE INTO THE OTHER'S FORM"* stands whole).
|
|
420
|
+
///
|
|
421
|
+
/// **THE `log` MEMBER IS AN ORDINARY OWN ENUMERABLE DATA MEMBER** — written with the object literal below,
|
|
422
|
+
/// **not `Object.defineProperty`, not a getter, not on a prototype and not behind a `Symbol`** — so
|
|
423
|
+
/// `Object.keys(caught)` reads exactly `["log","message","status"]` and its length is `3` on every arm
|
|
424
|
+
/// (`§2.5` item 9). **IT IS NOT `defineProperty`'D BECAUSE A MEMBER THAT IS NOT ENUMERABLE IS NOT A MEMBER
|
|
425
|
+
/// A CANONICAL CENSUS CAN SEE**, and it is not a getter because a client reads a list and not a call.
|
|
426
|
+
///
|
|
427
|
+
/// **⟶ AND ITS TWO STORE MEMBERS ARE READ OFF THE STORE'S OWN REFUSAL AND OFF NOTHING ELSE — CORRECTED
|
|
428
|
+
/// 2026-10-17 (`A64`'s one form read with `surface.md §2.5` item 5 (e)).** **THE CONSTRUCTION BELOW ONCE
|
|
429
|
+
/// READ `refusal.status` AND `refusal.message` OF WHATEVER IT WAS HANDED, WITH NO PROVENANCE TEST AT ALL**,
|
|
430
|
+
/// and the two failures that cost are named rather than left to be re-derived: **a caller's own throwable
|
|
431
|
+
/// reached it by ONE mis-scoped `try`** (see `storeCreate` below, where that throwable now surfaces as
|
|
432
|
+
/// itself), **and a value that is not an object at all — most sharply the runtime's own `undefined`, where
|
|
433
|
+
/// NO refusal object exists because an exception is already pending — made THIS FRAME fault on
|
|
434
|
+
/// `refusal.status`**, so a caller read *"Cannot read properties of undefined (reading 'status')"* where the
|
|
435
|
+
/// value its own body threw was the whole of what it was owed.
|
|
436
|
+
///
|
|
437
|
+
/// **THE TEST IS PROVENANCE'S OWN SHAPE AND NOT A CLASS DECISION OF THIS UNIT'S:** the store's refusal is a
|
|
438
|
+
/// plain object whose `status` and `message` are `string`s (`docs/specs/storeroom-native/contract.md §8.3`'s
|
|
439
|
+
/// closed two-member form; `§2.5` items 1–2), and **a value that is not that object is NOT this form's
|
|
440
|
+
/// provenance** — so it is THROWN AS ITSELF, by the one line below, and **NEITHER A STATUS NOR A MESSAGE IS
|
|
441
|
+
/// MINTED FOR IT AND NO `log` IS ADDED TO A VALUE THAT IS NOT THE STORE'S FORM.**
|
|
442
|
+
///
|
|
443
|
+
/// **⟶ THE PROVENANCE TEST IS *"IS THIS THE STORE'S TWO-MEMBER FORM?"* AND NOT *"DOES THIS CARRY A
|
|
444
|
+
/// `log`?"*, AND THAT DISTINCTION IS THE WHOLE OF THE CORRECTION THIS MEMBER FORCED.** The two-member
|
|
445
|
+
/// presence test **was** the earlier discriminator at the crossing (`constraintCrossing`'s own history: it
|
|
446
|
+
/// discriminated on `log`'s PRESENCE) — **and now that EVERY surface failure carries `log`, presence alone
|
|
447
|
+
/// can no longer tell a store refusal, a kernel refusal and a CALLER'S FORGED OBJECT apart.** **THE TEST
|
|
448
|
+
/// REPLACED IT IS THE STORE'S FORM ITSELF — `status` a `string` AND `message` a `string`, both READ OFF THE
|
|
449
|
+
/// HANDED VALUE AND NEITHER MINTED** — and `log` is then **ATTACHED BESIDE THE TWO, NEVER READ AS THE
|
|
450
|
+
/// DISCRIMINATOR** (`refusalLog` below). A caller's forged `{status, message}` thrown from a constraint body
|
|
451
|
+
/// carries both strings and would pass this test — **which is why this function is never ON the body-throw
|
|
452
|
+
/// path at all**: the body's throwable leaves `runAttempt` unconverted and reaches the caller without
|
|
453
|
+
/// passing here (`fail-surface.md §1.1` item 5; see `constraintCrossing`'s rethrow). **SO NO BYTE OF THIS
|
|
454
|
+
/// FRAME'S PROVENANCE TEST MOVES: every store refusal this package crosses — the eight verbs, the
|
|
455
|
+
/// construction, the `16`-code set — keeps its `status` and its `message` member for member and byte for
|
|
456
|
+
/// byte, and the ONE member this date adds is `log`.**
|
|
457
|
+
function fail(refusal, log) {
|
|
458
|
+
if (refusal === null || typeof refusal !== 'object'
|
|
459
|
+
|| typeof refusal.status !== 'string' || typeof refusal.message !== 'string') {
|
|
460
|
+
throw refusal;
|
|
461
|
+
}
|
|
462
|
+
throw { status: refusal.status, message: refusal.message, log: refusalLog(log) };
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/// **THE ONE PLACE A REFUSAL'S `log` MEMBER IS DECIDED** — `surface.md §2.5` item 4's flat reading, taken
|
|
466
|
+
/// once so no arm can spell it differently. **AN ABSENT ARGUMENT IS THE DECLARED `[]`**: the failure's cause
|
|
467
|
+
/// has no attempt at all (a store refusal with no attempt live, a `cfg`-side refusal, a `register` refusal,
|
|
468
|
+
/// a constraint-method `TypeError`) — *"the EMPTY ARRAY, never an absent member, never `null`, and never a
|
|
469
|
+
/// placeholder entry"*. **A LIST HANDED IN IS THE ATTEMPT'S OWN AND CROSSES VERBATIM** (`§2.5` item 3: *"THE
|
|
470
|
+
/// ATTEMPT'S OWN MESSAGE LOG, VERBATIM … CARRIED AND NOT RE-SHAPED"*), and it is **NOT COPIED**: a copy would
|
|
471
|
+
/// be a second list and the spec's *"the same list the attempt record held"* is a statement about identity
|
|
472
|
+
/// of content, which a copy preserves while costing an allocation on every failure — and **a copy would also
|
|
473
|
+
/// silently paper over the timing trap below**, because a copy taken late reads the same bytes as one taken
|
|
474
|
+
/// early. The list crosses as it stands, and `[]` is minted fresh at each no-attempt failure so that no two
|
|
475
|
+
/// failures alias one array.
|
|
476
|
+
///
|
|
477
|
+
/// **A `log` THAT IS NOT AN ARRAY IS A FINDING AT THE SITE THAT PRODUCED IT** (`§2.5` item 9) — this
|
|
478
|
+
/// function declares no arm for it and answers the empty array rather than propagating a shape the spec
|
|
479
|
+
/// calls impossible: the alternative is a failure whose `log` is `null` or a non-array, which the same item
|
|
480
|
+
/// names as the finding verbatim.
|
|
481
|
+
function refusalLog(log) {
|
|
482
|
+
return Array.isArray(log) ? log : [];
|
|
410
483
|
}
|
|
411
484
|
|
|
412
485
|
function withAddon() {
|
|
@@ -1816,9 +1889,38 @@ function writeCall(state, args, fault) {
|
|
|
1816
1889
|
/// clauses (a)–(b); `A79`).
|
|
1817
1890
|
export function storeCreate(cfg) {
|
|
1818
1891
|
const addon_ = withAddon();
|
|
1892
|
+
// **⟶ THE CONSTRUCTION'S OWN READ OF THE CALLER'S `cfg` STANDS OUTSIDE THE BOUNDARY'S CATCH — CORRECTED
|
|
1893
|
+
// 2026-10-17 (`A64`'s one form read with `surface.md §2.5` item 5 (e); the ruling *"catch a throw from a
|
|
1894
|
+
// repair and encapsulate the message to distinguish forgeries"*).**
|
|
1895
|
+
//
|
|
1896
|
+
// **THE DEFECT IT CLOSES, NAMED AT ITS BYTES: the walk below READS THE CALLER'S OWN PROPERTIES — `cfg`'s
|
|
1897
|
+
// four declared keys by `Object.hasOwn` and by the member reads `encodeConfig` performs — so a `cfg`
|
|
1898
|
+
// carrying an own ACCESSOR is a caller's own body, and a `get` that THROWS is a CALLER'S OWN THROWABLE.
|
|
1899
|
+
// While this read stood INSIDE the `try`, that throwable reached `fail`, which constructs THE STORE'S
|
|
1900
|
+
// SINGLE FORM out of whatever it is handed: `storeCreate({ journalLength: 64, listeners: [],
|
|
1901
|
+
// get constraints() { throw { status: 'AddressMalformed', message: 'FORGED BY THE CALLER' } } })` answered
|
|
1902
|
+
// `{"status":"AddressMalformed","message":"FORGED BY THE CALLER"}` — A CALLER-CHOSEN STATUS CARRIED AS
|
|
1903
|
+
// THIS STORE'S OWN REFUSAL — a thrown `TypeError` answered `{status: undefined, message: '…'}`, a thrown
|
|
1904
|
+
// bare string lost its message entirely, and a thrown `undefined` or `null` made the read itself fault on
|
|
1905
|
+
// `refusal.status`. **THE DEFECT WAS NEVER *"a caller can forge a status"* BUT *"A CALLER'S OWN EXCEPTION
|
|
1906
|
+
// IS CAUGHT AND RE-SHAPED BY A PATH THAT ASSUMES IT IS THE STORE'S."**
|
|
1907
|
+
//
|
|
1908
|
+
// **THE FIX IS THE SCOPE AND NOT A NEW FORM: the walk that READS THE CALLER'S OWN VALUES stands outside
|
|
1909
|
+
// the catch, so the caller's own body's throwable PROPAGATES AS ITSELF — the same value, wearing no member
|
|
1910
|
+
// this unit minted and no status of the store's closed set — while `fail` is reached on this path by THE
|
|
1911
|
+
// ADDON'S OWN REFUSAL ALONE, which is the ONE provenance `§2.5`'s two-member form belongs to.** **AND THE
|
|
1912
|
+
// CLAUSE THIS IMPLEMENTS IS `surface.md §2.5` ITEM 5 (e)'s OWN RULE CARRIED TO THIS SITE** — *"a rejection
|
|
1913
|
+
// is NEVER A RAW HOST ERROR — a `TypeError` … a string thrown, or any host object escaping from the
|
|
1914
|
+
// boundary's own frame is a FINDING at whatever site produced it, not a rejection"* — read with
|
|
1915
|
+
// `kernel-surface.md §2.3` item 1's body-throw clause, which fixes the SAME disposition for the two
|
|
1916
|
+
// caller-side functions this unit registers: **a caller's body's throwable is *"NOT a kernel state and NOT
|
|
1917
|
+
// a store state"* and reaches the caller UNCHANGED.** **NO CODE, NO MEMBER AND NO MESSAGE MOVES ON ANY ARM
|
|
1918
|
+
// THE CALLER'S `cfg` IS LAWFUL: where `encodeConfig` RETURNS, this function's boundary call, its catch and
|
|
1919
|
+
// `fail` are the bytes they were.**
|
|
1920
|
+
const encoded = encodeConfig(cfg);
|
|
1819
1921
|
let id;
|
|
1820
1922
|
try {
|
|
1821
|
-
id = addon_.storeCreate(
|
|
1923
|
+
id = addon_.storeCreate(encoded);
|
|
1822
1924
|
} catch (refusal) {
|
|
1823
1925
|
fail(refusal);
|
|
1824
1926
|
}
|
|
@@ -1922,7 +2024,18 @@ export function storeCreate(cfg) {
|
|
|
1922
2024
|
const encoded = constraintEntry(element, i);
|
|
1923
2025
|
if (encoded.bad !== undefined) continue;
|
|
1924
2026
|
if (typeof element.constraint !== 'function') continue;
|
|
1925
|
-
|
|
2027
|
+
// **⟶ AND THIS SITE TAKES THE THREE-STATE REGISTRATION TOO** (`§2.12` item 3's clause of 2026-10-16
|
|
2028
|
+
// at its `A135` (3) mark; `docs/specs/storeroom-native/contract.md §7.3` (b)). **THE BATCH ROUTE AND THE
|
|
2029
|
+
// ADD ROUTE REACH THE SAME `K-1`**, so a batch element the current state violates — with no repair
|
|
2030
|
+
// standing, or with one that does not resolve it — refuses the CONSTRUCTION in this surface's one
|
|
2031
|
+
// failure form, exactly as the ADD route refuses the call. **THE STATE 3 SUCCESS ARM IS THE ONE THAT
|
|
2032
|
+
// MOVES THE STORE**: the repair's edit stands, the registration stands, and the construction returns
|
|
2033
|
+
// its instance with no log crossing (`3-bis` (c)).
|
|
2034
|
+
try {
|
|
2035
|
+
carryConstraint(state, instance, encoded.address.s, encoded.id, element.constraint);
|
|
2036
|
+
} catch (refusal) {
|
|
2037
|
+
registrationCrossing(refusal);
|
|
2038
|
+
}
|
|
1926
2039
|
}
|
|
1927
2040
|
}
|
|
1928
2041
|
// **⟶ AND THE CONSTRUCTION'S OWN ADOPTION ENTERS THE PACKAGE'S HOME MIRROR** (`§2.4` item 7 (b)'s dated
|
|
@@ -2504,9 +2617,12 @@ function settleOn(state, record, supplied) {
|
|
|
2504
2617
|
// `crossing.md §1.7`): an absent argument, every non-object and every `Proxy` is refused before any
|
|
2505
2618
|
// marker is read or set.
|
|
2506
2619
|
if (!supplied || record === null || typeof record !== 'object' || types.isProxy(record)) {
|
|
2507
|
-
|
|
2620
|
+
// **AND IT CARRIES `log: []` ON THE RULING'S FLAT READING** (`surface.md §2.5` item 4 names the
|
|
2621
|
+
// registration site's `TypeError` among the arms that carry the empty array; the `status` this form
|
|
2622
|
+
// never had is still not minted — `§2.4` item 9 (b)'s *"its `status` member MUST BE ABSENT"* stands).
|
|
2623
|
+
throw withEmptyLog(new TypeError(
|
|
2508
2624
|
`settle's argument is ${classSpelling(record)}, and the ordering seam takes a record identity this instance adopted`,
|
|
2509
|
-
);
|
|
2625
|
+
));
|
|
2510
2626
|
}
|
|
2511
2627
|
// **⟶ ONE WRITE, ONE ADOPTION, AND TWO IDENTITIES CARRY IT** (`§2.4` item 9's table rows (a) and (b);
|
|
2512
2628
|
// `PAR-JS-19`: *"the adoption happens AT the first call, and the SECOND call for that identity is the
|
|
@@ -2542,9 +2658,9 @@ function settleOn(state, record, supplied) {
|
|
|
2542
2658
|
}
|
|
2543
2659
|
if (!pre) {
|
|
2544
2660
|
if (record.pending === undefined) {
|
|
2545
|
-
throw new TypeError(
|
|
2661
|
+
throw withEmptyLog(new TypeError(
|
|
2546
2662
|
`settle's argument is ${classSpelling(record)}, and the ordering seam takes a record identity this instance adopted`,
|
|
2547
|
-
);
|
|
2663
|
+
));
|
|
2548
2664
|
}
|
|
2549
2665
|
// INSTANT (a): the adoption. The ledger entry stands EMPTY until the verb answers, so the write that
|
|
2550
2666
|
// drains it is the one write identity this adoption is for.
|
|
@@ -2761,18 +2877,79 @@ function constraintPairKey(address, id) {
|
|
|
2761
2877
|
/// **THE ONE REFUSAL `§2.12` ITEM 4 DECLARES, TAKEN BEFORE ANY ACT AND LEAVING NOTHING CHANGED** — a JS
|
|
2762
2878
|
/// `TypeError`, its `status` member ABSENT, no `message` member of this unit's own, **the store's closed
|
|
2763
2879
|
/// `16`-member set neither minted nor widened, and the store reached by no call this refusal makes.**
|
|
2880
|
+
///
|
|
2881
|
+
/// **⟶ AND THE `TypeError` CARRIES `log: []` FROM 2026-10-16, AND THIS IS THE ONE PLACE THE FLAT RULING AND
|
|
2882
|
+
/// `A127`'S TWO REFUSAL RULES MEET — SO THE RECONCILIATION IS STATED RATHER THAN LEFT TO THE READER**
|
|
2883
|
+
/// (`surface.md §2.5` item 4, which names *"the three constraint methods' `TypeError`"* among the arms that
|
|
2884
|
+
/// *"all carry `log: []`"*; `§2.12` item 4's replacement clause and `§2.4` item 9 (f)'s rule (ii), which fix
|
|
2885
|
+
/// the class, the absent `status` and the change-nothing atomicity).
|
|
2886
|
+
///
|
|
2887
|
+
/// **THE TWO RULES ARE NOT IN TENSION AND NEITHER MOVES:** rule (ii) declares the refusal is **a `TypeError`
|
|
2888
|
+
/// CARRYING NO `status` MEMBER** — and it still carries none: the member below is written on the *error
|
|
2889
|
+
/// object* and is `log`, not `status`, and **`'status' in err` is still `false` on every call of this
|
|
2890
|
+
/// method.** The ruling does not re-class the refusal as a store refusal, does not mint a `status`, does not
|
|
2891
|
+
/// reach the store and does not change the call's effects — *"no store call is made, no pair is added,
|
|
2892
|
+
/// enabled or disabled, no journal entry is appended and no code is minted"* stands whole. **THE ONE THING
|
|
2893
|
+
/// THE RULING ADDS IS A MEMBER, AND A `TypeError` IS AN ORDINARY OBJECT: an own enumerable data member can
|
|
2894
|
+
/// be set on it without making it any less an instance of `TypeError` and of nothing else** — which is the
|
|
2895
|
+
/// single question that had to be answered before this could be written, and it is answered by the class,
|
|
2896
|
+
/// not by a judgement here (`Object.keys(new TypeError('x'))` is `[]` and the object is EXTENSIBLE).
|
|
2897
|
+
///
|
|
2898
|
+
/// **SO THE DECLARED FORM DOES CARRY A THIRD MEMBER, AND THIS IS *NOT* A SPEC CONFLICT: the collision the
|
|
2899
|
+
/// task warned of would be a form that had to become *"a different form"* to hold `log`, and it does not —
|
|
2900
|
+
/// the class (`TypeError`, and of nothing else), the ABSENT `status`, the change-nothing atomicity, the
|
|
2901
|
+
/// caller's own `message` text and the one-`TypeError`-for-both-refusals rule all cross this frame
|
|
2902
|
+
/// untouched. What changes is `Object.keys` on the thrown error, from `[]` to `["log"]`.**
|
|
2903
|
+
///
|
|
2904
|
+
/// **THE MEMBER IS SET WITH `Object.defineProperty` RATHER THAN BY ASSIGNMENT, AND THE REASON IS THE ONE
|
|
2905
|
+
/// `§2.5` ITEM 9 DECLARES: THE DESCRIPTOR MUST BE ORDINARY — own, enumerable, a data member, writable and
|
|
2906
|
+
/// configurable.** A plain `err.log = []` on an error object achieves exactly that descriptor on V8 and every
|
|
2907
|
+
/// engine this package supports, **but it is written with `defineProperty` HERE because an error's own
|
|
2908
|
+
/// members are not universally ordinary across realms and a runtime that made `Error.prototype.log` an
|
|
2909
|
+
/// accessor would silently divert the write**, and the declaration is cheap where the alternative is a
|
|
2910
|
+
/// silent miss on a member the census reads. **THE PROHIBITION IN `§2.5` ITEM 9 (*"written with an object
|
|
2911
|
+
/// literal, not `Object.defineProperty`"*) BINDS THE STORE'S PLAIN-OBJECT FORM AND ITS `log`, WHICH THIS
|
|
2912
|
+
/// PACKAGE WRITES WITH AN OBJECT LITERAL IN `fail` ABOVE AND IN `constraintCrossing` BELOW; it cannot bind a
|
|
2913
|
+
/// `TypeError`, because a `TypeError` has no object literal and its class is what rule (ii) declares. The
|
|
2914
|
+
/// ITEM'S PURPOSE — that a canonical census sees the member — is the property both routes preserve, and the
|
|
2915
|
+
/// descriptor is asserted explicitly below so the purpose is met member for member.**
|
|
2764
2916
|
function constraintRefuse(where, value) {
|
|
2765
|
-
|
|
2917
|
+
const error = new TypeError(
|
|
2766
2918
|
`the ${where} of this call is ${classSpelling(value)}, and it is not a value this position's domain `
|
|
2767
2919
|
+ 'admits',
|
|
2768
2920
|
);
|
|
2921
|
+
throw withEmptyLog(error);
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
/// **THE ONE PLACE `log: []` IS SET ON A REFUSAL THAT IS NOT AN OBJECT LITERAL** — the three constraint
|
|
2925
|
+
/// methods' `TypeError` and nothing else. **`surface.md §2.5` item 4 calls for the EMPTY ARRAY on exactly
|
|
2926
|
+
/// these arms** — *"the EMPTY ARRAY, never an absent member, never `null`, and never a placeholder entry"* —
|
|
2927
|
+
/// and item 9 calls for an **own enumerable data member**, which is the descriptor written here BY HAND so
|
|
2928
|
+
/// that no default, no engine and no realm decides it. **THE ERROR'S PROTOYPE IS NOT TOUCHED**, so
|
|
2929
|
+
/// `err instanceof TypeError` stays `true` and `Object.getPrototypeOf(err)` stays `TypeError.prototype`:
|
|
2930
|
+
/// the member is the error's own and the class is the error's own.
|
|
2931
|
+
///
|
|
2932
|
+
/// **THE ARRAY IS A FRESH `[]` AT EACH THROW**, so two refusals never alias one list — a shared frozen
|
|
2933
|
+
/// constant would be a value a caller could observe as the *same* array across calls, and `§2.5` item 4
|
|
2934
|
+
/// declares a VALUE (`[]`), not a shared identity.
|
|
2935
|
+
function withEmptyLog(error) {
|
|
2936
|
+
Object.defineProperty(error, 'log', {
|
|
2937
|
+
value: [],
|
|
2938
|
+
writable: true,
|
|
2939
|
+
enumerable: true,
|
|
2940
|
+
configurable: true,
|
|
2941
|
+
});
|
|
2942
|
+
return error;
|
|
2769
2943
|
}
|
|
2770
2944
|
|
|
2771
2945
|
/// **A POSITION BELOW THE DECLARED ONE — `§2.12` item 4 AND `§2.4` item 9 (f)'s RULE (ii): a SHORT ARITY
|
|
2772
2946
|
/// TAKES THE SAME ONE `TypeError` AND CHANGES NOTHING.** *"No assertion is made over `message`, and its
|
|
2773
2947
|
/// absence is the declared reading"* — the member is not one of the three this form is observed by.
|
|
2948
|
+
/// **AND IT IS THE SAME ONE `TypeError` IN THE RULING'S OWN SENSE TOO: the SHORT-ARITY refusal and the
|
|
2949
|
+
/// OUTSIDE-VALUE refusal are ONE form, so `log: []` is set by the same `withEmptyLog` and neither refusal
|
|
2950
|
+
/// gains a `status`** (`surface.md §2.5` item 4's *"the three constraint methods' `TypeError`"*).
|
|
2774
2951
|
function constraintArity(verb) {
|
|
2775
|
-
throw new TypeError(`\`${verb}\` declares two positions, and this call supplied fewer`);
|
|
2952
|
+
throw withEmptyLog(new TypeError(`\`${verb}\` declares two positions, and this call supplied fewer`));
|
|
2776
2953
|
}
|
|
2777
2954
|
|
|
2778
2955
|
/// **`§2.12` ITEM 4'S TWO CALLER POSITIONS, CLASS FIRST AND IN THEIR DECLARED ORDER** (`PAR-JS-22`–`PAR-JS-24`)
|
|
@@ -2812,7 +2989,18 @@ function constraintSite(verb, instance, supplied, pair, constraint) {
|
|
|
2812
2989
|
/// opacity is the observable** — *"it has no own enumerable member at all"* — so it is a null-prototype
|
|
2813
2990
|
/// object and NOT the entry record: every datum above stays the entry's own and never crosses.
|
|
2814
2991
|
function carryConstraint(state, instance, address, id, constraint) {
|
|
2815
|
-
|
|
2992
|
+
// **⟶ AND THE REGISTRATION IS NOW A THREE-STATE ACT, WHOSE THIRD STATE LANDS AN EDIT** (`§2.12` item 3's
|
|
2993
|
+
// 2026-10-16 clause, read through its `A135` (3) mark; `docs/specs/storeroom-native/contract.md §7.3` (b)
|
|
2994
|
+
// states 1–3 and `3-bis`). `K-1` evaluates the constraint at registration: on states 1 and 3-success it
|
|
2995
|
+
// RETURNS the handle and no log crosses; on states 2 and 3-failure it THROWS a refusal this entry renders
|
|
2996
|
+
// and re-throws in the surface's own single form (`registrationCrossing` below). **THE ENTRY'S OWN
|
|
2997
|
+
// RECORD IS WRITTEN ONLY WHERE THE REGISTRATION STOOD**, so a refused registration leaves this state
|
|
2998
|
+
// exactly as it stood (`§2.12` item 3: *"NO identity is returned and NO element is carried"*).
|
|
2999
|
+
try {
|
|
3000
|
+
constraintsKernel().register(instance, address, id, constraint);
|
|
3001
|
+
} catch (refusal) {
|
|
3002
|
+
registrationCrossing(refusal);
|
|
3003
|
+
}
|
|
2816
3004
|
const entry = {
|
|
2817
3005
|
address,
|
|
2818
3006
|
addressKey: JSON.stringify(address),
|
|
@@ -2825,6 +3013,54 @@ function carryConstraint(state, instance, address, id, constraint) {
|
|
|
2825
3013
|
return entry;
|
|
2826
3014
|
}
|
|
2827
3015
|
|
|
3016
|
+
/// **THE REGISTRATION REFUSAL'S CROSSING — THE KERNEL HANDS BACK A CODE AND ITS SLOTS, AND THIS ENTRY
|
|
3017
|
+
/// RENDERS THE TEXT THROUGH THE GENERATOR IT ALREADY HOLDS** (`docs/specs/storeroom-native/contract.md
|
|
3018
|
+
/// §8.2`'s 2026-10-16 clause, items 1–5; `surface.md §2.12` item 3's clause of the same date).
|
|
3019
|
+
///
|
|
3020
|
+
/// **NO MESSAGE IS AUTHORED HERE AND NONE IS AUTHORED IN THE KERNEL.** `DD-52` forbids a code's message
|
|
3021
|
+
/// from a second source, so the sentence is produced by the store's own generator — reached through
|
|
3022
|
+
/// `addon_.errorMessage(code, subject[, container])`, the very path `boundaryReject` already takes — from
|
|
3023
|
+
/// the `§8.2` row's own SLOTS: `<CONTAINER>` the pair's own list name `constraints`, and `<SEGMENT>` the
|
|
3024
|
+
/// added pair's `address` spelling joined by `/`. **THE FIXED PHRASE IS THE ROW'S AND IS RENDERED VERBATIM**
|
|
3025
|
+
/// (`§8.2` clause 3), and no per-instant template stands.
|
|
3026
|
+
///
|
|
3027
|
+
/// **⟶ AND THE 2026-10-17 FORGERY FIX SURVIVES INTACT, WHICH IS THIS FRAME'S HIGHEST-RISK OBLIGATION.** The
|
|
3028
|
+
/// classification is **IDENTITY, NOT SHAPE** — the kernel's own mark under the `Symbol.for` key both sides
|
|
3029
|
+
/// spell (`KERNEL_REFUSAL` above) and nothing a caller can spell — so:
|
|
3030
|
+
/// * **A KERNEL-BUILT REFUSAL** (its `status` a string, its slot members present) is rendered and
|
|
3031
|
+
/// re-thrown in the surface's single two-member-plus-`log` form below;
|
|
3032
|
+
/// * **EVERYTHING ELSE IS THE CALLER'S AND CROSSES AS ITSELF** — a forged two-member object, a forged
|
|
3033
|
+
/// three-member object, a `TypeError`, a bare string and `undefined` all reach the caller as the very
|
|
3034
|
+
/// value that was thrown, `caught === thrown`, and none of them reaches the generator.
|
|
3035
|
+
///
|
|
3036
|
+
/// **AND A BODY'S OWN THROW IS THAT SECOND ARM AND NOT A THIRD**: `fail-surface.md §1.1` item 5 leaves a
|
|
3037
|
+
/// throwing constraint or repair body *"untouched and unconverted"*, and it carries no mark, so it is
|
|
3038
|
+
/// re-thrown by the one line above the render.
|
|
3039
|
+
function registrationCrossing(refusal) {
|
|
3040
|
+
if (isKernelBuiltRefusal(refusal) === false) throw refusal;
|
|
3041
|
+
const addon_ = withAddon();
|
|
3042
|
+
// THE SLOTS THE KERNEL HANDS BACK ARE THE `§8.2` ROW'S OWN, and the generator's own three-argument call
|
|
3043
|
+
// fills `<CONTAINER>` beside `<SEGMENT>`. Where an artefact loaded but does not carry the generator, the
|
|
3044
|
+
// declared absent/failed-addon state is the answer, exactly as `boundaryReject` takes it — and where a
|
|
3045
|
+
// marked value carries no usable slots the handler below answers it, so no unsubstituted placeholder can
|
|
3046
|
+
// reach a caller from this frame.
|
|
3047
|
+
const usable = typeof addon_.errorMessage === 'function'
|
|
3048
|
+
&& typeof refusal.status === 'string'
|
|
3049
|
+
&& typeof refusal.segment === 'string';
|
|
3050
|
+
if (usable === false) throw refusal;
|
|
3051
|
+
const generated = addon_.errorMessage(refusal.status, refusal.segment, refusal.container);
|
|
3052
|
+
// **THE FORM IS THIS SURFACE'S ONE FORM** (`§2.5` items 3–4, whose `log` is PRESENT and never absent):
|
|
3053
|
+
// `{status, message, log}`, the `status` the STORE's `ConstraintListInvalid`, the `message` the STORE'S
|
|
3054
|
+
// OWN GENERATED SENTENCE, and the `log` the synthetic attempt's log where a repair was attempted and `[]`
|
|
3055
|
+
// where none was. **NO `KC` TOKEN CROSSES** (`A120` (2); `§2.12` item 3 item 2): the synthetic attempt's
|
|
3056
|
+
// terminal token stays in the kernel and reaches no caller.
|
|
3057
|
+
throw {
|
|
3058
|
+
status: refusal.status,
|
|
3059
|
+
message: generated,
|
|
3060
|
+
log: refusalLog(refusal.log),
|
|
3061
|
+
};
|
|
3062
|
+
}
|
|
3063
|
+
|
|
2828
3064
|
/// **THE DISABLED PAIR'S STANDING ELEMENT** — a function that PASSES (`kernel-surface.md §2.3` item 1:
|
|
2829
3065
|
/// `true` is the only pass value). **THE ELEMENT IS PARKED AND NEVER WITHDRAWN**: `constraintOn` re-registers
|
|
2830
3066
|
/// `entry.fn`, so *"it is the element the entry carried at that pair — never a second constraint and never a
|
|
@@ -2837,12 +3073,13 @@ function constraintParked() {
|
|
|
2837
3073
|
/// `PAR-JS-24`'s second declared answer: at EITHER toggle, in EITHER direction, an OUTSIDE VALUE taking
|
|
2838
3074
|
/// item 4's refusal, ONE THROWN `TypeError`, THE ENTRY NOT WIDENED.** It is NOT a third population route:
|
|
2839
3075
|
/// were the entry widened with the function the refused call carried, a pair would stand ENABLED WITH NO
|
|
2840
|
-
/// FUNCTION — a state no clause of that directory declares.
|
|
3076
|
+
/// FUNCTION — a state no clause of that directory declares. **AND IT IS THAT SAME ONE `TypeError`, carrying
|
|
3077
|
+
/// `log: []` on the ruling's flat reading and no `status` on rule (ii)'s** (`surface.md §2.5` item 4).
|
|
2841
3078
|
function constraintUncarried(verb, pair) {
|
|
2842
|
-
throw new TypeError(
|
|
3079
|
+
throw withEmptyLog(new TypeError(
|
|
2843
3080
|
`the pair at the ${ARGUMENT_POSITION_FIRST} of \`${verb}\` carries no constraint in this instance, and `
|
|
2844
3081
|
+ 'a toggle names a pair the entry carries',
|
|
2845
|
-
);
|
|
3082
|
+
));
|
|
2846
3083
|
}
|
|
2847
3084
|
|
|
2848
3085
|
/**
|
|
@@ -2862,7 +3099,16 @@ function addConstraint(instance, n, pair, constraint) {
|
|
|
2862
3099
|
if (held === undefined) {
|
|
2863
3100
|
return carryConstraint(site.state, instance, site.address, site.id, constraint).identity;
|
|
2864
3101
|
}
|
|
2865
|
-
|
|
3102
|
+
// **THE OVERWRITE ARM TAKES THE SAME THREE-STATE REGISTRATION** (`§2.12` item 3's clause of 2026-10-16
|
|
3103
|
+
// read at its `A135` (3) mark): a second ADD at a held pair registers the supplied function through `K-1`
|
|
3104
|
+
// exactly as the fresh arm does, so a registration the store REFUSES refuses THIS call too — and the held
|
|
3105
|
+
// element is left EXACTLY AS IT STOOD, because the entry's own record is written only after the
|
|
3106
|
+
// registration returns (`§2.12` item 3: *"NO identity is returned and NO element is carried"*).
|
|
3107
|
+
try {
|
|
3108
|
+
constraintsKernel().register(instance, site.address, site.id, constraint);
|
|
3109
|
+
} catch (refusal) {
|
|
3110
|
+
registrationCrossing(refusal);
|
|
3111
|
+
}
|
|
2866
3112
|
held.fn = constraint;
|
|
2867
3113
|
held.enabled = true;
|
|
2868
3114
|
return held.identity;
|
|
@@ -2889,7 +3135,16 @@ function constraintToggle(enabled, instance, n, pair, constraint) {
|
|
|
2889
3135
|
const entry = site.state.constraints.get(constraintPairKey(site.address, site.id));
|
|
2890
3136
|
if (entry === undefined) constraintUncarried(verb, pair);
|
|
2891
3137
|
if (entry.enabled !== enabled) {
|
|
2892
|
-
|
|
3138
|
+
// **THE ENABLE HALF RE-REGISTERS THE PAIR'S OWN FUNCTION, SO IT TAKES THE SAME THREE-STATE REGISTRATION
|
|
3139
|
+
// AS EVERY OTHER REGISTRATION SITE** (`§2.12` item 3's clause of 2026-10-16 at its `A135` (3) mark;
|
|
3140
|
+
// `docs/specs/storeroom-native/contract.md §7.3` (b)). A registration the store REFUSES refuses THIS
|
|
3141
|
+
// call in the same one form, and the pair's own `enabled` member is UNMOVED — written only after the
|
|
3142
|
+
// registration returns — so a refused toggle leaves the pair exactly as it stood.
|
|
3143
|
+
try {
|
|
3144
|
+
constraintsKernel().register(instance, site.address, site.id, enabled ? entry.fn : constraintParked);
|
|
3145
|
+
} catch (refusal) {
|
|
3146
|
+
registrationCrossing(refusal);
|
|
3147
|
+
}
|
|
2893
3148
|
entry.enabled = enabled;
|
|
2894
3149
|
}
|
|
2895
3150
|
return undefined;
|
|
@@ -2941,19 +3196,155 @@ function constraintWrite(state, instance, address, tier, value) {
|
|
|
2941
3196
|
}
|
|
2942
3197
|
|
|
2943
3198
|
/// **THE FAIL ARM'S CROSSING — `A120` (2): THE ENTRY CARRIES THE KERNEL'S TOKEN, THE THROW KEEPS THE
|
|
2944
|
-
/// STORE'S
|
|
2945
|
-
///
|
|
2946
|
-
///
|
|
2947
|
-
///
|
|
2948
|
-
///
|
|
3199
|
+
/// STORE'S — AND THE FORM CROSSES AT THREE MEMBERS FROM 2026-10-16** (`surface.md §2.5`'s clause of that
|
|
3200
|
+
/// date, items 3–4 and 10 (i)–(iii); `§2.12` item 1's mark of the same date).
|
|
3201
|
+
///
|
|
3202
|
+
/// **WHAT MOVES IS THE REACHABILITY OF `log` AND NOTHING ELSE.** The member `status` carries is still the
|
|
3203
|
+
/// store's `FileCommitFailed`, because no caller-side status can carry a `KC` token and a
|
|
3204
|
+
/// constraint-refused write is a commit that did not stand; **the kernel token does NOT enter `status`**
|
|
3205
|
+
/// (`A120` (2)'s rule survives whole). **A STORE VERB'S OWN REFUSAL CROSSES VERBATIM AND UNCONVERTED**
|
|
3206
|
+
/// (`fail-surface.md §1.2`): its `status` and its `message` are carried BYTE-FOR-BYTE, never re-mapped and
|
|
3207
|
+
/// never re-spelled, and `log` is ATTACHED BESIDE them as an own member — *"nothing is converted, and a
|
|
3208
|
+
/// member is added"* (`§2.5` item 10 (ii)).
|
|
3209
|
+
///
|
|
3210
|
+
/// **THE TWO ARMS, EACH AT ITS OWN FORM:**
|
|
3211
|
+
/// * **A `KC`-TOKEN REFUSAL — THE KERNEL'S OWN PASS PRODUCED IT.** Its `{status, message, log}` is the
|
|
3212
|
+
/// KERNEL'S OWN three-member form (`docs/specs/storeroom-constraints/fail-surface.md §1.1`, whose member
|
|
3213
|
+
/// set is the same three), and it would cross UNCHANGED were it not that `status` must carry the store's
|
|
3214
|
+
/// `FileCommitFailed` on this surface: **the `log` it carries is the attempt's, VERBATIM, and it crosses
|
|
3215
|
+
/// with the store-side `status` in its place.**
|
|
3216
|
+
/// * **A STORE VERB'S OWN REFUSAL.** Its `status` and `message` cross verbatim and `log` is attached beside
|
|
3217
|
+
/// them — the attempt's log where this write's own attempt holds one, and `[]` where it does not (a `K-2`
|
|
3218
|
+
/// the store refused opened no attempt, so there is no attempt at all — `§2.5` item 4).
|
|
3219
|
+
///
|
|
3220
|
+
/// **AND THE TIMING TRAP IS HONOURED, WHICH IS THE WHOLE OF ITEM 10 (iii): `log` IS TAKEN BEFORE THE
|
|
3221
|
+
/// ATTEMPT IS DISPOSED OF, NOT AFTER.** The kernel's terminal act has already run when this frame is
|
|
3222
|
+
/// reached (its `refuse` was thrown WITH the log in hand, `constraint-kernel.mjs`'s `refuse`), so the list
|
|
3223
|
+
/// read here is the list AS IT STOOD WHEN THE REFUSAL WAS BUILT — the failure arm's `outcome` entry
|
|
3224
|
+
/// included — and it is read OFF THE THROWN VALUE AND NEVER OFF A LATER READ: the registry entry is gone
|
|
3225
|
+
/// and a reader that reached for the attempt afterwards would reach nothing.
|
|
3226
|
+
///
|
|
3227
|
+
/// **⟶ THE FORGERY DISCRIMINATOR, RE-EXAMINED AND REPLACED 2026-10-16, BECAUSE THE RULING MADE THE OLD ONE
|
|
3228
|
+
/// UNSAFE — THIS IS THE HIGH-RISK EDIT AND IT IS NAMED WITH WHAT IT WAS AND WHAT IT IS.**
|
|
3229
|
+
///
|
|
3230
|
+
/// **WHAT IT WAS.** The previous pass fixed a broken forgery guard by discriminating on **`log`'s
|
|
3231
|
+
/// PRESENCE**: *a value carrying a `log` was the kernel's, and a value carrying none was the caller's.*
|
|
3232
|
+
/// That was sound only while the KERNEL'S OWN form was the only three-member form in the system.
|
|
3233
|
+
///
|
|
3234
|
+
/// **WHY IT NO LONGER SUFFICES.** `surface.md §2.5` item 4 now declares **`log` flat on EVERY failure this
|
|
3235
|
+
/// surface throws** — so every surface-produced failure carries one, **and so does a CALLER'S forged object
|
|
3236
|
+
/// that happens to carry a `log` member.** A caller's constraint body may throw
|
|
3237
|
+
/// `{status: 'ValueNotAdmitted', message: 'FORGED BY THE CALLER', log: []}` — a plain object it authored,
|
|
3238
|
+
/// carrying the member the old test looked for — **and under the old test that object was RE-WRAPPED into a
|
|
3239
|
+
/// fresh three-member object, so `caught === thrown` was `false` for a value the caller threw.** Measured on
|
|
3240
|
+
/// the tree before this edit: `forged {status,message,log} => caught===thrown: false`. **A caller's own
|
|
3241
|
+
/// throwable must surface AS ITSELF** (`fail-surface.md §1.1` item 5 — the body's exception *"propagates out
|
|
3242
|
+
/// of the kernel's own invocation, untouched and unconverted"*; `kernel-surface.md §2.3` item 1 — a body's
|
|
3243
|
+
/// throwable *"is NOT a kernel state and NOT a store state"*), **so the test had to stop reading a member
|
|
3244
|
+
/// the caller can forge.**
|
|
3245
|
+
///
|
|
3246
|
+
/// **WHAT REPLACED IT — IDENTITY, NOT SHAPE.** The kernel's own refusals are **built by the kernel**, and
|
|
3247
|
+
/// every one of them is thrown from `constraint-kernel.mjs`'s single `refuse` frame. The entry therefore
|
|
3248
|
+
/// **MARKS WHAT THE KERNEL BUILT**, at the one place the kernel's values enter this entry, **with a
|
|
3249
|
+
/// module-private `WeakSet`** — `kernelRefusals` above — **and this frame asks whether the handed value IS
|
|
3250
|
+
/// ONE OF THOSE VALUES, never whether it LOOKS LIKE one.** A caller cannot forge membership of a set it
|
|
3251
|
+
/// cannot reach, so:
|
|
3252
|
+
/// * a `KC`-token value the kernel built → **the kernel's arm**, and `FileCommitFailed` crossings below;
|
|
3253
|
+
/// * a store verb's own refusal (built by the addon, carrying the store's code) → the store's arm below;
|
|
3254
|
+
/// * **EVERYTHING ELSE IS THE CALLER'S AND CROSSES AS ITSELF** — a forged three-member object, a forged
|
|
3255
|
+
/// two-member object, a `TypeError`, a bare string, `undefined` — `caught === thrown` on all of them.
|
|
3256
|
+
///
|
|
3257
|
+
/// **THE MARK IS SET WHERE THE KERNEL'S FAILURE IS FIRST SEEN** — at the two `catch` frames in
|
|
3258
|
+
/// `constraintWrite` above, which are the only places a kernel-thrown value reaches this entry — and **NOT
|
|
3259
|
+
/// by a test over members, which is the whole defect being repaired.** **IT IS A `WeakSet` AND NOT A MEMBER
|
|
3260
|
+
/// ON THE VALUE**: no member is added to the kernel's own form (`fail-surface.md §1.1`'s member set stays the
|
|
3261
|
+
/// three), nothing is mutated, nothing is frozen, and the mark is invisible to every census — while a value
|
|
3262
|
+
/// that is not an object (a string, `undefined`) is simply never in the set and needs no special case, since
|
|
3263
|
+
/// `WeakSet.has` on a primitive is `false` rather than a throw.
|
|
3264
|
+
/// **THE KERNEL'S OWN REFUSAL-CLASS QUESTION, AND WHY THE ENTRY ASKS THE KERNEL IT RATHER THAN READING A
|
|
3265
|
+
/// MEMBER** — the discriminator that replaced `log`'s presence, and the reason a `WeakSet` local to this
|
|
3266
|
+
/// entry will not do.
|
|
3267
|
+
///
|
|
3268
|
+
/// **THE MARK CANNOT LIVE HERE, AND THAT WAS MEASURED RATHER THAN REASONED:** a `WeakSet` populated from the
|
|
3269
|
+
/// two `catch` frames in `constraintWrite` marks **EVERY** value leaving the kernel's frames — **a caller's
|
|
3270
|
+
/// constraint BODY throws from inside `runAttempt` too**, so the body's own throwable passes the same frame
|
|
3271
|
+
/// and is marked alongside the kernel's. On the tree with the `WeakSet` in place, all three of
|
|
3272
|
+
/// `forged {status,message}`, `forged {status,message,log}` and `TypeError` answered `caught === thrown:
|
|
3273
|
+
/// false`: **the mark was set by the frame and not by the author of the value.** A mark is only worth
|
|
3274
|
+
/// anything if the thing that SETS it is the thing that BUILT the value, and for a kernel refusal that thing
|
|
3275
|
+
/// is `constraint-kernel.mjs`'s own `refuse`.
|
|
3276
|
+
///
|
|
3277
|
+
/// **SO THE KERNEL DECLARES IT, AT ITS ONE THROW SITE, UNDER A `Symbol.for` KEY BOTH SIDES SPELL** — exactly
|
|
3278
|
+
/// the pattern `SETTLED_ON_THE_PASSING_ARM` and `SAVE_FAILED_AT_THE_TERMINAL_ARM` already use across this
|
|
3279
|
+
/// same boundary (`constraint-kernel.mjs`'s `KERNEL_REFUSAL`): the entry imports no kernel at load and the
|
|
3280
|
+
/// kernel imports no entry, and **a symbol key is invisible to `Object.keys`**, so the thrown form's readable
|
|
3281
|
+
/// member set stays the three `§2.5` items 3–4 declare (`§2.5` item 9's census reads `["log","message",
|
|
3282
|
+
/// "status"]` and no fourth). **A CALLER'S BODY CANNOT SET IT**: the mark is written in a frame no caller
|
|
3283
|
+
/// reaches, and it is not a member a caller would think to spell.
|
|
3284
|
+
///
|
|
3285
|
+
/// **AND A KERNEL THAT DID NOT CARRY THE DECLARATION ANSWERS `false`** — every value is then the caller's and
|
|
3286
|
+
/// surfaces as itself, which is the safe direction: a refusal crossed unconverted is the declared form once
|
|
3287
|
+
/// the surface stops re-wrapping it, while a caller's value crossed converted is the FINDING this whole
|
|
3288
|
+
/// discriminator exists to prevent.
|
|
3289
|
+
|
|
3290
|
+
/// **THE SAME `Symbol.for` KEY THE KERNEL WRITES, SPELLED HERE SO THE ENTRY IMPORTS NO KERNEL AND THE KERNEL
|
|
3291
|
+
/// IMPORTS NO ENTRY** — the pattern `SETTLED_ON_THE_PASSING_ARM` and `SAVE_FAILED_AT_THE_TERMINAL_ARM`
|
|
3292
|
+
/// already cross this boundary by (`constraint-kernel.mjs`'s `KERNEL_REFUSAL`).
|
|
3293
|
+
///
|
|
3294
|
+
/// **IT IS A SYMBOL AND NOT A KERNEL FUNCTION, AND THE REASON IS A SPEC COUNT: `kernel-surface.md §1` item 2
|
|
3295
|
+
/// declares that module's export set as EXACTLY the five `K-1`–`K-5` items — *"no sixth name"* — so a
|
|
3296
|
+
/// predicate exported from the kernel to serve this entry would be a FINDING.** The fact travels on the
|
|
3297
|
+
/// VALUE, under a key both sides spell, and the kernel's namespace is untouched.
|
|
3298
|
+
///
|
|
3299
|
+
/// **THE QUESTION IS ANSWERED WITHOUT REACHING THE KERNEL AT ALL**, which is the shape `WeakSet.has` gave
|
|
3300
|
+
/// for free and is what lets this entry keep loading where nothing is staged beside it: no `require` of
|
|
3301
|
+
/// `./src/` is triggered by a failure's own classification.
|
|
3302
|
+
const KERNEL_REFUSAL = Symbol.for('provident-storeroom.kernel-refusal');
|
|
3303
|
+
|
|
3304
|
+
/// **WHETHER THE HANDED VALUE IS A REFUSAL THE KERNEL ITSELF BUILT** — the discriminator that replaced
|
|
3305
|
+
/// `log`'s presence, answered by the mark the kernel's one `refuse` frame sets and by nothing a caller can
|
|
3306
|
+
/// spell. **A NON-OBJECT IS `false`** without a member read, and **a value the kernel never built is
|
|
3307
|
+
/// `false`** whatever members it carries.
|
|
3308
|
+
function isKernelBuiltRefusal(value) {
|
|
3309
|
+
return value !== null && typeof value === 'object' && value[KERNEL_REFUSAL] === true;
|
|
3310
|
+
}
|
|
3311
|
+
|
|
2949
3312
|
function constraintCrossing(refusal) {
|
|
2950
|
-
const
|
|
2951
|
-
|
|
3313
|
+
const isObject = refusal !== null && typeof refusal === 'object';
|
|
3314
|
+
const status = isObject ? refusal.status : undefined;
|
|
3315
|
+
// **THE CALLER'S OWN VALUE CROSSES AS ITSELF, FIRST AND UNCONDITIONALLY.** The test is IDENTITY against
|
|
3316
|
+
// the kernel's marked set (above) and NOT any member's presence: a caller's forged `log`, a forged
|
|
3317
|
+
// `status` spelling and a forged two-member object are all its own, and `caught === thrown` holds for
|
|
3318
|
+
// each (`fail-surface.md §1.1` item 5). A value that is not an object at all is never the kernel's either.
|
|
3319
|
+
if (!isObject || isKernelBuiltRefusal(refusal) === false) throw refusal;
|
|
3320
|
+
// THE LOG IS THE THROWN VALUE'S OWN `log` MEMBER — the same list either arm carries — and `[]` where the
|
|
3321
|
+
// value carries none (`§2.5` item 4: never absent, never `null`, never a non-array; a non-array here is a
|
|
3322
|
+
// finding at the site that produced it and is answered with the empty array rather than a shape).
|
|
3323
|
+
// **AND IT IS TAKEN HERE, BEFORE THE ATTEMPT IS DISPOSED OF** — item 10 (iii)'s timing trap: the list is
|
|
3324
|
+
// READ OFF THE THROWN VALUE, which the kernel built with the log in hand, and never off a later read.
|
|
3325
|
+
const log = Array.isArray(refusal.log) ? refusal.log : [];
|
|
3326
|
+
// **A MARKED VALUE WHOSE `status` IS NOT A `KC` TOKEN IS THE STORE VERB'S OWN REFUSAL CROSSING BACK
|
|
3327
|
+
// THROUGH THE KERNEL'S OWN LEG** (`constraint-kernel.mjs`'s `attempt.throwState` carries the store's code
|
|
3328
|
+
// at the repair arm): its `status` and `message` cross VERBATIM and `log` is attached BESIDE them —
|
|
3329
|
+
// *"nothing is converted, and a member is added"* (`§2.5` item 10 (ii)).
|
|
3330
|
+
if (typeof status !== 'string' || KC_TOKENS.includes(status) === false) {
|
|
3331
|
+
throw {
|
|
3332
|
+
status: refusal.status,
|
|
3333
|
+
message: refusal.message,
|
|
3334
|
+
log: refusalLog(log),
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
// **THE KERNEL'S OWN `KC` REFUSAL.** Its `{status, message, log}` is the KERNEL'S OWN three-member form
|
|
3338
|
+
// (`docs/specs/storeroom-constraints/fail-surface.md §1.1`), and it crosses with the STORE's
|
|
3339
|
+
// `FileCommitFailed` in `status` because no caller-side status can carry a `KC` token and a
|
|
3340
|
+
// constraint-refused write is a commit that did not stand: **the kernel token does NOT enter `status`, and
|
|
3341
|
+
// the `log` it carries is the attempt's, VERBATIM.**
|
|
2952
3342
|
throw {
|
|
2953
3343
|
status: 'FileCommitFailed',
|
|
2954
3344
|
message: typeof refusal.message === 'string'
|
|
2955
3345
|
? refusal.message
|
|
2956
3346
|
: 'the write was refused by a constraint of this attempt',
|
|
3347
|
+
log: refusalLog(log),
|
|
2957
3348
|
};
|
|
2958
3349
|
}
|
|
2959
3350
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "provident-storeroom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"src/constraint-kernel.mjs"
|
|
39
39
|
],
|
|
40
40
|
"optionalDependencies": {
|
|
41
|
-
"@auspicion/provident-storeroom-js-linux-x64-gnu": "0.
|
|
42
|
-
"@auspicion/provident-storeroom-js-linux-arm64-gnu": "0.
|
|
43
|
-
"@auspicion/provident-storeroom-js-darwin-x64": "0.
|
|
44
|
-
"@auspicion/provident-storeroom-js-darwin-arm64": "0.
|
|
45
|
-
"@auspicion/provident-storeroom-js-win32-x64-msvc": "0.
|
|
41
|
+
"@auspicion/provident-storeroom-js-linux-x64-gnu": "0.4.0",
|
|
42
|
+
"@auspicion/provident-storeroom-js-linux-arm64-gnu": "0.4.0",
|
|
43
|
+
"@auspicion/provident-storeroom-js-darwin-x64": "0.4.0",
|
|
44
|
+
"@auspicion/provident-storeroom-js-darwin-arm64": "0.4.0",
|
|
45
|
+
"@auspicion/provident-storeroom-js-win32-x64-msvc": "0.4.0"
|
|
46
46
|
},
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
@@ -131,8 +131,27 @@ const SETTLED_ON_THE_PASSING_ARM = Symbol.for('provident-storeroom.settled-on-th
|
|
|
131
131
|
const SAVE_FAILED_AT_THE_TERMINAL_ARM = Symbol.for('provident-storeroom.save-failed-at-the-terminal-arm');
|
|
132
132
|
|
|
133
133
|
/** `fail-surface.md §1.1` — ONE THROWN PLAIN OBJECT, EXACTLY THREE MEMBERS, NEVER AN `Error`. */
|
|
134
|
+
const KERNEL_REFUSAL = Symbol.for('provident-storeroom.kernel-refusal');
|
|
134
135
|
function refuse(status, message, log) {
|
|
135
|
-
throw {
|
|
136
|
+
throw {
|
|
137
|
+
status,
|
|
138
|
+
message,
|
|
139
|
+
log: log === undefined ? [] : log,
|
|
140
|
+
[KERNEL_REFUSAL]: true,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// **WHETHER A VALUE IS A REFUSAL THIS KERNEL BUILT** — the entry's crossing and this kernel's own repair
|
|
145
|
+
/// arm both ask this and nothing else.
|
|
146
|
+
///
|
|
147
|
+
/// **IT IS NOT AN EXPORT, AND THE REASON IS THE SPEC'S OWN CLOSED COUNT:** `kernel-surface.md §1` item 2
|
|
148
|
+
/// declares the module's export set as **EXACTLY the five `K-1`–`K-5` items** — *"the kernel exports no
|
|
149
|
+
/// route, no addon handle and no sixth name"* — so a predicate exported from here would be a SIXTH NAME and
|
|
150
|
+
/// a FINDING. **The mark is therefore read through the `Symbol.for` key itself, which both sides spell**
|
|
151
|
+
/// (`KERNEL_REFUSAL` above), and the fact travels on the VALUE rather than in the module's namespace —
|
|
152
|
+
/// exactly as `SETTLED_ON_THE_PASSING_ARM` and `SAVE_FAILED_AT_THE_TERMINAL_ARM` already travel.
|
|
153
|
+
function isKernelRefusal(value) {
|
|
154
|
+
return value !== null && typeof value === 'object' && value[KERNEL_REFUSAL] === true;
|
|
136
155
|
}
|
|
137
156
|
|
|
138
157
|
// ---------------------------------------------------------------------------------------------
|
|
@@ -380,9 +399,364 @@ export function register(store, address, id, constraint) {
|
|
|
380
399
|
} else {
|
|
381
400
|
standing.constraint = constraint;
|
|
382
401
|
}
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
405
|
+
// THE THIRD STEP — THE REGISTRATION-TIME EVALUATION (`docs/specs/storeroom-native/contract.md §7.3`
|
|
406
|
+
// (b) states 1–3 and its `3-bis` clause of 2026-10-16; `kernel-surface.md §2.1` item 1's third step).
|
|
407
|
+
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
408
|
+
//
|
|
409
|
+
// **WHAT THIS STEP OWES, IN THE RULING'S OWN TERMS: after channels (i) and (ii) are passed and the pair
|
|
410
|
+
// stands in the registry, the kernel EVALUATES THAT ONE CONSTRAINT AGAINST THE STORE'S CURRENT STATE,
|
|
411
|
+
// ONCE, BEFORE THE HANDLE IS RETURNED.** The scope is THAT ONE PAIR and no other: no pass is opened over
|
|
412
|
+
// the registry and no other registered pair is re-evaluated.
|
|
413
|
+
//
|
|
414
|
+
// **⟶ THE THREE STATES, EACH ANSWERED HERE AND AT NO OTHER SITE:**
|
|
415
|
+
// (i) the state PASSES → the call returns the handle exactly as before, and nothing else happened;
|
|
416
|
+
// (ii) it VIOLATES and NO repair is registered → the registration is REFUSED;
|
|
417
|
+
// (iii) it VIOLATES and a repair IS registered → THE REPAIR IS ATTEMPTED on the synthetic attempt
|
|
418
|
+
// `3-bis` (a) declares, and its outcome answers the call as (i) or as (ii).
|
|
419
|
+
//
|
|
420
|
+
// **AND WHAT THE KERNEL HANDS THE SURFACE IS A CODE AND ITS SLOTS, NEVER A SENTENCE.** This module owns
|
|
421
|
+
// no message generator, and `kernel-surface.md §1` item 2 closes its surface at the FIVE `K-1`…`K-5`
|
|
422
|
+
// items with no sixth name — so it imports none, is handed none, and declares no channel to one. The
|
|
423
|
+
// refusal it throws carries `status` (the STORE's member, `A120` (2)) and the `§8.2` row's own slot
|
|
424
|
+
// VALUES, and the surface renders the text through the generator it already holds. **NO `KC` TOKEN IS
|
|
425
|
+
// MINTED:** the synthetic attempt's own terminal token stays inside this module (`registrationRefusal`).
|
|
426
|
+
const refused = registrationEvaluation(kernel, store, address, id, constraint);
|
|
427
|
+
if (refused !== null) {
|
|
428
|
+
// **A REFUSED REGISTRATION LEAVES THE REGISTRY EXACTLY AS IT STOOD** (`§2.1` item 1's sentence, whose
|
|
429
|
+
// regulatory force reaches this third refusing act — `§7.3` (b) state 2's own reading of it): the pair
|
|
430
|
+
// row this call wrote is withdrawn, with its handle and its place in the address's order list.
|
|
431
|
+
withdrawRegistration(kernel, address, id, standing === undefined, home);
|
|
432
|
+
throw refused;
|
|
433
|
+
}
|
|
434
|
+
return home;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* **WITHDRAWING THE REGISTRY ROW A REFUSED REGISTRATION WROTE** — `kernel-surface.md §2.1` item 1: *"a
|
|
439
|
+
* refused registration leaves the registry exactly as it stood"*, read at `docs/specs/storeroom-native/
|
|
440
|
+
* contract.md §7.3` (b) state 2 by that item's own clause (*"the sentence's `2` counts `KC` CHANNELS and
|
|
441
|
+
* the registration-time refusal is a THIRD REFUSING ACT carrying no `KC` token, so the sentence's FIGURE IS
|
|
442
|
+
* UNMOVED while its regulatory force (no entry on a refusal) reaches this third act"*).
|
|
443
|
+
*
|
|
444
|
+
* **WHAT IT UNDOES IS THIS CALL'S OWN WRITE AND NOTHING ELSE**, which is why the prior-standing fact is
|
|
445
|
+
* passed in: on the FRESH arm the pair row, its handle and its address-list entry all go; on the
|
|
446
|
+
* REPLACEMENT arm (a second `register` under a pair that already stood) the row's own POSITION and handle
|
|
447
|
+
* are left exactly as they were — the pair's idempotence rule (`CC-7`) puts the replaced registration's
|
|
448
|
+
* position back by never moving it.
|
|
449
|
+
*/
|
|
450
|
+
function withdrawRegistration(kernel, address, id, fresh, home) {
|
|
451
|
+
if (!fresh) return;
|
|
452
|
+
const key = pairKey(address, id);
|
|
453
|
+
kernel.pairs.delete(key);
|
|
454
|
+
kernel.handles.delete(key);
|
|
455
|
+
const token = addressToken(address);
|
|
456
|
+
const list = kernel.byAddress.get(token);
|
|
457
|
+
if (list !== undefined) {
|
|
458
|
+
const at = list.indexOf(key);
|
|
459
|
+
if (at >= 0) list.splice(at, 1);
|
|
460
|
+
if (list.length === 0) kernel.byAddress.delete(token);
|
|
461
|
+
}
|
|
462
|
+
// THE ADDRESS'S HOME ENTRY STANDS: it was minted by the store's own `listen`, which this act has already
|
|
463
|
+
// performed, and no clause of this unit declares a kernel-side withdrawal of it (`§2.1` item 1: *"nothing
|
|
464
|
+
// withdraws a constraint's store registration"* — `unlisten` is the app's own verb and never this one's).
|
|
383
465
|
return home;
|
|
384
466
|
}
|
|
385
467
|
|
|
468
|
+
/**
|
|
469
|
+
* **THE REGISTRATION-TIME EVALUATION, AT ITS ONE SITE** (`docs/specs/storeroom-native/contract.md §7.3`
|
|
470
|
+
* (b) and its `3-bis` clause of 2026-10-16; `kernel-surface.md §2.1` item 1's third step and `§2.3` item
|
|
471
|
+
* 1's clause of 2026-10-17). It answers `null` on state 1 and on state 3's passing arm, and **the refusal
|
|
472
|
+
* to throw** on state 2 and on state 3's failing one.
|
|
473
|
+
*
|
|
474
|
+
* **THE EVALUATION'S CONTEXT IS `§2.3` ITEM 1'S CLAUSE OF 2026-10-17, MEMBER FOR MEMBER, AND IT IS THE
|
|
475
|
+
* SAME FIVE MEMBERS AS AT A LANDING** — `address` the pair's own; `tier` ABSENT, spelled `null`; `value`
|
|
476
|
+
* THE STORE'S CURRENT VALUE AT THE PAIR'S ADDRESS, READ AND NOT LANDED; `attempt` the synthetic attempt's
|
|
477
|
+
* `AttemptRef` on state 3 and `null` on states 1/2; `op` ABSENT, spelled `null`. **A SIXTH MEMBER IS
|
|
478
|
+
* REFUSED BY NAME** (`5 + 1 = 6` is refused at that item's (6)), and both `null`s are THAT CLAUSE's own
|
|
479
|
+
* spellings of an absence inside a closed record, taken from the `RollbackStep.checkpoint` precedent, and
|
|
480
|
+
* are not tokens minted here.
|
|
481
|
+
*
|
|
482
|
+
* **THE `value` IS OBTAINED BY THE STORE'S OWN `read` AT THE PAIR'S ADDRESS WITH THE TIER ARGUMENT
|
|
483
|
+
* OMITTED** — the zero-tier call — **and where that read REFUSES `AddressNotFound` the member carries
|
|
484
|
+
* `undefined`**, which is that clause's (3) (e) arm. **NO `null` IS MINTED FOR IT** (`DD-12` forbids a
|
|
485
|
+
* READ answering one) and no `AddressNotFound` code is put in a `Value` slot: the fresh-pair outcome is
|
|
486
|
+
* the CALLER'S OWN BODY's answer to absence, and no clause decides which a given body is.
|
|
487
|
+
*
|
|
488
|
+
* **⟶ AND THE BODY'S OWN THROW IS NOT CONVERTED HERE.** A throw out of the constraint body at this instant
|
|
489
|
+
* SURFACES AS ITSELF (`fail-surface.md §1.1` item 5, at `kernel-surface.md §2.3` item 1's clause of
|
|
490
|
+
* 2026-10-17): not re-shaped into this module's form, not wrapped, and carrying no `KC` token. So the
|
|
491
|
+
* invocation below is NOT wrapped — a throwing body reaches the caller as the very value it threw.
|
|
492
|
+
*/
|
|
493
|
+
function registrationEvaluation(kernel, store, address, id, constraint) {
|
|
494
|
+
const outcome = constraint(registrationContext(store, address, null));
|
|
495
|
+
// THE OUTCOME IS `PAR-C-5`'S CLOSED THREE-ARM SET, read as the landing pass reads it: `true` is the pass
|
|
496
|
+
// arm; an object carrying `message` is the violation arm (its `repair`, where present, the repair the
|
|
497
|
+
// caller registered); a value outside the three arms is READ AS the `{message}` arm (`VA-11`) and never as
|
|
498
|
+
// an arm of its own. **A REPAIR THE OUTCOME DOES NOT CARRY IS NO REPAIR REGISTERED FOR THE PAIR.**
|
|
499
|
+
if (outcome === true) return null;
|
|
500
|
+
const repair = outcome !== null && typeof outcome === 'object' && 'message' in outcome
|
|
501
|
+
&& 'repair' in outcome && typeof outcome.repair === 'function'
|
|
502
|
+
? outcome.repair
|
|
503
|
+
: null;
|
|
504
|
+
// STATE 2 — THE STATE VIOLATES IT AND NO REPAIR IS REGISTERED. Nothing is attempted and no attempt is
|
|
505
|
+
// opened; the refusal carries the store's code and the row's own slots.
|
|
506
|
+
if (repair === null) return registrationRefusal(address, id, []);
|
|
507
|
+
// STATE 3 — THE REPAIR IS ATTEMPTED, on the synthetic attempt `3-bis` (a) declares.
|
|
508
|
+
return registrationAttempt(kernel, store, { address, id, repair });
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/// **THE FIVE-MEMBER EVALUATION CONTEXT** (`kernel-surface.md §2.3` item 1's clause of 2026-10-17), built
|
|
512
|
+
/// at ONE site so states 1, 2 and 3 hand the caller's body the SAME record and only `attempt` moves:
|
|
513
|
+
/// `null` on states 1 and 2, the synthetic attempt's `AttemptRef` on state 3.
|
|
514
|
+
function registrationContext(store, address, attemptRef) {
|
|
515
|
+
return {
|
|
516
|
+
address: address.slice(),
|
|
517
|
+
// `tier` — ABSENT, and `op` — ABSENT: the two members carrying the landing's own absence, spelled
|
|
518
|
+
// `null` on that clause's (2) and (5).
|
|
519
|
+
tier: null,
|
|
520
|
+
// `value` — READ, not landed, and `undefined` at an address holding nothing (that clause's (3) (e)).
|
|
521
|
+
value: readCurrent(store, address),
|
|
522
|
+
attempt: attemptRef,
|
|
523
|
+
op: null,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/// The store's current value at an address, read NOT landed: the zero-tier call whose tier argument is
|
|
528
|
+
/// OMITTED, and `undefined` where that read refuses.
|
|
529
|
+
function readCurrent(store, address) {
|
|
530
|
+
try {
|
|
531
|
+
return store.read(address);
|
|
532
|
+
} catch (refused) {
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* **THE SIX-MEMBER `RepairContext` THE REPAIR IS HANDED AT REGISTRATION** (`kernel-surface.md §2.3` item
|
|
539
|
+
* 2's shape, its sixth member `pending: Handle[]` added 2026-10-15; `surface.md §2.11` clause 6, the one
|
|
540
|
+
* home of the architect's ruling that a repair *"IS PASSED THE COMMIT IT IS PART OF"*).
|
|
541
|
+
*
|
|
542
|
+
* **THE REPAIR'S CONTEXT IS NOT THE CONSTRAINT'S CONTEXT, AND THE TWO ARE NOT INTERCHANGEABLE**: the
|
|
543
|
+
* constraint receives the FIVE-member `AttemptContext` and the repair the SIX-member `RepairContext`, whose
|
|
544
|
+
* extra member is the commit's own `pending` — *"so that they can make their own write call use that
|
|
545
|
+
* commit"*. **THE SYNTHETIC ATTEMPT'S OWN `commit` MEMBER IS WHAT THIS SLOT CARRIES** (`3-bis` (a): *"the
|
|
546
|
+
* `CommitRecord` of the registration act"*), handed as a FRESH LIST the way the landing instant hands it, so
|
|
547
|
+
* the record's member is never aliased and a repair that mutated its context's list moves nothing on the
|
|
548
|
+
* commit.
|
|
549
|
+
*
|
|
550
|
+
* **AND THE ABSENCE AT THIS INSTANT IS SPELLED BY THE `AttemptContext`'S OWN CLAUSE, NOT MINTED HERE:** there
|
|
551
|
+
* is no landing, so `op` is `null` (that clause's (5)) and `tier` is `null` (its (2)) — the two absences the
|
|
552
|
+
* `RollbackStep.checkpoint` precedent already fixes — while `value` is the store's CURRENT value at the
|
|
553
|
+
* pair's address, read and not landed (its (3)). **`id` IS THE PAIR'S OWN**, which the constraint's context
|
|
554
|
+
* does not carry at all, the repair's shape declaring it.
|
|
555
|
+
*/
|
|
556
|
+
function registrationRepairContext(store, address, id, commitRecord) {
|
|
557
|
+
return {
|
|
558
|
+
address: address.slice(),
|
|
559
|
+
id,
|
|
560
|
+
// `tier` — ABSENT, spelled `null`; `value` — READ, not landed; `op` — ABSENT, spelled `null`.
|
|
561
|
+
tier: null,
|
|
562
|
+
value: readCurrent(store, address),
|
|
563
|
+
op: null,
|
|
564
|
+
// THE COMMIT THE REPAIR IS PART OF — a FRESH LIST, never the record's own member (`§2.3` item 2).
|
|
565
|
+
pending: Array.isArray(commitRecord.pending) ? commitRecord.pending.slice() : [],
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* **STATE 3 — THE SYNTHETIC ATTEMPT AND THE REPAIR IT CARRIES** (`docs/specs/storeroom-native/contract.md
|
|
571
|
+
* §7.3` (b) `3-bis` (a)–(f); `attempt-lifecycle.md §2.4` items 1, 3, 4 arm (b)).
|
|
572
|
+
*
|
|
573
|
+
* **THE ATTEMPT'S RECORD IS ITEM 1's NINE MEMBERS UNCHANGED — NO TENTH MEMBER IS MINTED AND NO MEMBER'S
|
|
574
|
+
* DOMAIN MOVES:** `ref`, `commit`, `ops`, `log`, `ran`, `appliedRepairs`, `open`, `rollback`, `checkpoint`.
|
|
575
|
+
* **ITS `address` IS THE PAIR'S OWN**, **`ITS `checkpoint` BEGINS `null`*** — that member's declared `null`
|
|
576
|
+
* arm, because no landing at that address has yet left it valid for THIS attempt — and **its `ref` is a
|
|
577
|
+
* kernel-minted `AttemptRef` unique within the instance**. **Its `log` is a real `LogEntry[]` carrying this
|
|
578
|
+
* kernel's own `seq` ordinal**, and the `constraint-check` and `repair-run` entries arm (b) appends stand in
|
|
579
|
+
* it. **IT IS TERMINAL-AWARE ON BOTH ARMS**: it reaches `PASSED` or `FAILING` and closes, and no
|
|
580
|
+
* registration leaves an open attempt in the registry.
|
|
581
|
+
*
|
|
582
|
+
* **THE OP THE REPAIR LANDS IS HELD BY THIS ATTEMPT AND NOTHING ELSE** — `3-bis` (a)'s selection of the
|
|
583
|
+
* synthetic branch, so principle (1) (*"a repair's op is an attempt's op"*) still binds and no op is
|
|
584
|
+
* admitted outside one.
|
|
585
|
+
*
|
|
586
|
+
* **AND ITS OP LANDS DURABLY** (`3-bis` (f)): the repair's edit goes through the store's OWN verbs, its
|
|
587
|
+
* `op` is a real `JournalOp` in the store's own journal, readable back through every read verb at that
|
|
588
|
+
* address, and it stands after the registration returns. **THIS IS NOT A DRY RUN**, and no clause of that
|
|
589
|
+
* contract may be read as one. **ON SUCCESS NO LOG CROSSES** (`3-bis` (c), under `A135` (1)'s
|
|
590
|
+
* failure-only bubbling): the caller receives the identity ALONE, and the repair's outcome is carried by
|
|
591
|
+
* this attempt's own `log` and `ops` — the two carriers that clause fixes.
|
|
592
|
+
*
|
|
593
|
+
* **ON FAILURE THE REGISTRATION IS REFUSED** (`3-bis` (d)'s arms (d)/(e)/(f)): the store's
|
|
594
|
+
* `ConstraintListInvalid` is answered in the SAME form and with the SAME THREE SLOTS as state 2's. The
|
|
595
|
+
* synthetic attempt's `KC-4`/`KC-5`/`KC-6` **stays inside this module** and reaches no caller, because the
|
|
596
|
+
* caller's act is the registration and it is the registration that is refused (`§7.3` (e)'s re-reading).
|
|
597
|
+
*/
|
|
598
|
+
function registrationAttempt(kernel, store, pair) {
|
|
599
|
+
const address = pair.address;
|
|
600
|
+
const key = pairKey(address, pair.id);
|
|
601
|
+
ATTEMPTS += 1;
|
|
602
|
+
const attempt = {
|
|
603
|
+
ref: { id: `attempt-${ATTEMPTS}` },
|
|
604
|
+
store,
|
|
605
|
+
address: address.slice(),
|
|
606
|
+
tier: null,
|
|
607
|
+
value: undefined,
|
|
608
|
+
// `commit` — THE REGISTRATION ACT'S OWN `CommitRecord` (`3-bis` (a)): this kernel's four members, with
|
|
609
|
+
// no write's op and no write's triggered set, because a registration lands no `K-2` of its own.
|
|
610
|
+
commit: { attempt: null, op: null, triggered: [], pending: [] },
|
|
611
|
+
write: null,
|
|
612
|
+
ops: [],
|
|
613
|
+
log: [],
|
|
614
|
+
ran: [],
|
|
615
|
+
appliedRepairs: [],
|
|
616
|
+
rollback: [],
|
|
617
|
+
checkpoint: null,
|
|
618
|
+
checkedOff: [],
|
|
619
|
+
status: 'open',
|
|
620
|
+
report: null,
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
// ARM (b) VERBATIM: the `constraint-check` entry and the `repair-run` entry are appended, the repair runs
|
|
624
|
+
// through the caller's own verb, and the op its `{ok: true, op}` return names is added to `ops` while its
|
|
625
|
+
// pair is appended to BOTH `ran` and `appliedRepairs` (`3-bis` (b): the pair JOINS both members — of the
|
|
626
|
+
// SYNTHETIC attempt, and of no other). **THE PAIR ENTERS `ran` BEFORE THE REPAIR RUNS**, which is that
|
|
627
|
+
// arm's own ordering and is what makes the repeat arms reachable at the re-run below.
|
|
628
|
+
append(attempt, 'constraint-check', pair.id, null, `the evaluation of ${pair.id}`);
|
|
629
|
+
attempt.ran.push(key);
|
|
630
|
+
append(attempt, 'repair-run', pair.id, null, 'the pair\'s repair was attempted at registration');
|
|
631
|
+
|
|
632
|
+
let result;
|
|
633
|
+
try {
|
|
634
|
+
result = pair.repair(registrationRepairContext(store, address, pair.id, attempt.commit));
|
|
635
|
+
} catch (body) {
|
|
636
|
+
// A REPAIR WHOSE BODY THROWS IS A FAILED REPAIR AND THE REGISTRATION IS REFUSED — the caller's act is
|
|
637
|
+
// the registration, so the refusal is this module's one form (`3-bis` (d); the `KC` boundary at (e)).
|
|
638
|
+
// **THE BODY'S THROWABLE IS NOT CONVERTED INTO A STORE FORM AND IS NOT REACHED BY THE CALLER HERE**: it
|
|
639
|
+
// is caught so the attempt can close and the registration can be refused in the declared form; a drive
|
|
640
|
+
// that expected the body's own value out of `addConstraint` has read a route no clause declares.
|
|
641
|
+
closeRegistrationAttempt(attempt);
|
|
642
|
+
return registrationRefusal(address, pair.id, attempt.log);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const ok = result !== null && typeof result === 'object' && result.ok === true;
|
|
646
|
+
const produced = ok ? landedOp(attempt, result, null) : null;
|
|
647
|
+
if (produced === null) {
|
|
648
|
+
// ARM (d) — THE REPAIR PRODUCED NO OP: `{ok: false, message}`, an outside-form return, or an
|
|
649
|
+
// `ok === true` return whose `op` is absent, `undefined` or not the one it landed.
|
|
650
|
+
closeRegistrationAttempt(attempt);
|
|
651
|
+
return registrationRefusal(address, pair.id, attempt.log);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
attempt.ops.push(produced);
|
|
655
|
+
attempt.appliedRepairs.push(key);
|
|
656
|
+
const entry = attempt.log[attempt.log.length - 1];
|
|
657
|
+
entry.opId = produced.opId;
|
|
658
|
+
entry.message = `the repair ${pair.id} landed ${produced.opId}`;
|
|
659
|
+
|
|
660
|
+
// THE RE-RUN — `3-bis` (d)'s arms (e)/(f) and `3-bis` (e)'s ordinary landing rules: the repair's op
|
|
661
|
+
// LANDED, so the pairs registered at ITS OWN landing's address are evaluated by the ordinary pass
|
|
662
|
+
// (`kernel-surface.md §2.3` item 1), in first-registration order, against THAT op.
|
|
663
|
+
const failed = registrationRerun(kernel, attempt, produced);
|
|
664
|
+
if (failed !== null) {
|
|
665
|
+
closeRegistrationAttempt(attempt);
|
|
666
|
+
return registrationRefusal(address, pair.id, attempt.log);
|
|
667
|
+
}
|
|
668
|
+
// THE PASSING ARM: `PASSED` → `CLOSED` and the registration STANDS. **NO LOG CROSSES**, and the repair's
|
|
669
|
+
// edit STANDS in the store — the side effect the architect's trust clause licenses (`3-bis` (f)).
|
|
670
|
+
closeRegistrationAttempt(attempt, 'passed');
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/// **THE SYNTHETIC ATTEMPT'S RE-RUN** — every pair standing at the attempt's own address, evaluated once
|
|
675
|
+
/// against the repair's own op (`attempt-lifecycle.md §2.4` item 5 (iv)'s evaluated set, which the
|
|
676
|
+
/// registration instant neither widens nor displaces). Answers `null` where the re-run passes and the arm's
|
|
677
|
+
/// token where it does not.
|
|
678
|
+
///
|
|
679
|
+
/// **THE ARM IS READ OFF THE PAIR THAT FAILED AND OFF NOTHING ELSE** (item 4's disjointness rule): the
|
|
680
|
+
/// pair under repair is IN `ran` — arm (b) wrote it — and arm (b) has just put it in `appliedRepairs`, so a
|
|
681
|
+
/// repeat by the repair's OWN edit reaches `(e)`; a pair IN `ran` and NOT in `appliedRepairs` reaches
|
|
682
|
+
/// `(f)`. **`(c)` is unreachable here**, the pair's own function having already run at this instant.
|
|
683
|
+
function registrationRerun(kernel, attempt, produced) {
|
|
684
|
+
const list = kernel.byAddress.get(addressToken(attempt.address));
|
|
685
|
+
if (list === undefined) return null;
|
|
686
|
+
for (const key of list.slice()) {
|
|
687
|
+
const pair = kernel.pairs.get(key);
|
|
688
|
+
if (pair === undefined) continue;
|
|
689
|
+
const outcome = pair.constraint({
|
|
690
|
+
address: attempt.address.slice(),
|
|
691
|
+
tier: produced.tier === undefined ? null : produced.tier,
|
|
692
|
+
value: produced.after === undefined ? undefined : produced.after.value,
|
|
693
|
+
attempt: attempt.ref,
|
|
694
|
+
op: produced,
|
|
695
|
+
});
|
|
696
|
+
if (outcome === true) continue;
|
|
697
|
+
attempt.terminalArm = attempt.appliedRepairs.includes(key) ? 'KC-5' : 'KC-6';
|
|
698
|
+
return attempt.terminalArm;
|
|
699
|
+
}
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* **THE REFUSAL THE REGISTRATION ANSWERS — `ConstraintListInvalid` WITH ITS `§8.2`-GENERATED MESSAGE —
|
|
705
|
+
* COMPOSED HERE AS A CODE AND ITS SLOTS, AND RENDERED BY THE SURFACE.**
|
|
706
|
+
*
|
|
707
|
+
* **⟶ THIS IS THE ROUTE THE ARCHITECT SETTLED, AND IT IS NOT A MESSAGE FROM A SECOND SOURCE.** `DD-52`
|
|
708
|
+
* forbids a code's message being produced from a second source, and `§8.2`'s one row declares the slots
|
|
709
|
+
* this instant supplies: **`<CONTAINER>` the pair's own list name, `constraints`**; and **`<SEGMENT>` the
|
|
710
|
+
* ADDED PAIR's `address` spelling, joined by `/`** — the pair's OWN address and not a failing element's,
|
|
711
|
+
* because at this instant the entry is WELL-FORMED and the pair is SUBMITTED rather than found wrong.
|
|
712
|
+
* (`<KEYLIST>`, the row's third slot, is the added pair's members present; no slot of it is asserted here,
|
|
713
|
+
* `§8.2` clause 3 declaring that the sentence the slots make is asserted by NO clause of that contract.)
|
|
714
|
+
*
|
|
715
|
+
* **THE FIXED PHRASE *"is not a valid constraint entry in"* IS RENDERED VERBATIM AND IS NOT RE-AUTHORED** —
|
|
716
|
+
* `§8.2`'s clause 3 of 2026-10-16, which names the honest consequence: at this instant the sentence's SHAPE
|
|
717
|
+
* reports an entry that failed its own validity check while the state is a well-formed pair whose FUNCTION
|
|
718
|
+
* DID NOT PASS. **A HAND-AUTHORED REGISTRATION MESSAGE IS A FAIL OF `P-TP-9` AND NONE STANDS HERE**: not a
|
|
719
|
+
* byte of the text is written in this module, and the sentence is produced by the store's own generator at
|
|
720
|
+
* the surface's existing `errorMessage` path.
|
|
721
|
+
*
|
|
722
|
+
* **THE VALUE CARRIES THIS MODULE'S OWN MARK** (`KERNEL_REFUSAL`) so the surface can tell it from a
|
|
723
|
+
* caller's throw, and the mark is set HERE — in the frame that BUILT the value — and never by a test over
|
|
724
|
+
* members. **A CALLER'S OWN THROWN VALUE STILL SURFACES AS ITSELF**: the 2026-10-17 forgery fix's whole
|
|
725
|
+
* point, and the five shapes are re-probed with this arm in place.
|
|
726
|
+
*/
|
|
727
|
+
function registrationRefusal(address, id, log) {
|
|
728
|
+
return {
|
|
729
|
+
status: 'ConstraintListInvalid',
|
|
730
|
+
segment: address.map((segment) => String(segment)).join('/'),
|
|
731
|
+
container: 'constraints',
|
|
732
|
+
id,
|
|
733
|
+
log: Array.isArray(log) ? log : [],
|
|
734
|
+
[KERNEL_REFUSAL]: true,
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/// **THE SYNTHETIC ATTEMPT'S TERMINAL ACT — `PASSED` OR `FAILING`, AND `CLOSED` FROM THOSE TWO AND FROM
|
|
739
|
+
/// NOWHERE ELSE** (`attempt-lifecycle.md §2.4` item 3). It reaches neither the per-op rollback composition
|
|
740
|
+
/// nor the delivery seam: **the registration instant opens no `K-2`, delivers no listener and composes no
|
|
741
|
+
/// rollback** — the repair's edit STANDS on the passing arm (`3-bis` (f)), and a failed repair's own state
|
|
742
|
+
/// is left where the store's own verb left it (`3-bis` (d): the store's state is left where the composition
|
|
743
|
+
/// restored it, which for an attempt with no rollback composed is the state the verb produced).
|
|
744
|
+
function closeRegistrationAttempt(attempt, outcome = 'failed') {
|
|
745
|
+
attempt.status = 'closed';
|
|
746
|
+
const report = {
|
|
747
|
+
attempt: attempt.ref,
|
|
748
|
+
outcome,
|
|
749
|
+
ops: attempt.ops.slice(),
|
|
750
|
+
log: attempt.log,
|
|
751
|
+
rollback: [],
|
|
752
|
+
};
|
|
753
|
+
attempt.report = report;
|
|
754
|
+
CLOSED.set(attempt.ref.id, report);
|
|
755
|
+
LIVE.delete(attempt.ref.id);
|
|
756
|
+
return report;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
|
|
386
760
|
/** The store holds ONE registration per address, and its `listen` takes a function. */
|
|
387
761
|
function noopListener() {}
|
|
388
762
|
|
|
@@ -908,10 +1282,24 @@ function evaluate(kernel, attempt, landing) {
|
|
|
908
1282
|
// (the store's form is `{status, message}`, carrying no `log` member — `§1.2` item 2; the
|
|
909
1283
|
// kernel's own form carries three members, and a `KC` token is never named as a store code).
|
|
910
1284
|
// The entry's `state` stays `null`; the thrown form's `status` is `KC-4`.
|
|
1285
|
+
// **⟶ THE TEST THAT THIS THROWABLE IS *NOT* THE KERNEL'S OWN WAS `!('log' in body)`, AND THAT
|
|
1286
|
+
// TEST DIED ON 2026-10-16 WITH THE FLAT `log` RULING — THIS IS THE SECOND SITE THE RULING BROKE AND
|
|
1287
|
+
// IS REPORTED AS A FINDING, NOT SILENTLY REPAIRED.** The old test read *"the store's form carries two
|
|
1288
|
+
// members and the kernel's carries three, so a `log` member means the kernel built it"*. **`surface.md
|
|
1289
|
+
// §2.5` item 4 now puts `log` on EVERY failure the JS surface throws, so a STORE REFUSAL REACHING
|
|
1290
|
+
// THIS FRAME THROUGH THE PACKAGE CARRIES A `log` AND THE OLD TEST READ IT AS THE KERNEL'S OWN** —
|
|
1291
|
+
// measured: the two `S-JOIN` `WriteParentNotLink` cells went red with the caller's `status` reading
|
|
1292
|
+
// `WriteParentNotLink` instead of `KC-4`, because `storeCode` was answered `null` and the refusal fell
|
|
1293
|
+
// through to the unconverted `throw body` below.
|
|
1294
|
+
//
|
|
1295
|
+
// **THE REPLACEMENT IS THE SAME ONE THE ENTRY'S CROSSING TOOK — THE KERNEL'S OWN REFUSAL-CLASS MARK
|
|
1296
|
+
// AND NEVER A MEMBER'S PRESENCE** (`KERNEL_REFUSAL` above): a value this kernel built is marked, and
|
|
1297
|
+
// everything unmarked that carries a store code IS a store code, whatever members the surface has
|
|
1298
|
+
// attached to it on its way back. A `KC` token is still never a store code on either spelling.
|
|
911
1299
|
const storeCode = body !== null && typeof body === 'object'
|
|
1300
|
+
&& isKernelRefusal(body) === false
|
|
912
1301
|
&& typeof body.status === 'string'
|
|
913
1302
|
&& body.status.length > 0
|
|
914
|
-
&& !('log' in body)
|
|
915
1303
|
&& !KC_TOKENS.includes(body.status)
|
|
916
1304
|
? body.status
|
|
917
1305
|
: null;
|