@quo-systems/quo 0.2.9 → 0.2.10

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.
Files changed (52) hide show
  1. package/README.md +19 -10
  2. package/SPEC.md +161 -89
  3. package/dist/being/being.d.ts +2 -2
  4. package/dist/being/being.js +27 -11
  5. package/dist/being/digest.js +11 -7
  6. package/dist/being/types.d.ts +2 -2
  7. package/dist/conformance/estate.js +1 -3
  8. package/dist/conformance/index.js +1 -1
  9. package/dist/harbor/core.d.ts +2 -0
  10. package/dist/harbor/core.js +114 -25
  11. package/dist/harbor/dial.js +5 -3
  12. package/dist/harbor/memory.d.ts +1 -1
  13. package/dist/harbor/memory.js +3 -2
  14. package/dist/harbor/reach.js +32 -7
  15. package/dist/ward/allowance.js +8 -2
  16. package/dist/ward/arithmetic.js +11 -3
  17. package/dist/ward/cells.d.ts +3 -1
  18. package/dist/ward/cells.js +79 -21
  19. package/dist/ward/door.d.ts +1 -0
  20. package/dist/ward/door.js +24 -5
  21. package/dist/ward/ground.d.ts +1 -0
  22. package/dist/ward/heirs.d.ts +1 -1
  23. package/dist/ward/heirs.js +15 -8
  24. package/dist/ward/owner.d.ts +5 -26
  25. package/dist/ward/owner.js +24 -15
  26. package/dist/ward/seal.js +3 -0
  27. package/dist/ward/stance.d.ts +4 -1
  28. package/dist/ward/stance.js +116 -54
  29. package/dist/ward/ward.d.ts +10 -0
  30. package/dist/ward/ward.js +87 -36
  31. package/package.json +4 -2
  32. package/src/being/being.ts +26 -10
  33. package/src/being/digest.ts +13 -11
  34. package/src/being/types.ts +10 -4
  35. package/src/conformance/estate.ts +1 -3
  36. package/src/conformance/index.ts +1 -1
  37. package/src/harbor/core.ts +110 -26
  38. package/src/harbor/dial.ts +6 -4
  39. package/src/harbor/memory.ts +3 -2
  40. package/src/harbor/reach.ts +38 -11
  41. package/src/ward/allowance.ts +8 -2
  42. package/src/ward/arithmetic.ts +11 -3
  43. package/src/ward/cells.ts +76 -25
  44. package/src/ward/door.ts +22 -5
  45. package/src/ward/ground.ts +9 -2
  46. package/src/ward/heirs.ts +13 -6
  47. package/src/ward/owner.ts +24 -24
  48. package/src/ward/seal.ts +2 -0
  49. package/src/ward/stance.ts +117 -48
  50. package/src/ward/ward.ts +86 -35
  51. package/vectors/arithmetic.json +7 -0
  52. package/vectors/framing.json +14 -5
package/SPEC.md CHANGED
@@ -86,9 +86,12 @@ 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 sixth thing has found 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
96
  `src/ward/ground.ts`.
94
97
 
@@ -133,7 +136,7 @@ ever offered, and nothing here may be missing.
133
136
  stance
134
137
  cells her state. values only.
135
138
 
136
- occupants.invite(id) -> invitation | null awaitable: a key is minted
139
+ occupants.invite(id, notes?) -> invitation | null awaitable: a key is minted
137
140
  occupants.remove(id) -> nothing
138
141
 
139
142
  standings.knock(invitation, method?, args?, wanted?) -> object | silence | word
@@ -142,7 +145,8 @@ stance
142
145
  standings[id].ask(method?, args?, wanted?) -> object | silence | word
143
146
  standings.remove(id) -> nothing
144
147
 
145
- boot(class, key) -> key | null a new being of her ward, by class name
148
+ boot(class, key, id?) -> key | null a new being of her ward, by class name.
149
+ with an id, her standing to her under it
146
150
 
147
151
  wanted = { time? } what this one ask may spend, in milliseconds. optional,
148
152
  and so is saying anything at all
@@ -152,7 +156,7 @@ Return table.
152
156
 
153
157
  | call | returns | when |
154
158
  | ------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
155
- | invite(id) | invitation | she minted a fresh id; the occupant record exists from now |
159
+ | invite(id, notes?) | invitation | she minted a fresh id; the occupant record exists from now, with those notes on it |
156
160
  | | null | the id already names a record, occupant or standing, or is a reserved word |
157
161
  | remove(id) | nothing | always. removing what is not there is nothing |
158
162
  | knock(inv, m, a, w) | object | the far being answered |
@@ -166,17 +170,25 @@ Return table.
166
170
  | ask(m, a, w) | object | she answered |
167
171
  | | silence | she chose to say nothing, or bytes came back that are not Quo's |
168
172
  | | word | why not: removed, absent, repeated, threw, unreached, late, dropped |
