provident-storeroom 0.1.3 → 0.3.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.md CHANGED
@@ -32,20 +32,63 @@ addon's path directly is outside every clause of this contract.
32
32
 
33
33
  ## The surface
34
34
 
35
- **The eight verbs of `surface.md §2` and NOTHING ELSE**, plus the one member of the object `storeCreate`
36
- returned:
35
+ **The eight verbs of `surface.md §2` and NOTHING ELSE**, plus the instance `storeCreate` returned — whose own
36
+ member set is the FOUR the dated clause below prints:
37
37
 
38
38
  | The member | Its answer |
39
39
  | --- | --- |
40
- | `storeCreate(cfg)` | the package's own instance handle — `cfg` carries the store's three declared keys and no fourth |
40
+ | `storeCreate(cfg)` | the package's own instance handle — `cfg` carries the store's four declared keys and no fifth |
41
41
  | `read(instance, address, tier?)` | a leaf's literal, a branch's assembled value, the empty address's whole register |
42
42
  | `readLiteral(instance, address, tier?)` | the same, narrowed to a leaf (`ReadTargetIsBranch` on a branch) |
43
- | `write(instance, address, tier, value)` | `{op, watched, triggered}` |
43
+ | `write(instance, address, tier, value, commit?)` | `{op, watched, triggered}` — the fifth argument OPTIONAL and declared LAST; its absence is in domain |
44
44
  | `delete(instance, address, tier?)` | `{address, tiers, triggered}` |
45
45
  | `rollback(instance, opId)` | `{opId, undoneOps, restoredTo}` |
46
46
  | `listen(instance, address)` | a fresh opaque handle |
47
47
  | `unlisten(instance, handle)` | `undefined` — and a no-op success for every value outside the domain |
48
48
  | `instance.register(handle, listener)` | `undefined`; a non-function listener or a handle this instance never minted throws a `TypeError` |
49
+ | `instance.on(address, listener)` | a fresh opaque handle — the store's `listen` plus this package's own registration |
50
+ | `instance.off(handle)` | `undefined` — the store-side withdrawal, and this package's own registry removal |
51
+ | `instance.settle(record)` | `undefined` — the ordering seam: the one member THE KERNEL CALLS, and the arm that performs the `file`-tier save |
52
+
53
+ **⟶ AMENDED 2026-10-15 — THE TABLE ABOVE IS READ AT THE FOUR-KEY CONSTRUCTION, THE FOURTH OWN MEMBER AND THE
54
+ WRITE'S FIFTH ARGUMENT** (`surface.md §2.1`'s dated clause of 2026-10-15 and its `cfg` block; `§2.2`'s dated
55
+ clause of the same date and its clause 4; `§2.11`; `parameter-semantics.md §2.20` = `PAR-JS-20` and `§2.21` =
56
+ `PAR-JS-21`; `docs/decisions.md` · `A116`). **THE THREE CELLS IT RE-SPELLS, EACH NAMED BY ITS OWN WORDS: the
57
+ cells above are ALREADY RE-SPELLED IN PLACE, so the table stands in its OPERATIVE form and the as-filed wording
58
+ is the one NAMED here — *"the store's three declared keys and no fourth"* READS *"the store's four declared keys
59
+ and no fifth"*; *"plus the one member of the object `storeCreate` returned"* READS *"plus the instance
60
+ `storeCreate` returned — whose own member set is the FOUR printed above"*; and the `write` cell's
61
+ *"`write(instance, address, tier, value)`"* READS *"`write(instance, address, tier, value, commit?)`"*.**
62
+
63
+ 1. **THE FOUR DECLARED KEYS, AND NO FIFTH.** **They are `filePath` · `journalLength` · `listeners` ·
64
+ `constraints` — `4` — each passed through WITHOUT a default, a rename or a key of the package's own, and
65
+ the declared arity is `4`.** **THE FOURTH IS `constraints`, OPTIONAL AND ABSENT-IN-DOMAIN like `filePath`:
66
+ it is the APPLICATION'S OWN constraint list, supplied at startup — and THE LIST IS NOT PERSISTED, so the
67
+ store writes no byte of it into the file and holds no register key for it, while at a boot over an existing
68
+ file the LOADED STATE is validated against the supplied list.** **AND A CALLER-SUPPLIED KEY BEYOND THE FOUR
69
+ IS IGNORED AND PRODUCES NO CODE** — *"no fifth"* is a constraint on the PACKAGE's own passing and never a
70
+ refusal of the caller's extra key (`parameter-semantics.md §2.21`; `docs/specs/storeroom-native/contract.md
71
+ §7.1`).
72
+ 2. **THE INSTANCE'S OWN MEMBERS ARE FOUR: `{ register, on, off, settle }`, AND NOTHING ELSE.** **`register` is
73
+ the registration site; `on` and `off` are the listener members; and `settle(record) -> undefined` is THE
74
+ ORDERING SEAM the kernel calls at the two instants of a kernel-driven write** (`surface.md §2.1`'s dated
75
+ clause of 2026-10-15 (a); `§2.4` item 9; `A116` (D1)). **AND NO RELEASE VERB IS ONE OF THEM** — none of the
76
+ four releases the instance.
77
+ 3. **THE WRITE'S DECLARED ARITY IS `4` REQUIRED ARGUMENTS WITH A FIFTH OPTIONAL `commit`, DECLARED LAST**, and
78
+ the declaration governs over the flow's own order: the `commit` is the kernel's own `{ attempt, op,
79
+ triggered, pending }` record — `K-2 commit`'s return — and **AN ABSENT `commit` IS IN DOMAIN**, because the
80
+ write opens or joins a commit all the same (`surface.md §2.2` clause 1). **THE PACKAGE READS THE CALL'S
81
+ ARGUMENT COUNT AT THE FIFTH POSITION AND NOWHERE ELSE** (`§2.2` clause 4): the position ABSENT proceeds, and
82
+ a SUPPLIED `undefined` at the position — or any other form outside the admitted one — is REFUSED, so no
83
+ verb is reached and no byte moves. **AND NO OTHER POSITION OF ANY VERB GAINS AN ARITY READ, A DEFAULT OR A
84
+ SUBSTITUTED ARGUMENT.**
85
+ 4. **THE VERB PERFORMS NO FILE I/O ON ANY OF ITS ARMS** (`§2.11` clause 2): the durable `file`-tier save is the
86
+ instance's `settle` member's own act at THE TERMINAL ARM of a kernel-driven pass and ON ITS PASSING ARM
87
+ ALONE — constraints, then save, then the delivered listener bodies, the save first because no listener body
88
+ runs before it — keyed by the `op` the settled record carries. **AND THE SAVE *IS* A CONSTRAINT, EVALUATED
89
+ LAST: a FAILED SAVE IS AN UNREPAIRABLE CONSTRAINT VIOLATION** (`§2.11` clause 5). **WHERE THE SAVE'S ACT
90
+ FAILS, THE STORE ROLLS THE WRITE BACK AND THE CALLER RECEIVES THE FAILURE AFTER IT AND NEVER THE
91
+ ROLLED-BACK STATE**, and the package compensates for nothing (`§2.11` clauses 3 and 5).
49
92
 
50
93
  **The failure form is ONE** (`surface.md §2.5`, `DD-12`): a THROWN plain object carrying exactly
51
94
  `{status, message}` — never an `Error` subclass, never a returned tagged union and never a `Promise`.
@@ -61,7 +104,11 @@ session's token names no registration of this process, and `unlisten` over it is
61
104
  a `file`-tier version and then constructs a fresh instance over an equal `filePath` sees the removed version
62
105
  STAND AGAIN — that re-boot is the store's own declared boot and not a defect. And a `file`-tier `write` that
63
106
  fails answers `FileCommitFailed` after the store's own automatic journal rollback has run; the package
64
- compensates for nothing.
107
+ compensates for nothing. **⟶ AMENDED 2026-10-15 — THE SECOND READING'S *"a `file`-tier `write` that fails"* IS
108
+ RE-SPELLED IN PLACE, BECAUSE THE VERB IS NO LONGER WHAT PERFORMS THE SAVE: it READS *"a `file`-tier save that
109
+ fails"* — the `settle` member's terminal-arm act of the clause above — the cell above standing in that
110
+ operative form** (`surface.md §2.8` item 2 and `§2.11` clause 5; `parameter-semantics.md
111
+ §2.19`; `A116` (D3)).
65
112
 
66
113
  ## How the addon is resolved — three rungs, and the covered/uncovered answer
67
114
 
package/index.d.ts CHANGED
@@ -6,23 +6,71 @@
6
6
  // banner, no build-time code generator produces it, and it is the file the package's own `types` field
7
7
  // reaches and the package's own `files` allowlist ships.
8
8
  //
9
- // **IT DECLARES THREE THINGS AND NOTHING ELSE** (`distribution.md §5.2`): (1) the EIGHT VERBS of the
10
- // claimed ESM entry, exactly as the sibling directory enumerates them and with NO ninth name; (2) the
11
- // instance's own member set, `{ register, on, off }` — three own members and nothing else; and (3) the
12
- // failure surface, a thrown plain object with exactly `{status, message}`.
9
+ // **IT DECLARES THREE THINGS AND NOTHING ELSE** (`distribution.md §5.2`): (1) the claimed entry's OWN
10
+ // NAMED EXPORT SET — **ONE NAME, `storeCreate`, AND NOTHING ELSE** (`surface.md §2.9` item 1's `A127`
11
+ // clause; `docs/decisions.md` · `A127`/`A128`, 2026-10-16: the module-level count is `11 → 1` ✓, the
12
+ // deprecation window of `A128`'s fiat being declared away at that clause); (2) the instance's own member
13
+ // set, **TWELVE OWN MEMBERS AND NOTHING ELSE — `10 + 1 + 1 = 12` ✓** (`distribution.md §5.2` item 2 read
14
+ // with `surface.md §2.4` item 9 (f)'s `A127` clause): **THE TEN METHODS** `read(address, tier?)` ·
15
+ // `readLiteral(address, tier?)` · `write(address, tier, value, commit?)` · `delete(address, tier?)` ·
16
+ // `rollback(opId)` · `listen(address)` · `unlisten(handle)` · `addConstraint(pair, constraint)` ·
17
+ // `constraintOn(pair, constraint)` · `constraintOff(pair, constraint)`, **PLUS `register(handle, listener)
18
+ // -> undefined` and `settle(record) -> undefined`** — the last being THE ORDERING SEAM the kernel calls and
19
+ // the entry implements; and (3) the failure surface, a thrown plain object with exactly
20
+ // `{status, message}`.
13
21
  //
