nervur 0.17.0 → 0.18.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/quo-kit.md DELETED
@@ -1,652 +0,0 @@
1
- # quo-kit
2
-
3
- This is the kit: one TypeScript implementation of Quo, run directly on Node
4
- with no dependencies, published as `nervur`. It assumes
5
- `quo/SPEC.md`, which is the protocol and assumes nothing, and it adds
6
- nothing to it. Everything here is a choice this kit made and another kit may
7
- refuse: a base class, a spelling for silence, a file layout, a store, a
8
- bundle, a gate. Where this paper and the protocol disagree the protocol wins,
9
- because a sentence that a kit in another language needs to interoperate is
10
- not this paper's to hold.
11
-
12
- It carries no version and keeps no history, and it is rewritten in place to
13
- say what the tree says.
14
-
15
- ## The tree
16
-
17
- The repository is one TypeScript implementation of the protocol, run
18
- directly on Node's type stripping, no dependencies. Node 22.18
19
- or later. The package is `nervur`, the unscoped headline name of the kit
20
- and the library itself rather than a wrapper over it; the dock and the
21
- component kit stand beside it under `@nervur-org`, named for what they are.
22
- Before 1.0.0 every version may change the words, and nothing is kept for a
23
- holder of an earlier one.
24
-
25
- The tree runs as TypeScript and the package ships as JavaScript. Node
26
- strips types nowhere under `node_modules`, so a consumer cannot load the
27
- source. `npm run build` emits `dist/` from `src`
28
- alone, one JavaScript file and one declaration file per source file with
29
- every relative import rewritten, and the exports map points there, types
30
- beside default. The
31
- build runs before every gate and every publish and is never tracked;
32
- nothing in this repository imports it except through the package name,
33
- which is how a consumer does. `test/package.test.ts` is the one
34
- suite that meets the package as a stranger: it packs the tarball,
35
- installs it into an empty folder, and imports every entry point under
36
- plain Node. `npm pack --dry-run` shows what ships: `dist/`, the four
37
- source folders, the protocol shelf, this paper, the README, the licence and
38
- the notice, and nothing else. The protocol shelf and one paper ship, and
39
- the build copies them in, each to where it belongs: the spec and the
40
- vectors from `quo/` at the repository root into `protocol/`, away from
41
- every line of TypeScript, because that folder is what a kit in another
42
- language is written against and nothing else; this paper to the package
43
- root, where it says which of what a reader sees here was a choice.
44
- Publishing runs both gates first, `npm run check` and `npm run deep`, and
45
- refuses on a failure.
46
-
47
- ```
48
- protocol/ the shelf a second kit reads: SPEC.md and the vectors, copied in by the build from quo/ at the root.
49
- protocol/vectors/ fixed inputs and outputs: the arithmetic, Quo's own framing, the frames on the wire, the door's thirteen cases.
50
- src/being/ the Being side. types, the base class, silence, the digest.
51
- src/ward/ the ward. the Ground contract, door, seal, arithmetic, heirs, stance, owner, partition, cells, allowance.
52
- src/harbor/ the memory harbor, the store, the reach, the dialer and the harbor core.
53
- src/conformance/ the behaviours any ward must show, and the fixed beings they are shown with.
54
- src/vector/ the world the door's cases are taken in, the cases as records, and vector mode.
55
- test/ the suites.
56
- ```
57
-
58
- ## The three shelves
59
-
60
- The package holds three kinds of thing and they are not interchangeable.
61
- Knowing which shelf a file is on decides whether a kit in another language
62
- may read it, whether this paper or the spec governs it, and whether it
63
- travels the day a second kit exists.
64
-
65
- | shelf | what stands there | language |
66
- | -------- | ---------------------------------------------------- | ----------------------- |
67
- | protocol | `protocol/`: `SPEC.md` and the vectors | none, prose and bytes |
68
- | kit | `src/being/`, `src/ward/`, `src/harbor/`, this paper | TypeScript, chosen here |
69
- | harness | `src/conformance/`, `src/vector/`, `test/` | TypeScript, ours |
70
-
71
- The protocol shelf is the only one a kit in Rust or Go reads. It is a
72
- document that assumes nothing and four files of fixed bytes, and it is
73
- written so that folder alone, lifted into an empty repository, is the whole
74
- protocol. Nothing on it imports anything, because nothing on it is code.
75
-
76
- The kit shelf is this interpretation and another kit may refuse every line
77
- of it: a base class, a spelling for silence, a store interface, a reach, a
78
- dialer, a file layout.
79
-
80
- The harness shelf proves the kit shelf, and it is not the protocol however
81
- much it reads like it. `src/conformance/` imports `Being`, `silence.ts`,
82
- `digest.ts` and the kit's own `Store` and `Reach`, so a kit in another
83
- language cannot run one line of it. It is exported all the same, as
84
- `nervur/conformance`, because every harbor the dock stands on is
85
- a TypeScript harbor and the suite is how one is accepted. The day a second
86
- kit exists, the conformance suite does not run there. It is ported: a kit
87
- writes the six obligations of the probe, carries the suite and its beings
88
- into its own language, and reads them beside its own tests.
89
-
90
- The hand to that kit is two things of two kinds, as the spec has it. The
91
- vectors are the byte-level hand and the ported checklist is the
92
- behavioural one. The suite does not become data, because the beings it is
93
- shown with run only in the ward its kit wrote. The four areas are the
94
- whole byte-level hand: `arithmetic.json`, `framing.json`, `wire.json` and
95
- `door.json`, the last being the door's thirteen cases, each an arrival with
96
- the bytes in, the bytes out and the partition's digest on both sides of the
97
- judgement. The shelf owes nothing beyond them.
98
-
99
- The vector shelf, `src/vector/`, is the harness's other half. It is the
100
- world `door.json` is taken in, two harbors linked as a wire with every byte
101
- of entropy drawn from one SplitMix64 stream, the thirteen cases as records
102
- with their setup held apart from their arrival, and `Stand`, which is
103
- vector mode as the spec's chapter of that name has it: one handler that
104
- names no runtime, answering the request reach, `stand` and `digest`, and
105
- open to any origin. It is exported because a kit is stood for a verifier
106
- from wherever a listener is, and a listener is the terrain's; on Node it is
107
- `test/stand.ts`, one loopback server in front of the handler. Nothing a
108
- world runs on imports the shelf, and the mode is unreachable from a harbor
109
- that is not in it.
110
-
111
- Entry points: `nervur` is the Being side, `nervur/ward`
112
- is `Ward`, `nervur/harbor` is `MemoryHarbor`, `Harbor`, the
113
- store, the reach and the dialer, `nervur/conformance` is
114
- `conform` with the store and reach suites beside it, and
115
- `nervur/vector` is the world, the cases and `Stand`.
116
-
117
- ## The terrain
118
-
119
- Under `src/being/`, `src/ward/`, `src/harbor/`, `src/conformance/` and
120
- `src/vector/` no runtime is named. The whole
121
- platform surface is the language plus ten globals. Six are the ward's own:
122
- `crypto`, `TextEncoder`, `TextDecoder`, `structuredClone`, `setTimeout` and
123
- `atob`. Four more came with the harbor, and are the whole of what a reach
124
- costs: `fetch` and `WebSocket`, the two kinds of reach; `DataView`, the frame
125
- id on a socket; and `clearTimeout`, the dialer's reconnect called off. That
126
- list is a promise, not an accident: `test/terrain.test.ts` fails the build
127
- both when a file names a platform and when it reaches for a global outside
128
- the list, and when the list names one the tree has stopped using.
129
-
130
- The package exports the emitted `dist/`, JavaScript with a declaration
131
- beside it, on every specifier, so plain Node imports it; the tree runs the
132
- source directly, and every other terrain reaches a ward through a
133
- bundler. `test/bundle.test.ts` bundles the three words and runs them, and
134
- asserts the artefact carries nothing a terrain cannot provide.
135
-
136
- The five algorithms are read out of WebCrypto, which is why the ward names no
137
- package, on any terrain that carries them. `crypto.subtle` is read at every
138
- use and never captured at load, so a page without one, a plain http:// origin
139
- or a sandboxed frame, fails at the first ask with one sentence rather than
140
- deep inside a key import. The floor is probed in `test/floor.test.ts`, the
141
- arithmetic is `src/ward/arithmetic.ts` and the seal is `src/ward/seal.ts`.
142
-
143
- ## The being side
144
-
145
- Silence is the symbol `quo.silence` and a word is a frozen object under the
146
- symbol key `quo.word` holding its name, both from `src/being/silence.ts`;
147
- `isWord` and `wordOf` read them, and `isUnreached` is the one word a being
148
- asks about most. `told` names a word and leaves everything else exactly as it
149
- came, so asking which word arrived is one comparison rather than two joined by
150
- an and: `told(out) === 'late'`. A kit in another language spells it however
151
- that language spells one value standing for either, and owes nothing here.
152
-
153
- The digest is `src/being/digest.ts`.
154
-
155
- ### The base class
156
-
157
- The kit offers a base class, `Being` in `src/being/being.ts`, which is a
158
- convenience and not Quo:
159
-
160
- - `static cells` are her defaults, merged at birth only where a key is
161
- missing, so a restart keeps what she wrote.
162
- - `static asks` declares what she can be asked, name to
163
- `{ description?, input?, output?, for? }`, in blueprint order.
164
- `for(occupant, asker)` decides whether this asker sees the ask, and so
165
- whether this asker may call it: what she shows is what she can be asked,
166
- one gate for describe and for dispatch.
167
- - Both statics are read off the class the object was made from, and a
168
- subclass that declares either **replaces** its parent's rather than adding
169
- to it. That is the rule and not an oversight: a being's blueprint is
170
- exactly what the class in front of you declares, in the order she chose,
171
- and a merge would hand her asks she may mean to drop and an order she did
172
- not write. A subclass that means to extend says so, in one spelling,
173
- `static override asks = { ...Parent.asks, mine: {} }`, and the same for
174
- cells. A parent that means to be subclassed at all annotates rather than
175
- infers, `static override cells: JsonObject = { ... }`, since this language
176
- holds a subclass's static side to its parent's and would otherwise refuse a
177
- subclass declaring fewer keys than the parent happened to write.
178
- - `answer` is written for her. The empty ask is `describe(asker)`, which she
179
- may override by hand. A named ask calls the method of that name with
180
- `(args, asker)`. Anything not declared, hidden from this asker, or
181
- inherited from Object's prototype is `{ error: 'unknown ask' }` and the
182
- method is never entered.
183
- - A declared ask with no method, or one named after the base's own members,
184
- fails at birth, loudly, so a boot fails and nothing half-lives. The
185
- method is one on her prototype chain below Object's: a class field
186
- holding a function is not there yet when the base checks, and the
187
- refusal says so.
188
- - `occupant(asker)` is the occupant record for whoever is at the door, and
189
- undefined at a public being. `invite`, `knock`, `take`, `boot`, `cells`,
190
- `standings` and `occupants` reach the stance and nothing else.
191
-
192
- ### Examples
193
-
194
- The smallest being. Answers whoever her ward names, describes one ask.
195
-
196
- ```js
197
- class Echo {
198
- constructor(stance) {
199
- this.s = stance;
200
- }
201
- answer(asker, method, args) {
202
- if (method === undefined) return { asks: [{ name: 'echo', input: {} }], notes: {} };
203
- return { from: asker.id ?? null, ...args };
204
- }
205
- }
206
- ```
207
-
208
- A shop. Invites in her own time, hands the invitation out by any channel,
209
- and takes a guest back only if the guest offers a way.
210
-
211
- ```js
212
- class Shop {
213
- constructor(stance) {
214
- this.s = stance;
215
- }
216
- async invite(name) {
217
- const id = `g-${name}`;
218
- const inv = await this.s.occupants.invite(id);
219
- this.s.cells.occupants[id].notes.expireAt = 2028; // hers, not Quo's
220
- return inv; // goes by mail
221
- }
222
- async answer(asker, method, args) {
223
- if (method === undefined) return { asks: [{ name: 'hello', input: {} }], notes: {} };
224
- if (asker.id === undefined) return { welcome: false }; // a stranger at the public door has no record
225
- const rec = this.s.cells.occupants[asker.id];
226
- if (method === 'hello' && args.invitation) {
227
- const back = await this.s.standings.knock(args.invitation, 'hi');
228
- if (back !== silence && !isUnreached(back))
229
- await this.s.standings.take(`back-${asker.id}`, args.invitation);
230
- }
231
- return { welcome: rec.notes.expireAt > 2026 };
232
- }
233
- }
234
- ```
235
-
236
- A guest. Consumes an invitation, and only then decides to keep the shop.
237
-
238
- ```js
239
- class Guest {
240
- constructor(stance) {
241
- this.s = stance;
242
- }
243
- async join(invitation) {
244
- const mine = await this.s.occupants.invite('shop'); // so the shop can reach me
245
- const out = await this.s.standings.knock(invitation, 'hello', { invitation: mine });
246
- if (out === silence || isUnreached(out)) return out; // nothing was born
247
- await this.s.standings.take('shop', invitation); // now, and only now
248
- return out;
249
- }
250
- answer(asker, method) {
251
- if (method === undefined) return { asks: [{ name: 'hi', input: {} }], notes: {} };
252
- return { heard: method };
253
- }
254
- }
255
- ```
256
-
257
- A relay. Forwards every ask to one standing and never looks inside, and asks
258
- for a short wait because she is one door of several. Silence passes through
259
- her; a word does not, since a word out of a being is `threw` at the door,
260
- D13, so she says it as an error of her own.
261
-
262
- ```js
263
- class Relay {
264
- constructor(stance) {
265
- this.s = stance;
266
- }
267
- async answer(asker, method, args) {
268
- const out = await this.s.standings.next.ask(method, args, { time: 2000 });
269
- return isWord(out) ? { error: wordOf(out) } : out; // unreached and late reach her asker as an error, not as a throw
270
- }
271
- }
272
- ```
273
-
274
- A watcher. Notices a standing changed shape, then decides.
275
-
276
- ```js
277
- class Watcher {
278
- constructor(stance) {
279
- this.s = stance;
280
- }
281
- async answer(asker, method, args) {
282
- if (method === undefined) return { asks: [{ name: 'poke', input: {} }], notes: {} };
283
- const out = await this.s.standings.src.ask('read', args);
284
- const rec = this.s.cells.standings.src;
285
- if (rec.seen !== rec.digest) {
286
- const bp = await this.s.standings.src.ask(); // refresh, or
287
- if (!bp?.asks.some((a) => a.name === 'read')) this.s.standings.remove('src'); // walk away
288
- }
289
- return out;
290
- }
291
- }
292
- ```
293
-
294
- ## The ward side
295
-
296
- The protocol names the ground as nine capabilities and leaves how they are
297
- gathered to a kit. This kit gathers them into one object, `Ground` in
298
- `src/ward/ground.ts`, with one name each:
299
-
300
- ```
301
- ground
302
- seed bytes, or a string. 32 bytes are the seed; anything else is SHA-256'd to 32 bytes first.
303
- memory the partition. an object.
304
- instantiate (class name, stance) -> object | null
305
- carry (ward pk, bytes) -> bytes | undefined undefined: no door was reached. a throw is read the same.
306
- random (n) -> n bytes of entropy
307
- wrote (row) -> nothing. said after every write, naming the row: a being by her key, or HEAD. left out by a harbor that keeps nothing.
308
- keep () -> kept. asked once at the end of an arrival, before the reply is sealed. false makes that ask a failed one. left out by a harbor that keeps nothing.
309
- calling () -> lower. raised when a being reaches out, lowered when that call ends. left out by a harbor that keeps nothing.
310
- lend lend(name, take) -> taken. left out by a harbor that lends nothing.
311
- ```
312
-
313
- Beside that contract are the three pieces every harbor in this kit builds one
314
- out of: `maker`, the code half, which finds a class by own key in the first
315
- registry that holds it and remembers the object by the cells; `entropy`, the
316
- one line every terrain has; and `learnPk`, the empty ask, since a harbor
317
- learns its ward's pk the way anyone learns anything and has no second
318
- derivation to keep in step. They are convenience and never contract: a kit
319
- writes its own harbor, and may write these again.
320
-
321
- The cells guard is `src/ward/cells.ts`. Beside the nesting bound the protocol
322
- sets, it refuses a hole in a list, an accessor and a key named `__proto__`,
323
- because this runtime reads each one back as something JSON never wrote. The
324
- same guard reads args at the seal and her answer at the door.
325
-
326
- It also bounds breadth, at `BREADTH`, a million values, which is this kit's
327
- number and no word of the protocol: a bound on what a being holds is never
328
- the protocol's business, and what crosses is bounded in bytes at the seal.
329
- Depth alone does not bound what a value costs to keep. One subvalue may sit
330
- under two keys, and nesting that forty levels deep is inside the nesting
331
- bound and is a trillion values once written down. So the walk counts the tree
332
- while it proves the graph, and a value already counted is a value already
333
- proven: a graph that shares is walked once per node and never once per path,
334
- which is the difference between a guard and a ward stopped by one write.
335
-
336
- The names this kit reserves beyond `OWNER` and `PUBLIC` are `__proto__`,
337
- `knock`, `take` and `remove`. The last three are the calls on `standings`,
338
- which is an object here whose methods are named on the same face as her ids,
339
- so a standing under one of them would be unreachable. A kit with free
340
- functions has no such collision, and no far ward can tell either way, because
341
- an id never crosses a door.
342
-
343
- This ward's allowance is thirty seconds by default and five minutes at the
344
- ceiling, in `src/ward/allowance.ts`. Those two numbers are a ward's own
345
- policy, never negotiated and never on the wire.
346
-
347
- The partition shape is `src/ward/partition.ts`, and the three bounded lists
348
- the protocol leaves to a ward are numbers here: eight pks under `minted`,
349
- and `gone` and `knocks` bounded the same way, oldest out. `last` on the heir
350
- is the cut slot for a reply a later version might keep; nothing writes it and
351
- nothing reads it.
352
-
353
- The seal is `src/ward/seal.ts` and the arithmetic is `src/ward/arithmetic.ts`.
354
- `SIZE` there is the protocol's one mebibyte, read before an ask is opened and
355
- before a reply is. `test/ward.test.ts` reads every byte string that crossed,
356
- so that nothing inner is readable in the bytes.
357
-
358
- An ask over two wards on two harbors spends thirty-four calls into
359
- `crypto.subtle`, fourteen of them key imports, and `test/cost.test.ts` holds
360
- it to forty and sixteen. Importing a key is the most expensive thing on that
361
- path and most of the imports are the same key again: a ward signs every reply
362
- with one key, opens every ask with one padlock, and verifies a relation under
363
- the key it verified it under last time. So the arithmetic keeps an imported
364
- key by the bytes it was imported from, and the public half beside the key it
365
- was read from. The cache is bounded at `KEYS`, five hundred and twelve, least
366
- recently used out, because a relation mints a fresh key on every ask and one
367
- that only grew would hold a key for every ask a ward ever made. None of it is
368
- a decision a peer can see: a kit that caches nothing speaks the same bytes,
369
- which is why this is the kit's paper and not the protocol's.
370
-
371
- ## The harbor side
372
-
373
- The **store** is `src/harbor/store.ts`, the **reach** is
374
- `src/harbor/reach.ts`, the **harbor core** is `src/harbor/core.ts` and the
375
- **dialer** is `src/harbor/dial.ts`. Both kinds of reach are written on the
376
- standard surface every terrain carries, fetch and WebSocket. The memory store
377
- beside the store interface is the kit's own; a disk, a tab and an edge object
378
- each have theirs, outside this tree, and every one of them passes
379
- `src/conformance/store.ts` untouched, as every reach passes
380
- `src/conformance/reach.ts`.
381
-
382
- A store keeps a ward in rows. A being's cells are the one part of a partition
383
- that grows without limit, so she is a row of her own, her cells and her bind
384
- table under her key; everything else is one head row, and every part of that
385
- is bounded already. `wrote` names the row, the harbor gathers the names into
386
- the burst it saves, and `save` is handed them beside the partition. What a
387
- store does with them is its own: `rowsOf` in `src/harbor/store.ts` is what
388
- one writing the few uses, and one writing all of it every time is correct and
389
- slower. The split itself is `src/ward/partition.ts`, where the shape is, so
390
- that a harbor keeps what it is given and reads none of it, and a field that
391
- file grows later needs no line in any store to survive a round trip.
392
-
393
- A refused save stands the ward at what is kept, and the harbor holds that
394
- point itself rather than asking the store for it: `kept` in
395
- `src/harbor/core.ts` is the copy of every row handed to a save that succeeded
396
- while no call of that ward was in flight, seeded at host from the partition as
397
- it was hosted. A call the ward names through `calling` moves nothing: what a
398
- save takes under one is written and is recorded apart, and it joins the point
399
- when the call ends and the ward is whole again. A refusal puts the whole point
400
- back, in memory and in the store together, and a refusal met under a call is
401
- answered no there and put back when the call ends. No save waits for a call:
402
- the store is what survives a restart, and an ask still costs thirty-four calls
403
- into subtle and about a millisecond and a half on a quiet Mac.
404
-
405
- The dialer's wait doubles from a second to thirty when a line drops, and
406
- returns to that first second where the far side announced and was taken.
407
- Those are this harbor's numbers: what a far side sees is only that a dialer
408
- refused for a suite waits.
409
-
410
- ## The memory harbor
411
-
412
- The memory harbor, `src/harbor/memory.ts`, is one process and no wire. It
413
- keeps partitions by seed, routes its own doors, and may be linked to peers,
414
- which stands in for a wire, and cut, which stands in for weather. It routes
415
- one hop: a pk that is not its own and not a direct peer's is nothing. It
416
- keeps no lease: two of them may hold one seed and one partition, which is
417
- the broken vouch every real harbor refuses, kept here so that the tests can
418
- show what divergence looks like. Every ward and being assertion in the tree
419
- is made on it first, so that the network never hides a fault in the words;
420
- the harbor core then passes the same suite over memory stores.
421
-
422
- ## The suites
423
-
424
- The beings are fixed and the ward is what is tested. A ward kit in any
425
- language offers the ground, the door, and the owner's ask as written, and
426
- passes the same suite. Those tests are the checklist, not the mock.
427
-
428
- - `test/being.test.ts`: the base class against a stance stub. No ward, no
429
- harbor. Defaults, describe, dispatch, the gate, the reserved names, the
430
- digest.
431
- - `src/conformance/index.ts`: one suite of behaviours, written against the
432
- stance and one probe. The suite is this kit's, not the protocol's: what a
433
- ward owes outward is its door, and `quo/SPEC.md` names that byte for byte
434
- and says nothing about a harness. `World` is the probe, six obligations a
435
- ward must meet to be put under this suite, and `conform` takes a call that
436
- makes one: boot a being of a named class and say which key she has; hand
437
- over the ward's ask pointer, so the suite pilots it as its owner; show the
438
- heir table and the bind table as values, read and never written, so the
439
- suite sees that a refusal wrote nothing and a knock bound what it should;
440
- boot a ward from a partition it is handed, which proves a restart and an
441
- adoption; move a ward between harbors keeping its pk, which proves a
442
- relation survives the move; and produce a knock signed with a key nobody
443
- announced, the one thing the suite sends through a door as a stranger
444
- would. A ward that cannot meet one of them under the topology it runs in
445
- says so at the call, and the chapters that need it skip by name rather
446
- than pass in silence. Another kit ports this shape or writes its own.
447
- With the beings in `src/conformance/beings.ts`: a
448
- printer, a shop, two customers, one raw being with no base class, and a
449
- member of an estate. The probe is asked to build a world, and what it is
450
- asked for includes what the box lends: a name and the class of the being
451
- it lends under it. The harness stands one of each in a ward its harbor
452
- roots and grounds every ward it boots to lend them, which is how the
453
- seventh member is reached from inside the suite. A harness with no such
454
- ward to stand says `canLend: false` at the call and that chapter skips,
455
- named, the way `canDown` already works. Any ward must pass it, under any
456
- topology.
457
- - `src/conformance/estate.ts`: the estate, and the last chapter of that
458
- suite. Every other chapter is a scene: three beings, one move, one answer.
459
- This one is a graph under churn, which is the shape an organisation running
460
- on Quo actually has -- scattered wards on scattered harbors, partners and
461
- employees invited, knocking, taken, kicked, and moving to harbors of their
462
- own. It keeps a model of the graph, plays legal moves against it from three
463
- fixed seeds, and after every move holds two things: that the ledger every
464
- ward keeps closes on both ends, and that every arc in it answers when asked
465
- exactly what being that arc means. The second is held under all three
466
- topologies, and that is the promise of Quo at a scale a scene cannot
467
- reach: the model never learns the topology, so neither may any answer. The
468
- model is the script's own bookkeeping and is never compared with itself
469
- across topologies, which would hold by construction and prove nothing. A
470
- relation is two arcs and never one edge:
471
- the occupant is the host's, the standing is the guest's, and the model
472
- keeps them apart because the ward does. A red run prints its seed and the
473
- moves that got there. It is read beside one hand-written story that says in
474
- prose what the model is for.
475
- - `test/ward.test.ts`: the conformance suite against the real ward under
476
- three topologies over the memory harbor, one ward, one harbor with a ward
477
- per being, two harbors; and what only a real ward can be asked: the
478
- owner's asks, the door judged byte by byte, rotation and a lost reply,
479
- replay, a restart, and every byte on the wire inspected for anything inner.
480
- - `test/public.test.ts`: the public being, what the door does and does not
481
- do for her.
482
- - `test/silence.test.ts`: the protocol's chapter "Silence, the words, error"
483
- by its numbers: the five cases and two unreacheds of her ward, the thirteen
484
- cases of the door with a partition snapshot under each, seven strangers
485
- met with one silence and six bound keys hearing their word, hops refused
486
- at zero, and the six lines of the law of one silence. The world it runs in
487
- and the thirteen cases as records are the vector shelf, `src/vector/`,
488
- which draws no entropy from the device: every byte comes from one
489
- SplitMix64 stream, so the cases are the same bytes twice. The suite reads
490
- `protocol/vectors/door.json` and holds the tree to it, and the two laws it
491
- states over the whole list, one length for every stranger and one
492
- plaintext under the box, run over the corpus rather than a table beside
493
- it. `test/write-door-vectors.ts` writes that corpus, by a hand and never
494
- by the gate: a diff in it is a protocol change.
495
- - `test/vector.test.ts`: vector mode, held to the spec's chapter. The
496
- verifier's round on every record with no key in hand, stand, ask, digest,
497
- against the handler in process; a record stood alone and out of order;
498
- nothing delivered before a stand, for a record not in the corpus, a suite
499
- the door does not speak or a pk it does not hold; every answer open to
500
- any origin; and the same round over `test/stand.ts` on loopback with
501
- fetch and nothing else.
502
- - `test/blueprint.test.ts`: blueprints and instantiation through a real
503
- ward. What a boot leaves behind, what a restart brings back when the code
504
- moved under the cells, the gate and the door, the reserved ids.
505
- - `test/allowance.test.ts`: the allowance. Default, ceiling, nonsense, the
506
- bound, the signed body, the door's refusal, and one ask through a ward.
507
- - `test/lend.test.ts`: `lend`, the ground's last member, over two real wards
508
- on one memory harbor. The ground answers an invitation and the ward knocks
509
- and takes it, so a being is handed an id and never the value; null is every
510
- kind of no; a being of the harbor's own ward wakes her by holding a
511
- standing she minted, and her door names it as the occupant she chose;
512
- removing that occupant is the whole of unsubscribe; the relation is born
513
- again under the same id; a taker that will not take leaves the faculty no
514
- occupant and no key, and the next lend stands; and a being taken out of her
515
- ward lends nothing.
516
- - `test/seal.test.ts`: the arithmetic against `protocol/vectors/arithmetic.json`,
517
- then the seal, round trip, and what it refuses; then the framing against
518
- `protocol/vectors/framing.json`. The arithmetic is standard and any language has
519
- it. The framing is Quo's own, and a kit that reproduces the hashes and
520
- not the ward pk, the digest, the signed ask body, the two sealed shapes,
521
- the invitation or the knock is not this protocol. Every seed in that file
522
- is fixed, so every output is fixed. The ask body is the payload as JSON
523
- and is not canonical: the vectors pin the order the type declares, and a
524
- kit that emits another order interoperates, because a door verifies the
525
- bytes it received, and will not reproduce the vectors. `hops` is in no
526
- vector, because nothing sets it. The invitation is JSON too, and the
527
- knock is pinned as the ask it is, by the heir, to the heir, announcing
528
- the knocker's own key, and then proven at a real door: a ward booted on
529
- the vector's seed, drawing the heir secret as its first entropy, mints
530
- the invitation vector, binds the knock vector at its door, answers it,
531
- spends the heir, and refuses the same bytes again.
532
- - `test/break.test.ts`: adversarial probes. Each states what the protocol
533
- promises, then tries to break it.
534
- - `test/gaps.test.ts` and `test/gaps2.test.ts`: cases the memory harbor
535
- cannot express because it is honest, in-order and lossless: a lost reply,
536
- a cycle, a partition written down and read back, a long relation, one
537
- seed booted twice. Each test is a claim that the ward is wrong; one that
538
- will not go red is not a bug.
539
- - `src/conformance/store.ts`: the store suite, written against the store
540
- interface alone and handed a maker of fresh stores. A fresh store keeps
541
- nothing; what was put comes back as it went in, as values and not as the
542
- object; a name already kept is refused; save and record touch only their
543
- part and are nothing on a name not kept; take hands a ward out and frees
544
- the name; hints are kept by pk and the last one wins.
545
- - `src/conformance/reach.ts`: the reach suite, written against the reach
546
- interface alone and handed a far side it controls: a door held behind a
547
- pk over there, and the far side dropped. The door's bytes come back;
548
- nothing for a pk nobody holds; asks in flight at once each get their own
549
- answer; what crosses is a copy both ways; and once the far side is gone,
550
- nothing. It cannot assert that a reach which sent and then lost the line
551
- answers nothing at all, since a suite cannot wait forever.
552
- - `test/harbor.test.ts`: the harbor pieces on the library's own ground,
553
- no device and no wire. The store suite against the memory store; the
554
- reach suite against the socket framing over two lines in one process, so
555
- the frames are asserted with no network under them; the conformance
556
- suite against two harbor cores over memory stores reaching each other
557
- in-process, drop and adopt as the migration; a ward that moves harbor
558
- keeping its pk and every relation, the rendezvous told on the line in
559
- hand; a ward booted or dropped after a line opened, announced on that
560
- line, and a claim on a pk nobody holds binding nothing; a restart from
561
- the store with the hints; the dialer over a stubbed line, announce, a claim proven
562
- at a real door before it binds and a claim nobody there holds left
563
- unbound, fallback, unbind and the wait before it dials again; and the frames against
564
- `protocol/vectors/wire.json`, the ask, the reply, nothing delivered and the
565
- announce, so a kit reproduces the bytes on a socket; and the request
566
- reach against the request record in the same file, over a fetch that
567
- sees what a listener would, one POST with the suite in its header, the
568
- reply as a 200 and nothing delivered as a 404. A socket to a real
569
- listener and every real store pass the same suites outside this tree.
570
- - `test/terrain.test.ts`: the terrain census. Nothing under `src/being/`,
571
- `src/ward/`, `src/harbor/` or `src/conformance/` names a runtime, and
572
- nothing reaches for a global outside the ones it names; nor does the
573
- census name one the tree has stopped using. It reads the source as text
574
- and not as a parse: it is there to catch drift, and does not pretend to
575
- stop someone determined to get around it.
576
- - `test/assert.test.ts`: `src/conformance/assert.ts` against
577
- `node:assert/strict`, pair by pair. The suite means the same thing on
578
- every terrain only if those two agree, so they are compared and not
579
- trusted.
580
- - `test/floor.test.ts`: the five algorithms this terrain must carry, probed
581
- one by one; that the arithmetic spends every one of them; and the two ways
582
- a terrain can be short -- no `crypto.subtle` at all, and a subtle without
583
- the curves -- each failing at the first call, in one sentence.
584
- - `test/cost.test.ts`: what an ask costs. Every other suite is blind to it:
585
- a change that doubles the work per ask leaves all of them green. The
586
- assertion is the count of calls into `crypto.subtle`, which is the same
587
- number on every terrain and does not move because another lane of the gate
588
- is running; a regression in it is somebody deriving again what the ward
589
- already holds. Beside it, that the kept keys stay under their bound however
590
- long a ward talks, and one wall clock that prints what an ask took and
591
- asserts nothing, because the gate runs every file at once and a clock there
592
- measures the machine.
593
- - `test/package.test.ts`: the package as a stranger meets it. The tarball
594
- is packed, installed into an empty folder with nothing but Node, and
595
- every entry point the exports map names is imported. Every other suite
596
- reaches the source through a path or a workspace link, which resolves
597
- outside `node_modules`, where Node strips types; this is the one that
598
- cannot.
599
- - `test/bundle.test.ts`: the three words bundled as a consumer must bundle
600
- them, the artefact read for anything a terrain cannot provide, and then the
601
- whole conformance suite run out of the bundle.
602
- - `test/terrain/browser.test.ts`, `test/terrain/edge.test.ts`,
603
- `test/terrain/deno.test.ts` and `test/terrain/bun.test.ts`: that same
604
- bundle and that same suite in a real Chromium, in workerd, in Deno and in
605
- Bun, plus each terrain's floor, and, for the browser, a page whose
606
- `crypto` has no `subtle`. Deno runs it a second time with every permission
607
- denied but read -- no net, no environment, no write, no subprocess -- which
608
- is where a ward that had quietly come to need one of them would fail, and
609
- nowhere else in this repository. A terrain whose binary is absent skips and
610
- names the command that installs it; it never passes quietly.
611
- `test/terrain/engine.ts` runs the bundle in another engine on this machine.
612
- Behind `npm run deep:nervur`. `test/terrain/bundle.ts` is the
613
- bundler and the reference run, `test/terrain/exercise.ts` is what every
614
- terrain runs, `test/terrain/floor.ts` is the floor -- each written once, so
615
- no terrain can be probed for less than another.
616
- - `test/world.ts`: the memory-harbor probe and the three topologies, held
617
- apart from any one chapter because every terrain drives the same one. It
618
- also answers the two asks the estate needs: the census, which is every
619
- partition in the world as values, and a migration, which lifts a partition
620
- out of one harbor and boots it from the same seed in the other -- same
621
- seed, same pk, so every standing anyone holds still points at her.
622
- - `test/repo.test.ts`: the papers, the README and the project instructions
623
- against the repository: every path they name exists, every
624
- source file carries its licence, the package names no host and no user,
625
- the awaitable calls are marked and
626
- awaited in the examples above, the allowance is decided in the protocol and
627
- off its Open list, and the allowance is time alone on both sides of the
628
- door.
629
-
630
- The conformance suite is checkable wherever a ward runs. Its runner is handed
631
- in, and the five assertions it makes are `src/conformance/assert.ts`, held to
632
- `node:assert/strict`'s own behaviour by `test/assert.test.ts`.
633
- `test/terrain/exercise.ts` is what every terrain runs -- the whole suite,
634
- under all three topologies, and the floor probe. Node is the reference: no
635
- terrain carries a count of its own, so a test added to the suite is demanded
636
- of every terrain at once. Five run it: Node, a browser, workerd, Deno and
637
- Bun. Bun is the one that is not V8, so "the language alone" is checked
638
- against two implementations of the language and not one.
639
-
640
- ## The gate
641
-
642
- The gate is `npm run check`: typecheck under TypeScript 7, oxlint with
643
- type-aware rules, markdownlint, then every suite under `node --test`. There
644
- is no CI; the gate runs in seconds and is run before every commit. Nothing
645
- red is committed except a test marked todo, which is a claim the tree does
646
- not yet meet and says so.
647
-
648
- `npm run check` is Node alone, and stays fast. `npm run deep:nervur` is
649
- every other terrain, the browser, workerd, Deno and Bun, kept apart because
650
- each is a binary of its own and the browser is a download and not a
651
- package: a fresh clone needs `npx playwright install chromium` first, and is
652
- told so in one sentence rather than a stack trace.