169
- | boot(class, key) | key | she exists from now, with fresh cells, and a restart finds her |
170
- | | null | the key is already booted, the harbor holds no such class, or the class threw at birth |
173
+ | 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 |
174
+ | | null | the key is already booted, the harbor holds no such class, the class threw at birth, the id is one the maker |
175
+ | | | already holds or a reserved word, or the relation was refused; nothing of the being made is left |
171
176
 
172
177
  A being may make, and only the owner reaches into another. Boot touches
173
- nobody: the being made has empty cells and no relation, hers included, until
174
- one is invited and taken like any other. What the owner has that she does
175
- not is every ask that reaches into a being from outside: public, invite and
176
- knock for her, remove, unboot. Who may ask her to boot is her gate, as who
177
- may ask her anything is.
178
-
179
- Ask, knock, invite and take are awaitable. Async where the language has it,
178
+ nobody else: the being made has empty cells and no relation but the one her
179
+ maker named, and every other is invited and taken like any other. That one is
180
+ made the way all of them are, and it is the whole of what making gives: the
181
+ being made mints an occupant for her maker under the maker's own key, so she
182
+ knows who made her by that name and by nothing else, and her maker knocks
183
+ with it and takes the standing under the id she gave. Naming no id makes no
184
+ relation at all, and a being made that way is reachable by the owner alone. A
185
+ relation that could not be made is a boot that made nobody: the being made
186
+ goes out again, and nobody saw her, since she is a moment old and named to
187
+ no one yet. What the owner has that the maker does not is every ask that
188
+ reaches into a being from outside: public, invite and knock for her, remove,
189
+ unboot. Who may ask her to boot is her gate, as who may ask her anything is.
190
+
191
+ Ask, knock, invite, take and boot are awaitable. Async where the language has it,
180
192
  blocking where it does not. Every ask she makes is a new call.
181
193
 
182
194
  The asker has three shapes and no fourth, and nothing else ever reaches her.
@@ -281,8 +293,8 @@ S4 the reply is not one bytes came back that do not open, or are n
281
293
  S5 the far door answered silence, or a word, exactly as the door said it.
282
294
  ```
283
295
 
284
- And unreached in two: `U1` the args are not a value, or could not be
285
- sealed, so nothing left;
296
+ And unreached in two: `U1` the args are not one object of values, or could
297
+ not be sealed, so nothing left;
286
298
  `U2` the harbor returned nothing, or threw, so no door was reached. The number is
287
299
  taken all the same, and the gap it leaves in the count is harmless: the door
288
300
  honours any number above its mark.
@@ -302,9 +314,9 @@ strangers: silence, nothing written, heard false
302
314
  D1 the box does not open wrong padlock, garbage, too short. the reply is sealed to the lid if
303
315
  the bytes carried one, and is noise otherwise. a lid that will not
304
316
  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 not an object, seq
306
- below one, time not a whole number above zero, hops not a whole
307
- number or at zero.
317
+ D2 the payload is malformed by or next not 64 lowercase hex, method not a string, args present and
318
+ not one object of values, seq not a whole number from one, time not a
319
+ whole number above zero, hops not a whole number or at zero.
308
320
  D3 for nobody, and nobody is home no public being on this ward.
309
321
  D4 for nobody, signature fails the payload names a key it was not signed with.
310
322
  D5 the heir is not held never minted here, and not one she removed either.
@@ -320,7 +332,7 @@ D10 the number is refused `repeated`: already honoured, or at or belo
320
332
  choices: the number spent, the keys rotated, heard true
321
333
  D11 she threw `threw`
322
334
  D12 she answered silence on a named ask, or on the empty ask. nothing at all is silence too.
323
- D13 she answered a word `threw`: a word is not hers to make.
335
+ D13 she answered a non-value `threw`: a word, a Date, a cycle, a NaN, none is hers to make.
324
336
  ```
325
337
 
326
338
  The signature is verified before anything is written and before any word is
@@ -380,7 +392,9 @@ Nothing else is a value: no dates, no references, no functions, no native
380
392
  types. An id or a standing is never a value.
381
393
 
382
394
  Args are held to the same rule before they are sealed: an ask whose args
383
- hold a non-value is unreached, because nothing left. Cells hold values and
395
+ are not one object of values is unreached, because nothing left. Her answer
396
+ is held to it at the door: a shape that is not a value is `threw` to a bound
397
+ key and silence to a stranger, so nothing crosses altered. Cells hold values and
384
398
  refuse anything else at the moment of writing, in her own frame: a Map, a
385
399
  Date, a NaN, a cyclic object, a function, an object that is not a plain one.
386
400
  The refusal is a throw where she wrote it, which her ward turns into the
@@ -468,7 +482,12 @@ and take refuse them like the ward's words.
468
482
  ### Cells
469
483
 
470
484
  Cells are I-JSON values. The ward may persist them. A restart is silent: she