14
- // **AND THE RECORDS THOSE VERBS ANSWER WITH ARE DECLARED BESIDE THEM, WHICH IS STILL PART (1) AND NOT A
22
+ // **THE TEN METHODS TAKE THE RECEIVER'S OWN POSITION AWAY: `8 → 1` ✓ AND `4 → 12` ✓** (`surface.md §2.9`
23
+ // item 1's and `§2.4` item 9 (f)'s `A127` clauses). The seven verbs that reach the store are METHODS of the
24
+ // object `storeCreate` returned, so **NO DECLARED SIGNATURE CARRIES A LEADING `instance` POSITION** — the
25
+ // receiver is not a position — and the module namespace's own spelling, not a second name at any layer,
26
+ // is what a consumer reaches them through. **`on` AND `off` ARE MERGED AWAY BY `A127` AND ARE NOT
27
+ // MEMBERS**: the listener registration route is `listen` + `register` and its withdrawal is `unlisten`.
28
+ //
29
+ // **AND THE RECORDS THOSE METHODS ANSWER WITH ARE DECLARED BESIDE THEM, WHICH IS STILL PART (1) AND NOT A
15
30
  // FOURTH THING**: `Address` · `Tier` · `TierSet` · `StoreConfig` · `BaseState` · `JournalOp` ·
16
31
  // `WriteRecord` · `DeleteRecord` · `RollbackRecord` · `Handle` · `Listener` are the SHAPES OF THE
17
32
  // ARGUMENTS AND OF THE ANSWERS, in `DD-39`'s own member spellings (the sibling directory's `contract.md
18
- // §0.2`), and a declaration that did not carry them would declare eight names and no surface. **None of
33
+ // §0.2`), and a declaration that did not carry them would declare one name and no surface. **None of
19
34
  // them is a STORE type**: no register, no anchor, no tier tree, no journal and no store verb is declared
20
35
  // here (`§5.2` item 4).
21
36
  //
