nervur 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CONTRIBUTING.md +13 -0
  2. package/LICENSE +55 -202
  3. package/NOTICE +3 -8
  4. package/README.md +14 -156
  5. package/RELEASING.md +15 -0
  6. package/SECURITY.md +9 -0
  7. package/bin/nervur.js +6 -0
  8. package/package.json +26 -81
  9. package/AUTHORING.md +0 -935
  10. package/COMMAND.md +0 -179
  11. package/FACES.md +0 -280
  12. package/FACULTIES.md +0 -578
  13. package/GROUNDS.md +0 -315
  14. package/KIT-SPEC.md +0 -304
  15. package/WORLD.md +0 -195
  16. package/dist/app/app-ground.d.ts +0 -18
  17. package/dist/app/app-ground.js +0 -23
  18. package/dist/app/index.d.ts +0 -2
  19. package/dist/app/index.js +0 -5
  20. package/dist/app/native.d.ts +0 -11
  21. package/dist/app/native.js +0 -13
  22. package/dist/being/being.d.ts +0 -306
  23. package/dist/being/being.js +0 -20
  24. package/dist/being/covers.d.ts +0 -9
  25. package/dist/being/covers.js +0 -21
  26. package/dist/being/index.d.ts +0 -4
  27. package/dist/being/index.js +0 -6
  28. package/dist/being/need.d.ts +0 -49
  29. package/dist/being/need.js +0 -33
  30. package/dist/being/schema.d.ts +0 -100
  31. package/dist/being/schema.js +0 -132
  32. package/dist/being/table.d.ts +0 -48
  33. package/dist/being/table.js +0 -344
  34. package/dist/bench/bench-ground.d.ts +0 -73
  35. package/dist/bench/bench-ground.js +0 -153
  36. package/dist/bench/bench.d.ts +0 -101
  37. package/dist/bench/bench.js +0 -368
  38. package/dist/bench/fake-clock.d.ts +0 -17
  39. package/dist/bench/fake-clock.js +0 -34
  40. package/dist/bench/fake-memory.d.ts +0 -16
  41. package/dist/bench/fake-memory.js +0 -46
  42. package/dist/bench/fake-network.d.ts +0 -66
  43. package/dist/bench/fake-network.js +0 -222
  44. package/dist/bench/fake-unlock.d.ts +0 -6
  45. package/dist/bench/fake-unlock.js +0 -10
  46. package/dist/bench/index.d.ts +0 -3
  47. package/dist/bench/index.js +0 -5
  48. package/dist/bench/seeded.d.ts +0 -11
  49. package/dist/bench/seeded.js +0 -37
  50. package/dist/bench/settle.d.ts +0 -2
  51. package/dist/bench/settle.js +0 -49
  52. package/dist/bench/stewards.d.ts +0 -169
  53. package/dist/bench/stewards.js +0 -128
  54. package/dist/bodies/class-list.d.ts +0 -14
  55. package/dist/bodies/class-list.js +0 -33
  56. package/dist/bodies/joined-carry.d.ts +0 -29
  57. package/dist/bodies/joined-carry.js +0 -48
  58. package/dist/bodies/kept.d.ts +0 -44
  59. package/dist/bodies/kept.js +0 -91
  60. package/dist/bodies/noble-crypto.d.ts +0 -22
  61. package/dist/bodies/noble-crypto.js +0 -88
  62. package/dist/bodies/seed-keys.d.ts +0 -10
  63. package/dist/bodies/seed-keys.js +0 -42
  64. package/dist/bodies/strict-tools.d.ts +0 -10
  65. package/dist/bodies/strict-tools.js +0 -306
  66. package/dist/bodies/vouch.d.ts +0 -20
  67. package/dist/bodies/vouch.js +0 -71
  68. package/dist/bodies/web-carry.d.ts +0 -72
  69. package/dist/bodies/web-carry.js +0 -245
  70. package/dist/bodies/web-clock.d.ts +0 -12
  71. package/dist/bodies/web-clock.js +0 -33
  72. package/dist/browser/browser-ground.d.ts +0 -76
  73. package/dist/browser/browser-ground.js +0 -294
  74. package/dist/browser/index.d.ts +0 -4
  75. package/dist/browser/index.js +0 -7
  76. package/dist/browser/indexeddb-memory.d.ts +0 -17
  77. package/dist/browser/indexeddb-memory.js +0 -97
  78. package/dist/browser/locked-unlock.d.ts +0 -24
  79. package/dist/browser/locked-unlock.js +0 -85
  80. package/dist/browser/origin-classes.d.ts +0 -7
  81. package/dist/browser/origin-classes.js +0 -31
  82. package/dist/edge/durable-clock.d.ts +0 -19
  83. package/dist/edge/durable-clock.js +0 -61
  84. package/dist/edge/durable-memory.d.ts +0 -5
  85. package/dist/edge/durable-memory.js +0 -11
  86. package/dist/edge/durable.d.ts +0 -18
  87. package/dist/edge/durable.js +0 -24
  88. package/dist/edge/edge-ground.d.ts +0 -49
  89. package/dist/edge/edge-ground.js +0 -223
  90. package/dist/edge/index.d.ts +0 -7
  91. package/dist/edge/index.js +0 -9
  92. package/dist/edge/native-crypto.d.ts +0 -8
  93. package/dist/edge/native-crypto.js +0 -102
  94. package/dist/edge/secret-unlock.d.ts +0 -7
  95. package/dist/edge/secret-unlock.js +0 -13
  96. package/dist/edge/socket-carry.d.ts +0 -39
  97. package/dist/edge/socket-carry.js +0 -111
  98. package/dist/foundation.d.ts +0 -162
  99. package/dist/foundation.js +0 -4
  100. package/dist/ground/dock.d.ts +0 -1460
  101. package/dist/ground/dock.js +0 -1159
  102. package/dist/ground/ground.d.ts +0 -239
  103. package/dist/ground/ground.js +0 -787
  104. package/dist/ground/views.d.ts +0 -76
  105. package/dist/ground/views.js +0 -208
  106. package/dist/house/crossing.d.ts +0 -50
  107. package/dist/house/crossing.js +0 -153
  108. package/dist/house/house.d.ts +0 -88
  109. package/dist/house/house.js +0 -2069
  110. package/dist/house/rows-shape.d.ts +0 -110
  111. package/dist/house/rows-shape.js +0 -12
  112. package/dist/house/rows.d.ts +0 -27
  113. package/dist/house/rows.js +0 -185
  114. package/dist/index.d.ts +0 -33
  115. package/dist/index.js +0 -29
  116. package/dist/node/bridge.d.ts +0 -20
  117. package/dist/node/bridge.js +0 -284
  118. package/dist/node/cli.d.ts +0 -2
  119. package/dist/node/cli.js +0 -225
  120. package/dist/node/file-memory.d.ts +0 -13
  121. package/dist/node/file-memory.js +0 -86
  122. package/dist/node/folder-classes.d.ts +0 -5
  123. package/dist/node/folder-classes.js +0 -40
  124. package/dist/node/gone.d.ts +0 -2
  125. package/dist/node/gone.js +0 -7
  126. package/dist/node/hand.d.ts +0 -39
  127. package/dist/node/hand.js +0 -107
  128. package/dist/node/http.d.ts +0 -11
  129. package/dist/node/http.js +0 -90
  130. package/dist/node/index.d.ts +0 -11
  131. package/dist/node/index.js +0 -13
  132. package/dist/node/ledger-memory.d.ts +0 -17
  133. package/dist/node/ledger-memory.js +0 -152
  134. package/dist/node/lock.d.ts +0 -10
  135. package/dist/node/lock.js +0 -78
  136. package/dist/node/node-ground.d.ts +0 -26
  137. package/dist/node/node-ground.js +0 -228
  138. package/dist/node/notify.d.ts +0 -1
  139. package/dist/node/notify.js +0 -18
  140. package/dist/node/shell.d.ts +0 -11
  141. package/dist/node/shell.js +0 -35
  142. package/dist/node/sync-folder.d.ts +0 -6
  143. package/dist/node/sync-folder.js +0 -18
  144. package/dist/node/tcp-carry.d.ts +0 -42
  145. package/dist/node/tcp-carry.js +0 -193
  146. package/dist/node/unlock.d.ts +0 -17
  147. package/dist/node/unlock.js +0 -86
  148. package/dist/node/websocket.d.ts +0 -12
  149. package/dist/node/websocket.js +0 -134
  150. package/dist/quo/frame.d.ts +0 -33
  151. package/dist/quo/frame.js +0 -92
  152. package/dist/quo/index.d.ts +0 -1
  153. package/dist/quo/index.js +0 -5
  154. package/dist/quo/room.d.ts +0 -154
  155. package/dist/quo/room.js +0 -362
  156. package/dist/serve/index.d.ts +0 -45
  157. package/dist/serve/index.js +0 -71
