@quo-systems/quo 0.2.15 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/ward/ward.ts CHANGED
@@ -8,7 +8,7 @@ import { silence, isSilence, unreached, isWord, word } from '../being/silence.ts
8
8
  import { OWNER } from '../being/types.ts';
9
9
  import type { Asker, BeingLike, Cells, JsonObject, Reply, Stance, Wanted, Word } from '../being/types.ts';
10
10
  import type { Ground, WardPointers } from './ground.ts';
11
- import { at, drop, open, put, emptyBind, emptyCells, MINTED, type Bind, type Partition, type StandingKeys } from './partition.ts';
11
+ import { at, drop, open, put, emptyBind, emptyCells, HEAD, MINTED, type Bind, type Partition, type StandingKeys } from './partition.ts';
12
12
  import { Heirs } from './heirs.ts';
13
13
  import { makeDoor, type Door } from './door.ts';
14
14
  import { buildStance } from './stance.ts';
@@ -50,7 +50,13 @@ class Self implements BeingLike {
50
50
  this.key = key;
51
51
  this.pk = key.pk;
52
52
  this.p = open(ground.memory); // the partition: the ward's own state, and every being's row
53
- this.heirs = new Heirs(this.p, () => this.#wrote());
53
+ // Opening is itself a write: a memory nobody has written comes back with
54
+ // a version stamped on it and the ward's own tables under it. A ward that
55
+ // said nothing here would have every being of it kept and the head that
56
+ // says which version they are written under kept by nobody, so the next
57
+ // boot would read a partition of no version and refuse it.
58
+ this.#wrote(HEAD);
59
+ this.heirs = new Heirs(this.p, () => this.#wrote(HEAD));
54
60
  this.door = makeDoor(key, this.heirs, this.doors, () => this.p.public, (n) => ground.random(n)); // pointer one
55
61
  this.#boot(this.pk, () => this); // the ward's ward is itself
56
62
  // a restart is silent: every being in the cells is constructed again, unasked.
@@ -103,7 +109,7 @@ class Self implements BeingLike {
103
109
  unboot: (key) => this.#unboot(key),
104
110
  setPublic: (key) => {
105
111
  this.p.public = key;
106
- this.#wrote();
112
+ this.#wrote(HEAD);
107
113
  },
108
114
  },
109
115
  asker,
@@ -114,10 +120,13 @@ class Self implements BeingLike {
114
120
 
115
121
  // ---- ward functions. on the object. no stance reaches them.
116
122
 
117
- // The partition was written. The harbor is told, and nothing more: what it
118
- // does with the word is its own, and the ward never learns.
119
- #wrote(): void {
120
- this.g.wrote?.();
123
+ // The partition was written, and which row of it: a being by her key, or
124
+ // the head. The harbor is told, and nothing more: what it does with the
125
+ // word is its own, and the ward never learns. Every write says its row,
126
+ // because a harbor told only that something moved must keep all of it, and
127
+ // a being's row is the one part of a partition that grows without limit.
128
+ #wrote(row: string): void {
129
+ this.g.wrote?.(row);
121
130
  }
122
131
 
123
132
  // The rows no door holds this run: beings whose class threw at birth or
@@ -151,7 +160,7 @@ class Self implements BeingLike {
151
160
  }
152
161
  if (!door) return null;
153
162
  unguarded(door.cells).class = className; // so a restart finds her. the ward's key, written behind her guard
154
- this.#wrote();
163
+ this.#wrote(key);
155
164
  return door;
156
165
  }
157
166
 
@@ -184,7 +193,8 @@ class Self implements BeingLike {
184
193
  drop(this.p.beings, key);
185
194
  drop(this.p.bind, key);
186
195
  this.doors.delete(key);
187
- this.#wrote();
196
+ this.#wrote(key); // she is gone, and her row goes with her
197
+ this.#wrote(HEAD); // her heirs were closed, and the public being may have been her
188
198
  return [...occupants, ...standings];
189
199
  }
190
200
 
@@ -196,7 +206,7 @@ class Self implements BeingLike {
196
206
  // makers: the ground's `instantiate` for a being of the ward, and the ward
197
207
  // itself, which is the first being in its own map and is already made.
198
208
  #boot(key: string, make: (stance: Stance) => BeingLike | null): Resident | null {
199
- const cells = guardCells(at(this.p.beings, key) ?? emptyCells(), () => this.#wrote());
209
+ const cells = guardCells(at(this.p.beings, key) ?? emptyCells(), () => this.#wrote(key));
200
210
  const bind = at(this.p.bind, key) ?? emptyBind();
201
211
  const stance: Stance = buildStance(
202
212
  {
@@ -204,10 +214,10 @@ class Self implements BeingLike {
204
214
  // This stance, not merely this key: unboot and boot again under the
205
215
  // same key makes a new being, and the old stance is not hers.
206
216
  live: () => this.doors.get(key)?.stance === stance,
207
- mintKey: (b) => this.#mintKey(b),
217
+ mintKey: (b) => this.#mintKey(b, key),
208
218
  openHeir: (heir, being, id) => this.heirs.open(heir, being, id),
209
219
  closeHeir: (heir) => this.heirs.close(heir),
210
- send: (b, keys, method, args, wanted) => this.#send(b, keys, method, args, wanted),
220
+ send: (b, keys, method, args, wanted) => this.#send(b, keys, method, args, wanted, key),
211
221
  // A throw at birth is null to her, not a throw in her method: she asked
212
222
  // for a being and got none, and her own answer is still hers to give.
213
223
  instantiate: (className, k) => {
@@ -224,7 +234,7 @@ class Self implements BeingLike {
224
234
  // names there are, which ward may ask for one, and what becomes of one
225
235
  // she did not take, is the harbor's and no word of the ward.
226
236
  lend: async (name, take) => (await this.g.lend?.(name, take)) ?? false,
227
- wrote: () => this.#wrote(),
237
+ wrote: () => this.#wrote(key),
228
238
  },
229
239
  key,
230
240
  cells,
@@ -236,11 +246,11 @@ class Self implements BeingLike {
236
246
  put(this.p.bind, key, bind);
237
247
  const door: Resident = { key, cells, bind, stance, being };
238
248
  this.doors.set(key, door);
239
- this.#wrote();
249
+ this.#wrote(key);
240
250
  return door;
241
251
  }
242
252
 
243
- async #mintKey(bind: Bind): Promise<{ seed: string; pk: string }> {
253
+ async #mintKey(bind: Bind, row: string): Promise<{ seed: string; pk: string }> {
244
254
  const k = await beingKey(this.g.random(32));
245
255
  // The last few she minted, and no more. A relation rotates on every ask,
246
256
  // so a list of all of them is a partition that grows for as long as she
@@ -248,7 +258,7 @@ class Self implements BeingLike {
248
258
  // but the keys of the moment.
249
259
  bind.minted.push(k.pk);
250
260
  if (bind.minted.length > MINTED) bind.minted.splice(0, bind.minted.length - MINTED);
251
- this.#wrote();
261
+ this.#wrote(row);
252
262
  return k;
253
263
  }
254
264
 
@@ -257,7 +267,7 @@ class Self implements BeingLike {
257
267
  // next, seals to the far ward, opens the reply with the ephemeral secret,
258
268
  // and rotates to the announced key once the far door has answered under
259
269
  // the current one.
260
- async #send(bind: Bind, keys: StandingKeys, method: string | undefined, args: JsonObject, wanted?: Wanted): Promise<ReplyPayload | typeof silence | Word> {
270
+ async #send(bind: Bind, keys: StandingKeys, method: string | undefined, args: JsonObject, wanted: Wanted | undefined, row: string): Promise<ReplyPayload | typeof silence | Word> {
261
271
  // What she asked for, held to what this ward allows. Asking for nothing is
262
272
  // the default, and asking for more than the ceiling is the ceiling: budget
263
273
  // is granted by a ward, never minted by a being.
@@ -267,7 +277,7 @@ class Self implements BeingLike {
267
277
  // whoever asked: no key it vouched for, so nothing to announce and nothing
268
278
  // to rotate to. A standing on her signs with one key for life. Every other
269
279
  // ask announces its next: there is no send that does not.
270
- if (keys.next === null && keys.heir !== null) keys.next = (await this.#mintKey(bind)).seed;
280
+ if (keys.next === null && keys.heir !== null) keys.next = (await this.#mintKey(bind, row)).seed;
271
281
  const next = keys.next === null ? null : (await beingKey(unhex(keys.next))).pk;
272
282
  // Her count for this relation, one higher every call and never reused. The
273
283
  // far door honours each number once. One relation sends one at a time, so
@@ -289,10 +299,14 @@ class Self implements BeingLike {
289
299
  return unreached();
290
300
  }
291
301
  const { bytes, ephemeral } = sealed;
292
- // The wait is bounded, and this is the one thing the ward times. A being
293
- // holds three answers and a wait that does not end is none of them: a
294
- // relation that comes back round holds a lane the answer needs, and only a
295
- // bound on the wait can break that. What comes back late is not read.
302
+ // The wait is bounded here, and again around the lane in the stance. Two
303
+ // bounds and not one, because they end two different things: the stance's
304
+ // ends the wait a being is held in, and this one ends the occupancy of the
305
+ // relation's lane. A being holds three answers and a wait that does not
306
+ // end is none of them, and a lane nobody ever leaves is a relation the
307
+ // next ask never reaches. Only a bound on the wire breaks the second, and
308
+ // taking it out would leave one quiet far side holding the lane for good.
309
+ // What comes back late is not read.
296
310
  //
297
311
  // A wait that ran out is `late`, never unreached. Unreached promises
298
312
  // nothing was delivered and is safe to retry; a bound that expired knows
@@ -313,7 +327,7 @@ class Self implements BeingLike {
313
327
  keys.current = keys.next; // the far door holds `next` as announced. move to it.
314
328
  keys.next = null;
315
329
  }
316
- this.#wrote(); // the count moved, and the keys may have
330
+ this.#wrote(row); // the count moved, and the keys may have
317
331
  return reply;
318
332
  }
319
333
  }
File without changes
File without changes
File without changes