37
+ // **AND TWO MORE SHAPES STAND BESIDE THOSE ELEVEN WITHOUT A BYTE OF EITHER BEING MINTED HERE, BECAUSE
38
+ // `settle`'s ONE ARGUMENT POSITION IS THE KERNEL'S OWN RECORD AND NOT THIS PACKAGE'S** (`§2.4` item 9
39
+ // (f)'s *"each with its argument types"* read with its *"no `pending`-shaped record type this unit does
40
+ // not declare"*): **`AttemptRef` (`1` member) and `CommitRecord` (`4` members — `attempt` · `op` ·
41
+ // `triggered` · `pending`) are THE KERNEL'S OWN NAMED SHAPES, DECLARED BY THE KERNEL AND NOT BY THIS
42
+ // UNIT** (`kernel-surface.md §1` item 4's closed record enumeration; its `§2.1` item 2 for the record's
43
+ // four members; `attempt-lifecycle.md §2.4` item 1 for the one-member `AttemptRef`) — so the seam's
44
+ // argument carries its own `pending` member and this file MINTS NO RECORD TYPE OF ITS OWN to carry it.
45
+ // **`AttemptRef` and `CommitRecord` are therefore not STORE types either, and not store records**: they
46
+ // are kernel-side shapes the instance's `settle` member takes, cited from their own unit's declaration.
47
+ //
22
48
  // **AND THE ONE THING THIS DECLARATION MUST NOT CARRY, STATED SO THE FINDING RULE IS CHECKABLE**
23
49
  // (`distribution.md §5.2` item 4): **it declares NO store type, NO store verb, NO `findAddress`, NO
24
50
  // release verb and NO constraint or repair seam** — each of those is a declaration the sibling directory
25
51
  // refuses, and a declaration file carrying one would declare a surface the package does not publish.
52
+ //
53
+ // **⟶ AND THE LIMITS OF THIS FILE ARE STATED RATHER THAN IMPLIED, ADDED 2026-10-17** (`DEF-2026-10-16-Q`:
54
+ // *"`bindings/js/index.d.ts` IS TYPE-CHECKED NOWHERE, AND THE TYPES SHIP TO CONSUMERS"*). **NOTHING IN THIS
55
+ // REPOSITORY TYPE-CHECKS THIS FILE — no `tsc`, no `tsd`, no `checkJs` and no type-test file anywhere in the
56
+ // tree — so EVERY CHANGE MADE HERE IS TEXTUAL: it is a claim read by a HUMAN and by a consumer's own
57
+ // compiler, never a claim this repository's own suite can fail on.** **THE THREE CLAIMS A `TypeScript`
58
+ // DECLARATION CANNOT ENFORCE, EACH NAMED SO NO READER READS THEM AS ENFORCED:**
59
+ // 1. **`tier?: TierSet` CANNOT EXPRESS SUPPLIED-VERSUS-OMITTED `undefined`** (`PAR-JS-6`: a SUPPLIED
60
+ // `undefined` at the tier position is PRESENT and takes the store's `AddressMalformed`, while the call
61
+ // that supplied NOTHING there folds to the ABSENT row). An optional parameter admits both spellings
62
+ // identically and no type can separate them; the distinction is a RUNTIME one, driven at
63
+ // `a127-surface.test.mjs`.
64
+ // 2. **`Address = readonly (string | number)[]` CANNOT EXPRESS NON-NEGATIVE INTEGER** (`PAR-JS-5`). The
65
+ // domain is a string key or a non-negative integer a `u64` can carry exactly; `number` admits `-1`,
66
+ // `1.5`, `NaN` and `Infinity`, each of which the boundary REFUSES with the store's own
67
+ // `AddressMalformed`. The narrowest lawful widening a declaration can make is `number`, and this file
68
+ // makes it.
69
+ // 3. **THE INSTANCE'S *"TWELVE OWN MEMBERS AND NOTHING ELSE"* IS NOT STRUCTURALLY ENFORCEABLE HERE**
70
+ // (`§2.4` item 9 (f)'s `A127` clause; `§2.9` item 1's). An interface declares the members a value HAS
71
+ // and constrains no excess member, so a product carrying a thirteenth own member still satisfies
72
+ // `StoreInstance`. The count is driven at the boundary instead (`a127-surface.test.mjs`'s
73
+ // `Object.getOwnPropertyNames` cell, which exists precisely because this declaration cannot fail on it).
26
74
 
27
75
  /**
28
76
  * A position in the register: the address a verb is called at, as a sequence of path segments.
@@ -51,7 +99,19 @@ export type Tier = 'mem' | 'file' | 'temp';
51
99
  */
52
100
  export type TierSet = Tier | readonly Tier[];
53
101
 