package/AUTHORING.md DELETED
@@ -1,935 +0,0 @@
1
- # Writing for nervur
2
-
3
- This guide teaches the two things you write with `nervur`. A **being**
4
- holds logic and state. A **faculty** reaches the world outside, and
5
- [Writing a faculty](FACULTIES.md) teaches it whole. A **ground** runs them on
6
- a machine, and the library ships it. The examples build one small shop,
7
- and every file here is a file the package's own tests run.
8
-
9
- The shop has three classes and one faculty.
10
-
11
- - `Order` is one order, from its first item to its shipping.
12
- - `Shop` is the steward, the being that runs the house.
13
- - `Lobby` is the public being, which strangers may ask.
14
- - `Payments` is a faculty that charges money, which `recipe.ts` holds
15
- by name.
16
-
17
- ## Words
18
-
19
- | Word | What it is |
20
- | --- | --- |
21
- | being | an instance of a class, born for one ask and dropped after it |
22
- | cells | her state, JSON values, kept when an ask lands |
23
- | ask | a method others may call on her, with its entry |
24
- | asker | who calls her now: an id and notes |
25
- | occupant | someone who may ask her, by id |
26
- | standing | someone she may ask, by id |
27
- | blueprint | the shape of what can be called: a name and its methods |
28
- | need | the blueprint she calls, at its minimum, under a member of her own |
29
- | faculty | anything outside the house that answers a blueprint |
30
- | offer | a faculty the ground hands the house: its blueprint and its object |
31
- | role | a named test over the asker and her cells |
32
- | state | a name read from her cells that decides which asks exist |
33
- | house | what holds beings, keeps their cells, and seals every ask |
34
- | ground | the process houses run in, holding one key and sealing their seeds, faculties and secrets under it |
35
- | registry | code that holds faculties by name, for the ground to stand |
36
- | body | a faculty stood: the living instance houses and bodies use |
37
-
38
- ## A being
39
-
40
- A being is pure logic over her cells. She never knows where she runs,
41
- who carries her asks, or how her cells are kept. The house does all of
42
- it, and she trusts it.
43
-
44
- ```ts
45
- // classes/order.ts
46
- import { Being, s, need, type Args } from 'nervur/being';
47
-
48
- export const Payments = need('payments', {
49
- charge: {
50
- args: s.object({ order: s.string(), amount: s.number(), notify: s.handle() }),
51
- result: s.object({ pending: s.boolean() }),
52
- },
53
- });
54
-
55
- export const Courier = need('courier', {
56
- pickup: { args: s.object({ items: s.array(s.string()) }) },
57
- });
58
-
59
- export class Order extends Being.of({
60
- kind: 'com.acme.order',
61
- description: 'One order, from its first item to its shipping.',
62
- needs: { pay: Payments },
63
- cells: {
64
- items: [] as string[],
65
- total: 0,
66
- state: 'open',
67
- paidAt: 0,
68
- courier: '',
69
- },
70
- roles: { owner: (asker) => asker.steward.owner === true },
71
- state: (me) => me.cells.state,
72
- asks: {
73
- hire: {
74
- for: 'steward',
75
- hints: { idempotent: true },
76
- args: s.object({ courier: s.handle() }),
77
- result: s.string(),
78
- },
79
- add: {
80
- in: 'open',
81
- for: 'owner',
82
- to: 'open',
83
- args: s.object({ sku: s.string(), price: s.number() }),
84
- result: s.object({ total: s.number() }),
85
- },
86
- checkout: { in: 'open', for: 'owner', to: 'paying' },
87
- charged: { in: 'paying', args: s.reply(Payments.charge), to: ['paying', 'open'] },
88
- settled: { in: 'paying', for: 'handle', to: 'paid' },
89
- ship: { in: 'paid', for: 'owner', to: 'shipped' },
90
- },
91
- }) {
92
- // The courier's invitation arrives as her standing. The same one twice is the same standing.
93
- hire({ courier }: Args<Order, 'hire'>) {
94
- this.cells.courier = courier;
95
- return courier;
96
- }
97
-
98
- add({ sku, price }: Args<Order, 'add'>) {
99
- this.cells.items = [...this.cells.items, sku];
100
- this.cells.total += price;
101
- return { total: this.cells.total };
102
- }
103
-
104
- checkout() {
105
- if (this.cells.items.length === 0) this.fail('Add an item first.');
106
- const notify = this.handle('settled', { once: true });
107
- this.pay.charge({ order: this.id, amount: this.cells.total, notify }, { reply: 'charged' });
108
- this.cells.state = 'paying';
109
- }
110
-
111
- charged({ error }: Args<Order, 'charged'>) {
112
- if (error) this.cells.state = 'open';
113
- }
114
-
115
- settled() {
116
- this.cells.state = 'paid';
117
- this.cells.paidAt = this.house.now();
118
- }
119
-
120
- ship() {
121
- if (this.cells.courier === '') this.fail('Hire a courier first.');
122
- this.held(this.cells.courier, Courier).pickup({ items: this.cells.items });
123
- this.cells.state = 'shipped';
124
- }
125
- }
126
- ```
127
-
128
- The order wrote no retry, no catch, no key and no address. `charge` is
129
- an effect, so it leaves only once `checkout` has landed. Its answer comes
130
- back to `charged`, and a refused charge opens the order again. The
131
- provider calls `settled` through the handle once the money arrives.
132
- `hire` takes a courier's invitation as her standing, and `ship` asks the
133
- courier through it. `shipped` is a terminal state, and nothing leaves it.
134
-
135
- ### The declaration
136
-
137
- A class extends `Being.of({ … })`. That one object declares the class,
138
- and TypeScript reads from it the types of her cells and her needs.
139
-
140
- | Field | What it is |
141
- | --- | --- |
142
- | `kind` | the code's name: a reversed domain you own, then a name |
143
- | `description` | one line for readers and agents |
144
- | `cells` | the state and its defaults, written where a key is missing |
145
- | `needs` | blueprints she calls, each under a member name she chooses |
146
- | `roles` | named tests over the asker and her cells |
147
- | `state` | a function of the being that names her current state |
148
- | `asks` | one entry per method she answers |
149
- | `view` | markup as text over her asks, which a screen renders |
150
-
151
- A view is data, at most 64 KiB, carried in her describe to every asker.
152
- It holds no script, and a renderer loads nothing it names, so a view
153
- neither acts nor tracks. The library defines no markup: a renderer
154
- speaks its own.
155
-
156
- Every field is optional but `kind` and `asks`. A class with no `state`
157
- has one state, named `ready`. The kind is how the house finds her code
158
- again, so a bundler that renames classes changes nothing.
159
-
160
- A method in TypeScript names its args with `Args<Class, 'method'>`,
161
- since a subclass's method takes no type from its base. A method in
162
- JavaScript writes nothing.
163
-
164
- ### An ask's entry
165
-
166
- | Field | What it says |
167
- | --- | --- |
168
- | `in` | the states where the ask exists; omitted, every state |
169
- | `for` | the roles that may call it; omitted, every occupant but handles |
170
- | `to` | the states it may land in; omitted, the state it began in |
171
- | `args` | the schema of what it takes; omitted, the empty object alone |
172
- | `result` | the schema of what it answers; omitted, nothing |
173
- | `hints` | `readOnly`, `idempotent`, `destructive` |
174
- | `examples` | a history of her asks, a role, args, fakes, and what it gives |
175
- | `description` | one line for readers and agents |
176
- | `wait` | milliseconds she may run; omitted, thirty seconds |
177
-
178
- `in`, `for` and `to` each take one name or a list of names. A method
179
- with no entry is never reached. An entry with no method is refused when
180
- the house first loads the class.
181
-
182
- Five roles are the house's. `handle` is whoever holds a handle to this
183
- ask. `stranger` is the asker of a public being. `steward` is her
184
- steward. `being` is another being her steward introduced to her. `root`
185
- is the owner, through the house's hand. Every other role is yours, a
186
- function of `(asker, me)`.
187
-
188
- The house checks the table when it first loads the class. It refuses a
189
- state no ask reaches, an ask no role reaches, and a role no ask names.
190
- After a method runs, a state outside the entry's `to` fails the ask, and
191
- nothing lands.
192
-
193
- ### What she reaches
194
-
195
- | Member | What it is |
196
- | --- | --- |
197
- | `this.id` | her own id |
198
- | `this.position` | `steward`, `public` or `normal` |
199
- | `this.asker` | `{ id, notes, steward }` of who asks now; `signer` for a stranger |
200
- | `this.cells` | her values |
201
- | `this.house.now()` | the time, in milliseconds since the epoch |
202
- | `this.house.random({ length })` | random bytes |
203
- | `this.house.alarm({ at, ask, args, key })` | one of her asks, at that time |
204
- | `this.house.cancelAlarm({ key })` | an alarm removed |
205
- | `this.<need>.<method>({…}, { reply? })` | an awaited call, or an effect |
206
- | `this.held(id, Need).<ask>({…}, { reply?, after? })` | the same, on a standing, and a watch where `after` is given |
207
- | `this.held(id).describe()`, `.ask(method, {…}, options)` | a standing with no need: what it shows her, then any ask it showed |
208
- | `this.stranger({ ward, at }, Need).<ask>({…})` | a far house's public being, asked as a stranger, every ask awaited |
209
- | `this.stranger({ ward, at }).describe()`, `.ask(method, {…})` | the same with no need: what she shows a stranger, then any ask it showed |
210
- | `this.standings` | `list()`, `note(id, notes)` and `drop(id)` |
211
- | `this.handle(ask, { bind?, notes?, once?, expires? })` | a handle to one of her asks |
212
- | `this.invite(id, { notes?, expires? })` | a new occupant, as a handle |
213
- | `this.occupants` | `list()`, `note(id, notes)` and `dismiss(id)` |
214
- | `this.steward` | her steward, where she is not one |
215
- | `this.powers` | the house's powers, where she is the steward |
216
- | `this.fail(message)` | an error the asker can act on |
217
-
218
- An alarm lives in the house's rows and survives every restart. A second
219
- alarm under one key replaces the first. When its time comes, the house
220
- asks her named ask as her steward would.
221
-
222
- ### Awaited calls and effects
223
-
224
- The callee decides how it is called, with one flag. A method or ask
225
- marked `idempotent` is safe to repeat, so the caller awaits it during
226
- her ask. Everything else is an effect. `readOnly` is stricter: it writes
227
- nothing, it implies `idempotent`, and the house holds it.
228
-
229
- An awaited call answers during her ask. `await this.fx.rate({…})`
230
- returns the answer, and a failure throws an error she may catch. It
231
- waits thirty seconds unless its entry says otherwise, and never more
232
- than five minutes.
233
-
234
- An awaited call never comes back to a being in its own chain. While she
235
- awaits, she holds her queue. A call back to her, other than a
236
- `readOnly` one, waits behind the ask that waits for it, until the wait
237
- runs out and the call fails as `answered nothing`. Call back with an
238
- effect instead.
239
-
240
- An effect leaves after her ask lands. She calls it and it returns
241
- nothing. The house writes it in the same write as her cells, then sends
242
- it with one call id until it is answered. So an effect acts at most
243
- once. Its answer comes back to the ask `reply` names, as `{ result }` or
244
- `{ error: { message } }`.
245
-
246
- An effect gives up at its deadline, seven days for a standing and the
247
- offer's window for a faculty. The reply then hears an error. Effects to
248
- one receiver leave one at a time, in the order she called them.
249
-
250
- Asks to one being run one at a time, in the order they arrive. A
251
- `readOnly` ask runs beside that queue, on the cells last landed.
252
-
253
- ### Watching an answer
254
-
255
- A watch is a `readOnly` ask asked with `after`, the answer you already
256
- hold. The house answers at once where the answer differs. Where it is
257
- the same, the house holds the ask and runs it again each time an ask of
258
- that being lands. It answers the first answer that differs, or the same
259
- one when the wait runs out. So a chat, an order's status or a dashboard
260
- is a loop of watches, and nothing polls.
261
-
262
- Through the hand, pass `after` beside the method, as the answer you
263
- hold: `{ result: [...] }`. From a being, pass the result she holds:
264
- `this.held(room, Messages).messages({}, { after: seen })`, inside a
265
- `readOnly` ask of her own, so she stays free while she waits. Only a
266
- `readOnly` ask is watched, and a watch on anything else is refused where
267
- she makes it.
268
-
269
- A watch may land as a reply instead: `{ after: seen, reply: 'heard' }`.
270
- It leaves once her ask lands, as an effect does, and its answer asks her
271
- `heard`, where she writes what she heard and watches again. So a device
272
- that only dials, a phone or a Pi behind a router, hears its station the
273
- moment something changes there, and opens no port.
274
-
275
- A watch moves only on what its asker could read, since it runs as that
276
- asker. One asker holds one watch on one ask with the same args, and a
277
- second answers the first at once. A watch across a door holds its
278
- relation until it answers, since Quo moves a relation one ask at a time.
279
- So watch a far being through a handle to the watched ask alone, a
280
- relation of its own, and ask everything else on your other standing.
281
-
282
- ### Relations
283
-
284
- An **occupant** is someone who may ask her. She mints one with
285
- `this.invite(id, { notes })`, which answers a handle, and lets one go with
286
- `dismiss`.
287
-
288
- A **standing** is someone she may ask. She receives one where an ask's
289
- args carry an invitation under `s.handle`, or where her steward
290
- introduces one. She asks through it with `this.held(id, Need)`, which
291
- checks the standing's describe covers the need. A standing from an
292
- invitation is named `standing:` and sixteen hex digits, and the id is
293
- what her ask receives. One her steward introduced is named by the being
294
- it reaches. She asks a far standing from the ask after the one that took
295
- it.
296
-
297
- Every relation carries two sets of notes. `notes` are hers alone.
298
- `steward` are her steward's, written when the steward made the relation,
299
- and she reads them and never writes them. The order's `owner` role reads
300
- the steward's notes, so only the steward decides who owns an order.
301
-
302
- A **handle** is the only way a relation leaves her. `this.handle(ask)`
303
- admits its holder to that one ask. `once` dismisses it after its first
304
- ask lands, and `bind` fixes args the holder cannot change. The house
305
- turns a handle into an invitation for a far house, or a token for a
306
- faculty. A handle never enters her cells.
307
-
308
- `expires`, on `this.handle`, `this.invite` and the steward's `invite`,
309
- gives each invitation minted from the handle that many milliseconds to
310
- be taken. Its first knock lands within that time, or it hears silence.
311
- One taken in time never expires, and one without `expires` waits for
312
- ever. Give it to every invitation a being mints on each answer, so the
313
- unspent ones go.
314
-
315
- ### The steward
316
-
317
- Every house has one steward, with the id `steward`. The holder of the
318
- house's hand asks her as the occupant `root`, which no sealed box can
319
- forge. She alone holds `this.powers`.
320
-
321
- ```ts
322
- // classes/shop.ts
323
- import { Being, s, type Args } from 'nervur/being';
324
-
325
- export class Shop extends Being.of({
326
- kind: 'com.acme.shop',
327
- description: 'The shop’s steward: opens orders, and enrols whoever signs up.',
328
- cells: { opened: 0 },
329
- roles: { pilot: (asker) => asker.id === 'root' },
330
- asks: {
331
- open: {
332
- for: 'pilot',
333
- description: 'Opens an order, and hands back an invitation for its owner.',
334
- args: s.object({ id: s.string() }),
335
- result: s.object({ owner: s.invitation() }),
336
- },
337
- orders: { for: 'pilot', hints: { readOnly: true }, result: s.array(s.string()) },
338
- hire: {
339
- for: 'pilot',
340
- description: 'Hands a courier’s invitation to an order, which takes it.',
341
- hints: { idempotent: true },
342
- args: s.object({ order: s.string(), courier: s.invitation() }),
343
- result: s.string(),
344
- },
345
- enroll: {
346
- for: 'being',
347
- hints: { idempotent: true },
348
- args: s.object({ signer: s.bytes() }),
349
- result: s.object({ invitation: s.invitation() }),
350
- },
351
- },
352
- }) {
353
- open({ id }: Args<Shop, 'open'>) {
354
- this.powers!.bear({ kind: 'com.acme.order', id });
355
- this.cells.opened += 1;
356
- return { owner: this.powers!.invite({ id, occupant: 'owner', notes: { owner: true } }) };
357
- }
358
-
359
- async orders() {
360
- return (await this.powers!.list()).filter((being) => being.kind === 'com.acme.order').map((being) => being.id);
361
- }
362
-
363
- // She carries the invitation unopened, and the order she names takes it.
364
- async hire({ order, courier }: Args<Shop, 'hire'>) {
365
- return (await this.powers!.ask({ id: order, method: 'hire', args: { courier } })) as string;
366
- }
367
-
368
- // One order a signer: asked twice, the same id is borne once.
369
- enroll({ signer }: Args<Shop, 'enroll'>) {
370
- const id = `order-${Array.from(signer.subarray(0, 8), (byte) => byte.toString(16).padStart(2, '0')).join('')}`;
371
- this.powers!.bear({ kind: 'com.acme.order', id });
372
- const occupant = `owner-${Array.from(this.house.random({ length: 4 }), (byte) => byte.toString(16).padStart(2, '0')).join('')}`;
373
- return { invitation: this.powers!.invite({ id, occupant, notes: { owner: true } }) };
374
- }
375
- }
376
- ```
377
-
378
- | Power | What it does |
379
- | --- | --- |
380
- | `bear({ kind, id, args })` | places a new being; the same id twice answers the first |
381
- | `remove({ id })` | removes a being and everything of hers |
382
- | `list()` | every being, her kind, whether she is absent, and her dead letters |
383
- | `ask({ id, method, args }, { reply? })` | asks any being as her occupant `steward`; with no method, reads what she shows the steward |
384
- | `introduce({ from, to, notes })` | gives `from` a standing on `to`, and `to` an occupant |
385
- | `invite({ id, occupant, notes, expires? })` | gives a being a new occupant, and the steward its handle |
386
-
387
- `bear`, `remove`, `introduce` and `invite` land in the steward's own
388
- write. If her ask fails, none of them happened. A being borne runs her
389
- `born` ask first, where her class declares one, asked as the occupant
390
- `steward`, so its entry says `for: 'steward'`.
391
-
392
- Every other being is placed as `normal`. She holds the standing
393
- `steward` and the occupant `steward`, and can drop neither.
394
-
395
- An invitation from outside lands where the owner says. The courier's
396
- invitation reaches the owner by any road, a mail or a link. The owner
397
- hands it to the steward's `hire` with the order it is for. `hire`
398
- declares it `s.invitation`, so the steward carries it unopened and never
399
- holds it. The order's `hire` declares it `s.handle`, so the order takes
400
- it, and the standing is hers.
401
-
402
- Taking an invitation is safe to repeat. The same invitation taken again
403
- gives the same standing, so the order's `hire` is `idempotent`, and the
404
- steward awaits it. The owner hears the standing, or why it was refused.
405
- A steward that bears a being for an invitation bears her first, then
406
- hands it to her the same way.
407
-
408
- ### A public being
409
-
410
- A house may name one public being, with the id `public`. She answers
411
- strangers: every asker with no relation is the occupant `stranger`, and
412
- `this.asker.signer` is the key the ask was signed with.
413
-
414
- ```ts
415
- // classes/lobby.ts
416
- import { Being, need, s } from 'nervur/being';
417
-
418
- /** What the lobby asks of her steward. */
419
- const Signup = need('signup', {
420
- enroll: {
421
- hints: { idempotent: true },
422
- args: s.object({ signer: s.bytes() }),
423
- result: s.object({ invitation: s.invitation() }),
424
- },
425
- });
426
-
427
- export class Lobby extends Being.of({
428
- kind: 'com.acme.lobby',
429
- description: 'The shop’s front door: a stranger signs up and receives an order of their own.',
430
- asks: {
431
- signup: { for: 'stranger', result: s.object({ invitation: s.invitation() }) },
432
- },
433
- }) {
434
- signup() {
435
- return this.held('steward', Signup).enroll({ signer: this.asker.signer! });
436
- }
437
- }
438
- ```
439
-
440
- A public being's asks are idempotent by default, since a stranger's box
441
- may arrive twice. The house answers a replayed stranger's box from a
442
- cache for ten minutes, and nothing runs twice. An ask marked
443
- `hints: { idempotent: false }` is refused to strangers.
444
-
445
- Signup awaits the steward. The lobby asks `enroll`, which is
446
- `idempotent`, so the lobby awaits its answer and returns the invitation
447
- unopened. A stranger who signs up twice holds one order.
448
-
449
- Signup is this shop's choice, not the house's. A house is its owner's,
450
- and a public being does only what its owner wrote. One may answer who
451
- the house is and nothing more. A house with no public being answers
452
- strangers silence.
453
-
454
- ### Schemas
455
-
456
- One builder gives the schema and the TypeScript type: `s.object`,
457
- `s.string`, `s.number`, `s.integer`, `s.boolean`, `s.array`, `s.enum`,
458
- `s.const`, `s.bytes`, `s.optional`, `s.handle`, `s.invitation` and
459
- `s.reply`. They write JSON Schema 2020-12, in a subset the house checks
460
- on every ask.
461
-
462
- - `s.bytes` is a `Uint8Array` in the process and lowercase hex across a
463
- door.
464
- - `s.handle` carries a relation. A handle leaves as an invitation, and
465
- an invitation arrives as a new standing id.
466
- - `s.invitation` carries an invitation unopened, as the lobby does.
467
- Passed on under `s.handle`, it is taken by the being that receives
468
- it. Taking one is safe to repeat: the same invitation gives the same
469
- standing.
470
- - `s.reply(method)` is the args of an effect's reply: `{ result }` or
471
- `{ error: { message } }`.
472
-
473
- ### Needs
474
-
475
- A need is a blueprint at its minimum: what she will call, never what a
476
- faculty offers. `need(name, methods)` writes one, and she binds it to a
477
- member of her own in `needs`. An offer covers a need when four things
478
- hold.
479
-
480
- 1. The blueprint's name is the same.
481
- 2. Every method the need names is offered. More are allowed.
482
- 3. The offer requires no property the need does not require.
483
- 4. Each method is `idempotent` in both, or in neither.
484
-
485
- Every need is covered, or she is absent. An absent being answers silence
486
- and keeps her cells, and answers again once an offer covers her needs.
487
-
488
- A standing is matched to a need by rules two to four alone. A describe
489
- names no blueprint, so the need's name is hers to choose there.
490
-
491
- A need she forgot to declare is a member she does not hold, and the call
492
- throws inside her ask, which answers only `the ask failed`. So check your
493
- classes with `npx tsc --noEmit` beside your tests, which run with
494
- `node --test`.
495
-
496
- ### Testing on the bench
497
-
498
- The bench opens two houses on one ground in memory, on fake memory,
499
- keys and clock. A being of the bench's own house asks hers through a
500
- door, so every ask crosses as it would in production.
501
-
502
- ```ts
503
- // order.test.ts
504
- import assert from 'node:assert/strict';
505
- import { test } from 'node:test';
506
- import { Bench } from 'nervur/bench';
507
- import { Order } from './classes/order.ts';
508
- import { Payments, paymentsOffer } from './payments.ts';
509
-
510
- test('Order keeps her table: every state and role shows what it owes', async () => {
511
- await Bench.check(Order);
512
- });
513
-
514
- test('An order is paid once the provider calls the handle it was given', async () => {
515
- const payments = new Payments();
516
- const bench = await Bench.open({ classes: [Order], offers: [paymentsOffer(payments)] });
517
- const order = await bench.place(Order, { id: 'first' });
518
-
519
- assert.deepEqual(await order.ask('checkout'), { error: { message: 'Add an item first.' } });
520
- assert.deepEqual(await order.ask('add', { sku: 'tea', price: 4 }), { result: { total: 4 } });
521
- assert.deepEqual(await order.ask('checkout'), { result: null });
522
- await bench.settle();
523
- assert.equal((await order.describe())?.state, 'paying', 'the charge left once checkout landed, and answered pending');
524
-
525
- assert.deepEqual(await payments.settle('first'), { result: null });
526
- await bench.settle();
527
- assert.equal((await order.describe())?.state, 'paid');
528
- assert.deepEqual(await order.ask('add', { sku: 'jam', price: 1 }), { error: { message: 'not in this state' } });
529
- });
530
- ```
531
-
532
- `place(Class, { id, born })` has the bench's steward bear a being. A
533
- placed being is asked with `ask(method, args, { role })` and described
534
- with `describe({ role })`. Test her through her asks first, as every
535
- asker meets her. `cells()` reads her cells through the hand, as her owner
536
- inspects them. An effect answers with the reply it brings once it lands.
537
- `settle()` lets every effect and reply run, and `advance(ms)` moves the
538
- fake clock.
539
-
540
- The bench plays a role as an owner could, judged on her cells as they
541
- stand. `root`, and a role root holds, is the hand. `steward` is the
542
- bench's steward, and `being` a being it introduces to her. Any other
543
- role is an occupant the bench's steward invites, with the role `true` in
544
- its steward notes. A role read from her own notes is hers to grant, and
545
- a handle only her own ask mints.
546
-
547
- A steward and a public being are placed where the house places them.
548
- `Bench.open({ steward: Shop, public: Lobby, classes: [Order] })` opens the
549
- author's house with them there, and `place(Shop)` and `place(Lobby)` find
550
- them. On the public being, a role a stranger holds is played by a being
551
- of the bench's own house, asking as a stranger. Beside a steward the test
552
- brings, the bench plays `root` and `stranger` alone, and places no other
553
- being. A world of your steward and the beings she bears is tested on a
554
- BenchGround, as [Faces](FACES.md) tests its desk.
555
- `Bench.check(Shop, { position: 'steward' })` and `Bench.check(Lobby, {
556
- position: 'public' })` check them.
557
-
558
- An entry's `examples` are tests the bench runs. Each is a history, then
559
- one ask, on a fresh bench. `given` lists the asks of hers that bring her
560
- from her `born` to where the example starts. `role` asks, `args` are the
561
- ask's, `fakes` answer her needs, and `gives` is the answer owed.
562
- `Bench.check` runs every example twice from one seed and flags a class
563
- that answers differently, or leaves her cells differently. It then
564
- describes every state to every role it plays, and names every finding
565
- that failed.
566
-
567
- ## A faculty
568
-
569
- A faculty is anything a being may call that is not a being: a payment
570
- provider, a mail sender, a model, a sensor. The ground hands it to the
571
- house as an offer, and the house matches it to every need it covers.
572
-
573
- ```ts
574
- // payments.ts
575
- import type { FacultyContext, Offer } from 'nervur';
576
- import { need, s } from 'nervur/being';
577
-
578
- /** What the faculty offers. An order's need is covered by it. */
579
- export const PaymentsBlueprint = need('payments', {
580
- charge: {
581
- description: 'Charges an order, and calls notify once the money arrives.',
582
- args: s.object({ order: s.string(), amount: s.number(), notify: s.handle() }),
583
- result: s.object({ pending: s.boolean() }),
584
- },
585
- });
586
-
587
- type Answer = { result: { pending: boolean } } | { error: { message: string } };
588
-
589
- /**
590
- * A payment provider in the ground's process. It answers a call id it has
591
- * seen with the answer it gave, so an effect sent twice charges once. A
592
- * provider that changes the world keeps these in the memory its faculty's
593
- * `up` receives, where a restart and a move keep them.
594
- */
595
- export class Payments {
596
- readonly #answered = new Map<string, Answer>();
597
- readonly #waiting = new Map<string, { notify: string; context: FacultyContext }>();
598
-
599
- async charge({ order, amount, notify }: { order: string; amount: number; notify: string }, context: FacultyContext): Promise<Answer> {
600
- const seen = this.#answered.get(context.id);
601
- if (seen !== undefined) return seen;
602
- const answer: Answer = amount > 0 ? { result: { pending: true } } : { error: { message: 'Nothing to charge.' } };
603
- if (amount > 0) this.#waiting.set(order, { notify, context });
604
- this.#answered.set(context.id, answer);
605
- return answer;
606
- }
607
-
608
- /** The money for an order arrived: the provider calls the handle it was given. */
609
- settle(order: string) {
610
- const waiting = this.#waiting.get(order);
611
- if (waiting === undefined) throw new Error(`no charge waits for ${order}`);
612
- this.#waiting.delete(order);
613
- return waiting.context.call({ token: waiting.notify, id: `settle:${order}` });
614
- }
615
- }
616
-
617
- /** The offer a ground hands: the blueprint, the object, and a week's memory of call ids. */
618
- export const paymentsOffer = (payments: Payments): Offer => ({ blueprint: PaymentsBlueprint, object: payments, window: 7 * 86_400_000 });
619
- ```
620
-
621
- An offer is `{ blueprint, object, kinds?, window? }`. The object answers
622
- each call with its call id, and one that changes the world answers a
623
- call id it has seen with the answer it gave. A registry holds each
624
- faculty by name, as `{ up, install? }`. The ground raises a faculty by
625
- its `up` when an entry names it, and the entry's `kinds` grants it to
626
- the classes it names. [Writing a faculty](FACULTIES.md) teaches the
627
- craft whole, with a faculty written in Python.
628
-
629
- ```ts
630
- // recipe.ts
631
- import { Payments, paymentsOffer } from './payments.ts';
632
-
633
- // A registry: the ground raises each faculty an entry names by its `up` here.
634
- export const faculties = {
635
- payments: { up: () => paymentsOffer(new Payments()) },
636
- };
637
- ```
638
-
639
- ## A ground
640
-
641
- A ground is the process houses run in, and you write none. `nervur up`
642
- runs one on a folder of code: a folder for each house, and each module
643
- your entries name. It holds one key in `state/`, and keeps every entry
644
- sealed as the cells of its dock's beings: which faculties stand, and
645
- which houses open on which bodies.
646
-
647
- ### The shop's folder
648
-
649
- ```text
650
- nervur-ground/
651
- recipe.ts
652
- payments.ts
653
- classes/index.ts, order.ts, shop.ts, lobby.ts
654
- state/ made by the ground, its owner's alone
655
- ```
656
-
657
- The folder is a package of ECMAScript modules, so Node reads its
658
- TypeScript as it is written, with no build step.
659
-
660
- ```bash
661
- npm init -y && npm pkg set type=module && npm install nervur
662
- ```
663
-
664
- A house's folder names what the house holds.
665
-
666
- ```ts
667
- // classes/index.ts
668
- export { Shop as steward } from './shop.ts';
669
- export { Lobby as public } from './lobby.ts';
670
- import { Order } from './order.ts';
671
-
672
- export const beings = [Order];
673
- ```
674
-
675
- ### Running it
676
-
677
- ```bash
678
- npx nervur up .
679
- ```
680
-
681
- The ground boots in one order, and a stop is that order reversed, on an
682
- interrupt and on `SIGTERM`.
683
-
684
- 1. **Primordial.** Its ledger goes up and takes the lock on its state,
685
- so one ground runs on it. Its unlock, crypto and tools go up. Its key
686
- is read from `state/key`, drawn there on the first start.
687
- 2. **The ground's work.** The library's `ground` faculty goes up, which
688
- the dock alone reaches.
689
- 3. **Dock.** The ground's own house opens in the ledger, under a seed
690
- its key derives. Its beings hold every entry, seed, secret and
691
- setting as their cells.
692
- 4. **Ladder.** The dock's steward joins your entries to the defaults its
693
- code fixes, yours winning by name. Each entry is held to what its
694
- faculty takes. Each body is installed where its entry is new, and
695
- goes up. One that fails stays down, and says why.
696
- 5. **Houses.** Each house opens on its bodies, and its door joins the
697
- carry.
698
- 6. **Hand.** The hand takes its socket, and the ground tells systemd it
699
- is up.
700
-
701
- Its environment names what opens its memory, its key and its hand, and
702
- nothing else.
703
-
704
- | Variable | What it names |
705
- | --- | --- |
706
- | `NERVUR_STATE` | its state, `state/` in its folder where unset |
707
- | `NERVUR_UNLOCK` | `keychain:<account>` keeps its key in the macOS keychain, in place of `state/key` |
708
- | `NERVUR_HAND` | its hand's socket, `state/hand` where unset |
709
-
710
- Every other setting is an arg of an entry its dock keeps, set through
711
- the hand. Its `tcp` entry listens on every address at 9110. Its `web`
712
- entry serves the ground's one listener over HTTP, for Quo over the web
713
- and every handler, once its args name a `port`. It names that listener
714
- in its `faculties`. Both take `bind`, the public `addresses` written
715
- into invitations, and `allowPrivate` to dial loopback addresses, as two
716
- grounds on one machine do. `web` also takes the `origins` of pages it
717
- answers. `wait set` keeps its bound on every ask.
718
-
719
- ```bash
720
- npx nervur faculties update name=web make=web faculties='["listener"]' args='{"port":8080}'
721
- ```
722
-
723
- The state holds the key in a file its owner alone reads, and the
724
- ground's ledger. Every house keeps its rows in that ledger, sealed. A
725
- ledger appends every write and never rewrites one. Its witness keeps
726
- where it last stood, and a ledger behind its witness is refused. So a
727
- ledger restored alone cannot replay what a house already answered,
728
- though a whole state folder restored with its witness is not seen. A
729
- lost key is a lost ground.
730
-
731
- The ladder stands once, and the ground stands it again at every start.
732
- The first entry stands the folder's `recipe.ts` as a registry, by the
733
- faculty `module` the folder's registry holds. The second raises the
734
- payments from it. An entry names only faculties that stand already.
735
-
736
- ```bash
737
- npx nervur faculties add name=recipe from=folder make=module args='{"at":"recipe.ts"}'
738
- ```
739
-
740
- ```bash
741
- npx nervur faculties add name=payments from=recipe make=payments
742
- ```
743
-
744
- A house is added once, and the ground opens it again at every start.
745
-
746
- ```bash
747
- npx nervur houses add name=shop classes='{"faculty":"folder","at":"classes"}' faculties='["payments"]'
748
- ```
749
-
750
- `classes` names the faculty whose body serves the house's code. `folder`
751
- is the ground's own, and a registry may add more, a git repository among
752
- them. A house keeps its rows in the ground's ledger unless its entry
753
- names a `memory` faculty. `faculties` names what the house receives, and
754
- within it each faculty's entry names in `kinds` the classes that hold
755
- it. `houses update` and `faculties update` land a new entry in one
756
- write, and `faculties restart` takes a body down and up again.
757
-
758
- A secret reaches a faculty the same way, and never through the
759
- environment. `npx nervur secrets set -` reads `{ name, value }` from
760
- standard input into a being of the dock, whose cells no one reads. A
761
- faculty's entry names the secrets its `up` receives in `secrets`.
762
-
763
- ### The hand
764
-
765
- The command is a face on the ground's hand. It holds no word of its own
766
- beyond `up` and `service`, and reads every other from what the ground
767
- describes.
768
-
769
- ```bash
770
- npx nervur help
771
- ```
772
-
773
- Two words ask the dock, the ground's own steward, so `houses list` asks
774
- her `housesList`. A faculty named alone shows its methods, and a method
775
- after it is called through the dock. Args are one JSON object, or words
776
- `key=value`.
777
-
778
- ```bash
779
- npx nervur houses list
780
- ```
781
-
782
- `ask` asks a being in a house as `root`: the steward, or the being
783
- `--id` names. The owner opens an order through the steward, and hands a
784
- courier's paper to it the same way. The steward's `hire` carries the
785
- paper unopened, and the order takes it.
786
-
787
- ```bash
788
- npx nervur ask shop open id=first
789
- ```
790
-
791
- ```bash
792
- npx nervur ask shop hire order=first courier=7b22…
793
- ```
794
-
795
- `--id` names the being asked in the steward's place, as `npx nervur ask
796
- shop --id first` shows the order's describe. `--cells` reads her cells
797
- and asks nothing, as `npx nervur ask shop --id first --cells`. No one
798
- but the owner reads them, and only her own asks write them.
799
-
800
- Each prints one JSON value. It exits 0 on a result and 1 on an error
801
- answered. It exits 2 where nothing was asked, so a script tells a
802
- refusal from a ground that is down. The hand is `state/hand` in the
803
- folder where the command runs, or the socket `--at` or `NERVUR_HAND`
804
- names.
805
-
806
- ### Running it as a service
807
-
808
- `nervur service` writes the unit that runs a folder: a systemd user unit
809
- on Linux, started again after any exit, and a launchd agent on macOS.
810
-
811
- ```bash
812
- npx nervur service . > ~/.config/systemd/user/nervur-ground.service
813
- ```
814
-
815
- ```bash
816
- systemctl --user enable --now nervur-ground
817
- ```
818
-
819
- A user unit stops when its user logs out, unless lingering is enabled
820
- with `loginctl enable-linger`. On macOS, the agent goes to
821
- `~/Library/LaunchAgents/` and is started with `launchctl bootstrap`.
822
-
823
- ### In a page
824
-
825
- `BrowserGround.open({ registry })` from `nervur/browser` runs the same
826
- houses in a page. Every tab and the service worker of one origin share
827
- one ground: the one holding the Web Lock runs it, and the others reach
828
- its hand over a `BroadcastChannel`. When it closes, the next opens the
829
- ground from the same storage. `hand` takes the same requests the
830
- command sends: `describe`, and an ask of a being in a named house. A
831
- request that names no house asks the dock's steward, as
832
- `{ method: 'housesList' }`.
833
-
834
- Its bodies are the browser's. The ground's key is sealed under an AES
835
- key that IndexedDB holds unextractable, and its memory is IndexedDB.
836
- Classes load from the page's own origin through the `origin` faculty, `{
837
- faculty: 'origin', at: '/house/index.js' }`, and a path off the origin
838
- is refused. The registry is the object you pass: faculties by name,
839
- foundation and custom alike, beside the terrain's own.
840
-
841
- Any script on the origin can use the ground's keys, so the ground is
842
- whoever serves the origin's script. Give it an origin of its own, serve
843
- nothing a stranger wrote there, and set a strict content security
844
- policy. The page and the house's module must share one copy of
845
- `nervur/being`, since a house knows a class by a mark that module gives.
846
- A bundler's shared chunk or an import map gives the one copy.
847
-
848
- A service worker opens the ground the same way, on a push, where no tab
849
- runs it. It may not `import()`, so hand it the modules it imported
850
- itself: `platform: { load: (href) => modules[new URL(href).pathname] }`.
851
-
852
- ### In an app
853
-
854
- `AppGround.open({ shell })` from `nervur/app` is a BrowserGround in the
855
- app's web view, on two interfaces the shell fills in native code:
856
-
857
- - `NativeSecrets`: `get(name)` and `set(name, value)`, text kept by the
858
- iOS Keychain or the Android Keystore on this device alone.
859
- - `NativeStore`: `get(key)`, `keys(prefix)`, and `swap(writes, expect)`,
860
- which lands every write only where each key in `expect` still holds
861
- what it names, and answers whether it landed.
862
-
863
- The library holds the rest. The ground's key goes into the secret store,
864
- and its memory into the native store, which the system never evicts as
865
- it may a web view's storage. A push token reaches the ground through a
866
- faculty your registry holds.
867
-
868
- ## What the house guarantees
869
-
870
- 1. **Every need is covered, or she is absent.** An absent being answers
871
- silence and keeps her cells.
872
- 2. **The asker's id is true.** Wherever the asker lives, the id she reads
873
- is who asked.
874
- 3. **Her notes are hers.** No one else writes them, and she never writes
875
- her steward's.
876
- 4. **She never holds an invitation's bytes.** Handles leave, standing ids
877
- arrive, and `s.invitation` passes through unopened.
878
- 5. **One ask at a time.** Asks to one being run in order, and `readOnly`
879
- asks run beside them.
880
- 6. **An ask lands whole or not at all.** Her cells, her relations, her
881
- effects and her call ids land in one write.
882
- 7. **An effect acts at most once, and its outcome is known.** Its answer,
883
- or its giving up, reaches her through `reply`.
884
- 8. **Her class is checked before her first ask.** A class that fails
885
- leaves her absent, and the refusal says why.
886
-
887
- A failed ask changed nothing she owns, so asking again is safe.
888
-
889
- ## What the house refuses
890
-
891
- Each refusal answers why, where it is met: at her class's first resolve,
892
- at her call, or where an ask arrives.
893
-
894
- - A being reaching anything her position, her needs and `this.house` do
895
- not give.
896
- - A ground's own references handed to a being, or offered to her as a
897
- faculty.
898
- - A handle or an invitation in her cells.
899
- - Her cells read by anyone but the owner's hand.
900
- - A standing she mints herself. Standings arrive from the house.
901
- - A far standing asked in the ask that took it. She asks it from her next
902
- ask.
903
- - A write by anyone else to her notes, and by her to her steward's.
904
- - An occupant id the house reserves, and one she already holds.
905
- - Two member names that clash.
906
- - An ask with no entry.
907
- - A state no ask reaches, an ask no role reaches, and a role unused.
908
- - A method landing in a state its `to` does not name.
909
- - A `readOnly` ask that writes.
910
- - A need and an offer that disagree on `idempotent`.
911
- - A schema keyword outside the subset `s` writes.
912
- - Two offers covering one need for one kind, and a kind two sources
913
- claim.
914
- - An effect sent before its ask landed, or sent again while a call for
915
- it is pending.
916
- - An ask a stranger reaches that is not idempotent.
917
- - An invite from a public being.
918
- - A seed inside the house, and a seed that is not sixty-four hex digits.
919
- - A memory opened with keys that derive another bound.
920
- - A send to a private address, unless its ground allows it.
921
- - A call on the house beside `House.open`, `door` and `ask`.
922
- - A faculty in a house's code. Faculties are the ground's.
923
- - A drawer opened with a key that did not seal it.
924
- - A secret read by a being, a describe or anyone but a faculty whose
925
- entry names it.
926
- - A faculty raised any way but its `up`, foundation or custom.
927
- - An entry named `dock`, for a house or a faculty. The dock is the
928
- library's.
929
- - A secret or a move asked by anyone but the hand.
930
- - A grant naming a faculty or a secret the ground does not hold.
931
- - A secret's cells read through the hand.
932
- - An entry naming, making or granting `ground` or `shell`. Both are the
933
- dock's alone.
934
- - A second ground on the state one runs on.
935
- - A ground an owner must write. Each terrain's ships.