471
- is constructed again with the same cells.
485
+ is constructed again with the same cells. Three keys at their root are the
486
+ ward's, `standings`, `occupants` and `class`, and a write of hers to them is
487
+ refused where she wrote it, like a non-value. A value nested past sixty-four
488
+ levels, a hole in a list, an accessor, and a key named `__proto__` are
489
+ refused the same way: JSON writes each one way and a runtime reads it
490
+ another, so no harbor can keep them.
472
491
 
473
492
  ```
474
493
  cells
@@ -483,7 +502,10 @@ cells
483
502
  - `seen` is the digest her ward last saw arrive with an answer. A silent
484
503
  refresh leaves it untouched.
485
504
  - `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.
505
+ occupant and a standing that are the same far being: all hers. `invite`
506
+ may seed it, which is how an inviter says the terms it mints under, and
507
+ after that it is written by nobody but her. The owner's `invite` passes
508
+ what it was given straight through; the ward reads none of it.
487
509
 
488
510
  ## Relations
489
511
 
@@ -543,7 +565,9 @@ and a knock on a taken invitation joins the standing's lane.
543
565
  The keys an ask sends under are read when she calls, not when the lane
544
566
  reaches her: an ask issued while the standing stood is answered even if she
545
567
  drops it in the next line. An ask on a standing she has already dropped is
546
- silence, and so is a knock on the invitation it was born on: after take the
568
+ the word `dropped`, and nothing is sent. A knock on the invitation it was
569
+ born on, after take and a drop, is a knock as a heir the far door has already
570
+ spent, so bytes leave and the door's silence comes back: after take the
547
571
  invitation names the standing and nothing else, so it is exactly as alive as
548
572
  the standing is.
549
573
 
@@ -622,8 +646,8 @@ is sealed to. Beings never own a padlock.
622
646
  - **Her own key** is what the knocker mints at knock. She signs the knock
623
647
  with the heir and announces her own key in it. The door binds the id to
624
648
  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.
649
+ signs with a key the inviter never held. A knock that announces nothing,
650
+ or announces the heir itself, binds nothing.
627
651
  - **Next.** Every ask she sends announces the key she will sign with next.
628
652
  The door holds two pks for her: the one that may speak now, and the one
629
653
  it vouched for. Whichever speaks first wins, and the other dies. There is
@@ -709,12 +733,12 @@ what makes three answers three. A wait that does not end is not an object,
709
733
  not silence and not unreached, and before the allowance a cycle of legal asks
710
734
  could produce one: A asks B, B answering asks A back, A answering asks B on
711
735
  the relation the first ask still holds. Now the innermost wait gives up, the
712
- silence unwinds outward, and the ask ends.
736
+ word `late` unwinds outward, and the ask ends.
713
737
 
714
- **A wait that ran out is silence, never unreached.** Unreached promises
715
- nothing was delivered and is safe to ask again. A bound that expired knows no
716
- such thing: the far door may have heard and be working still. What comes
717
- back late is not read.
738
+ **A wait that ran out is the word `late`, never silence and never
739
+ unreached.** Unreached promises nothing was delivered and is safe to ask
740
+ again. A bound that expired knows no such thing: the far door may have heard
741
+ and be working still. What comes back late is not read.
718
742
 
719
743
  The harbor keeps a patience of its own, and the two never read each other.
720
744
  What a harbor hands back as nothing came back is unreached, and unreached
@@ -722,7 +746,7 @@ says nothing was delivered: a harbor may answer it only where it knows the
722
746
  bytes never arrived, no reach for that pk, a socket that would not open, a
723
747
  link that is down. A harbor that sent them and then gave up knows no such
724
748
  thing, and must not answer at all; the ward's bound will ring, and that is
725
- silence, which promises nothing. A harbor that throws has answered nothing
749
+ `late`, which promises nothing. A harbor that throws has answered nothing
726
750
  in a louder voice, and the ward reads it as nothing: unreached. So a harbor
727
751
  may hold a shorter patience than the ward for its own reasons, a socket it
728
752
  wants back or a queue it will not grow, and whichever ends first ends the
@@ -747,7 +771,10 @@ Every arrival is judged by the door, and named by it or falls silent.
747
771
  payload names, and dispatch as `{}`. Nothing is written.
748
772
  3. For a heir: admit the signer if it is the key held for that heir or the
749
773
  key that key announced, or the key held when she removed the id. Verify
750
- the signature. Only then say anything or write anything: a removed
774
+ the signature. Read admission again, since the door judges arrivals
775
+ concurrently and a knock that raced this one may have spent the heir
776
+ while the signature was checked. Only then say anything or write
777
+ anything: a removed
751
778
  relation is `removed`, a being not back this run is `absent`, a knock
752
779
  with no key is `unannounced`, a number already honoured is `repeated`,
753
780
  and none of those writes. Else spend the number and settle the keys, so