54
- /** The configuration a store is constructed from — the store's three declared keys and no fourth. */
102
+ /**
103
+ * The configuration a store is constructed from — **the store's FOUR declared keys and no FIFTH**
104
+ * (`filePath` · `journalLength` · `listeners` · `constraints`), each passed through WITHOUT a default, a
105
+ * rename or a key of this package's own.
106
+ *
107
+ * **⟶ RE-SPELLED 2026-10-15 (`surface.md §2.1`'s `cfg` block and its dated clause of 2026-10-15;
108
+ * `contract.md` `DD-36` as amended 2026-10-15; `parameter-semantics.md §2.21` = `PAR-JS-21`): this cell as
109
+ * filed read *"the store's THREE declared keys and no fourth"* and is re-spelled IN PLACE to the four-key,
110
+ * no-FIFTH reading — the fourth declared key is `constraints`, whose own declaration stands below, and the
111
+ * set's declared arity is `4`.** **NO OTHER CELL OF THIS FILE MOVES** (`distribution.md §5.2`), **READ AT
112
+ * THE FIGURES `A127` MOVED** — the entry's `1` named export (`11 → 1` ✓), the addon's `5`, the instance's
113
+ * `12` own members (`4 → 12` ✓), the kernel's `5` and the store's `8` register rows.
114
+ */
55
115
  export interface StoreConfig {
56
116
  /** The journal's declared length: a positive integer (`PAR-JS-3`). */
57
117
  readonly journalLength: number;
@@ -68,21 +128,45 @@ export interface StoreConfig {
68
128
  readonly listeners: readonly unknown[];
69
129
  /** The file the file tier is backed by, where one is declared (`PAR-JS-2`; ABSENT is in domain). */
70
130
  readonly filePath?: string;
131
+ /**
132
+ * **⟶ ADDED 2026-10-15 (`parameter-semantics.md §2.21`; `surface.md §2.1`'s `cfg` block dated
133
+ * 2026-10-15; `contract.md §8.1` #16) — THE FOURTH DECLARED KEY: THE CONSTRUCTION'S CONSTRAINT LIST**,
134
+ * an array of `{ address, id }` pairs (`[{ address: [key], id: 'c1' }]`).
135
+ *
136
+ * **IT IS OPTIONAL AND ITS ABSENCE IS IN DOMAIN** — *"an ABSENT `constraints` is the ordinary
137
+ * no-constraint store, and no default is declared for it"* — **and every element and every shape outside
138
+ * the list is refused at the store's own construction with ITS OWN code and ITS OWN message**, which is
139
+ * why the element type is the caller's own shape and not a narrowed record here.
140
+ */
141
+ readonly constraints?: readonly { readonly address: Address; readonly id: string }[];
71
142
  }
72
143
 
73
144
  /**
74
145
  * **THE STORE'S OWN CLOSED SET OF FAILURE CODES, AS THE TYPE DECLARES IT — A UNION OVER A
75
146
  * DECLARED-BUT-OPEN SET** (`contract.md §2.4` item 2; `distribution.md §5.3`; `PUB-DD-3`).
76
147
  *
77
- * **THE FIFTEEN MEMBERS BELOW ARE THE STORE'S OWN, and their membership is the STORE'S to close and
148
+ * **THE SIXTEEN MEMBERS BELOW ARE THE STORE'S OWN, and their membership is the STORE'S to close and
78
149
  * never this package's**: this package MINTS NO MEMBER, WIDENS NO SET AND RENAMES NONE
79
150
  * (`distribution.md §5.3` item 3).
80
151
  *
81
152
  * **AND AN UNKNOWN STATUS IS STILL TYPED — THE ESCAPE IS LOAD-BEARING, NOT A LOOSENESS.** The store's set
82
- * has already moved from fourteen to fifteen members and the store's own park prices a sixteenth, so an
83
- * immutably-enumerated union would mis-type a LAWFUL refusal the moment the store's set moves
84
- * (`PUB-DD-3`'s refused alternative). The `(string & {})` arm is what keeps a member the store has added
85
- * typeable in an installed `0.1.0`, and its absence would be a finding rather than a strictness.
153
+ * has already moved twice: from fourteen members to fifteen, and 2026-10-15 to SIXTEEN, the sixteenth being
154
+ * `ConstraintListInvalid` (`contract.md §8.1` #16, amended 2026-10-15; `parameter-semantics.md §2.20` and
155
+ * `§2.21`). So an immutably-enumerated union would mis-type a LAWFUL refusal the moment the store's set
156
+ * moves (`PUB-DD-3`'s refused alternative). The `(string & {})` arm is what keeps a member the store has
157
+ * added typeable in an installed `0.1.0`, and its absence would be a finding rather than a strictness.
158
+ *
159
+ * **AND THE SIXTEENTH MEMBER IS DISCOVERABLE HERE AND NOT MERELY TYPEABLE**: `ConstraintListInvalid` is
160
+ * written among the literals at its rank's own place — LAST of the sixteen and BEFORE the escape — because
161
+ * `distribution.md §5.3` item 1 requires the store's members to be *"DISCOVERABLE in the type"*, and a
162
+ * member the declaration does not name is not discoverable from the type at all. **NO RANK OF `1`…`15`
163
+ * MOVES AND NO EXISTING TRIGGER MOVES: THE MEMBER IS APPENDED AS THE SIXTEENTH** (`contract.md §8.1`'s
164
+ * amended heading, whose algebra reads `11 + 2 + 1 + 1 + 1 = 16` ✓; the row that drives it is
165
+ * `docs/specs/storeroom-native/implementation-plan.md §10.9` row 8). **ITS TRIGGER IS THE VALIDATION OF
166
+ * THE SUPPLIED CONSTRAINT LIST** — at
167
+ * construction/startup, or of the LOADED state against that list at load — **and the store writes no byte of
168
+ * that list into the file and holds no register key for it** (`contract.md §7.1` step 4 and `§7.2` item 6 as
169
+ * amended 2026-10-15; `seams-and-lifecycle.md §8.1`).
86
170
  */
87
171
  export type StoreStatus =
88
172
  | 'AddressMalformed'
@@ -100,6 +184,7 @@ export type StoreStatus =
100
184
  | 'FilePathUnreachable'
101
185
  | 'ValueNotAdmitted'
102
186
  | 'FileCommitFailed'
187
+ | 'ConstraintListInvalid'
103
188
  | (string & {});
104
189
 
105
190
  /**
@@ -189,17 +274,242 @@ export interface RollbackRecord {
189
274
  }
190
275
 
191
276
  /**
192
- * **THE INSTANCE `storeCreate` RETURNS — `{ register, on, off }`, THREE OWN MEMBERS AND NOTHING ELSE**
193
- * (`distribution.md §5.2` item 2). **The instance's own state is released with the instance and by nothing
194
- * else: none of the three is a release verb.**
277
+ * **THE ATTEMPT'S IDENTITY — THE KERNEL'S OWN ONE-MEMBER RECORD AND NOT THIS PACKAGE'S**
278
+ * (`attempt-lifecycle.md §2.4` item 1: *"`AttemptRef { id: string }` — the attempt's identity: a non-empty,
279
+ * kernel-unique token"*; read with `kernel-surface.md §1` item 4's closed record enumeration, which counts
280
+ * it as a named kernel-side shape).
281
+ *
282
+ * **IT IS DECLARED HERE FOR ONE POSITION AND NO OTHER**: the `attempt` member of the `CommitRecord` the
283
+ * instance's `settle` member takes (`§2.4` item 9 (f)'s *"each with its argument types"*). **No verb of
284
+ * this entry answers with it and this package mints it nowhere.**
285
+ */
286
+ export interface AttemptRef {
287
+ /** The attempt's identity: a non-empty, kernel-unique token. */
288
+ readonly id: string;
289
+ }
290
+
291
+ /**
292
+ * **THE ORDERING SEAM'S ONE ARGUMENT — THE KERNEL'S OWN `{ attempt, op, triggered, pending }` RECORD, AND
293
+ * NOT THE STORE'S `WriteRecord`** (`kernel-surface.md §2.1` item 2's return-shape block: *"`CommitRecord`,
294
+ * a record with exactly FOUR members, the FOURTH added at the `A108` landing pass of 2026-10-13"*; its
295
+ * `§1` item 4 counts it among the kernel's own named shapes).
296
+ *
297
+ * **THE RECORD THE KERNEL PASSES IS THIS ONE AND THE STORE'S IS NOT.** **The kernel passes the `CommitRecord`
298
+ * `commit` built and the pass's terminal arm reads again — one identity, at both instants** (`surface.md`
299
+ * `§2.4` item 9 (a)–(b)'s table: *"the record identity (the `CommitRecord` `commit` is building)"* then
300
+ * *"the SAME record identity"*; `PAR-JS-19`'s `supplier` cell: THE KERNEL, *"at instant (a) from `commit`
301
+ * … and at instant (b) from the pass's terminal arm"*). **AND IT IS `NOT` THE STORE'S OWN RECORD**:
302
+ * `kernel-surface.md §2.1` item 2's *"WHAT IT IS NOT"* clause reads *"the `CommitRecord` is the KERNEL'S
303
+ * OWN record and is NOT the store's `WriteResult`"* — the store's write answers `{op, watched, triggered}`
304
+ * and `WriteRecord` above is that three-member record, carrying NO `attempt` and NO `pending`.
305
+ *
306
+ * **SO THE `pending` MEMBER BELOW IS THE KERNEL'S, CARRIED VERBATIM FROM THE KERNEL'S OWN DECLARATION AND
307
+ * MINTED NOWHERE HERE** (`surface.md` `§2.4` item 9 (f)'s *"no `pending`-shaped record type this unit does
308
+ * not declare"*; `A116` (D4) — *"the carrier `CommitRecord.pending` and its two removal rules unchanged"*):
309
+ * it carries THE WHOLE RETURNED SET OF TRIGGERED CONSTRAINTS this call's write returned, each entry leaving
310
+ * it only by being checked off as it passes (`kernel-surface.md §2.1` item 2).
311
+ *
312
+ * **`triggered` and `pending` are the store's own returned handle set and the kernel's own member
313
+ * respectively, each read as a SET** (`§2.1` item 2; `Handle` above is this file's opaque-handle spelling);
314
+ * **`op` is the op the store's write returned, VERBATIM** (`JournalOp` above, the store's own eight-member
315
+ * record — `§2.1` item 2: *"the op the store's write returned, VERBATIM"*).
316
+ */
317
+ export interface CommitRecord {
318
+ /** The attempt this commit opened — its identity (`attempt-lifecycle.md §2.4` item 1). */
319
+ readonly attempt: AttemptRef;
320
+ /** The op the store's write returned, VERBATIM (`JournalOp` above; `§2.1` item 2). */
321
+ readonly op: JournalOp;
322
+ /** The store's own `triggered` member, VERBATIM, read as a SET (`§2.1` item 2). */
323
+ readonly triggered: readonly Handle[];
324
+ /** THE WHOLE RETURNED SET OF TRIGGERED CONSTRAINTS, each entry leaving it only by being checked off as it passes (`§2.1` item 2). */
325
+ readonly pending: readonly Handle[];
326
+ }
327
+
328
+ /**
329
+ * **THE INSTANCE `storeCreate` RETURNS — THE TWELVE OWN MEMBERS OF `surface.md §2.4` item 9 (f)'s `A127`
330
+ * clause, `10 + 1 + 1 = 12` ✓: THE TEN METHODS, `register` AND `settle`.** Each is reached through the
331
+ * factory's own product alone (`package.md §1.3` item 3) — **NO member below is a named export**, because
332
+ * the module namespace carries ONE name, `storeCreate` (`§2.9` item 1's `A127` clause; `11 → 1` ✓).
333
+ *
334
+ * **THE TEN METHODS ARE THE DECLARED POSITIONS OF `§2.2`, `§2.4`, `§2.10` AND `§2.12` WITH THE LEADING
335
+ * `instance` POSITION DROPPED** (`A127`): `a.read(address, tier?)` is the declared `read`, `a.write(address,
336
+ * tier, value, commit?)` the declared `write`, and so on — **the receiver IS the instance, so the position
337
+ * is not a position and the arity every one of them is judged by is the arity of the method's OWN call.**
338
+ * **`on` and `off` are merged away and are NOT members**: registration is `listen` + `register`, and
339
+ * withdrawal is `unlisten`.
340
+ *
341
+ * **THE STATE IS PRIVATE AND NONE OF THE TWELVE IS A RELEASE VERB** (`surface.md §2.1` (e) item 1; `A74`):
342
+ * the instance's own state is released with the instance and by nothing else — no `dispose()`, no `close()`
343
+ * and no finalizer is declared here.
195
344
  */
196
345
  export interface StoreInstance {
197
- /** Register `listener` under the opaque `handle`, and answer `undefined`. */
346
+ /**
347
+ * Read a leaf's literal, a branch's assembled value, or the empty address's whole register.
348
+ *
349
+ * **`tier` IS THE READER'S ARITY** (`PAR-JS-6`): absent, ONE token, or an ARRAY of tokens read as an
350
+ * ANY-MATCH set — **so the earlier `tier?: Tier` spelling refused, as a type error, a lawful call
351
+ * spelling a set**.
352
+ *
353
+ * **AND `undefined` AT THIS POSITION IS NOT THE SAME CALL AS NO POSITION AT ALL** (`parameter-semantics.md
354
+ * §2.6`, read with `acceptance.md §4.1` item 7): **a SUPPLIED `undefined` is PRESENT and the store answers
355
+ * `AddressMalformed` for it**, while ONLY the call that spells NO tier folds to absent. **THE DECLARATION
356
+ * CANNOT TELL THE TWO APART** — `tier?: TierSet` admits both spellings, which is why `TierSet` carries no
357
+ * `undefined` member — and the distinction is a RUNTIME one at this member (`a127`'s
358
+ * `read_the_absent_tier_position_is_in_domain`).
359
+ */
360
+ read(address: Address, tier?: TierSet): unknown;
361
+ /** The same read, narrowed to a leaf — a branch answers `ReadTargetIsBranch`; `tier` is `TierSet`, with the same SUPPLIED-`undefined` reading as `read`. */
362
+ readLiteral(address: Address, tier?: TierSet): unknown;
363
+ /**
364
+ * Write `value` at `address` on `tier` — EXACTLY ONE token, never an array (`PAR-JS-7`).
365
+ *
366
+ * **THE DECLARED ORDER IS `write(address, tier, value, commit?)`** (`surface.md §2.2`'s dated clause of
367
+ * 2026-10-15; `parameter-semantics.md §2.20`), read with `§2.4` item 9 (f)'s `A127` clause: **THREE
368
+ * REQUIRED ARGUMENTS AND THE OPTIONAL ONE LAST — the commit, at the FOURTH position of the METHOD**,
369
+ * which is the position the `instance`-leading spelling made FIVE (`A124`).
370
+ *
371
+ * **AN ABSENT `commit` IS IN DOMAIN** (§2.2 clause 3: *"the write opens or joins a commit all the
372
+ * same"*) and **NO DEFAULT RECORD IS FABRICATED FOR IT**; **the admitted form is the kernel's own
373
+ * `CommitRecord`** (`surface.md §2.4` item 9 (g) item 1: an object carrying a `pending` member present
374
+ * and not `undefined`), and **every other form at this position — absent, `undefined`, `null`, a
375
+ * primitive, a function, a `Proxy`, an object whose `pending` member is absent or `undefined` — throws
376
+ * THE CLASS TEST'S OWN `TypeError`, whose `status` member is ABSENT and whose STRING `message` member is
377
+ * REQUIRED** (`surface.md` §2.4 item 9 (g) item 1's discriminator, landed 2026-10-15 on `A116` (D1); the
378
+ * operative predicate is `file-tier-save.test.mjs`'s `positionRefusal`, which asserts exactly those two
379
+ * halves). **A REFUSED POSITION STOPS THE WRITE**: no verb is reached and no byte moves.
380
+ *
381
+ * **⟶ CORRECTED 2026-10-17 — THIS CELL ATTRIBUTED THAT `TypeError` TO *"the registration site's own"*
382
+ * FORM, AND THE ATTRIBUTION WAS FALSE** (`DEF-2026-10-16-Q`; `surface.md` §2.5 item 5 (g), THE OPERATIVE
383
+ * READING). **THE REGISTRATION SITE THROWS NO `TypeError` AT ALL**: its refusal *"IS a rejection under
384
+ * `A76` and travels in THIS section's single form, with its `status` drawn from the store's closed set —
385
+ * the store's own `AddressMalformed`"*, `message` generated as clause (d) declares, so `register`'s
386
+ * outside argument answers a plain `{status, message}` (driven at `register.test.mjs`'s
387
+ * `isRegistrationRefusal`, which counts a `TypeError` as a FAILURE). **A `TypeError` thrown by any
388
+ * STORE-REACHING VERB is itself a FINDING** (`a127-surface.test.mjs`'s
389
+ * `a127_no_store_reaching_verb_throws_the_class_test_form`). The two forms are DIFFERENT forms of
390
+ * DIFFERENT sites, and this position's is the class test's own, declared at `§2.4` item 9 (g) —
391
+ * beside, and not drawn from, the registration site's `§2.4` item 5.
392
+ *
393
+ * **AND A SUPPLIED `undefined` AT THE `tier` POSITION IS PRESENT HERE TOO** (`parameter-semantics.md
394
+ * §2.6`; `PAR-JS-6`): it is not the absent tier and the store answers `AddressMalformed` for it.
395
+ */
396
+ write(address: Address, tier: Tier, value: unknown, commit?: CommitRecord): WriteRecord;
397
+ /**
398
+ * Remove the versions the address names, and answer the operation's record.
399
+ *
400
+ * **THE NAME IS `delete` AND IT IS A METHOD NAME, WHICH IS WHY THIS DECLARATION PARSES**: `delete` is a
401
+ * RESERVED WORD, so under the superseded module-level spelling the function had to be declared as
402
+ * `deleteOp` and re-exported (`export { deleteOp as delete }`). **A METHOD NAME IS NOT AN IDENTIFIER
403
+ * BINDING, so the member is declared under the one name the surface publishes** (`A127`).
404
+ */
405
+ delete(address: Address, tier?: Tier): DeleteRecord;
406
+ /**
407
+ * Roll the journal back to `opId`, and answer what the rollback restored.
408
+ *
409
+ * **`opId` IS A NON-EMPTY `string` AND NOT A NUMBER** (`PAR-JS-9`'s own unit: *"the `JournalOp.opId`
410
+ * string"*): a number is an OUTSIDE value the store answers `AddressMalformed` for, and the ordinary
411
+ * call `a.rollback(w.op.opId)`, whose id is the string `write` returned, is a correct call.
412
+ */
413
+ rollback(opId: string): RollbackRecord;
414
+ /**
415
+ * Begin watching an address, and answer the fresh opaque handle it is keyed by.
416
+ *
417
+ * **AND IT IS AN ADDRESS SITE THAT DECLARES ITS ARGUMENT POSITION** (`parameter-semantics.md §2.17`'s
418
+ * dated clause; `surface.md §2.5` item 5 (b)'s position half): the address is `1` of `1`, so a CLASS
419
+ * refusal here — a `Proxy` over an array included — carries `a Proxy` AND `first argument` inside the one
420
+ * failure form's message, and NO trap is run (`NG-JS-I`).
421
+ *
422
+ * **A REPEATED CALL AT A HELD ADDRESS MINTS NOTHING AND ANSWERS THE ADDRESS'S EXISTING ENTRY'S HANDLE**
423
+ * (`write-and-read.md §6.5` item 12 (c); `§0.4` clause 2), so the two calls answer ONE opaque value.
424
+ */
425
+ listen(address: Address): Handle;
426
+ /**
427
+ * Withdraw a watching, and answer `undefined` — a no-op success for every value outside the domain.
428
+ *
429
+ * **AND THE WITHDRAWAL CARRIES THE PACKAGE'S OWN HALF TOO** (`surface.md §2.4` item 7 (b)'s
430
+ * VALIDATE · UNLISTEN · DEREGISTER step list, MERGED INTO THIS ONE MEMBER by `A127`'s receiver ruling;
431
+ * `contract.md §5.5`'s fourth added entry): **the store-side home entry named by this call is withdrawn,
432
+ * and the registry's entry for the identity is REMOVED where the identity no longer stands anywhere** — so
433
+ * the registered function is unreachable afterwards and a re-`listen` at the withdrawn address answers a
434
+ * DIFFERENT handle. **AT `DD-39`'s CONSTRUCTION DUPLICATE — ONE caller-spelled token naming MORE THAN ONE
435
+ * entry at ONE address — ONE entry is withdrawn per call while the address still holds the identity, and
436
+ * the registry's entry STANDS: a later trigger there STILL returns that identity and the function fires
437
+ * for it ONCE, never once per entry** (`contract.md §5.5`'s third added entry; `§2.4` rule 4's *"never the
438
+ * function"*).
439
+ */
440
+ unlisten(handle: Handle): void;
441
+ /**
442
+ * **THE POST-CREATION ADD ROUTE — `addConstraint(pair, constraint) -> constraint identity`**
443
+ * (`surface.md §2.12` item 2 (a) and item 3's ADD row; `parameter-semantics.md §2.25` = `PAR-JS-25`):
444
+ * **the pair's element IS the supplied `constraint` from this call on, whether the pair was HELD or
445
+ * NOT**, and at a pair already held the supplied constraint OVERWRITES the held one under **THE SAME
446
+ * IDENTITY** the pair was already added under, so the call throws nothing for the mere fact that the
447
+ * pair was held.
448
+ *
449
+ * **Every outside form of either position throws ONE `TypeError`, whose `status` member is ABSENT, and
450
+ * nothing is added, enabled, disabled or otherwise changed.**
451
+ */
452
+ addConstraint(pair: ConstraintPair, constraint: Constraint): ConstraintIdentity;
453
+ /** **THE ENABLE HALF** (`§2.12` item 2 (a) and item 3's `constraintOn` row): `undefined`. **The
454
+ * `constraint` position is REQUIRED and is a NO-OP on every success** — the caller supplies as a function
455
+ * the identity it holds at that pair, the entry never substitutes one, and it is the element the entry
456
+ * carried at that pair that is evaluated at the next write. **Idempotent success where the pair already
457
+ * stands ENABLED.** */
458
+ constraintOn(pair: ConstraintPair, constraint: Constraint): void;
459
+ /** **THE DISABLE HALF** (`§2.12` item 2 (a) and item 3's `constraintOff` row): `undefined`; the pair's
460
+ * element is NOT evaluated on a subsequent write, and **a write the disabled constraint would have
461
+ * refused is ACCEPTED**. The `constraint` position's rule is `constraintOn`'s, clause for clause.
462
+ * **Idempotent success where the pair already stands DISABLED.** */
463
+ constraintOff(pair: ConstraintPair, constraint: Constraint): void;
464
+ /** Register `listener` under the opaque `handle`, and answer `undefined` (`surface.md §2.4` item 5 (b)). */
198
465
  register(handle: Handle, listener: Listener): void;
199
- /** Register a listener at `address` and answer the fresh opaque handle it is keyed by. */
200
- on(address: Address, listener: Listener): Handle;
201
- /** Withdraw the store-side home entry the `handle` names, and answer `undefined`. */
202
- off(handle: Handle): void;
466
+ /**
467
+ * **THE ORDERING SEAM — `settle(record) -> undefined`** (`surface.md §2.4` item 9; `A116` (D1)–(D2);
468
+ * `PAR-JS-19`): the one member THE KERNEL CALLS and the entry implements, at the two instants of a
469
+ * kernel-driven write — **the adoption at the first call for a record identity**, taken before the write
470
+ * verb (the write in flight is withheld: the in-window invocation set is empty), **and the delivery at
471
+ * the second call for that identity**, taken at the pass's terminal arm (the residue standing in the
472
+ * record's own `pending` member is delivered through this instance's own registry, one invocation per
473
+ * handle, each with the triggering address as its single argument). **Every other form at the record
474
+ * position — absent, `undefined`, `null`, a primitive, a function, a `Proxy`, an identity this instance
475
+ * never adopted — throws THE ORDERING SEAM'S OWN `TypeError`, whose `status` member is ABSENT and whose
476
+ * STRING `message` member is REQUIRED, and changes nothing.**
477
+ *
478
+ * **⟶ CORRECTED 2026-10-17 — THIS CELL ATTRIBUTED THAT `TypeError` TO *"the registration site's own"*
479
+ * FORM AND THAT ATTRIBUTION WAS FALSE** (`DEF-2026-10-16-Q`; `surface.md` §2.5 item 5 (g), the operative
480
+ * reading of the registration site; `§2.4` item 9 (b), landed 2026-10-15 on `A116` (D1), which re-spells
481
+ * the re-spelling this position takes). **THE REGISTRATION SITE ANSWERS A PLAIN `{status, message}` with
482
+ * `status` `AddressMalformed` — a `TypeError` there is a FAILURE** (`register.test.mjs`'s
483
+ * `isRegistrationRefusal`), and **the seam's own form is declared at `§2.4` item 9 (b) and not at item
484
+ * 5**: *"a `TypeError` with its `status` member ABSENT and a STRING `message` member REQUIRED AND NOT
485
+ * FORBIDDEN"* (`§2.5` item 5 (g)'s own record of that re-spelling, whose two dated readings of one
486
+ * phrase it reports and settles by no clause). **SO THE TWO SITES' FORMS ARE NOT ONE FORM, and this
487
+ * member's is the seam's.**
488
+ *
489
+ * **THE RECORD POSITION TAKES THE KERNEL'S OWN `CommitRecord` — `{ attempt, op, triggered, pending }`,
490
+ * FOUR MEMBERS — AND NOT THE STORE'S `WriteRecord`** (`surface.md` `§2.4` item 9 (f)'s *"each with its
491
+ * argument types"* read with item 9's own two-instant table; `PAR-JS-19`'s `supplier` cell; `A116` (D4):
492
+ * *"the carrier `CommitRecord.pending` and its two removal rules unchanged"*). **THE INSTANTS' OWN TABLE
493
+ * NAMES IT: the record is *"the `CommitRecord` `commit` is building"* at instant (a) and *"the SAME record
494
+ * identity"* at instant (b)** (`surface.md` `§2.4` item 9 (a)–(b)). **AND THE STORE'S RECORD IS NOT ONE:
495
+ * `WriteRecord` above is the three-member `{op, watched, triggered}` the `write` member answers with and
496
+ * carries NO `pending` member, `PAR-JS-13` is that record's returned `op` field (`parameter-semantics.md
497
+ * §2.13`) and not the record's own shape, and the kernel's record carries TWO of the store's members
498
+ * VERBATIM beside its own `attempt` identity and its own `pending` member** (`kernel-surface.md §2.1` item
499
+ * 2's *"WHAT IT IS NOT"* clause: *"the `CommitRecord` is the KERNEL'S OWN record and is NOT the store's
500
+ * `WriteResult`"*).
501
+ *
502
+ * **`CommitRecord` IS THE KERNEL'S DECLARED SHAPE AND IS NOT MINTED HERE** (`surface.md` `§2.4` item 9
503
+ * (f) forbids *"a `pending`-shaped record type this unit does not declare"*, and this unit declares none):
504
+ * the type is declared above with the kernel's own four members and cited from its own unit's declaration
505
+ * — `kernel-surface.md §1` item 4's closed record enumeration, `§2.1` item 2 for the record, and
506
+ * `attempt-lifecycle.md §2.4` item 1 for its `AttemptRef` — **and NO named export is added for it or for
507
+ * `settle`.**
508
+ *
509
+ * **It is NOT a named export of this entry** (`package.md §1.3` item 3): it is reached through
510
+ * `storeCreate`'s own product alone.
511
+ */
512
+ settle(record: CommitRecord): void;
203
513
  }
204
514
 
205
515
  /**
@@ -215,43 +525,32 @@ export interface StoreInstance {
215
525
  export function storeCreate(cfg: StoreConfig): StoreInstance;
216
526
 
217
527
  /**
218
- * Read a leaf's literal, a branch's assembled value, or the empty address's whole register.
219
- *
220
- * **`tier` IS THE READER'S ARITY** (`PAR-JS-6`): absent, ONE token, or an ARRAY of tokens read as an
221
- * ANY-MATCH set — **so the shipped `tier?: Tier` refused, as a type error, a lawful call spelling a set**.
528
+ * **THE POST-CREATION CONSTRAINT PAIR — `parameter-semantics.md §2.24` (`PAR-JS-24`)**: the key the three
529
+ * constraint methods name — **an `address` inside `§1.5`'s segment array, and an `id` that is a NON-EMPTY
530
+ * `string`** — **and NOT the whole of a batch element**, which is this pair PLUS its constraint function.
531
+ * **Every outside form of the pair throws the three methods' one `TypeError`**, and **a well-formed pair
532
+ * the entry does not carry is outside the two toggles' domain**: it is NOT a third population route.
222
533
  */
223
- export function read(instance: StoreInstance, address: Address, tier?: TierSet): unknown;
224
-
225
- /** The same read, narrowed to a leaf — a branch answers `ReadTargetIsBranch`; `tier` is `TierSet`. */
226
- export function readLiteral(instance: StoreInstance, address: Address, tier?: TierSet): unknown;
227
-
228
- /** Write `value` at `address` on `tier` — EXACTLY ONE token, never an array (`PAR-JS-7`). */
229
- export function write(instance: StoreInstance, address: Address, tier: Tier, value: unknown): WriteRecord;
534
+ export interface ConstraintPair {
535
+ readonly address: Address;
536
+ readonly id: string;
537
+ }
230
538
 
231
539
  /**
232
- * Remove the versions the address names, and answer the operation's record.
233
- *
234
- * **AND THE NAME IS `delete`, WHICH THIS DECLARATION CANNOT BIND AS AN IDENTIFIER**: `delete` is a RESERVED
235
- * WORD, so the function is declared as `deleteOp` and EXPORTED under the name the entry publishes —
236
- * `export { deleteOp as delete }` — exactly as `bindings/js/index.mjs` does on its own side.
237
- * **`export function delete(…)`, WHICH THE SHIPPED FILE CARRIED, IS NOT A PARSEABLE DECLARATION AT ALL**, so
238
- * a consumer's compiler read no surface from this file rather than a mis-typed one (`P-PUB-7`; `Q3-4`).
540
+ * **THE CONSTRAINT FUNCTION — `parameter-semantics.md §2.22` (`PAR-JS-22`)**: a JS function, supplied by THE
541
+ * CALLER at whichever of the three methods it takes — **the ADD route's own argument** or the batch
542
+ * element's own — **invoked by the KERNEL with ONE argument, the attempt's own context** (`PAR-C-16`: *"the
543
+ * attempt context — the constraint's ONE argument"*), and read for its answer (`kernel-surface.md §2.3`
544
+ * item 1: `true` is the only pass value). **Every non-function is outside the position AT EVERY ONE OF THE
545
+ * THREE METHODS**, and a non-function at the toggle's position is refused on the ARGUMENT's ground and
546
+ * never on the pair's.
239
547
  */
240
- declare function deleteOp(instance: StoreInstance, address: Address, tier?: Tier): DeleteRecord;
241
- export { deleteOp as delete };
548
+ export type Constraint = (context: unknown) => unknown;
242
549
 
243
550
  /**
244
- * Roll the journal back to `opId`, and answer what the rollback restored.
245
- *
246
- * **`opId` IS A NON-EMPTY `string` AND NOT A NUMBER** (`PAR-JS-9`'s own unit: *"the `JournalOp.opId`
247
- * string"*): the shipped `opId: number` both mis-declared the domain — a number is an OUTSIDE value the
248
- * store answers `AddressMalformed` for — and made the ordinary call `rollback(i, w.op.opId)`, whose id is
249
- * the string `write` returned, a type error.
551
+ * **THE CONSTRAINT IDENTITY — `parameter-semantics.md §2.25` (`PAR-JS-25`)**: ONE OPAQUE VALUE THE PACKAGE
552
+ * OWNS, minted once per pair, **equal to itself on a second `addConstraint` at the SAME pair** (the
553
+ * overwrite arm) **and distinguishable from every other pair's**. **No spelling for it is declared, no
554
+ * accessor reaches a member of it, and a consumer compares identities and never contents.**
250
555
  */
251
- export function rollback(instance: StoreInstance, opId: string): RollbackRecord;
252
-
253
- /** Begin watching an address, and answer the fresh opaque handle it is keyed by. */
254
- export function listen(instance: StoreInstance, address: Address): Handle;
255
-
256
- /** Withdraw a watching, and answer `undefined` — a no-op success for every value outside the domain. */
257
- export function unlisten(instance: StoreInstance, handle: Handle): void;
556
+ export type ConstraintIdentity = object;