@serfab/cadre-core 0.11.0 → 0.13.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 (121) hide show
  1. package/README.md +3 -2
  2. package/dist/announce-addrs.d.ts +49 -0
  3. package/dist/announce-addrs.js +78 -0
  4. package/dist/announce-addrs.js.map +1 -0
  5. package/dist/cadre-node.d.ts +607 -53
  6. package/dist/cadre-node.js +1268 -157
  7. package/dist/cadre-node.js.map +1 -1
  8. package/dist/control-database.d.ts +174 -23
  9. package/dist/control-database.js +317 -107
  10. package/dist/control-database.js.map +1 -1
  11. package/dist/control-read-retry.d.ts +103 -0
  12. package/dist/control-read-retry.js +145 -0
  13. package/dist/control-read-retry.js.map +1 -0
  14. package/dist/control-retry.d.ts +101 -0
  15. package/dist/control-retry.js +108 -0
  16. package/dist/control-retry.js.map +1 -0
  17. package/dist/control-schema.d.ts +1 -1
  18. package/dist/control-schema.js +50 -6
  19. package/dist/control-schema.js.map +1 -1
  20. package/dist/control-write-retry.d.ts +59 -35
  21. package/dist/control-write-retry.js +21 -92
  22. package/dist/control-write-retry.js.map +1 -1
  23. package/dist/delegate-admission.d.ts +17 -15
  24. package/dist/delegate-admission.js +17 -15
  25. package/dist/delegate-admission.js.map +1 -1
  26. package/dist/enrolled-machine-store-file.d.ts +13 -0
  27. package/dist/enrolled-machine-store-file.js +41 -0
  28. package/dist/enrolled-machine-store-file.js.map +1 -0
  29. package/dist/enrolled-machine-store.d.ts +81 -0
  30. package/dist/enrolled-machine-store.js +225 -0
  31. package/dist/enrolled-machine-store.js.map +1 -0
  32. package/dist/file-durable-slot.js +5 -3
  33. package/dist/file-durable-slot.js.map +1 -1
  34. package/dist/index.d.ts +10 -6
  35. package/dist/index.js +39 -12
  36. package/dist/index.js.map +1 -1
  37. package/dist/membership-connection-gater.d.ts +226 -26
  38. package/dist/membership-connection-gater.js +316 -30
  39. package/dist/membership-connection-gater.js.map +1 -1
  40. package/dist/node-local-snapshot.d.ts +6 -0
  41. package/dist/node-local-snapshot.js +7 -1
  42. package/dist/node-local-snapshot.js.map +1 -1
  43. package/dist/{strand-backfill.d.ts → peer-join-backfill.d.ts} +49 -20
  44. package/dist/{strand-backfill.js → peer-join-backfill.js} +146 -56
  45. package/dist/peer-join-backfill.js.map +1 -0
  46. package/dist/peer-record.d.ts +26 -0
  47. package/dist/peer-record.js +32 -0
  48. package/dist/peer-record.js.map +1 -1
  49. package/dist/relay-addrs.d.ts +145 -22
  50. package/dist/relay-addrs.js +314 -31
  51. package/dist/relay-addrs.js.map +1 -1
  52. package/dist/relay-reservation.d.ts +20 -15
  53. package/dist/relay-reservation.js +18 -14
  54. package/dist/relay-reservation.js.map +1 -1
  55. package/dist/strand-addr-protocol.js +16 -0
  56. package/dist/strand-addr-protocol.js.map +1 -1
  57. package/dist/strand-database.d.ts +12 -0
  58. package/dist/strand-database.js +16 -0
  59. package/dist/strand-database.js.map +1 -1
  60. package/dist/strand-formation-manager.d.ts +22 -9
  61. package/dist/strand-formation-manager.js +20 -12
  62. package/dist/strand-formation-manager.js.map +1 -1
  63. package/dist/strand-formation-protocol.d.ts +83 -9
  64. package/dist/strand-formation-protocol.js +86 -10
  65. package/dist/strand-formation-protocol.js.map +1 -1
  66. package/dist/strand-instance-manager.d.ts +151 -17
  67. package/dist/strand-instance-manager.js +237 -32
  68. package/dist/strand-instance-manager.js.map +1 -1
  69. package/dist/strand-membership-writer.d.ts +118 -14
  70. package/dist/strand-membership-writer.js +203 -15
  71. package/dist/strand-membership-writer.js.map +1 -1
  72. package/dist/strand-network-config.d.ts +84 -0
  73. package/dist/strand-network-config.js +136 -0
  74. package/dist/strand-network-config.js.map +1 -0
  75. package/dist/strand-revocation-enforcer.d.ts +392 -0
  76. package/dist/strand-revocation-enforcer.js +533 -0
  77. package/dist/strand-revocation-enforcer.js.map +1 -0
  78. package/dist/strand-solicitation.d.ts +10 -3
  79. package/dist/strand-solicitation.js +12 -7
  80. package/dist/strand-solicitation.js.map +1 -1
  81. package/dist/strand-wake-protocol.d.ts +47 -2
  82. package/dist/strand-wake-protocol.js +76 -6
  83. package/dist/strand-wake-protocol.js.map +1 -1
  84. package/dist/strand-watcher.js +6 -1
  85. package/dist/strand-watcher.js.map +1 -1
  86. package/dist/types.d.ts +282 -43
  87. package/dist/types.js +7 -1
  88. package/dist/types.js.map +1 -1
  89. package/package.json +16 -8
  90. package/src/announce-addrs.ts +93 -0
  91. package/src/cadre-node.ts +1366 -171
  92. package/src/control-database.ts +2628 -2406
  93. package/src/control-read-retry.ts +167 -0
  94. package/src/control-retry.ts +190 -0
  95. package/src/control-schema.ts +50 -6
  96. package/src/control-write-retry.ts +30 -130
  97. package/src/delegate-admission.ts +17 -15
  98. package/src/enrolled-machine-store-file.ts +43 -0
  99. package/src/enrolled-machine-store.ts +280 -0
  100. package/src/file-durable-slot.ts +5 -3
  101. package/src/index.ts +477 -407
  102. package/src/membership-connection-gater.ts +539 -204
  103. package/src/node-local-snapshot.ts +13 -1
  104. package/src/peer-addr-book.ts +251 -250
  105. package/src/{strand-backfill.ts → peer-join-backfill.ts} +187 -75
  106. package/src/peer-record.ts +33 -0
  107. package/src/relay-addrs.ts +436 -111
  108. package/src/relay-reservation.ts +828 -823
  109. package/src/strand-addr-protocol.ts +17 -0
  110. package/src/strand-database.ts +17 -0
  111. package/src/strand-formation-manager.ts +511 -491
  112. package/src/strand-formation-protocol.ts +808 -692
  113. package/src/strand-instance-manager.ts +899 -611
  114. package/src/strand-membership-writer.ts +232 -15
  115. package/src/strand-network-config.ts +172 -0
  116. package/src/strand-revocation-enforcer.ts +653 -0
  117. package/src/strand-solicitation.ts +484 -472
  118. package/src/strand-wake-protocol.ts +94 -8
  119. package/src/strand-watcher.ts +319 -314
  120. package/src/types.ts +1554 -1309
  121. package/dist/strand-backfill.js.map +0 -1