@@ -800,14 +827,17 @@ on the bytes.
800
827
  ```
801
828
  ask on the wire box = ephemeral X25519 pk (32) || AES-GCM( payload || signature (64) )
802
829
  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.
830
+ payload = JSON { to, by, next, seq, time, hops?, method?, args? }
831
+ signed by `by`. to, by, next: 64 lowercase hex. to, next may be null.
832
+ to names the heir, or null for the public being. seq is a whole
833
+ number from one. args, when present, is one object of values.
806
834
  hops is reserved: a whole number, never below zero,
807
835
  refused at zero, and nothing sets it.
808
836
  reply on the wire box = ephemeral X25519 pk (32) || AES-GCM( reply || signature (64) )
809
837
  sealed to the ask's ephemeral pk, signed by the ward key
810
838
  reply = JSON { object, seen } | { silence: true } | { quo: word }
839
+ seen is always present: the digest, 64 hex, on a named ask that
840
+ had one, and null otherwise, the empty ask included.
811
841
  word: removed | absent | unannounced | repeated | threw. only to a key the door bound.
812
842
  ```
813
843
 
@@ -854,8 +884,9 @@ It owns nothing durable. It is three things, all in the harbor's hands:
854
884
  its seed, its partition, and the classes its beings are made of. The
855
885
  partition names each class and the harbor holds the bodies, so a ward is
856
886
  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 and never decides, asks, or
858
- learns whether anything was kept. Between one run and the next, a ward is
887
+ the other two came from. It writes as it runs, says so after every write,
888
+ and never decides, asks, or learns whether anything was kept. Between one
889
+ run and the next, a ward is
859
890
  nothing at all.
860
891
 
861
892
  One ward is one runtime and one language, and every being in it shares both.
@@ -871,8 +902,9 @@ list is a promise, not an accident: `test/terrain.test.ts` fails the build
871
902
  both when a file names a platform and when it reaches for a global outside
872
903
  the list, and when the list names one the tree has stopped using.
873
904
 
874
- The package exports raw TypeScript, extension and all, on every specifier, so
875
- Node loads it directly and every other terrain reaches a ward through a
905
+ The package exports the emitted `dist/`, JavaScript with a declaration
906
+ beside it, on every specifier, so plain Node imports it; the tree runs the
907
+ source directly, and every other terrain reaches a ward through a
876
908
  bundler. `test/bundle.test.ts` bundles the three words and runs them, and
877
909
  asserts the artefact carries nothing a terrain cannot provide.
878
910
 
@@ -887,8 +919,9 @@ of every terrain at once. Five run it: Node, a browser, workerd, Deno and
887
919
  Bun. Bun is the one that is not V8, so "the language alone" is checked
888
920
  against two implementations of the language and not one.
889
921
 
890
- `npm run check` is Node alone, and stays fast. `npm run check:terrain` is the
891
- browser and the edge, kept apart because a browser is a download and not a
922
+ `npm run check` is Node alone, and stays fast. `npm run check:terrain` is
923
+ every other terrain, the browser, workerd, Deno and Bun, kept apart because
924
+ each is a binary of its own and the browser is a download and not a
892
925
  package: a fresh clone needs `npx playwright install chromium` first, and is
893
926
  told so in one sentence rather than a stack trace.
894
927
 
@@ -897,7 +930,9 @@ told so in one sentence rather than a stack trace.
897
930
  Everything durable a ward has is here, every secret included, and nothing
898
931
  here is ever in a being's cells. Values only, so the harbor may persist it as
899
932
  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. The shape is `src/ward/partition.ts`.
933
+ reboot from its JSON is the same ward. A harbor that keeps it copies it
934
+ through JSON and never structured-clones it: what the ward hands out is
935
+ behind the cells guard. The shape is `src/ward/partition.ts`.
901
936
 
902
937
  ```
903
938
  partition
@@ -949,7 +984,9 @@ A constructor that throws on a restart takes only herself down: she is
949
984
  absent this run, no door, so `absent` at her door to the keys she bound and
950
985
  silence to strangers, and her cells sit untouched waiting for the run that
951
986
  can read them. The ward is up and so is everyone
952
- else. A class the harbor no longer knows is the same absence, and so is a
987
+ else. Her row is hers while she is absent: the owner sees her as absent, no
988
+ class boots under her key, and the owner may unboot her. A class the harbor
989
+ does not hold this run is the same absence, and so is a
953
990
  class the harbor holds at a body the cells were not written for: which body
954
991
  a ward reboots on is the harbor's decision, and a ward cannot tell an old
955
992
  one from a new one. Loss of the partition is loss of every relation,
@@ -989,10 +1026,10 @@ renders anyone's and holds no list of its own.
989
1026
 
990
1027
  ```
991
1028
  ask() -> { asks: [boot, public, invite, knock, remove, unboot],
992
- notes: { pk, beings: { key: { class, public, digest } } } }
1029
+ notes: { pk, beings: { key: { class, public, digest, absent? } } } }
993
1030
  ask('boot', { key, class }) -> { booted: key } | { error }
994
1031
  ask('public', { key }) -> { public: key } | { error }
