@quo-systems/quo 0.2.9 → 0.2.11
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 +19 -10
- package/SPEC.md +301 -110
- package/dist/being/being.d.ts +2 -2
- package/dist/being/being.js +34 -12
- package/dist/being/digest.js +26 -8
- package/dist/being/index.d.ts +2 -2
- package/dist/being/index.js +2 -2
- package/dist/being/silence.d.ts +2 -0
- package/dist/being/silence.js +12 -0
- package/dist/being/types.d.ts +4 -2
- package/dist/being/types.js +25 -0
- package/dist/conformance/assert.js +40 -6
- package/dist/conformance/beings.d.ts +48 -5
- package/dist/conformance/beings.js +39 -8
- package/dist/conformance/estate.js +110 -21
- package/dist/conformance/index.d.ts +5 -2
- package/dist/conformance/index.js +165 -7
- package/dist/harbor/core.d.ts +5 -2
- package/dist/harbor/core.js +195 -45
- package/dist/harbor/dial.js +32 -15
- package/dist/harbor/index.d.ts +1 -0
- package/dist/harbor/index.js +3 -0
- package/dist/harbor/memory.d.ts +3 -3
- package/dist/harbor/memory.js +7 -12
- package/dist/harbor/reach.js +42 -17
- package/dist/ward/allowance.js +15 -4
- package/dist/ward/arithmetic.d.ts +1 -0
- package/dist/ward/arithmetic.js +22 -6
- package/dist/ward/cells.d.ts +3 -1
- package/dist/ward/cells.js +79 -21
- package/dist/ward/door.d.ts +3 -2
- package/dist/ward/door.js +38 -10
- package/dist/ward/ground.d.ts +5 -1
- package/dist/ward/ground.js +38 -1
- package/dist/ward/heirs.d.ts +2 -3
- package/dist/ward/heirs.js +19 -13
- package/dist/ward/index.d.ts +1 -0
- package/dist/ward/index.js +3 -0
- package/dist/ward/owner.d.ts +6 -27
- package/dist/ward/owner.js +59 -33
- package/dist/ward/partition.d.ts +3 -0
- package/dist/ward/partition.js +109 -4
- package/dist/ward/seal.d.ts +1 -0
- package/dist/ward/seal.js +41 -13
- package/dist/ward/stance.d.ts +7 -3
- package/dist/ward/stance.js +156 -66
- package/dist/ward/ward.d.ts +10 -0
- package/dist/ward/ward.js +123 -51
- package/package.json +4 -2
- package/src/being/being.ts +33 -11
- package/src/being/digest.ts +28 -13
- package/src/being/index.ts +2 -2
- package/src/being/silence.ts +14 -0
- package/src/being/types.ts +39 -5
- package/src/conformance/assert.ts +37 -4
- package/src/conformance/beings.ts +41 -10
- package/src/conformance/estate.ts +107 -20
- package/src/conformance/index.ts +188 -13
- package/src/harbor/core.ts +203 -46
- package/src/harbor/dial.ts +46 -17
- package/src/harbor/index.ts +3 -0
- package/src/harbor/memory.ts +8 -13
- package/src/harbor/reach.ts +47 -21
- package/src/ward/allowance.ts +15 -4
- package/src/ward/arithmetic.ts +25 -8
- package/src/ward/cells.ts +76 -25
- package/src/ward/door.ts +38 -12
- package/src/ward/ground.ts +52 -3
- package/src/ward/heirs.ts +19 -13
- package/src/ward/index.ts +3 -0
- package/src/ward/owner.ts +65 -46
- package/src/ward/partition.ts +109 -5
- package/src/ward/seal.ts +41 -12
- package/src/ward/stance.ts +163 -64
- package/src/ward/ward.ts +124 -52
- package/vectors/arithmetic.json +7 -0
- package/vectors/framing.json +30 -15
- package/vectors/wire.json +4 -4
package/SPEC.md
CHANGED
|
@@ -86,11 +86,20 @@ ground
|
|
|
86
86
|
instantiate (class name, stance) -> object | null
|
|
87
87
|
carry (ward pk, bytes) -> bytes | undefined undefined: no door was reached. a throw is read the same.
|
|
88
88
|
random (n) -> n bytes of entropy. every key a ward mints is drawn from it.
|
|
89
|
+
wrote () -> nothing. the ward says it after every write to its partition, and nothing else:
|
|
90
|
+
a harbor that keeps the partition saves after it, when it likes and in the order
|
|
91
|
+
it was told. a harbor that keeps nothing leaves it out.
|
|
89
92
|
```
|
|
90
93
|
|
|
91
|
-
Nothing else is ever passed. A harbor that needs a
|
|
94
|
+
Nothing else is ever passed. A harbor that needs a seventh thing has found a
|
|
92
95
|
gap in Quo or a leak into the ward. The shape is `Ground` in
|
|
93
|
-
`src/ward/ground.ts
|
|
96
|
+
`src/ward/ground.ts`, and beside it are the three pieces every harbor in this
|
|
97
|
+
kit builds one out of: `maker`, the code half, which finds a class by own key
|
|
98
|
+
in the first registry that holds it and remembers the object by the cells;
|
|
99
|
+
`entropy`, the one line every terrain has; and `learnPk`, the empty ask, since
|
|
100
|
+
a harbor learns its ward's pk the way anyone learns anything and has no second
|
|
101
|
+
derivation to keep in step. They are convenience and never contract: a kit
|
|
102
|
+
writes its own harbor, and may write these again.
|
|
94
103
|
|
|
95
104
|
Returned:
|
|
96
105
|
|
|
@@ -101,7 +110,9 @@ Returned:
|
|
|
101
110
|
harbor learns from an arrival, never a reason: a pk that only ever brings
|
|
102
111
|
strangers' bytes is the harbor's to rate or refuse, and what a bound key
|
|
103
112
|
hears is sealed to its own lid.
|
|
104
|
-
- **The ask.** One call: method and args in,
|
|
113
|
+
- **The ask.** One call: method and args in, a value or silence out. A value,
|
|
114
|
+
not an object: what a being answers is held to the value rule and nothing
|
|
115
|
+
narrower, so a string, a number and an array are all answers.
|
|
105
116
|
In-process and unsealed. This is the one unsealed ask in Quo, and the only
|
|
106
117
|
way a ward is piloted. Judgment, catching, and the return table are not
|
|
107
118
|
skipped: a throw inside is silence, and an unreached shape is silence.
|
|
@@ -133,7 +144,7 @@ ever offered, and nothing here may be missing.
|
|
|
133
144
|
stance
|
|
134
145
|
cells her state. values only.
|
|
135
146
|
|
|
136
|
-
occupants.invite(id)
|
|
147
|
+
occupants.invite(id, notes?) -> invitation | null awaitable: a key is minted
|
|
137
148
|
occupants.remove(id) -> nothing
|
|
138
149
|
|
|
139
150
|
standings.knock(invitation, method?, args?, wanted?) -> object | silence | word
|
|
@@ -142,7 +153,8 @@ stance
|
|
|
142
153
|
standings[id].ask(method?, args?, wanted?) -> object | silence | word
|
|
143
154
|
standings.remove(id) -> nothing
|
|
144
155
|
|
|
145
|
-
boot(class, key)
|
|
156
|
+
boot(class, key, id?) -> key | null a new being of her ward, by class name.
|
|
157
|
+
with an id, her standing to her under it
|
|
146
158
|
|
|
147
159
|
wanted = { time? } what this one ask may spend, in milliseconds. optional,
|
|
148
160
|
and so is saying anything at all
|
|
@@ -152,7 +164,7 @@ Return table.
|
|
|
152
164
|
|
|
153
165
|
| call | returns | when |
|
|
154
166
|
| ------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
|
|
155
|
-
| invite(id)
|
|
167
|
+
| invite(id, notes?) | invitation | she minted a fresh id; the occupant record exists from now, with those notes on it |
|
|
156
168
|
| | null | the id already names a record, occupant or standing, or is a reserved word |
|
|
157
169
|
| remove(id) | nothing | always. removing what is not there is nothing |
|
|
158
170
|
| knock(inv, m, a, w) | object | the far being answered |
|
|
@@ -166,17 +178,25 @@ Return table.
|
|
|
166
178
|
| ask(m, a, w) | object | she answered |
|
|
167
179
|
| | silence | she chose to say nothing, or bytes came back that are not Quo's |
|
|
168
180
|
| | word | why not: removed, absent, repeated, threw, unreached, late, dropped |
|
|
169
|
-
| boot(
|
|
170
|
-
| | null | the key is already booted, the harbor holds no such class,
|
|
181
|
+
| boot(cls, key, id?) | key | she exists from now, with fresh cells, and a restart finds her; with an id, her maker holds her standing |
|
|
182
|
+
| | null | the key is already booted, the harbor holds no such class, the class threw at birth, the id is one the maker |
|
|
183
|
+
| | | already holds or a reserved word, or the relation was refused; nothing of the being made is left |
|
|
171
184
|
|
|
172
185
|
A being may make, and only the owner reaches into another. Boot touches
|
|
173
|
-
nobody: the being made has empty cells and no relation
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
186
|
+
nobody else: the being made has empty cells and no relation but the one her
|
|
187
|
+
maker named, and every other is invited and taken like any other. That one is
|
|
188
|
+
made the way all of them are, and it is the whole of what making gives: the
|
|
189
|
+
being made mints an occupant for her maker under the maker's own key, so she
|
|
190
|
+
knows who made her by that name and by nothing else, and her maker knocks
|
|
191
|
+
with it and takes the standing under the id she gave. Naming no id makes no
|
|
192
|
+
relation at all, and a being made that way is reachable by the owner alone. A
|
|
193
|
+
relation that could not be made is a boot that made nobody: the being made
|
|
194
|
+
goes out again, and nobody saw her, since she is a moment old and named to
|
|
195
|
+
no one yet. What the owner has that the maker does not is every ask that
|
|
196
|
+
reaches into a being from outside: public, invite and knock for her, remove,
|
|
197
|
+
unboot. Who may ask her to boot is her gate, as who may ask her anything is.
|
|
198
|
+
|
|
199
|
+
Ask, knock, invite, take and boot are awaitable. Async where the language has it,
|
|
180
200
|
blocking where it does not. Every ask she makes is a new call.
|
|
181
201
|
|
|
182
202
|
The asker has three shapes and no fourth, and nothing else ever reaches her.
|
|
@@ -281,8 +301,8 @@ S4 the reply is not one bytes came back that do not open, or are n
|
|
|
281
301
|
S5 the far door answered silence, or a word, exactly as the door said it.
|
|
282
302
|
```
|
|
283
303
|
|
|
284
|
-
And unreached in two: `U1` the args are not
|
|
285
|
-
sealed, so nothing left;
|
|
304
|
+
And unreached in two: `U1` the args are not one object of values, or could
|
|
305
|
+
not be sealed, so nothing left;
|
|
286
306
|
`U2` the harbor returned nothing, or threw, so no door was reached. The number is
|
|
287
307
|
taken all the same, and the gap it leaves in the count is harmless: the door
|
|
288
308
|
honours any number above its mark.
|
|
@@ -302,9 +322,9 @@ strangers: silence, nothing written, heard false
|
|
|
302
322
|
D1 the box does not open wrong padlock, garbage, too short. the reply is sealed to the lid if
|
|
303
323
|
the bytes carried one, and is noise otherwise. a lid that will not
|
|
304
324
|
take a seal, a small-order point, is no lid: noise.
|
|
305
|
-
D2 the payload is malformed by or next not 64 hex, method not a string, args
|
|
306
|
-
|
|
307
|
-
number or at zero.
|
|
325
|
+
D2 the payload is malformed by or next not 64 lowercase hex, method not a string, args present and
|
|
326
|
+
not one object of values, seq not a whole number from one, time not a
|
|
327
|
+
whole number above zero, hops not a whole number or at zero.
|
|
308
328
|
D3 for nobody, and nobody is home no public being on this ward.
|
|
309
329
|
D4 for nobody, signature fails the payload names a key it was not signed with.
|
|
310
330
|
D5 the heir is not held never minted here, and not one she removed either.
|
|
@@ -315,12 +335,13 @@ D7 signature fails under an admitted key, or under the key hel
|
|
|
315
335
|
refusals to a bound key: a word, nothing written, heard true
|
|
316
336
|
D8 she is not there `removed`: the occupant record is gone, and this is the key it was
|
|
317
337
|
bound to when it went. `absent`: the being did not come back this run.
|
|
318
|
-
D9 a knock announces nothing `unannounced`: the heir is fresh and next is null
|
|
338
|
+
D9 a knock announces nothing `unannounced`: the heir is fresh and next is null, or is the heir
|
|
339
|
+
itself, which is no key of her own. it binds nothing.
|
|
319
340
|
D10 the number is refused `repeated`: already honoured, or at or below the span.
|
|
320
341
|
choices: the number spent, the keys rotated, heard true
|
|
321
342
|
D11 she threw `threw`
|
|
322
343
|
D12 she answered silence on a named ask, or on the empty ask. nothing at all is silence too.
|
|
323
|
-
D13 she answered a
|
|
344
|
+
D13 she answered a non-value `threw`: a word, a Date, a cycle, a NaN, none is hers to make.
|
|
324
345
|
```
|
|
325
346
|
|
|
326
347
|
The signature is verified before anything is written and before any word is
|
|
@@ -380,7 +401,9 @@ Nothing else is a value: no dates, no references, no functions, no native
|
|
|
380
401
|
types. An id or a standing is never a value.
|
|
381
402
|
|
|
382
403
|
Args are held to the same rule before they are sealed: an ask whose args
|
|
383
|
-
|
|
404
|
+
are not one object of values is unreached, because nothing left. Her answer
|
|
405
|
+
is held to it at the door: a shape that is not a value is `threw` to a bound
|
|
406
|
+
key and silence to a stranger, so nothing crosses altered. Cells hold values and
|
|
384
407
|
refuse anything else at the moment of writing, in her own frame: a Map, a
|
|
385
408
|
Date, a NaN, a cyclic object, a function, an object that is not a plain one.
|
|
386
409
|
The refusal is a throw where she wrote it, which her ward turns into the
|
|
@@ -399,7 +422,10 @@ None is an object, and none carries anything but its name. In this kit
|
|
|
399
422
|
silence is the symbol `quo.silence` and a word is a frozen object under the
|
|
400
423
|
symbol key `quo.word` holding its name, both from `src/being/silence.ts`;
|
|
401
424
|
`isWord` and `wordOf` read them, and `isUnreached` is the one word a being
|
|
402
|
-
asks about most.
|
|
425
|
+
asks about most. `told` names a word and leaves everything else exactly as it
|
|
426
|
+
came, so asking which word arrived is one comparison rather than two joined by
|
|
427
|
+
an and: `told(out) === 'late'`. A kit in another language spells it however
|
|
428
|
+
that language spells one value standing for either, and owes nothing here.
|
|
403
429
|
|
|
404
430
|
### Blueprint, schema, digest
|
|
405
431
|
|
|
@@ -425,6 +451,16 @@ holding what is not a value is dropped before hashing and an array slot
|
|
|
425
451
|
holding one is null, which is what crossing an edge does to them anyway. The
|
|
426
452
|
reference is `src/being/digest.ts`.
|
|
427
453
|
|
|
454
|
+
Two places in RFC 8785 are where languages part, and a kit is held to both by
|
|
455
|
+
`vectors/framing.json`. Keys sort by **UTF-16 code unit**, not by code point
|
|
456
|
+
and not by byte, so an astral character sorts before one in the surrogate
|
|
457
|
+
range: `U+1F600` comes before `U+FB33`, which is the reverse of what a
|
|
458
|
+
language sorting code points gives. Numbers are written as ECMAScript writes
|
|
459
|
+
them, `1e+21` and `1e-7` and `0.3333333333333333`, with a negative zero
|
|
460
|
+
written `0`. A kit that reproduces every ASCII vector and neither of these
|
|
461
|
+
hashes one blueprint to two digests, and every standing between the two wards
|
|
462
|
+
refreshes on every ask.
|
|
463
|
+
|
|
428
464
|
Capability and state are two axes, never mixed.
|
|
429
465
|
|
|
430
466
|
```
|
|
@@ -468,7 +504,12 @@ and take refuse them like the ward's words.
|
|
|
468
504
|
### Cells
|
|
469
505
|
|
|
470
506
|
Cells are I-JSON values. The ward may persist them. A restart is silent: she
|
|
471
|
-
is constructed again with the same cells.
|
|
507
|
+
is constructed again with the same cells. Three keys at their root are the
|
|
508
|
+
ward's, `standings`, `occupants` and `class`, and a write of hers to them is
|
|
509
|
+
refused where she wrote it, like a non-value. A value nested past sixty-four
|
|
510
|
+
levels, a hole in a list, an accessor, and a key named `__proto__` are
|
|
511
|
+
refused the same way: JSON writes each one way and a runtime reads it
|
|
512
|
+
another, so no harbor can keep them.
|
|
472
513
|
|
|
473
514
|
```
|
|
474
515
|
cells
|
|
@@ -479,11 +520,20 @@ cells
|
|
|
479
520
|
```
|
|
480
521
|
|
|
481
522
|
- `digest` is the hash of the blueprint she last fetched by the empty ask.
|
|
482
|
-
|
|
523
|
+
It is over what came back, whatever that was.
|
|
524
|
+
- `blueprint` is that blueprint, and only if it is one. A far describe is
|
|
525
|
+
somebody else's code and may answer any value at all; the ward reads it as
|
|
526
|
+
a blueprint before writing it as one, a list of asks with a name and an
|
|
527
|
+
input each, and writes `null` when it is not. A side walks `asks` by name,
|
|
528
|
+
and a side that broke on a far ward's answer would be one kit made wrong
|
|
529
|
+
by another. The answer itself still goes to whoever asked, unread.
|
|
483
530
|
- `seen` is the digest her ward last saw arrive with an answer. A silent
|
|
484
531
|
refresh leaves it untouched.
|
|
485
532
|
- `notes` is hers. Quo never reads it. Tier, expiry, kinship between an
|
|
486
|
-
occupant and a standing that are the same far being: all hers.
|
|
533
|
+
occupant and a standing that are the same far being: all hers. `invite`
|
|
534
|
+
may seed it, which is how an inviter says the terms it mints under, and
|
|
535
|
+
after that it is written by nobody but her. The owner's `invite` passes
|
|
536
|
+
what it was given straight through; the ward reads none of it.
|
|
487
537
|
|
|
488
538
|
## Relations
|
|
489
539
|
|
|
@@ -543,7 +593,9 @@ and a knock on a taken invitation joins the standing's lane.
|
|
|
543
593
|
The keys an ask sends under are read when she calls, not when the lane
|
|
544
594
|
reaches her: an ask issued while the standing stood is answered even if she
|
|
545
595
|
drops it in the next line. An ask on a standing she has already dropped is
|
|
546
|
-
|
|
596
|
+
the word `dropped`, and nothing is sent. A knock on the invitation it was
|
|
597
|
+
born on, after take and a drop, is a knock as a heir the far door has already
|
|
598
|
+
spent, so bytes leave and the door's silence comes back: after take the
|
|
547
599
|
invitation names the standing and nothing else, so it is exactly as alive as
|
|
548
600
|
the standing is.
|
|
549
601
|
|
|
@@ -561,8 +613,22 @@ An invitation to her is `{ ward }` alone. One with a secret and no heir is
|
|
|
561
613
|
not an invitation. She may be taken as a standing on that invitation, and
|
|
562
614
|
such a standing has no heir and never rotates.
|
|
563
615
|
|
|
616
|
+
The signature is checked here for no property, and the check is kept anyway.
|
|
617
|
+
Whoever asks chose that key a moment ago, the box is already authenticated to
|
|
618
|
+
the ward's padlock, and the door binds nothing, so nothing is proven by it and
|
|
619
|
+
nothing would be lost by dropping it. It stays because the payload has one
|
|
620
|
+
shape and the door has one path: `by`, `next` and `seq` are required of her
|
|
621
|
+
ask as of every other, and honoured by nobody. A kit author who goes looking
|
|
622
|
+
for the property behind this signature will not find one, and is not missing
|
|
623
|
+
anything.
|
|
624
|
+
|
|
564
625
|
She is reached without a heir, so the door keeps nothing for whoever asked:
|
|
565
|
-
no key it vouched for, and no count. The
|
|
626
|
+
no key it vouched for, and no count. The bit beside her reply is `heard`
|
|
627
|
+
false, as it is for every stranger: no key this door holds spoke. She is the
|
|
628
|
+
one place a stranger is answered by design, so she is the one place the
|
|
629
|
+
harbor's rating must still see a stranger arrive. A harbor that saves before
|
|
630
|
+
its reply goes out follows the ward writing, never the bit, since a public
|
|
631
|
+
being writes in her cells like anyone. The signature is still checked, under
|
|
566
632
|
whatever key signed. Once-only delivery does not reach her: the same sealed
|
|
567
633
|
bytes presented twice are delivered twice, and the number the payload carries
|
|
568
634
|
is required and honoured by nobody. A count per voice would be memory a
|
|
@@ -614,7 +680,17 @@ key does both: an Ed25519 pair to sign replies, an X25519 padlock every ask
|
|
|
614
680
|
is sealed to. Beings never own a padlock.
|
|
615
681
|
|
|
616
682
|
- **The ward key** comes from the seed. Its pk on the wire is the signing pk
|
|
617
|
-
then the padlock, 128 hex, and it routes.
|
|
683
|
+
then the padlock, 128 hex, and it routes. Two curves, and each secret is
|
|
684
|
+
HKDF-SHA-256 of the seed under its own label, `quo-ward-sign` and
|
|
685
|
+
`quo-ward-seal`, empty salt, 32 bytes out. Fed the seed straight the two
|
|
686
|
+
scalars would still differ, because Ed25519 hashes what it is given and
|
|
687
|
+
X25519 clamps it raw, but that is an accident of the two designs and no
|
|
688
|
+
separation: one secret would be doing two jobs with nothing said about it,
|
|
689
|
+
and a second kit would have to reproduce a construction nobody named. A
|
|
690
|
+
seed handed in as bytes of the key length is the seed; anything else, text
|
|
691
|
+
or bytes of another length, is SHA-256 first, so a thirty-two character
|
|
692
|
+
name is a name and not a key for being the right size.
|
|
693
|
+
`vectors/framing.json` pins it.
|
|
618
694
|
- **The heir** is the key the inviting ward mints at invite, for one id. It
|
|
619
695
|
keeps the heir's pk beside the id and gives the secret away. The
|
|
620
696
|
invitation IS the heir: ward pk, heir pk, heir secret. Rotation one: the
|
|
@@ -622,8 +698,8 @@ is sealed to. Beings never own a padlock.
|
|
|
622
698
|
- **Her own key** is what the knocker mints at knock. She signs the knock
|
|
623
699
|
with the heir and announces her own key in it. The door binds the id to
|
|
624
700
|
her key and the heir dies as it speaks. Rotation two: from now on she
|
|
625
|
-
signs with a key the inviter never held. A knock that announces nothing
|
|
626
|
-
binds nothing.
|
|
701
|
+
signs with a key the inviter never held. A knock that announces nothing,
|
|
702
|
+
or announces the heir itself, binds nothing.
|
|
627
703
|
- **Next.** Every ask she sends announces the key she will sign with next.
|
|
628
704
|
The door holds two pks for her: the one that may speak now, and the one
|
|
629
705
|
it vouched for. Whichever speaks first wins, and the other dies. There is
|
|
@@ -709,12 +785,12 @@ what makes three answers three. A wait that does not end is not an object,
|
|
|
709
785
|
not silence and not unreached, and before the allowance a cycle of legal asks
|
|
710
786
|
could produce one: A asks B, B answering asks A back, A answering asks B on
|
|
711
787
|
the relation the first ask still holds. Now the innermost wait gives up, the
|
|
712
|
-
|
|
788
|
+
word `late` unwinds outward, and the ask ends.
|
|
713
789
|
|
|
714
|
-
**A wait that ran out is
|
|
715
|
-
nothing was delivered and is safe to ask
|
|
716
|
-
such thing: the far door may have heard
|
|
717
|
-
back late is not read.
|
|
790
|
+
**A wait that ran out is the word `late`, never silence and never
|
|
791
|
+
unreached.** Unreached promises nothing was delivered and is safe to ask
|
|
792
|
+
again. A bound that expired knows no such thing: the far door may have heard
|
|
793
|
+
and be working still. What comes back late is not read.
|
|
718
794
|
|
|
719
795
|
The harbor keeps a patience of its own, and the two never read each other.
|
|
720
796
|
What a harbor hands back as nothing came back is unreached, and unreached
|
|
@@ -722,7 +798,7 @@ says nothing was delivered: a harbor may answer it only where it knows the
|
|
|
722
798
|
bytes never arrived, no reach for that pk, a socket that would not open, a
|
|
723
799
|
link that is down. A harbor that sent them and then gave up knows no such
|
|
724
800
|
thing, and must not answer at all; the ward's bound will ring, and that is
|
|
725
|
-
|
|
801
|
+
`late`, which promises nothing. A harbor that throws has answered nothing
|
|
726
802
|
in a louder voice, and the ward reads it as nothing: unreached. So a harbor
|
|
727
803
|
may hold a shorter patience than the ward for its own reasons, a socket it
|
|
728
804
|
wants back or a queue it will not grow, and whichever ends first ends the
|
|
@@ -747,7 +823,10 @@ Every arrival is judged by the door, and named by it or falls silent.
|
|
|
747
823
|
payload names, and dispatch as `{}`. Nothing is written.
|
|
748
824
|
3. For a heir: admit the signer if it is the key held for that heir or the
|
|
749
825
|
key that key announced, or the key held when she removed the id. Verify
|
|
750
|
-
the signature.
|
|
826
|
+
the signature. Read admission again, since the door judges arrivals
|
|
827
|
+
concurrently and a knock that raced this one may have spent the heir
|
|
828
|
+
while the signature was checked. Only then say anything or write
|
|
829
|
+
anything: a removed
|
|
751
830
|
relation is `removed`, a being not back this run is `absent`, a knock
|
|
752
831
|
with no key is `unannounced`, a number already honoured is `repeated`,
|
|
753
832
|
and none of those writes. Else spend the number and settle the keys, so
|
|
@@ -783,7 +862,11 @@ share no key learn nothing from each other.
|
|
|
783
862
|
|
|
784
863
|
Four algorithms, named once and never negotiated: Ed25519 signs, X25519
|
|
785
864
|
agrees, SHA-256 hashes, AES-256-GCM encrypts with key and nonce derived
|
|
786
|
-
together by HKDF-SHA-256 under an empty salt and the label `quo-seal`.
|
|
865
|
+
together by HKDF-SHA-256 under an empty salt and the label `quo-seal`. That
|
|
866
|
+
label is the message cipher's and no other: HKDF appears twice in this kit,
|
|
867
|
+
here from an agreement and again at the ward key from a seed, and the three
|
|
868
|
+
labels, `quo-seal`, `quo-ward-sign`, `quo-ward-seal`, are three so that two
|
|
869
|
+
derivations never answer to one name. The
|
|
787
870
|
ephemeral pk is the additional authenticated data of every box. A small-order
|
|
788
871
|
public key verifies nothing; an all-zero agreement is refused. All four are
|
|
789
872
|
in WebCrypto, which is why the ward names no package -- on any terrain that
|
|
@@ -800,14 +883,17 @@ on the bytes.
|
|
|
800
883
|
```
|
|
801
884
|
ask on the wire box = ephemeral X25519 pk (32) || AES-GCM( payload || signature (64) )
|
|
802
885
|
sealed to the ward padlock. nothing rides outside it.
|
|
803
|
-
payload = JSON { to, by, next, seq, time, hops?, method?, args }
|
|
804
|
-
signed by `by`. to, by, next: 64 hex. to, next may be null.
|
|
805
|
-
to names the heir, or null for the public being.
|
|
886
|
+
payload = JSON { to, by, next, seq, time, hops?, method?, args? }
|
|
887
|
+
signed by `by`. to, by, next: 64 lowercase hex. to, next may be null.
|
|
888
|
+
to names the heir, or null for the public being. seq is a whole
|
|
889
|
+
number from one. args, when present, is one object of values.
|
|
806
890
|
hops is reserved: a whole number, never below zero,
|
|
807
891
|
refused at zero, and nothing sets it.
|
|
808
892
|
reply on the wire box = ephemeral X25519 pk (32) || AES-GCM( reply || signature (64) )
|
|
809
893
|
sealed to the ask's ephemeral pk, signed by the ward key
|
|
810
894
|
reply = JSON { object, seen } | { silence: true } | { quo: word }
|
|
895
|
+
seen is always present: the digest, 64 hex, on a named ask that
|
|
896
|
+
had one, and null otherwise, the empty ask included.
|
|
811
897
|
word: removed | absent | unannounced | repeated | threw. only to a key the door bound.
|
|
812
898
|
```
|
|
813
899
|
|
|
@@ -854,8 +940,9 @@ It owns nothing durable. It is three things, all in the harbor's hands:
|
|
|
854
940
|
its seed, its partition, and the classes its beings are made of. The
|
|
855
941
|
partition names each class and the harbor holds the bodies, so a ward is
|
|
856
942
|
whole only where all three are, and a harbor that keeps one remembers where
|
|
857
|
-
the other two came from. It writes as it runs
|
|
858
|
-
learns whether anything was kept. Between one
|
|
943
|
+
the other two came from. It writes as it runs, says so after every write,
|
|
944
|
+
and never decides, asks, or learns whether anything was kept. Between one
|
|
945
|
+
run and the next, a ward is
|
|
859
946
|
nothing at all.
|
|
860
947
|
|
|
861
948
|
One ward is one runtime and one language, and every being in it shares both.
|
|
@@ -871,8 +958,9 @@ list is a promise, not an accident: `test/terrain.test.ts` fails the build
|
|
|
871
958
|
both when a file names a platform and when it reaches for a global outside
|
|
872
959
|
the list, and when the list names one the tree has stopped using.
|
|
873
960
|
|
|
874
|
-
The package exports
|
|
875
|
-
|
|
961
|
+
The package exports the emitted `dist/`, JavaScript with a declaration
|
|
962
|
+
beside it, on every specifier, so plain Node imports it; the tree runs the
|
|
963
|
+
source directly, and every other terrain reaches a ward through a
|
|
876
964
|
bundler. `test/bundle.test.ts` bundles the three words and runs them, and
|
|
877
965
|
asserts the artefact carries nothing a terrain cannot provide.
|
|
878
966
|
|
|
@@ -887,8 +975,9 @@ of every terrain at once. Five run it: Node, a browser, workerd, Deno and
|
|
|
887
975
|
Bun. Bun is the one that is not V8, so "the language alone" is checked
|
|
888
976
|
against two implementations of the language and not one.
|
|
889
977
|
|
|
890
|
-
`npm run check` is Node alone, and stays fast. `npm run check:terrain` is
|
|
891
|
-
|
|
978
|
+
`npm run check` is Node alone, and stays fast. `npm run check:terrain` is
|
|
979
|
+
every other terrain, the browser, workerd, Deno and Bun, kept apart because
|
|
980
|
+
each is a binary of its own and the browser is a download and not a
|
|
892
981
|
package: a fresh clone needs `npx playwright install chromium` first, and is
|
|
893
982
|
told so in one sentence rather than a stack trace.
|
|
894
983
|
|
|
@@ -897,7 +986,9 @@ told so in one sentence rather than a stack trace.
|
|
|
897
986
|
Everything durable a ward has is here, every secret included, and nothing
|
|
898
987
|
here is ever in a being's cells. Values only, so the harbor may persist it as
|
|
899
988
|
it likes: as this process's objects, as a row, as a line of JSON on a disk. A
|
|
900
|
-
reboot from its JSON is the same ward.
|
|
989
|
+
reboot from its JSON is the same ward. A harbor that keeps it copies it
|
|
990
|
+
through JSON and never structured-clones it: what the ward hands out is
|
|
991
|
+
behind the cells guard. The shape is `src/ward/partition.ts`.
|
|
901
992
|
|
|
902
993
|
```
|
|
903
994
|
partition
|
|
@@ -908,8 +999,10 @@ partition
|
|
|
908
999
|
occupants id -> heir pk
|
|
909
1000
|
knocks <ward>:<heir> | public:<ward> -> { current, next, spoke, sent, seq } before take
|
|
910
1001
|
spoke: bytes came back once. sent: bytes went out once, answered or not
|
|
1002
|
+
bounded, oldest out, and one that answered outlives one that never did
|
|
911
1003
|
answered <ward>:<heir> | public:<ward> -> true knocked and answered
|
|
912
|
-
minted the last eight pks her side minted
|
|
1004
|
+
minted the last eight pks her side minted. nothing in the ward reads it: it is there to
|
|
1005
|
+
be looked at, and a kit that keeps the list empty holds the same ward
|
|
913
1006
|
heirs heir pk -> { being, id, current, announced, fresh, mark, spent } the door's view of every occupant
|
|
914
1007
|
gone heir pk -> { current, announced } the keys held when an id was removed, bounded, so their
|
|
915
1008
|
holder hears `removed` and nobody else hears a thing
|
|
@@ -921,6 +1014,12 @@ alone: an invitation carries the heir to whoever it is for, and anyone
|
|
|
921
1014
|
holding one could quote that heir back inside an invitation naming a ward of
|
|
922
1015
|
their own.
|
|
923
1016
|
|
|
1017
|
+
Only take ends a knock record, so the list is bounded like `gone`: past the
|
|
1018
|
+
count the oldest go, and one that was answered outlives one that never was,
|
|
1019
|
+
since an answered knock is a relation she may still take. A being who knocks
|
|
1020
|
+
without ever taking keeps a fixed number of keys behind her, not one per
|
|
1021
|
+
invitation she ever met.
|
|
1022
|
+
|
|
924
1023
|
The version is one value and it does not move until 1.0.0. There is nobody
|
|
925
1024
|
holding a partition of another shape to tell apart: if the shape changes, a
|
|
926
1025
|
partition is thrown away, not migrated and not counted. A ward opening a
|
|
@@ -928,6 +1027,17 @@ version it cannot read throws at birth and does not boot. Birth is where a
|
|
|
928
1027
|
ward is allowed to be loud; silence is the door's word, for asks that were
|
|
929
1028
|
made, and no ask has been made yet.
|
|
930
1029
|
|
|
1030
|
+
The version says which shape, and the ward reads the shape as well, once, at
|
|
1031
|
+
birth: every field above that the ward, the door or the heirs later act on
|
|
1032
|
+
without looking again. A partition this ward wrote is that shape by
|
|
1033
|
+
construction. One adopted from elsewhere was written by a hand, another kit,
|
|
1034
|
+
or a file that was cut short, and a `spent` that is not a list or a `mark`
|
|
1035
|
+
that is not a number is a door that honours every number, or one that
|
|
1036
|
+
rejects where it promised a word. A ward that meets one throws at birth with
|
|
1037
|
+
the path that failed, which names what is wrong to whoever is holding the
|
|
1038
|
+
file. A being's own cells are read no further than the two records the ward
|
|
1039
|
+
keeps in them: what she puts in her own is hers, of any shape JSON carries.
|
|
1040
|
+
|
|
931
1041
|
What a ward can read is a list, `READS`, and today it has one member. The
|
|
932
1042
|
list and the step that carries an older partition forward exist before
|
|
933
1043
|
1.0.0 because after it there is nowhere to put them. A partition holds every
|
|
@@ -949,7 +1059,9 @@ A constructor that throws on a restart takes only herself down: she is
|
|
|
949
1059
|
absent this run, no door, so `absent` at her door to the keys she bound and
|
|
950
1060
|
silence to strangers, and her cells sit untouched waiting for the run that
|
|
951
1061
|
can read them. The ward is up and so is everyone
|
|
952
|
-
else.
|
|
1062
|
+
else. Her row is hers while she is absent: the owner sees her as absent, no
|
|
1063
|
+
class boots under her key, and the owner may unboot her. A class the harbor
|
|
1064
|
+
does not hold this run is the same absence, and so is a
|
|
953
1065
|
class the harbor holds at a body the cells were not written for: which body
|
|
954
1066
|
a ward reboots on is the harbor's decision, and a ward cannot tell an old
|
|
955
1067
|
one from a new one. Loss of the partition is loss of every relation,
|
|
@@ -989,10 +1101,10 @@ renders anyone's and holds no list of its own.
|
|
|
989
1101
|
|
|
990
1102
|
```
|
|
991
1103
|
ask() -> { asks: [boot, public, invite, knock, remove, unboot],
|
|
992
|
-
notes: { pk, beings: { key: { class, public, digest } } } }
|
|
1104
|
+
notes: { pk, beings: { key: { class, public, digest, absent? } } } }
|
|
993
1105
|
ask('boot', { key, class }) -> { booted: key } | { error }
|
|
994
1106
|
ask('public', { key }) -> { public: key } | { error }
|
|
995
|
-
ask('invite', { being, id })
|
|
1107
|
+
ask('invite', { being, id, notes? }) -> invitation | null | { error }
|
|
996
1108
|
ask('knock', { being | { boot: class, key },
|
|
997
1109
|
id, invitation, method?, args?, wanted? })
|
|
998
1110
|
-> { taken: id | null, answer } | { error: 'silence' | 'unreached' | ... }
|
|
@@ -1004,16 +1116,24 @@ anything else -> { error: 'unknown ask' }
|
|
|
1004
1116
|
- The owner is a caller like any other: `wanted` says what its knock may
|
|
1005
1117
|
spend, and saying nothing is the ward's default, exactly as for a being.
|
|
1006
1118
|
- The describe runs every being's own describe as `OWNER` and hashes it; a
|
|
1007
|
-
being that throws or falls silent there shows a null digest.
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1119
|
+
being that throws or falls silent there shows a null digest. A being
|
|
1120
|
+
absent this run is listed with a null digest and `absent: true`.
|
|
1121
|
+
- Boot refuses a key that has a row in the partition, booted this run or
|
|
1122
|
+
absent, and a class the harbor does not know; a boot that made nobody
|
|
1123
|
+
leaves the partition as it found it. A throw at birth is that boot's
|
|
1124
|
+
error, `{ error: 'threw at birth' }`, and nothing half-lives; a being's
|
|
1125
|
+
own boot answers null for it.
|
|
1011
1126
|
- Public marks a being already booted as the ward's one public being. It
|
|
1012
1127
|
refuses a key not booted, the ward's own pk, and a second public being
|
|
1013
1128
|
while one stands, since marking a second would leave the first holding
|
|
1014
1129
|
every relation she had, reachable by nobody at the bare pk and told by
|
|
1015
1130
|
nobody she was replaced. Marking the one already public again is
|
|
1016
|
-
answered, and changes nothing.
|
|
1131
|
+
answered, and changes nothing. A public being absent this run is
|
|
1132
|
+
reachable by nobody already, so the mark may move to another. A null key
|
|
1133
|
+
takes the mark off: the being stays booted with every relation she holds,
|
|
1134
|
+
and the ward answers arrivals for no heir with silence as one that never
|
|
1135
|
+
had a public being does. Retiring her is not destroying her, and the mark
|
|
1136
|
+
is free for another.
|
|
1017
1137
|
- Invite on the ward's own pk mints an owner, and only the root may ask it:
|
|
1018
1138
|
from the door it is answered as an invite on nobody. The ward has
|
|
1019
1139
|
occupants, its owners, and no standings: a knock for the ward itself is a
|
|
@@ -1034,7 +1154,9 @@ anything else -> { error: 'unknown ask' }
|
|
|
1034
1154
|
heir with silence as one that never had a public being does. The ward
|
|
1035
1155
|
itself is refused, for the reason knock is: it would be a ward deleting
|
|
1036
1156
|
itself from inside its own map, leaving its owners bound to a door that is
|
|
1037
|
-
gone.
|
|
1157
|
+
gone. An absent being is unbooted the same way: she has no stance to speak
|
|
1158
|
+
for her, so the ward closes her heirs itself, and her occupants hear
|
|
1159
|
+
`removed`.
|
|
1038
1160
|
- The owner's remove is the mirror of its knock: a relation out of a being,
|
|
1039
1161
|
by id, and the id may be an occupant or a standing, since the two share
|
|
1040
1162
|
one namespace. The being's own remove says nothing; the owner hears
|
|
@@ -1099,12 +1221,24 @@ Not stressed with:
|
|
|
1099
1221
|
|
|
1100
1222
|
A harbor is what a device already has, offered to Quo: processes, storage, a
|
|
1101
1223
|
network, entropy, a clock. It fits into a device carved up by its owner,
|
|
1102
|
-
users, containers, mounts, profiles, and asks for none of them. It
|
|
1103
|
-
|
|
1224
|
+
users, containers, mounts, profiles, and asks for none of them. It judges
|
|
1225
|
+
nothing, holds no id, chooses no class, and is nobody outside its device.
|
|
1226
|
+
|
|
1227
|
+
It makes every being of every ward it serves, because `instantiate` is in
|
|
1228
|
+
the ground and the ward calls it, and it keeps what it made. That is not
|
|
1229
|
+
knowing a being. It has her object and knows nothing about her: not what she
|
|
1230
|
+
answers, not who her occupants are, not which of her cells is a secret. It
|
|
1231
|
+
never reads a partition to decide anything, and it never hands one out
|
|
1232
|
+
except as the values a store keeps.
|
|
1104
1233
|
|
|
1105
1234
|
The harbor:
|
|
1106
1235
|
|
|
1107
|
-
- Boots wards as processes, one seed each, and keeps each ward's partition
|
|
1236
|
+
- Boots wards as processes, one seed each, and keeps each ward's partition:
|
|
1237
|
+
saves it when the ward says it wrote, one save at a time per ward and in
|
|
1238
|
+
the order it was told, so a being driven in process is kept the way one
|
|
1239
|
+
reached through a door is. A save that fails is the harbor's to count and
|
|
1240
|
+
never a door's to answer: the door answered bytes, and a full disk is not
|
|
1241
|
+
a reason the far side may hear.
|
|
1108
1242
|
- Holds the class bodies for its wards, and remembers for each ward where
|
|
1109
1243
|
its bodies came from, so that a restart is on the same bodies unless the
|
|
1110
1244
|
harbor decides otherwise. Constructs a being when a ward names a class
|
|
@@ -1115,6 +1249,16 @@ The harbor:
|
|
|
1115
1249
|
- Passes every ward the ground, once, at birth. Receives a door and an ask.
|
|
1116
1250
|
Hands the ask to exactly one holder, by the device's own rules. That
|
|
1117
1251
|
holder is the ward's owner.
|
|
1252
|
+
- Hands its own device's code the beings it made for a ward, by key, and the
|
|
1253
|
+
keys it has. This is not a path around a door. The object is already in
|
|
1254
|
+
that process, made there a moment ago by the harbor itself, and reaching
|
|
1255
|
+
it is the device's own code calling its own object, the same reach a being
|
|
1256
|
+
has on one she booted herself. Nothing of it crosses an edge, so there is
|
|
1257
|
+
no door it could have passed instead. A key with no object is a being who
|
|
1258
|
+
is not here this run. What the device does not get is the partition: it
|
|
1259
|
+
holds every seed the ward has, and a side that wants to know which beings
|
|
1260
|
+
there are, or which one is public, asks the ward through the ask pointer,
|
|
1261
|
+
which is the only thing that answers for a ward anyway.
|
|
1118
1262
|
- Keeps the map of ward pk to door for its own wards, and ward pk to reach
|
|
1119
1263
|
for foreign ones. Learns its own wards' pks by asking them. Learns foreign
|
|
1120
1264
|
pks however it likes.
|
|
@@ -1141,8 +1285,8 @@ Not stressed with:
|
|
|
1141
1285
|
silence, and it never answers on a ward's behalf.
|
|
1142
1286
|
- Fanning out, broadcasting, or forwarding to a pk other than the one it was
|
|
1143
1287
|
given. One pk is one ward is one door.
|
|
1144
|
-
-
|
|
1145
|
-
|
|
1288
|
+
- Choosing a class, deciding an id, reading the keys inside a relation,
|
|
1289
|
+
minting an invitation, or acting on anything a partition contains.
|
|
1146
1290
|
- Judging anything. A ward judges its door. The harbor delivers to it.
|
|
1147
1291
|
- Speaking Quo. It is nobody's occupant and holds no standing anywhere. The
|
|
1148
1292
|
harbor is not a ward and is nobody's.
|
|
@@ -1154,12 +1298,15 @@ one hop: a pk that is not its own and not a direct peer's is nothing. It
|
|
|
1154
1298
|
keeps no lease: two of them may hold one seed and one partition, which is
|
|
1155
1299
|
the broken vouch every real harbor refuses, kept here so that the tests can
|
|
1156
1300
|
show what divergence looks like. Every ward and being assertion in the tree
|
|
1157
|
-
is made on it, so that the network never hides a fault in the words
|
|
1301
|
+
is made on it first, so that the network never hides a fault in the words;
|
|
1302
|
+
the harbor core then passes the same suite over memory stores.
|
|
1158
1303
|
|
|
1159
1304
|
What a harbor on a device keeps is a ward's three parts under one name: the
|
|
1160
1305
|
seed, the partition, and a **ward record**, which says where the class
|
|
1161
|
-
bodies come from and which being is the user's.
|
|
1162
|
-
|
|
1306
|
+
bodies come from and which being is the user's. `user` is a key and nothing
|
|
1307
|
+
else: a label the device's own code hands back to get the being it made,
|
|
1308
|
+
never read to route a byte or judge an ask. That is the **store**,
|
|
1309
|
+
`src/harbor/store.ts`: list, load, put, save the partition when the ward wrote,
|
|
1163
1310
|
save the record after a boot learned the pk, take a ward out as the first
|
|
1164
1311
|
move of a migration, and keep the directory's hints, a pk to a URL, across
|
|
1165
1312
|
a restart. A name already kept is refused. A store reads nothing it keeps
|
|
@@ -1183,14 +1330,17 @@ WebSocket, and this tree holds either end of a line and never a listener:
|
|
|
1183
1330
|
who accepts a socket is the terrain's business. A reach reads nothing; a
|
|
1184
1331
|
harbor opens no box but its own probe's.
|
|
1185
1332
|
Nothing comes back only where the reach knows nothing was delivered: no such
|
|
1186
|
-
pk at the far end, a connection that would not open
|
|
1333
|
+
pk at the far end, a connection that would not open or closed before it
|
|
1334
|
+
opened, a line already gone, a status from a request that says the listener
|
|
1335
|
+
did not take the bytes, refused on their face or with nobody behind the
|
|
1336
|
+
gateway. A
|
|
1187
1337
|
reach that sent the bytes and lost the line after answers nothing at all,
|
|
1188
1338
|
and the ward's bound ends the ask. Every reach passes
|
|
1189
1339
|
`src/conformance/reach.ts` untouched, and the frames are pinned in
|
|
1190
1340
|
`vectors/wire.json`.
|
|
1191
1341
|
|
|
1192
1342
|
A reach also carries the **wire suite**: which frames these are, and which
|
|
1193
|
-
|
|
1343
|
+
five algorithms seal what they travel with. It is one number, it is not
|
|
1194
1344
|
negotiated, and today it is 1. It rides where a line is opened and never on
|
|
1195
1345
|
an ask: in the text frame a socket announces itself with, and as the header
|
|
1196
1346
|
`quo-suite` on a request. So an ask is still bytes from the first one, with
|
|
@@ -1209,7 +1359,7 @@ refused as it is written: the number is compared as it was sent, so a suite
|
|
|
1209
1359
|
is one spelling and not a family of them.
|
|
1210
1360
|
|
|
1211
1361
|
This is the only place a second suite could ever be told from the first.
|
|
1212
|
-
The
|
|
1362
|
+
The five algorithms are named once and never negotiated, which is right: a
|
|
1213
1363
|
choice offered on the wire is a choice a stranger can push. But named once
|
|
1214
1364
|
is not the same as unnameable, and a kit that must one day seal differently
|
|
1215
1365
|
has to be able to say so to a kit that cannot, or the day it arrives every
|
|
@@ -1221,9 +1371,14 @@ is: the store and the reach put together under the ground. It boots every
|
|
|
1221
1371
|
ward the store keeps, keeps the map of ward pk to door for its own wards
|
|
1222
1372
|
and the **directory**, pk to reach, for foreign ones, carries bytes to a
|
|
1223
1373
|
pk and delivers bytes from the wire to one door. The directory is filled
|
|
1224
|
-
|
|
1374
|
+
four ways, in this order: its own doors; a socket a dialer holds to it,
|
|
1225
1375
|
bound once the door behind the dialer's claim has proved it, and unbound
|
|
1226
|
-
when the line closes;
|
|
1376
|
+
when the line closes; the claims of a listener this harbor dialed, proven
|
|
1377
|
+
the same way and reached through that line; and a hint, a pk at a URL,
|
|
1378
|
+
kept in the store. A hint never displaces a reach proven at a door. An
|
|
1379
|
+
announce names at most sixty-four pks, proven a few at a time, and is the
|
|
1380
|
+
newest word: a proof still in flight from an earlier announce on the same
|
|
1381
|
+
line binds nothing when it lands.
|
|
1227
1382
|
|
|
1228
1383
|
An announce is a claim, and a claim binds nothing until proven: anyone who
|
|
1229
1384
|
can reach a listener could otherwise name a pk that is not theirs and take
|
|
@@ -1238,8 +1393,9 @@ listener proves the dialer's claims and the dialer the listener's. What a
|
|
|
1238
1393
|
relay that genuinely reaches a ward elsewhere can still do is forward the
|
|
1239
1394
|
probe and pass, and then it is a rendezvous for that ward like any other,
|
|
1240
1395
|
able to drop and nothing more. This is the one box a harbor ever opens,
|
|
1241
|
-
the one it sealed itself, and it reads nothing from it but
|
|
1242
|
-
signed. One rule makes a
|
|
1396
|
+
the one it sealed itself, and it reads nothing from it but that it is the
|
|
1397
|
+
silence a door owes such a box, signed by the claimed key. One rule makes a
|
|
1398
|
+
**rendezvous** of
|
|
1243
1399
|
any listener: bytes that arrive from the wire go to an own door or to a
|
|
1244
1400
|
socket this harbor holds for that pk, and never onward by request. So a
|
|
1245
1401
|
harbor that cannot be dialed is reached through the one it dialed, by
|
|
@@ -1253,18 +1409,28 @@ with a wait that doubles from a second to thirty when the line drops, and
|
|
|
1253
1409
|
while it is dialed it is one of the harbor's fallbacks, where a pk nobody
|
|
1254
1410
|
here knows is sent. A device that slept, a phone in a pocket, comes back
|
|
1255
1411
|
with that wait frozen and, often, its socket closed under it by the system
|
|
1256
|
-
without a word, so the dialer takes one call from the device, `wake`:
|
|
1257
|
-
line
|
|
1258
|
-
|
|
1259
|
-
|
|
1412
|
+
without a word, so the dialer takes one call from the device, `wake`:
|
|
1413
|
+
whatever line it holds, open or still opening, is put down and a new one is
|
|
1414
|
+
dialed now, the frozen wait called off. Nothing can tell a line the system
|
|
1415
|
+
dropped from a live one, and asking would cost a round trip the four words
|
|
1416
|
+
do not have; an announce written into a dead line is taken into the send
|
|
1417
|
+
buffer and errors only when TCP gives up, minutes later, and for all of it
|
|
1418
|
+
every ask to a pk bound behind that line hears `late`. Dialing costs one
|
|
1419
|
+
handshake when the line was fine, and an ask made meanwhile waits on the new
|
|
1420
|
+
socket. A line put down this way closes when the system gets round to it,
|
|
1421
|
+
gives back what it took, and dials nothing: only the line the dialer still
|
|
1422
|
+
holds dials again. Fallbacks are a list and a pk is tried down it in
|
|
1260
1423
|
order: a harbor may dial more than one listener, and a rendezvous is a
|
|
1261
1424
|
listener and nothing more, so a ward is never reachable through one place
|
|
1262
1425
|
by anything but its own choice. A line that drops takes only its own place
|
|
1263
1426
|
out of the list. A ward is born on the core by minting a seed under a name,
|
|
1264
1427
|
leaves it by being dropped, the partition written first, and arrives by
|
|
1265
|
-
being adopted, same seed, same pk.
|
|
1266
|
-
|
|
1267
|
-
|
|
1428
|
+
being adopted, same seed, same pk. Adopting is the one path a partition
|
|
1429
|
+
written elsewhere takes, so it is where the ward's shape check is met: one
|
|
1430
|
+
that will not boot is not adopted, it goes back out of the store, and the
|
|
1431
|
+
only copy is the one the caller is still holding. What a terrain adds is a
|
|
1432
|
+
store of its own, a loader for the class bodies, and the lease its device
|
|
1433
|
+
offers; what it never touches is a ward.
|
|
1268
1434
|
|
|
1269
1435
|
## The being
|
|
1270
1436
|
|
|
@@ -1285,8 +1451,7 @@ describes herself, per asker, by answering the empty ask.
|
|
|
1285
1451
|
|
|
1286
1452
|
Not stressed with: where anyone lives; crypto, keys, wire, storage, clocks,
|
|
1287
1453
|
or the harbor; strangers, because nobody her ward cannot name reaches her;
|
|
1288
|
-
whether an occupant is a person, a model or a program
|
|
1289
|
-
only the ward instantiates.
|
|
1454
|
+
whether an occupant is a person, a model or a program.
|
|
1290
1455
|
|
|
1291
1456
|
### Her obligations
|
|
1292
1457
|
|
|
@@ -1313,9 +1478,11 @@ only the ward instantiates.
|
|
|
1313
1478
|
asks is always a new call. The one exception is the public being, who is
|
|
1314
1479
|
reached with no heir and no count: the same bytes reach her twice, and
|
|
1315
1480
|
her answer must be safe to repeat.
|
|
1316
|
-
8.
|
|
1317
|
-
|
|
1318
|
-
|
|
1481
|
+
8. A being may make a being of her own ward, by class name and under a key
|
|
1482
|
+
she chooses, and holds no relation to her until one is invited and taken
|
|
1483
|
+
like any other; the ward builds the stance and the harbor holds the
|
|
1484
|
+
class, so she never touches either. Only the owner reaches into a being
|
|
1485
|
+
from outside.
|
|
1319
1486
|
9. Whatever her ward cannot name is not hers to worry about: what the ward
|
|
1320
1487
|
does with an arrival it cannot name is the ward's.
|
|
1321
1488
|
|
|
@@ -1332,16 +1499,30 @@ The raw shape needs no import from the kit. The kit also offers a base class,
|
|
|
1332
1499
|
`for(occupant, asker)` decides whether this asker sees the ask, and so
|
|
1333
1500
|
whether this asker may call it: what she shows is what she can be asked,
|
|
1334
1501
|
one gate for describe and for dispatch.
|
|
1502
|
+
- Both statics are read off the class the object was made from, and a
|
|
1503
|
+
subclass that declares either **replaces** its parent's rather than adding
|
|
1504
|
+
to it. That is the rule and not an oversight: a being's blueprint is
|
|
1505
|
+
exactly what the class in front of you declares, in the order she chose,
|
|
1506
|
+
and a merge would hand her asks she may mean to drop and an order she did
|
|
1507
|
+
not write. A subclass that means to extend says so, in one spelling,
|
|
1508
|
+
`static override asks = { ...Parent.asks, mine: {} }`, and the same for
|
|
1509
|
+
cells. A parent that means to be subclassed at all annotates rather than
|
|
1510
|
+
infers, `static override cells: JsonObject = { ... }`, since this language
|
|
1511
|
+
holds a subclass's static side to its parent's and would otherwise refuse a
|
|
1512
|
+
subclass declaring fewer keys than the parent happened to write.
|
|
1335
1513
|
- `answer` is written for her. The empty ask is `describe(asker)`, which she
|
|
1336
1514
|
may override by hand. A named ask calls the method of that name with
|
|
1337
1515
|
`(args, asker)`. Anything not declared, hidden from this asker, or
|
|
1338
1516
|
inherited from Object's prototype is `{ error: 'unknown ask' }` and the
|
|
1339
1517
|
method is never entered.
|
|
1340
1518
|
- A declared ask with no method, or one named after the base's own members,
|
|
1341
|
-
fails at birth, loudly, so a boot fails and nothing half-lives.
|
|
1519
|
+
fails at birth, loudly, so a boot fails and nothing half-lives. The
|
|
1520
|
+
method is one on her prototype chain below Object's: a class field
|
|
1521
|
+
holding a function is not there yet when the base checks, and the
|
|
1522
|
+
refusal says so.
|
|
1342
1523
|
- `occupant(asker)` is the occupant record for whoever is at the door, and
|
|
1343
|
-
undefined at a public being. `invite`, `knock`, `take`, `
|
|
1344
|
-
`occupants` reach the stance and nothing else.
|
|
1524
|
+
undefined at a public being. `invite`, `knock`, `take`, `boot`, `cells`,
|
|
1525
|
+
`standings` and `occupants` reach the stance and nothing else.
|
|
1345
1526
|
|
|
1346
1527
|
### Examples
|
|
1347
1528
|
|
|
@@ -1375,6 +1556,7 @@ class Shop {
|
|
|
1375
1556
|
}
|
|
1376
1557
|
async answer(asker, method, args) {
|
|
1377
1558
|
if (method === undefined) return { asks: [{ name: 'hello', input: {} }], notes: {} };
|
|
1559
|
+
if (asker.id === undefined) return { welcome: false }; // a stranger at the public door has no record
|
|
1378
1560
|
const rec = this.s.cells.occupants[asker.id];
|
|
1379
1561
|
if (method === 'hello' && args.invitation) {
|
|
1380
1562
|
const back = await this.s.standings.knock(args.invitation, 'hi');
|
|
@@ -1408,15 +1590,18 @@ class Guest {
|
|
|
1408
1590
|
```
|
|
1409
1591
|
|
|
1410
1592
|
A relay. Forwards every ask to one standing and never looks inside, and asks
|
|
1411
|
-
for a short wait because she is one door of several.
|
|
1593
|
+
for a short wait because she is one door of several. Silence passes through
|
|
1594
|
+
her; a word does not, since a word out of a being is `threw` at the door,
|
|
1595
|
+
D13, so she says it as an error of her own.
|
|
1412
1596
|
|
|
1413
1597
|
```js
|
|
1414
1598
|
class Relay {
|
|
1415
1599
|
constructor(stance) {
|
|
1416
1600
|
this.s = stance;
|
|
1417
1601
|
}
|
|
1418
|
-
answer(asker, method, args) {
|
|
1419
|
-
|
|
1602
|
+
async answer(asker, method, args) {
|
|
1603
|
+
const out = await this.s.standings.next.ask(method, args, { time: 2000 });
|
|
1604
|
+
return isWord(out) ? { error: wordOf(out) } : out; // unreached and late reach her asker as an error, not as a throw
|
|
1420
1605
|
}
|
|
1421
1606
|
}
|
|
1422
1607
|
```
|
|
@@ -1452,8 +1637,7 @@ words, and nothing is kept for a holder of an earlier one.
|
|
|
1452
1637
|
|
|
1453
1638
|
The tree runs as TypeScript and the package ships as JavaScript. Node
|
|
1454
1639
|
strips types nowhere under `node_modules`, so a consumer cannot load the
|
|
1455
|
-
source
|
|
1456
|
-
version a stranger can import. `npm run build` emits `dist/` from `src`
|
|
1640
|
+
source. `npm run build` emits `dist/` from `src`
|
|
1457
1641
|
alone, one JavaScript file and one declaration file per source file with
|
|
1458
1642
|
every relative import rewritten, and the exports map points there, types
|
|
1459
1643
|
beside default. The
|
|
@@ -1463,11 +1647,12 @@ which is how a consumer does. `test/package.test.ts` is the one
|
|
|
1463
1647
|
suite that meets the package as a stranger: it packs the tarball,
|
|
1464
1648
|
installs it into an empty folder, and imports every entry point under
|
|
1465
1649
|
plain Node. `npm pack --dry-run` shows what ships: `dist/`, the four
|
|
1466
|
-
source folders, the vectors, this document, the README
|
|
1467
|
-
and nothing else. This document ships, decided here: it is the
|
|
1468
|
-
source and the vectors are read against, and a kit in another
|
|
1469
|
-
written against it and nothing else. Publishing runs both
|
|
1470
|
-
`npm run check` and `npm run check:terrain`, and refuses on a
|
|
1650
|
+
source folders, the vectors, this document, the README, the licence and
|
|
1651
|
+
the notice, and nothing else. This document ships, decided here: it is the
|
|
1652
|
+
truth the source and the vectors are read against, and a kit in another
|
|
1653
|
+
language is written against it and nothing else. Publishing runs both
|
|
1654
|
+
gates first, `npm run check` and `npm run check:terrain`, and refuses on a
|
|
1655
|
+
failure.
|
|
1471
1656
|
|
|
1472
1657
|
```
|
|
1473
1658
|
src/being/ the Being side. types, the base class, silence, the digest.
|
|
@@ -1514,8 +1699,9 @@ passes the same suite. Those tests are the checklist, not the mock.
|
|
|
1514
1699
|
- `src/conformance/index.ts`: one suite of behaviours, written against the
|
|
1515
1700
|
stance and one probe: a kit hands the suite its ward's heir table and
|
|
1516
1701
|
bind table as values, and a forged knock, so the suite can see that a
|
|
1517
|
-
refusal wrote nothing and a knock bound what it should. It reads
|
|
1518
|
-
never writes them
|
|
1702
|
+
refusal wrote nothing and a knock bound what it should. It reads the
|
|
1703
|
+
tables and never writes them; the forged knock is the one thing it sends
|
|
1704
|
+
through a door. With the beings in `src/conformance/beings.ts`: a
|
|
1519
1705
|
printer, a shop, two customers, one raw being with no base class, and a
|
|
1520
1706
|
member of an estate. Any ward must pass it, under any topology.
|
|
1521
1707
|
- `src/conformance/estate.ts`: the estate, and the last chapter of that
|
|
@@ -1594,8 +1780,11 @@ passes the same suite. Those tests are the checklist, not the mock.
|
|
|
1594
1780
|
reach suite against the socket framing over two lines in one process, so
|
|
1595
1781
|
the frames are asserted with no network under them; the conformance
|
|
1596
1782
|
suite against two harbor cores over memory stores reaching each other
|
|
1597
|
-
in-process, drop and adopt as the migration; a
|
|
1598
|
-
|
|
1783
|
+
in-process, drop and adopt as the migration; a ward that moves harbor
|
|
1784
|
+
keeping its pk and every relation, the rendezvous told on the line in
|
|
1785
|
+
hand; a ward booted or dropped after a line opened, announced on that
|
|
1786
|
+
line, and a claim on a pk nobody holds binding nothing; a restart from
|
|
1787
|
+
the store with the hints; the dialer over a stubbed line, announce, a claim proven
|
|
1599
1788
|
at a real door before it binds and a claim nobody there holds left
|
|
1600
1789
|
unbound, fallback, unbind and the wait before it dials again; and the frames against
|
|
1601
1790
|
`vectors/wire.json`, the ask, the reply, nothing delivered and the
|
|
@@ -1614,7 +1803,7 @@ passes the same suite. Those tests are the checklist, not the mock.
|
|
|
1614
1803
|
`node:assert/strict`, pair by pair. The suite means the same thing on
|
|
1615
1804
|
every terrain only if those two agree, so they are compared and not
|
|
1616
1805
|
trusted.
|
|
1617
|
-
- `test/floor.test.ts`: the
|
|
1806
|
+
- `test/floor.test.ts`: the five algorithms this terrain must carry, probed
|
|
1618
1807
|
one by one; that the arithmetic spends every one of them; and the two ways
|
|
1619
1808
|
a terrain can be short -- no `crypto.subtle` at all, and a subtle without
|
|
1620
1809
|
the curves -- each failing at the first call, in one sentence.
|
|
@@ -1745,7 +1934,7 @@ Decided here, so that the answer is not rediscovered:
|
|
|
1745
1934
|
- **invite**: mint an id and get its invitation.
|
|
1746
1935
|
- **knock**: an ask carrying an invitation. Binds the far side to the id.
|
|
1747
1936
|
- **take**: keep an answered knock as a standing, under her own id.
|
|
1748
|
-
- **ask**: method and args to a standing. Object, silence, or
|
|
1937
|
+
- **ask**: method and args to a standing. Object, silence, or a word back.
|
|
1749
1938
|
- **answer**: her one function. Object or silence out.
|
|
1750
1939
|
- **the empty ask**: ask with no method. Her answer to it is her blueprint.
|
|
1751
1940
|
- **blueprint**: her interface as she chooses to show it to one asker.
|
|
@@ -1759,11 +1948,13 @@ Decided here, so that the answer is not rediscovered:
|
|
|
1759
1948
|
- **unreached**: the word for no far door reached. Retryable.
|
|
1760
1949
|
- **notes**: hers, inside every occupant record. Quo never reads it.
|
|
1761
1950
|
- **partition**: the ward's files. Everything durable, every secret.
|
|
1762
|
-
- **ward record**: what a harbor keeps
|
|
1763
|
-
|
|
1764
|
-
the ward's.
|
|
1951
|
+
- **ward record**: what a harbor keeps beside a ward's seed and partition
|
|
1952
|
+
to boot her again: her pk, where the class bodies come from, and which
|
|
1953
|
+
being is the user's. The harbor's, never the ward's.
|
|
1954
|
+
- **lid**: the ephemeral X25519 pk an ask carries in front of its box. The
|
|
1955
|
+
reply is sealed to it and to nothing else. One per ask, never reused.
|
|
1765
1956
|
- **edge**: one of the two seams of Quo, harbor to ward and ward to being.
|
|
1766
1957
|
An object crosses once at birth, calls cross for the rest of the ward's
|
|
1767
1958
|
life, and nothing else crosses.
|
|
1768
|
-
- **ground**: the one object a harbor passes a ward.
|
|
1959
|
+
- **ground**: the one object a harbor passes a ward. Six things.
|
|
1769
1960
|
- **door**: the ward's one voice outward. Sealed bytes in, sealed bytes out.
|