@@ -2,10 +2,11 @@ import debug from 'debug';
2
2
  import { createLibp2pNode } from '@optimystic/db-p2p';
3
3
  import { wrapStorageWithCache, disposeStorageCache } from '@serfab/quereus-plugin-sereus';
4
4
  import { StrandDatabase } from './strand-database.js';
5
- import { StrandBackfill } from './strand-backfill.js';
5
+ import { PeerJoinBackfill } from './peer-join-backfill.js';
6
+ import { StrandRevocationEnforcer, createRevocationConnectionGater, readStrandRevocationRows } from './strand-revocation-enforcer.js';
6
7
  import { assertSchemaSignature } from './schema-verification.js';
7
- import { resolveStrandClusterSize, STRAND_CLUSTER_POLICY } from './types.js';
8
- import { resolveListenAddrs } from './relay-addrs.js';
8
+ import { resolveStrandClusterSize, strandClusterPolicy } from './types.js';
9
+ import { strandNodeAddrs } from './strand-network-config.js';
9
10
  const log = debug('sereus:cadre:strand-manager');
10
11
  const timing = debug('sereus:cadre:timing');
11
12
  /**
@@ -81,6 +82,13 @@ export class StrandInstanceManager {
81
82
  * missed writes).
82
83
  */
83
84
  this.backfills = new Map();
85
+ /**
86
+ * The per-strand revoked-peer enforcer (closed strands only), keyed by strand
87
+ * id. Same lifecycle rationale as {@link backfills}: created in
88
+ * `buildStrandRuntime`, stopped and dropped in `releaseRuntime`, so quiesce →
89
+ * resume rebuilds it with a fresh (initially empty, fail-open) snapshot.
90
+ */
91
+ this.revocationEnforcers = new Map();
84
92
  /**
85
93
  * The resolved (cache-wrapped) raw storage per strand id — the instance's OWN
86
94
  * store, resolved once in `startStrand` and held until `stopStrand` disposes it.
@@ -145,6 +153,14 @@ export class StrandInstanceManager {
145
153
  throw new Error('StrandInstanceManager is stopping');
146
154
  }
147
155
  if (this.instances.has(strandId)) {
156
+ // Callers resolve founder-ness BEFORE reaching here (CadreNode.launchStrand) and
157
+ // honor a founder request on a tracked instance via foundExistingStrand — so a
158
+ // founder flag arriving at this early return against a non-founder retained
159
+ // config is a dropped bootstrap, and must never again be silent.
160
+ if (config.founder === true && this.launchConfigs.get(strandId)?.founder !== true) {
161
+ log('startStrand: strand %s is already running but was NOT launched as founder — ' +
162
+ 'this early return DROPS the founder request; use foundExistingStrand', strandId);
163
+ }
148
164
  log('Strand %s already running', strandId);
149
165
  return this.instances.get(strandId);
150
166
  }
@@ -211,8 +227,9 @@ export class StrandInstanceManager {
211
227
  * Build (or rebuild) the libp2p node + StrandDatabase for an instance and
212
228
  * attach them, transitioning it to `active`. Shared by `startStrand` (fresh
213
229
  * launch) and `resumeStrand` (rehydrating a quiesced instance). Reads all
214
- * volatile inputs (bootstrapNodes, network, profile, privateKey, sApp config)
215
- * from `config`, so the caller controls the cohort-derived values. Storage is the
230
+ * volatile inputs (bootstrapNodes, servingMachines, network, profile,
231
+ * privateKey, sApp config) from `config`, so the caller controls the
232
+ * cohort-derived values. Storage is the
216
233
  * one input it does NOT re-read from `config`: that belongs to the instance and
217
234
  * comes from `strandStorages`.
218
235
  */