995
- ask('invite', { being, id }) -> invitation | null | { error }
1032
+ ask('invite', { being, id, notes? }) -> invitation | null | { error }
996
1033
  ask('knock', { being | { boot: class, key },
997
1034
  id, invitation, method?, args?, wanted? })
998
1035
  -> { taken: id | null, answer } | { error: 'silence' | 'unreached' | ... }
@@ -1004,16 +1041,20 @@ anything else -> { error: 'unknown ask' }
1004
1041
  - The owner is a caller like any other: `wanted` says what its knock may
1005
1042
  spend, and saying nothing is the ward's default, exactly as for a being.
1006
1043
  - 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
- - Boot refuses a key already booted and a class the harbor does not know; a
1009
- boot that made nobody leaves the partition as it found it. A throw at
1010
- birth is that boot's error, and nothing half-lives.
1044
+ being that throws or falls silent there shows a null digest. A being
1045
+ absent this run is listed with a null digest and `absent: true`.
1046
+ - Boot refuses a key that has a row in the partition, booted this run or
1047
+ absent, and a class the harbor does not know; a boot that made nobody
1048
+ leaves the partition as it found it. A throw at birth is that boot's
1049
+ error, `{ error: 'threw at birth' }`, and nothing half-lives; a being's
1050
+ own boot answers null for it.
1011
1051
  - Public marks a being already booted as the ward's one public being. It
1012
1052
  refuses a key not booted, the ward's own pk, and a second public being
1013
1053
  while one stands, since marking a second would leave the first holding
1014
1054
  every relation she had, reachable by nobody at the bare pk and told by
1015
1055
  nobody she was replaced. Marking the one already public again is
1016
- answered, and changes nothing.
1056
+ answered, and changes nothing. A public being absent this run is
1057
+ reachable by nobody already, so the mark may move to another.
1017
1058
  - Invite on the ward's own pk mints an owner, and only the root may ask it:
1018
1059
  from the door it is answered as an invite on nobody. The ward has
1019
1060
  occupants, its owners, and no standings: a knock for the ward itself is a
@@ -1034,7 +1075,9 @@ anything else -> { error: 'unknown ask' }
1034
1075
  heir with silence as one that never had a public being does. The ward
1035
1076
  itself is refused, for the reason knock is: it would be a ward deleting
1036
1077
  itself from inside its own map, leaving its owners bound to a door that is
1037
- gone.
1078
+ gone. An absent being is unbooted the same way: she has no stance to speak
1079
+ for her, so the ward closes her heirs itself, and her occupants hear
1080
+ `removed`.
1038
1081
  - The owner's remove is the mirror of its knock: a relation out of a being,
1039
1082
  by id, and the id may be an occupant or a standing, since the two share
1040
1083
  one namespace. The being's own remove says nothing; the owner hears
@@ -1104,7 +1147,12 @@ being, holds no id, reads no partition, and is nobody outside its device.
1104
1147
 
1105
1148
  The harbor:
1106
1149
 
1107
- - Boots wards as processes, one seed each, and keeps each ward's partition.
1150
+ - Boots wards as processes, one seed each, and keeps each ward's partition:
1151
+ saves it when the ward says it wrote, one save at a time per ward and in
1152
+ the order it was told, so a being driven in process is kept the way one
1153
+ reached through a door is. A save that fails is the harbor's to count and
1154
+ never a door's to answer: the door answered bytes, and a full disk is not
1155
+ a reason the far side may hear.
1108
1156
  - Holds the class bodies for its wards, and remembers for each ward where
1109
1157
  its bodies came from, so that a restart is on the same bodies unless the
1110
1158
  harbor decides otherwise. Constructs a being when a ward names a class
@@ -1154,12 +1202,13 @@ one hop: a pk that is not its own and not a direct peer's is nothing. It
1154
1202
  keeps no lease: two of them may hold one seed and one partition, which is
1155
1203
  the broken vouch every real harbor refuses, kept here so that the tests can
1156
1204
  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.
1205
+ is made on it first, so that the network never hides a fault in the words;
1206
+ the harbor core then passes the same suite over memory stores.
1158
1207
 
1159
1208
  What a harbor on a device keeps is a ward's three parts under one name: the
1160
1209
  seed, the partition, and a **ward record**, which says where the class
1161
1210
  bodies come from and which being is the user's. That is the **store**,
1162
- `src/harbor/store.ts`: list, load, put, save the partition after a call,
1211
+ `src/harbor/store.ts`: list, load, put, save the partition when the ward wrote,
1163
1212
  save the record after a boot learned the pk, take a ward out as the first
1164
1213
  move of a migration, and keep the directory's hints, a pk to a URL, across
1165
1214
  a restart. A name already kept is refused. A store reads nothing it keeps
@@ -1183,14 +1232,17 @@ WebSocket, and this tree holds either end of a line and never a listener:
1183
1232
  who accepts a socket is the terrain's business. A reach reads nothing; a
1184
1233
  harbor opens no box but its own probe's.
1185
1234
  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, a line already gone. A
1235
+ pk at the far end, a connection that would not open or closed before it
1236
+ opened, a line already gone, a status from a request that says the listener
1237
+ did not take the bytes, refused on their face or with nobody behind the
1238
+ gateway. A
1187
1239
  reach that sent the bytes and lost the line after answers nothing at all,
1188
1240
  and the ward's bound ends the ask. Every reach passes
1189
1241
  `src/conformance/reach.ts` untouched, and the frames are pinned in
1190
1242
  `vectors/wire.json`.
1191
1243
 
1192
1244
  A reach also carries the **wire suite**: which frames these are, and which
1193
- four algorithms seal what they travel with. It is one number, it is not
1245
+ five algorithms seal what they travel with. It is one number, it is not
1194
1246
  negotiated, and today it is 1. It rides where a line is opened and never on
1195
1247
  an ask: in the text frame a socket announces itself with, and as the header
1196
1248
  `quo-suite` on a request. So an ask is still bytes from the first one, with
@@ -1209,7 +1261,7 @@ refused as it is written: the number is compared as it was sent, so a suite
1209
1261
  is one spelling and not a family of them.
1210
1262
 
1211
1263
  This is the only place a second suite could ever be told from the first.
1212
- The four algorithms are named once and never negotiated, which is right: a
1264
+ The five algorithms are named once and never negotiated, which is right: a
1213
1265
  choice offered on the wire is a choice a stranger can push. But named once
1214
1266
  is not the same as unnameable, and a kit that must one day seal differently
1215
1267
  has to be able to say so to a kit that cannot, or the day it arrives every
@@ -1221,9 +1273,14 @@ is: the store and the reach put together under the ground. It boots every
1221
1273
  ward the store keeps, keeps the map of ward pk to door for its own wards
1222
1274
  and the **directory**, pk to reach, for foreign ones, carries bytes to a
1223
1275
  pk and delivers bytes from the wire to one door. The directory is filled
1224
- three ways, in this order: its own doors; a socket a dialer holds to it,
1276
+ four ways, in this order: its own doors; a socket a dialer holds to it,
1225
1277
  bound once the door behind the dialer's claim has proved it, and unbound
1226
- when the line closes; and a hint, a pk at a URL, kept in the store.
1278
+ when the line closes; the claims of a listener this harbor dialed, proven
1279
+ the same way and reached through that line; and a hint, a pk at a URL,
1280
+ kept in the store. A hint never displaces a reach proven at a door. An
1281
+ announce names at most sixty-four pks, proven a few at a time, and is the
1282
+ newest word: a proof still in flight from an earlier announce on the same
1283
+ line binds nothing when it lands.
1227
1284
 
1228
1285
  An announce is a claim, and a claim binds nothing until proven: anyone who
1229
1286
  can reach a listener could otherwise name a pk that is not theirs and take
@@ -1238,8 +1295,9 @@ listener proves the dialer's claims and the dialer the listener's. What a
1238
1295
  relay that genuinely reaches a ward elsewhere can still do is forward the
1239
1296
  probe and pass, and then it is a rendezvous for that ward like any other,
1240
1297
  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 whose key
1242
- signed. One rule makes a **rendezvous** of
1298
+ the one it sealed itself, and it reads nothing from it but that it is the
1299
+ silence a door owes such a box, signed by the claimed key. One rule makes a
1300
+ **rendezvous** of
1243
1301
  any listener: bytes that arrive from the wire go to an own door or to a
1244
1302
  socket this harbor holds for that pk, and never onward by request. So a
1245
1303
  harbor that cannot be dialed is reached through the one it dialed, by
@@ -1285,8 +1343,7 @@ describes herself, per asker, by answering the empty ask.
1285
1343
 
1286
1344
  Not stressed with: where anyone lives; crypto, keys, wire, storage, clocks,
1287
1345
  or the harbor; strangers, because nobody her ward cannot name reaches her;
1288
- whether an occupant is a person, a model or a program; making beings, because
1289
- only the ward instantiates.
1346
+ whether an occupant is a person, a model or a program.
1290
1347
 
1291
1348
  ### Her obligations
1292
1349
 
@@ -1313,9 +1370,11 @@ only the ward instantiates.
1313
1370
  asks is always a new call. The one exception is the public being, who is
1314
1371
  reached with no heir and no count: the same bytes reach her twice, and
1315
1372
  her answer must be safe to repeat.
1316
- 8. Beings do not make beings. A being that could create would hold class,
1317
- memory and key, and there would be no ward. A being that wants a child
1318
- gets one from outside, as an invitation handed to her.
1373
+ 8. A being may make a being of her own ward, by class name and under a key
1374
+ she chooses, and holds no relation to her until one is invited and taken
1375
+ like any other; the ward builds the stance and the harbor holds the
1376
+ class, so she never touches either. Only the owner reaches into a being
1377
+ from outside.
1319
1378
  9. Whatever her ward cannot name is not hers to worry about: what the ward