@@ -231,8 +248,67 @@ export class StrandInstanceManager {
231
248
  // Determine relay mode: if explicitly set in config, use that;
232
249
  // otherwise default to true for storage profile nodes.
233
250
  const enableRelay = config.network?.enableRelay ?? (config.profile === 'storage');
234
- const listenAddrs = resolveListenAddrs(config.network);
251
+ // The CONFIGURED relay route (the default), deliberately NOT the control node's
252
+ // `'search'` route: nothing drives an explicit reservation for a strand node, so
253
+ // a bare `/p2p-circuit` search entry would register a pending reservation that
254
+ // never gets filled and leave the strand node undialable. The ordering hazard
255
+ // that pushed the control node onto the search route does not exist here — a
256
+ // strand node's protocol ids are namespaced `/optimystic/strand-<id>/…`, so a
257
+ // relay dialed from inside `libp2p.start()` is never in the strand's cohort and
258
+ // cannot refuse its database bring-up. See `relay-addrs.ts`.
259
+ //
260
+ // The strand-node VIEW of the machine's one `NetworkConfig`, not the control
261
+ // node's resolution: fixed direct listen ports become ephemeral (two nodes cannot
262
+ // bind one port) and the announce config is dropped (it names the control node's
263
+ // address). See `strand-network-config.ts` for both, and for the tradeoff.
264
+ const addrOptions = strandNodeAddrs(config.network);
265
+ // The CLOSED-strand revoked-peer gate (see strand-revocation-enforcer.ts).
266
+ // Constructed BEFORE the libp2p node because the node's options embed its
267
+ // predicates; its deny set starts empty (admit everything — fail-open, same
268
+ // posture as bring-up everywhere here) and is first populated after the
269
+ // strand database initializes below. Registered in the map immediately so
270
+ // the failure rollback (releaseRuntime) tears it down like every other
271
+ // runtime component. Open strands skip it entirely: their Member/MemberPeer
272
+ // tables are empty by schema (`OnlyClosed`), so there is nothing to derive
273
+ // a deny set from — arming would be pointless polling.
274
+ const revocationEnforcer = config.strandRow.Type === 'c' && config.revocationEnforcement?.enabled !== false
275
+ ? new StrandRevocationEnforcer({
276
+ label: strandId,
277
+ readRows: () => {
278
+ const database = instance.database;
279
+ if (!database) {
280
+ throw new Error(`strand ${strandId} has no live database`);
281
+ }
282
+ return readStrandRevocationRows(database.getDatabase());
283
+ },
284
+ // Read per sweep, never captured: this closure is built BEFORE the
285
+ // libp2p node exists (its options embed the enforcer's predicates),
286
+ // and `releaseRuntime` clears the field again on quiesce. Undefined
287
+ // therefore means "no transport right now", which the enforcer
288
+ // treats as "nothing to tear down".
289
+ getNetwork: () => instance.libp2pNode,
290
+ onSelfRevoked: () => config.onSelfRevoked?.(strandId)
291
+ }, config.revocationEnforcement)
292
+ : undefined;
293
+ if (revocationEnforcer) {
294
+ this.revocationEnforcers.set(strandId, revocationEnforcer);
295
+ }
296
+ // Closed strands compose revoked-peer denial onto the caller's gater and arm
297
+ // the fail-closed per-stream gate; open strands keep the raw configured gater
298
+ // (their peers are legitimately cross-party and nothing is ever revoked).
299
+ const revocationGateOptions = revocationEnforcer
300
+ ? {
301
+ connectionGater: createRevocationConnectionGater(revocationEnforcer, config.network?.connectionGater),
302
+ authorizeInboundStream: (remotePeerId, protocol) => revocationEnforcer.authorizeStream(remotePeerId, protocol)
303
+ }
304
+ : config.network?.connectionGater
305
+ ? { connectionGater: config.network.connectionGater }
306
+ : {};
235
307
  try {
308
+ // Bound once: the breadth is also the ceiling on the repair yardstick below, and the
309
+ // two must be derived from the same resolution. Inside the `try` deliberately — a
310
+ // rejected clusterSize is a build failure that runs the same cleanup as any other.
311
+ const strandClusterSize = resolveStrandClusterSize(config.clusterSize);
236
312
  let t0 = performance.now();
237
313
  const node = await createLibp2pNode({
238
314
  port: 0, // Random port
@@ -241,28 +317,38 @@ export class StrandInstanceManager {
241
317
  storage: strandStorage,
242
318
  fretProfile: config.profile === 'storage' ? 'core' : 'edge',
243
319
  relay: enableRelay,
244
- clusterSize: resolveStrandClusterSize(config.clusterSize),
320
+ clusterSize: strandClusterSize,
245
321
  // Deliberately NOT CONTROL_CLUSTER_POLICY: a strand is application data with its own
246
322
  // breadth reasoning, and the shape match with the control policy is a coincidence.
247
- clusterPolicy: STRAND_CLUSTER_POLICY,
323
+ //
324
+ // The builder declares this node's block-repair corroboration yardstick from the
325
+ // count of machines SERVING this strand, capped at the breadth above (a block
326
+ // never lives on more machines than the cohort is wide). Given no count — the
327
+ // production path today, since no per-strand serving count exists yet — it
328
+ // returns the frozen STRAND_CLUSTER_POLICY itself, declaring nothing. Resolved
329
+ // HERE rather than at `startStrand`, so a wake from hibernation would pick up a
330
+ // serving set that changed while the strand slept.
331
+ clusterPolicy: strandClusterPolicy(strandClusterSize, config.servingMachines),
248
332
  arachnode: {
249
333
  enableRingZulu: config.profile === 'storage'
250
334
  },
251
335
  ...(config.privateKey && { privateKey: config.privateKey }),
252
336
  ...(config.network?.transports && { transports: config.network.transports }),
253
- // NOTE: strand nodes receive the same RESOLVED listen addrs as the
254
- // control node. A fixed-port listen addr (e.g. cadre-cli's example
255
- // `/ip4/0.0.0.0/tcp/4001`) would have control + strand nodes racing to
256
- // bind one port — EADDRINUSE. Unverified; if a deployment configures a
257
- // fixed port and strands fail to start, rewrite the port per node here.
258
- // An inherited `/p2p-circuit` addr, by contrast, is deliberate — it is
259
- // what gives a NAT'd strand node a reachable relay slot — and works
260
- // because the launch path announces this strand's derived peerId to
261
- // the relay first (delegate admission; see cadre-node.ts). Those circuit
262
- // entries come either from a hand-written `network.listenAddrs` or from
263
- // `network.relayAddrs`, which `resolveListenAddrs` folds into the same list.
264
- ...(listenAddrs && { listenAddrs }),
265
- ...(config.network?.connectionGater && { connectionGater: config.network.connectionGater })
337
+ // Listen entries plus the WebSocket transport switch they imply — a strand node
338
+ // announces nothing the operator configured (`strand-network-config.ts`), and
339
+ // spreads AFTER `transports` above because the switch is a no-op whenever the
340
+ // embedder supplied its own factories. An inherited configured `/p2p-circuit` entry is
341
+ // deliberate and survives the derivation untouched: it is what gives a NAT'd
342
+ // strand node a reachable relay slot, and it works because the launch path
343
+ // announces this strand's derived peerId to the relay first (delegate admission;
344
+ // see cadre-node.ts). Those circuit entries come either from a hand-written
345
+ // `network.listenAddrs` or from `network.relayAddrs`, which the resolution folds
346
+ // into the same list on the configured route this call takes (see above).
347
+ ...addrOptions,
348
+ // The raw configured gater (open strands), or the revocation-composed
349
+ // gater plus the fail-closed per-stream revoked-peer gate (closed
350
+ // strands) — resolved above, before the try.
351
+ ...revocationGateOptions
266
352
  });
267
353
  timing('[buildStrandRuntime:%s] createLibp2pNode: %dms', strandId, Math.round(performance.now() - t0));
268
354
  instance.libp2pNode = node;
@@ -286,23 +372,31 @@ export class StrandInstanceManager {
286
372
  instance.database = strandDb;
287
373
  await strandDb.initialize();
288
374
  timing('[buildStrandRuntime:%s] strandDatabase.initialize: %dms', strandId, Math.round(performance.now() - t0));
375
+ // Arm the revoked-peer deny-set poll now that the database it reads
376
+ // exists. start() kicks an immediate refresh WITHOUT awaiting it —
377
+ // bring-up and resume are never blocked on a membership read; until the
378
+ // first read lands the empty snapshot admits everyone (fail-open).
379
+ revocationEnforcer?.start();
289
380
  // Peer-join block catch-up: push this strand's own blocks to each newly
290
381
  // connected peer, so a machine that joined after blocks were committed
291
382
  // still ends up physically holding them (without per-strand storage there
292
- // is nothing to copy). Armed for EVERY stored strand: `StrandBackfill`
383
+ // is nothing to copy). Armed for EVERY stored strand: `PeerJoinBackfill`
293
384
  // only does work when the strand's libp2p node reports a peer connection,
294
385
  // so on a device that is genuinely alone it is inert, and arming it at
295
386
  // launch is what closes the "founded alone, never replicates" hole — a
296
387
  // peer that joins later gets the founder's blocks without any relaunch.
388
+ // No `authorizePeer` gate, deliberately — see the module comment in
389
+ // peer-join-backfill.ts for the strand-side argument (and why the control
390
+ // network, which DOES gate, is different).
297
391
  //
298
- // NOTE: cost is one StrandBackfill object + one `connection:open` listener
392
+ // NOTE: cost is one PeerJoinBackfill object + one `connection:open` listener
299
393
  // per running strand — linear in strand count, negligible at the handful a
300
394
  // device or host runs today. If a node ever hosts strands by the hundred,
301
395
  // move to one shared listener that dispatches by strand id.
302
396
  if (strandStorage && config.backfill?.enabled !== false) {
303
397
  if (node.keyNetwork) {
304
- const backfill = new StrandBackfill({
305
- strandId,
398
+ const backfill = new PeerJoinBackfill({
399
+ label: strandId,
306
400
  libp2p: node,
307
401
  peerNetwork: node.keyNetwork,
308
402
  storage: strandStorage,
@@ -350,6 +444,13 @@ export class StrandInstanceManager {
350
444
  backfill.stop();
351
445
  this.backfills.delete(instance.strandId);
352
446
  }
447
+ // The revoked-peer enforcer goes with the runtime it gated: a resume
448
+ // rebuilds it with a fresh (initially empty, fail-open) snapshot.
449
+ const revocationEnforcer = this.revocationEnforcers.get(instance.strandId);
450
+ if (revocationEnforcer) {
451
+ revocationEnforcer.stop();
452
+ this.revocationEnforcers.delete(instance.strandId);
453
+ }
353
454
  if (instance.database) {
354
455
  await instance.database.close();
355
456
  instance.database = undefined;
@@ -361,9 +462,10 @@ export class StrandInstanceManager {
361
462
  instance.connectedPeers = 0;
362
463
  }
363
464
  /**
364
- * Drop the strand's owned store and release its cache registration with the shared
365
- * pool. Called only where the strand's whole lifetime ends (`stopStrand`, and the
366
- * failed-launch rollback) — never on a quiesce.
465
+ * Drop the strand's owned store and release this strand's claim on its cache. The
466
+ * wrapper counts holders, so the cache is emptied and unregistered from the shared
467
+ * pool only if no other scope still holds it. Called only where the strand's whole
468
+ * lifetime ends (`stopStrand`, and the failed-launch rollback) — never on a quiesce.
367
469
  *
368
470
  * A dispose failure is logged, not thrown: the store is already unreferenced here,
369
471
  * and failing the stop over a cache-bookkeeping error would leave the caller unable
@@ -383,6 +485,31 @@ export class StrandInstanceManager {
383
485
  log('Failed to dispose storage cache for strand %s: %o', strandId, error);
384
486
  }
385
487
  }
488
+ /**
489
+ * Refresh a strand's revoked-peer deny set NOW — and, with it, run the
490
+ * teardown sweep that hangs up every connected revoked peer.
491
+ *
492
+ * The gate is otherwise poll-driven (default
493
+ * `DEFAULT_REVOCATION_POLL_INTERVAL_MS`), because neither a replicated
494
+ * revocation nor a local `revokeMember`/`leaveStrand` raises anything this
495
+ * runtime can hook. A caller that just wrote a revocation against the
496
+ * strand's database should follow it with this call, which makes the cut
497
+ * immediate instead of waiting out the interval.
498
+ *
499
+ * Quiet no-op — matching `quiesceStrand`'s posture — when the strand is not
500
+ * tracked, is quiesced, is open, or has the gate disabled: in every one of
501
+ * those cases there is no enforcer to refresh. Never rejects (the enforcer's
502
+ * refresh contains its own failures), and resolves only once the sweep has
503
+ * finished.
504
+ */
505
+ async refreshRevocationEnforcement(strandId) {
506
+ const enforcer = this.revocationEnforcers.get(strandId);
507
+ if (!enforcer) {
508
+ log('refreshRevocationEnforcement: strand %s has no armed revocation enforcer', strandId);
509
+ return;
510
+ }
511
+ await enforcer.refresh();
512
+ }
386
513
  /**
387
514
  * Quiesce a strand: release its strand-network resources (stop the libp2p node,
388
515
  * close the StrandDatabase) while RETAINING the instance record — identity,
@@ -409,9 +536,9 @@ export class StrandInstanceManager {
409
536
  * Resume a previously-quiesced strand: rebuild its libp2p node + StrandDatabase
410
537
  * from the retained launch config and re-attach them, transitioning it back to
411
538
  * `active`. `overrides` re-applies volatile inputs that may have changed since
412
- * launch (the cohort `bootstrapNodes` seed) and updates the retained config so
413
- * a later resume reuses the latest values. Returns the live instance unchanged
414
- * if it is already running.
539
+ * launch (the cohort `bootstrapNodes` seed and the strand's `servingMachines`
540
+ * count) and updates the retained config so a later resume reuses the latest
541
+ * values. Returns the live instance unchanged if it is already running.
415
542
  */
416
543
  async resumeStrand(strandId, overrides) {
417
544
  if (this.stopping) {
@@ -432,9 +559,20 @@ export class StrandInstanceManager {
432
559
  log('Resuming strand instance: %s', strandId);
433
560
  const tTotal = performance.now();
434
561
  // Re-apply volatile inputs and persist them so a subsequent resume reuses them.
562
+ // Each `??` matters: a resume that passes no override must keep the retained value,
563
+ // and a resume that passes one must leave it retained for the next resume — otherwise
564
+ // a later no-override wake silently reverts to whatever launch time saw.
435
565
  const resumeConfig = {
436
566
  ...launchConfig,
437
- bootstrapNodes: overrides?.bootstrapNodes ?? launchConfig.bootstrapNodes
567
+ bootstrapNodes: overrides?.bootstrapNodes ?? launchConfig.bootstrapNodes,
568
+ // NOTE: `??` retains, so an override can raise or lower the count but cannot CLEAR it
569
+ // back to "this node no longer knows" — the direction that would declare nothing. Moot
570
+ // while nothing feeds `servingMachines` at all; if a source lands
571
+ // (`backlog/feat-strand-yardstick-from-serving-machines`) that can legitimately lose the
572
+ // count — a strand whose member rows became unreadable — this merge must gain an explicit
573
+ // clear rather than silently declaring a stale number over a serving set it can no longer
574
+ // see. Same applies to `bootstrapNodes` above, where a stale seed is harmless.
575
+ servingMachines: overrides?.servingMachines ?? launchConfig.servingMachines
438
576
  };
439
577
  this.launchConfigs.set(strandId, resumeConfig);
440
578
  instance.status = 'starting';
@@ -451,6 +589,73 @@ export class StrandInstanceManager {
451
589
  throw error;
452
590
  }
453
591
  }
592
+ /**
593
+ * Honor a founder request against an ALREADY-TRACKED strand — the seam that
594
+ * closes the "whoever launches first decides whether the bootstrap runs" gap:
595
+ * an instance first launched as a joiner (an app's own attach, or a watcher
596
+ * poll winning the launch race) used to swallow a later founder request
597
+ * silently, leaving the strand active with no `Strand.Header`.
598
+ *
599
+ * Flips the RETAINED launch config's `founder` to true, so every later
600
+ * quiesce → resume rebuild founds as well (the bootstrap is insert-if-absent —
601
+ * {@link StrandDatabase.ensureFounderBootstrap} — so re-running it per rebuild
602
+ * writes nothing twice), and runs the bootstrap against the live database now.
603
+ *
604
+ * @returns how the request resolved:
605
+ * - `'already-founder'` — the retained config already founds; nothing to do.
606
+ * - `'bootstrapped'` — config flipped and the live database ran the bootstrap.
607
+ * - `'needs-resume'` — config flipped, but the instance is quiesced (no live
608
+ * database), so the bootstrap could not run here: the CALLER must wake the
609
+ * strand (`CadreNode.wakeStrand`, which owns the hibernation bookkeeping this
610
+ * manager does not) so the rebuild — which now founds — runs it.
611
+ * @throws when the strand is not tracked — this seam exists only for the
612
+ * tracked-instance launch path; an untracked id is a caller bug.
613
+ */
614
+ async foundExistingStrand(strandId) {
615
+ const instance = this.instances.get(strandId);
616
+ const config = this.launchConfigs.get(strandId);
617
+ if (!instance || !config) {
618
+ throw new Error(`Cannot found strand ${strandId}: not tracked`);
619
+ }
620
+ if (config.founder === true) {
621
+ return 'already-founder';
622
+ }
623
+ // A fresh object rather than mutating in place: startStrand retains the CALLER'S
624
+ // config object, which is not ours to rewrite.
625
+ this.launchConfigs.set(strandId, { ...config, founder: true });
626
+ if (!instance.database) {
627
+ return 'needs-resume';
628
+ }
629
+ await this.ensureFounderBootstrap(strandId);
630
+ return 'bootstrapped';
631
+ }
632
+ /**
633
+ * Run the (idempotent) founder bootstrap against a tracked strand's LIVE
634
+ * database, independently of what the retained launch config says.
635
+ *
636
+ * Separate from {@link foundExistingStrand} because a caller that resolved
637
+ * `'needs-resume'` and woke the strand must not assume the wake's own rebuild
638
+ * founded it: `HibernationManager` COALESCES wakes, so a wake already in flight
639
+ * when the config flipped had already read the PRE-flip config and rebuilt as a
640
+ * joiner. Re-running the bootstrap costs one insert-if-absent probe per table
641
+ * and is the only thing that makes "founding resolves once the Header is
642
+ * written" true on that path.
643
+ *
644
+ * @throws when the strand is not tracked, or is still quiesced (no live
645
+ * database) — both mean the bootstrap did NOT run, which a founder request
646
+ * must never swallow.
647
+ */
648
+ async ensureFounderBootstrap(strandId) {
649
+ const instance = this.instances.get(strandId);
650
+ if (!instance) {
651
+ throw new Error(`Cannot run the founder bootstrap for strand ${strandId}: not tracked`);
652
+ }
653
+ if (!instance.database) {
654
+ throw new Error(`Cannot run the founder bootstrap for strand ${strandId}: it is quiesced, so there ` +
655
+ 'is no live database to write to — resume it first.');
656
+ }
657
+ await instance.database.ensureFounderBootstrap();
658
+ }
454
659
  /**
455
660
  * Stop a strand instance
456
661
  */
@@ -1 +1 @@
1
- {"version":3,"file":"strand-instance-manager.js","sourceRoot":"","sources":["../src/strand-instance-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strand-instance-manager.js","sourceRoot":"","sources":["../src/strand-instance-manager.ts"],"names":[],"mappings":"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"}
@@ -414,8 +414,15 @@ export interface RevokeMemberParams {
414
414
  * A manager must resign its `Manager` row before (or in the same transaction
415
415
  * as) losing membership — `Member.NotAManager` rejects un-membering a key that
416
416
  * still holds a Manager row. And the strand never drops to zero members
417
- * (`Member.MinOneMember`, a local-count floor with the same cross-node caveat
418
- * as `MinOneManager`).
417
+ * (`Member.MinOneMember`, a local-count floor with the cross-node caveat its
418
+ * schema NOTE states).
419
+ *
420
+ * Callers running inside a cadre runtime should follow this write with
421
+ * `CadreNode.refreshRevocationEnforcement(strandId)`. The removed party's
422
+ * machines are refused at the network layer by the strand's revoked-peer gate
423
+ * (`strand-revocation-enforcer.ts`), which polls for membership changes because
424
+ * this bare `Database` handle raises no event the runtime can hook — so without
425
+ * that call the cut lands up to one poll interval (default 30 s) later.
419
426
  *
420
427
  * @param db - The closed strand's database.
421
428
  * @param params - The revoking manager keypair and the target member key.
@@ -452,6 +459,11 @@ export interface LeaveStrandParams {
452
459
  * The same floors as {@link revokeMember} apply: a manager must resign first
453
460
  * (`NotAManager`) and the last member cannot leave (`MinOneMember`).
454
461
  *
462
+ * Like {@link revokeMember}, a caller inside a cadre runtime should follow this
463
+ * with `CadreNode.refreshRevocationEnforcement(strandId)` — here it is what
464
+ * makes the departing node notice its own departure promptly (the gate emits
465
+ * `strand:revoked` when it finds this node's own peer id revoked).
466
+ *
455
467
  * @param db - The closed strand's database.
456
468
  * @param params - The departing member's own keypair.
457
469
  * @throws If `Member.Authorized`, `Member.NotAManager`, or `Member.MinOneMember`
@@ -729,13 +741,19 @@ export interface RemoveManagerParams {
729
741
  * — deferred — IS enforced here: a signer that is neither an existing manager nor
730
742
  * the target itself is rejected at commit.
731
743
  *
732
- * THE LAST MANAGER CANNOT BE REMOVED. `Manager.MinOneManager` (`check on delete`,
733
- * deferred, so it sees the POST-delete count) rejects any delete that would leave the
734
- * strand with zero managers — an admin-less closed strand could never admit anyone
735
- * again, since `Invite`, `addMemberByManager`, and `addManager` all require a
736
- * `Manager` row. The bootstrap branch of `Manager.Authorized` is gated to INSERTs
744
+ * THE SOLE MANAGER CANNOT ORDINARILY RESIGN — it SEALS instead. The `'resign'`
745
+ * branch of `Manager.Authorized` requires at least one manager in the POST-delete
746
+ * image, so a resignation that would empty the `Manager` table is schema-rejected;
747
+ * emptying it deliberately is a distinct, self-signed act — {@link sealStrand} —
748
+ * that permanently freezes admission. This writer refuses the sole-manager
749
+ * self-resignation up front with an error naming `sealStrand`; that TS guard is UX,
750
+ * not the trust boundary — the schema rejects a mis-counted `'resign'` approval
751
+ * regardless. Reading the count inside a caller-joined transaction is correct: an
752
+ * add-then-resign hand-off composed in one transaction sees 2 and passes, while
753
+ * the already-rejected delete-then-add swap sees 1 and is refused here as well as
754
+ * by the schema. The bootstrap branch of `Manager.Authorized` is gated to INSERTs
737
755
  * (`old.MemberKey is null`), so it does not waive the signature check on a delete
738
- * that drops the count toward the floor: a second-to-last removal is authorized
756
+ * that drops the count toward zero: a second-to-last removal is authorized
739
757
  * exactly like any other.
740
758
  *
741
759
  * HAND-OFF ORDER: a sole manager transferring control must ADD the successor FIRST
@@ -744,14 +762,100 @@ export interface RemoveManagerParams {
744
762
  * successor's insert has no other manager to authorize it once the sole manager's
745
763
  * row is gone.
746
764
  *
747
- * Cross-node caveat: `MinOneManager` counts rows visible to THIS transaction, so two
748
- * nodes concurrently removing different managers can each see a survivor and still
749
- * converge to zero. Noted in the schema; a cross-node floor is not attempted here.
765
+ * Cross-node caveat: the `'resign'`/`'seal'` branches count rows visible to THIS
766
+ * transaction, so two nodes concurrently removing different managers can each see
767
+ * a survivor and still converge to zero — an unintended seal. Noted in the schema
768
+ * (the `Manager` table's seal-propagation NOTE); a cross-node floor is not
769
+ * attempted here.
750
770
  *
751
771
  * @param db - The closed strand's database.
752
772
  * @param params - The authorizing keypair and the target manager key.
753
- * @throws If `Manager.Authorized` rejects (a signer that is neither another existing
754
- * manager nor the target itself) or `Manager.MinOneManager` rejects (the removal
755
- * would leave no managers); the whole delete+tombstone transaction rolls back.
773
+ * @throws If the signer IS the target and it is the sole manager (before writing —
774
+ * the operation the caller wants is {@link sealStrand}), or if `Manager.Authorized`
775
+ * rejects (a signer that is neither another existing manager nor the target
776
+ * itself, or a raw sole-manager `'resign'` whose post-image count is zero); the
777
+ * whole delete+tombstone transaction rolls back.
756
778
  */
757
779
  export declare function removeManager(db: Database, params: RemoveManagerParams): Promise<void>;
780
+ /** Parameters for {@link sealStrand}. */
781
+ export interface SealStrandParams {
782
+ /**
783
+ * The SOLE manager's strand keypair. Its `publicKeyB64` must be the one live
784
+ * `Strand.Manager` row; it signs the seal-tagged digest over its own key and
785
+ * live stamp, and files the accompanying tombstone (it is still a committed
786
+ * member, which is what `Revocation.Authorized` checks).
787
+ */
788
+ managerKeyPair: Ed25519KeyPair;
789
+ }
790
+ /**
791
+ * Seal the strand: the SOLE manager deliberately steps down, permanently freezing
792
+ * membership.
793
+ *
794
+ * A sealed strand has zero `Manager` rows, and every admission path — issuing or
795
+ * cancelling an invitation, consuming one issued BEFORE the seal
796
+ * (`ConsumedInvite.NotSealed`), admitting a member, promoting a manager — requires
797
+ * one, so nobody can ever be let in again. That freeze is a privacy guarantee to
798
+ * everyone who contributed: no key holds the power to admit a party who would then
799
+ * read the strand's whole history. Sealing is irreversible — the founding branch
800
+ * of `Manager.Authorized` closes for good once any manager stamp is retired into
801
+ * `Strand.Revocation`. What remains possible: members may {@link leaveStrand}
802
+ * (floored by `MinOneMember`), manage their own `MemberPeer` rows, and file
803
+ * `Revocation` tombstones.
804
+ *
805
+ * The `'seal'` branch of `Manager.Authorized` accepts a self-signed delete only
806
+ * when the POST-image manager count is ZERO — a distinct action tag from
807
+ * `'resign'`, so a captured resignation approval can never seal and a raw writer
808
+ * cannot seal by accident. Like {@link removeManager}, the delete pairs with its
809
+ * `Strand.Revocation` tombstone in one transaction.
810
+ *
811
+ * The TS count/identity checks below are UX guards, not the trust boundary — the
812
+ * schema rejects a mis-tagged or mis-counted approval regardless of what this
813
+ * writer (or any raw writer) presents.
814
+ *
815
+ * NOTE: a seal approval is a bearer token for its row incarnation, like every other
816
+ * self-signed approval here — but the `'seal'` branch's post-image count of 0 is
817
+ * satisfied for EVERY row deleted in the same transaction, so N managers each
818
+ * presenting a valid `'seal'` approval seal jointly (pinned as an accepted case in
819
+ * `strand-seal.spec.ts`). Unreachable today: this writer mints a seal signature only
820
+ * while its caller is the SOLE manager, and spends it immediately, so a second
821
+ * manager never has one to combine. If seal-approval MINTING is ever split from
822
+ * spending — offline signing, a two-phase seal, a queued approval — one manager
823
+ * holding another's unspent seal approval could freeze the strand irreversibly
824
+ * without its current consent; re-gate here (or narrow the schema branch) then.
825
+ *
826
+ * @param db - The closed strand's database.
827
+ * @param params - The sole manager's own keypair.
828
+ * @throws If more than one manager exists (the caller wants {@link removeManager}),
829
+ * or the supplied keypair holds no `Manager` row while one exists, or the strand
830
+ * holds no `Manager` row and has never retired one (not founded yet — see
831
+ * {@link isStrandSealed}), or any schema constraint rejects; the whole
832
+ * delete+tombstone transaction rolls back. A strand that is ALREADY sealed logs
833
+ * and returns quietly (restart-safe, matching {@link bootstrapFounderMembership}
834
+ * and {@link removeManager}'s absent-row no-op).
835
+ */
836
+ export declare function sealStrand(db: Database, params: SealStrandParams): Promise<void>;
837
+ /**
838
+ * Whether the strand is sealed: a CLOSED strand that holds no `Manager` rows AND
839
+ * has retired at least one `Manager` stamp into `Strand.Revocation`.
840
+ *
841
+ * All three conjuncts are load-bearing:
842
+ * - `Header.Type` — an OPEN strand never holds `Manager` rows at all
843
+ * (`Manager.OnlyClosed`), so a bare manager-count test would report every open
844
+ * strand as sealed.
845
+ * - the manager count — sealing IS the empty `Manager` table.
846
+ * - the retired `Manager` stamp — "sealed" means admission is frozen FOREVER, and
847
+ * what makes it permanent is the founding branch of `Manager.Authorized`
848
+ * refusing to re-seat a generation-0 manager once any `Manager` stamp has been
849
+ * retired. Without this conjunct a closed strand that is merely NOT FOUNDED YET
850
+ * reads as sealed: {@link bootstrapFounderMembership} commits `Header`,
851
+ * `Member` and `Manager` as three sequential statements, so the window between
852
+ * the first and the last is exactly "closed, zero managers, still foundable".
853
+ *
854
+ * Reads locally visible rows — a node that has not yet converged on the seal
855
+ * still reports `false` (the schema's seal-propagation NOTE).
856
+ *
857
+ * @param db - The strand's database.
858
+ * @returns `true` iff the strand is closed, holds zero `Manager` rows, and has
859
+ * permanently closed its founding branch.
860
+ */
861
+ export declare function isStrandSealed(db: Database): Promise<boolean>;