1320
1379
  does with an arrival it cannot name is the ward's.
1321
1380
 
@@ -1338,10 +1397,13 @@ The raw shape needs no import from the kit. The kit also offers a base class,
1338
1397
  inherited from Object's prototype is `{ error: 'unknown ask' }` and the
1339
1398
  method is never entered.
1340
1399
  - 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.
1400
+ fails at birth, loudly, so a boot fails and nothing half-lives. The
1401
+ method is one on her prototype chain below Object's: a class field
1402
+ holding a function is not there yet when the base checks, and the
1403
+ refusal says so.
1342
1404
  - `occupant(asker)` is the occupant record for whoever is at the door, and
1343
- undefined at a public being. `invite`, `knock`, `take`, `standings` and
1344
- `occupants` reach the stance and nothing else.
1405
+ undefined at a public being. `invite`, `knock`, `take`, `boot`, `cells`,
1406
+ `standings` and `occupants` reach the stance and nothing else.
1345
1407
 
1346
1408
  ### Examples
1347
1409
 
@@ -1375,6 +1437,7 @@ class Shop {
1375
1437
  }
1376
1438
  async answer(asker, method, args) {
1377
1439
  if (method === undefined) return { asks: [{ name: 'hello', input: {} }], notes: {} };
1440
+ if (asker.id === undefined) return { welcome: false }; // a stranger at the public door has no record
1378
1441
  const rec = this.s.cells.occupants[asker.id];
1379
1442
  if (method === 'hello' && args.invitation) {
1380
1443
  const back = await this.s.standings.knock(args.invitation, 'hi');
@@ -1408,15 +1471,18 @@ class Guest {
1408
1471
  ```
1409
1472
 
1410
1473
  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.
1474
+ for a short wait because she is one door of several. Silence passes through
1475
+ her; a word does not, since a word out of a being is `threw` at the door,
1476
+ D13, so she says it as an error of her own.
1412
1477
 
1413
1478
  ```js
1414
1479
  class Relay {
1415
1480
  constructor(stance) {
1416
1481
  this.s = stance;
1417
1482
  }
1418
- answer(asker, method, args) {
1419
- return this.s.standings.next.ask(method, args, { time: 2000 }); // silence and unreached pass through
1483
+ async answer(asker, method, args) {
1484
+ const out = await this.s.standings.next.ask(method, args, { time: 2000 });
1485
+ return isWord(out) ? { error: wordOf(out) } : out; // unreached and late reach her asker as an error, not as a throw
1420
1486
  }
1421
1487
  }
1422
1488
  ```
@@ -1452,8 +1518,7 @@ words, and nothing is kept for a holder of an earlier one.
1452
1518
 
1453
1519
  The tree runs as TypeScript and the package ships as JavaScript. Node
1454
1520
  strips types nowhere under `node_modules`, so a consumer cannot load the
1455
- source, and 0.1.0, which shipped it, imported nowhere; 0.1.1 is the first
1456
- version a stranger can import. `npm run build` emits `dist/` from `src`
1521
+ source. `npm run build` emits `dist/` from `src`
1457
1522
  alone, one JavaScript file and one declaration file per source file with
1458
1523
  every relative import rewritten, and the exports map points there, types
1459
1524
  beside default. The
@@ -1463,11 +1528,12 @@ which is how a consumer does. `test/package.test.ts` is the one
1463
1528
  suite that meets the package as a stranger: it packs the tarball,
1464
1529
  installs it into an empty folder, and imports every entry point under
1465
1530
  plain Node. `npm pack --dry-run` shows what ships: `dist/`, the four
1466
- source folders, the vectors, this document, the README and the licence,
1467
- and nothing else. This document ships, decided here: it is the truth the
1468
- source and the vectors are read against, and a kit in another language is
1469
- written against it and nothing else. Publishing runs both gates first,
1470
- `npm run check` and `npm run check:terrain`, and refuses on a failure.
1531
+ source folders, the vectors, this document, the README, the licence and
1532
+ the notice, and nothing else. This document ships, decided here: it is the
1533
+ truth the source and the vectors are read against, and a kit in another
1534
+ language is written against it and nothing else. Publishing runs both
1535
+ gates first, `npm run check` and `npm run check:terrain`, and refuses on a
1536
+ failure.
1471
1537
 
1472
1538
  ```
1473
1539
  src/being/ the Being side. types, the base class, silence, the digest.
@@ -1514,8 +1580,9 @@ passes the same suite. Those tests are the checklist, not the mock.
1514
1580
  - `src/conformance/index.ts`: one suite of behaviours, written against the
1515
1581
  stance and one probe: a kit hands the suite its ward's heir table and
1516
1582
  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 them and
1518
- never writes them. With the beings in `src/conformance/beings.ts`: a
1583
+ refusal wrote nothing and a knock bound what it should. It reads the
1584
+ tables and never writes them; the forged knock is the one thing it sends
1585
+ through a door. With the beings in `src/conformance/beings.ts`: a
1519
1586
  printer, a shop, two customers, one raw being with no base class, and a
1520
1587
  member of an estate. Any ward must pass it, under any topology.
1521
1588
  - `src/conformance/estate.ts`: the estate, and the last chapter of that
@@ -1594,8 +1661,11 @@ passes the same suite. Those tests are the checklist, not the mock.
1594
1661
  reach suite against the socket framing over two lines in one process, so
1595
1662
  the frames are asserted with no network under them; the conformance
1596
1663
  suite against two harbor cores over memory stores reaching each other
1597
- in-process, drop and adopt as the migration; a restart from the store
1598
- with the hints; the dialer over a stubbed line, announce, a claim proven
1664
+ in-process, drop and adopt as the migration; a ward that moves harbor
1665
+ keeping its pk and every relation, the rendezvous told on the line in
1666
+ hand; a ward booted or dropped after a line opened, announced on that
1667
+ line, and a claim on a pk nobody holds binding nothing; a restart from
1668
+ the store with the hints; the dialer over a stubbed line, announce, a claim proven
1599
1669
  at a real door before it binds and a claim nobody there holds left
1600
1670
  unbound, fallback, unbind and the wait before it dials again; and the frames against
1601
1671
  `vectors/wire.json`, the ask, the reply, nothing delivered and the
@@ -1614,7 +1684,7 @@ passes the same suite. Those tests are the checklist, not the mock.
1614
1684
  `node:assert/strict`, pair by pair. The suite means the same thing on
1615
1685
  every terrain only if those two agree, so they are compared and not
1616
1686
  trusted.
1617
- - `test/floor.test.ts`: the four algorithms this terrain must carry, probed
1687
+ - `test/floor.test.ts`: the five algorithms this terrain must carry, probed
1618
1688
  one by one; that the arithmetic spends every one of them; and the two ways
1619
1689
  a terrain can be short -- no `crypto.subtle` at all, and a subtle without
1620
1690
  the curves -- each failing at the first call, in one sentence.
@@ -1745,7 +1815,7 @@ Decided here, so that the answer is not rediscovered:
1745
1815
  - **invite**: mint an id and get its invitation.
1746
1816
  - **knock**: an ask carrying an invitation. Binds the far side to the id.
1747
1817
  - **take**: keep an answered knock as a standing, under her own id.
1748
- - **ask**: method and args to a standing. Object, silence, or unreached back.
1818
+ - **ask**: method and args to a standing. Object, silence, or a word back.
1749
1819
  - **answer**: her one function. Object or silence out.
1750
1820
  - **the empty ask**: ask with no method. Her answer to it is her blueprint.
1751
1821
  - **blueprint**: her interface as she chooses to show it to one asker.
@@ -1759,11 +1829,13 @@ Decided here, so that the answer is not rediscovered:
1759
1829
  - **unreached**: the word for no far door reached. Retryable.
1760
1830
  - **notes**: hers, inside every occupant record. Quo never reads it.
1761
1831
  - **partition**: the ward's files. Everything durable, every secret.
1762
- - **ward record**: what a harbor keeps to boot one ward again: seed,
1763
- partition, and where its class bodies come from. The harbor's, never
1764
- the ward's.
1832
+ - **ward record**: what a harbor keeps beside a ward's seed and partition
1833
+ to boot her again: her pk, where the class bodies come from, and which
1834
+ being is the user's. The harbor's, never the ward's.
1835
+ - **lid**: the ephemeral X25519 pk an ask carries in front of its box. The
1836
+ reply is sealed to it and to nothing else. One per ask, never reused.
1765
1837
  - **edge**: one of the two seams of Quo, harbor to ward and ward to being.
1766
1838
  An object crosses once at birth, calls cross for the rest of the ward's
1767
1839
  life, and nothing else crosses.
1768
- - **ground**: the one object a harbor passes a ward. Five things.
1840
+ - **ground**: the one object a harbor passes a ward. Six things.
1769
1841
  - **door**: the ward's one voice outward. Sealed bytes in, sealed bytes out.
@@ -13,10 +13,10 @@ export declare class Being {
13
13
  get cells(): Cells;
14
14
  get standings(): Standings;
15
15
  get occupants(): Occupants;
16
- invite(id: string): Promise<Invitation | null>;
16
+ invite(id: string, notes?: JsonObject): Promise<Invitation | null>;
17
17
  knock(invitation: Invitation, method?: string, args?: JsonObject, wanted?: Wanted): Promise<Answer>;
18
18
  take(id: string, invitation: Invitation): Promise<string | null>;
19
- boot(className: string, key: string): string | null;
19
+ boot(className: string, key: string, id?: string): Promise<string | null>;
20
20
  occupant(asker: Asker): OccupantRecord | undefined;
21
21
  describe(asker: Asker): Blueprint;
22
22
  answer(asker: Asker, method?: string, args?: JsonObject): Promise<Reply>;