instar 1.3.628 → 1.3.630

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 (64) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +133 -5
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +52 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/FencedLease.d.ts +23 -4
  8. package/dist/core/FencedLease.d.ts.map +1 -1
  9. package/dist/core/FencedLease.js +44 -4
  10. package/dist/core/FencedLease.js.map +1 -1
  11. package/dist/core/HttpLeaseTransport.d.ts +56 -3
  12. package/dist/core/HttpLeaseTransport.d.ts.map +1 -1
  13. package/dist/core/HttpLeaseTransport.js +191 -51
  14. package/dist/core/HttpLeaseTransport.js.map +1 -1
  15. package/dist/core/LeaseCoordinator.d.ts +84 -0
  16. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  17. package/dist/core/LeaseCoordinator.js +129 -7
  18. package/dist/core/LeaseCoordinator.js.map +1 -1
  19. package/dist/core/MachineIdentity.d.ts +11 -0
  20. package/dist/core/MachineIdentity.d.ts.map +1 -1
  21. package/dist/core/MachineIdentity.js +22 -0
  22. package/dist/core/MachineIdentity.js.map +1 -1
  23. package/dist/core/MeshUrlAdvertiser.d.ts +50 -0
  24. package/dist/core/MeshUrlAdvertiser.d.ts.map +1 -1
  25. package/dist/core/MeshUrlAdvertiser.js +127 -0
  26. package/dist/core/MeshUrlAdvertiser.js.map +1 -1
  27. package/dist/core/MultiMachineCoordinator.d.ts +87 -0
  28. package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
  29. package/dist/core/MultiMachineCoordinator.js +241 -6
  30. package/dist/core/MultiMachineCoordinator.js.map +1 -1
  31. package/dist/core/PeerEndpointResolver.d.ts +0 -0
  32. package/dist/core/PeerEndpointResolver.d.ts.map +1 -0
  33. package/dist/core/PeerEndpointResolver.js +0 -0
  34. package/dist/core/PeerEndpointResolver.js.map +1 -0
  35. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  36. package/dist/core/PostUpdateMigrator.js +10 -0
  37. package/dist/core/PostUpdateMigrator.js.map +1 -1
  38. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  39. package/dist/core/devGatedFeatures.js +15 -0
  40. package/dist/core/devGatedFeatures.js.map +1 -1
  41. package/dist/core/types.d.ts +131 -0
  42. package/dist/core/types.d.ts.map +1 -1
  43. package/dist/core/types.js.map +1 -1
  44. package/dist/scaffold/templates.d.ts.map +1 -1
  45. package/dist/scaffold/templates.js +3 -0
  46. package/dist/scaffold/templates.js.map +1 -1
  47. package/dist/server/AgentServer.d.ts.map +1 -1
  48. package/dist/server/AgentServer.js +15 -2
  49. package/dist/server/AgentServer.js.map +1 -1
  50. package/dist/server/machineAuth.d.ts +24 -0
  51. package/dist/server/machineAuth.d.ts.map +1 -1
  52. package/dist/server/machineAuth.js +71 -0
  53. package/dist/server/machineAuth.js.map +1 -1
  54. package/dist/server/machineRoutes.d.ts +7 -1
  55. package/dist/server/machineRoutes.d.ts.map +1 -1
  56. package/dist/server/machineRoutes.js +28 -3
  57. package/dist/server/machineRoutes.js.map +1 -1
  58. package/package.json +1 -1
  59. package/src/data/builtin-manifest.json +22 -22
  60. package/src/scaffold/templates.ts +3 -0
  61. package/upgrades/1.3.629.md +31 -0
  62. package/upgrades/1.3.630.md +38 -0
  63. package/upgrades/side-effects/multi-machine-lease-self-heal.md +45 -0
  64. package/upgrades/side-effects/multi-transport-mesh-comms.md +70 -0
@@ -16,7 +16,7 @@
16
16
  * The HTTP layer is injected (fetchImpl) so the broadcast/observe/reachability
17
17
  * logic is unit-testable without a network.
18
18
  */
19
- import { signRequest } from '../server/machineAuth.js';
19
+ import { signRequest, verifyLeaseAck, verifyLeaseAckIdentity, newReqNonce } from '../server/machineAuth.js';
20
20
  import { PeerFailureLogGate } from './PeerFailureLogGate.js';
21
21
  export class HttpLeaseTransport {
22
22
  d;
@@ -63,34 +63,170 @@ export class HttpLeaseTransport {
63
63
  this.lastBroadcastOkAt = this.now();
64
64
  return true;
65
65
  }
66
+ const results = await Promise.all(peers.map((peer) => this.dialPeer(peer, '/api/lease', { lease }, lease.epoch)));
67
+ const anyOk = results.some((r) => r.confirmed);
68
+ if (anyOk)
69
+ this.lastBroadcastOkAt = this.now();
70
+ return anyOk;
71
+ }
72
+ meshOn() {
73
+ if (!this.d.resolver)
74
+ return false;
75
+ return this.d.meshTransportEnabled ? this.d.meshTransportEnabled() : true;
76
+ }
77
+ /**
78
+ * Dial one peer over its resolved endpoints with hedged failover (Decision 3):
79
+ * try the best (last-known-good / due) rope first; after `hedgeDelayMs` fire the
80
+ * remaining ropes in parallel; the first rope that genuinely CONFIRMS wins and
81
+ * the losers are aborted. Confirmation = a verified accept-ack from the expected
82
+ * peer (Decision 9) for an ack-capable peer, else a 2xx (back-compat). When the
83
+ * mesh path is off (no resolver / disabled) it is the legacy single-`url` dial.
84
+ */
85
+ async dialPeer(peer, path, bodyBase, sentEpoch) {
66
86
  const fetchImpl = this.d.fetchImpl ?? fetch;
67
- let anyOk = false;
68
- await Promise.all(peers.map(async (peer) => {
87
+ if (!this.meshOn()) {
88
+ return this.legacyDial(peer, path, bodyBase, fetchImpl);
89
+ }
90
+ const resolved = this.d.resolver.resolve(peer.machineId, peer.endpoints, peer.url);
91
+ if (resolved.length === 0)
92
+ return { confirmed: false, lease: null };
93
+ const attempt = async (ep, signal) => {
94
+ const reqNonce = newReqNonce();
95
+ const body = { ...bodyBase, reqNonce };
96
+ const headers = signRequest(this.d.selfMachineId, this.d.signingKeyPem, body, this.d.nextSequence());
97
+ const started = this.now();
69
98
  try {
70
- const body = { lease };
71
- const headers = signRequest(this.d.selfMachineId, this.d.signingKeyPem, body, this.d.nextSequence());
72
- const res = await fetchImpl(`${peer.url.replace(/\/$/, '')}/api/lease`, {
99
+ const res = await fetchImpl(`${ep.url.replace(/\/$/, '')}${path}`, {
73
100
  method: 'POST',
74
101
  headers: { 'Content-Type': 'application/json', ...headers },
75
102
  body: JSON.stringify(body),
76
- // P19 brake: a hung socket aborts instead of holding the caller open.
77
- signal: AbortSignal.timeout(this.requestTimeoutMs),
103
+ signal: mergeSignals(signal, AbortSignal.timeout(this.requestTimeoutMs)),
78
104
  });
79
- if (res && res.ok) {
80
- anyOk = true;
81
- this.logSuccess(`broadcast to ${peer.machineId}`);
82
- }
83
- else {
84
- this.logFailure(`broadcast to ${peer.machineId}`, `status ${res?.status}`);
85
- }
105
+ const httpOk = !!res && res.ok;
106
+ const data = httpOk ? (await res.json().catch(() => null)) : null;
107
+ const outcome = this.interpretResponse(peer, path, reqNonce, sentEpoch, data, httpOk);
108
+ this.d.resolver.recordResult(peer.machineId, ep.kind, outcome.confirmed, this.now() - started);
109
+ if (outcome.confirmed)
110
+ this.logSuccess(`${path} ${peer.machineId}/${ep.kind}`);
111
+ else
112
+ this.logFailure(`${path} ${peer.machineId}/${ep.kind}`, 'unconfirmed');
113
+ return outcome;
86
114
  }
87
115
  catch (err) {
88
- this.logFailure(`broadcast to ${peer.machineId}`, err instanceof Error ? err.message : String(err));
116
+ this.d.resolver.recordResult(peer.machineId, ep.kind, false, this.now() - started);
117
+ this.logFailure(`${path} ${peer.machineId}/${ep.kind}`, err instanceof Error ? err.message : String(err));
118
+ return { confirmed: false, lease: null };
89
119
  }
90
- }));
91
- if (anyOk)
92
- this.lastBroadcastOkAt = this.now();
93
- return anyOk;
120
+ };
121
+ return this.hedge(resolved, attempt);
122
+ }
123
+ /** Legacy single-`url` dial — byte-for-byte today (2xx = confirmed, no ack). */
124
+ async legacyDial(peer, path, bodyBase, fetchImpl) {
125
+ try {
126
+ const headers = signRequest(this.d.selfMachineId, this.d.signingKeyPem, bodyBase, this.d.nextSequence());
127
+ const res = await fetchImpl(`${peer.url.replace(/\/$/, '')}${path}`, {
128
+ method: 'POST',
129
+ headers: { 'Content-Type': 'application/json', ...headers },
130
+ body: JSON.stringify(bodyBase),
131
+ signal: AbortSignal.timeout(this.requestTimeoutMs),
132
+ });
133
+ const httpOk = !!res && res.ok;
134
+ if (!httpOk) {
135
+ this.logFailure(`${path} to ${peer.machineId}`, `status ${res?.status}`);
136
+ return { confirmed: false, lease: null };
137
+ }
138
+ this.logSuccess(`${path} to ${peer.machineId}`);
139
+ if (path === '/api/lease/pull') {
140
+ const data = (await res.json().catch(() => null));
141
+ return { confirmed: true, lease: data?.lease ?? null };
142
+ }
143
+ return { confirmed: true, lease: null };
144
+ }
145
+ catch (err) {
146
+ this.logFailure(`${path} to ${peer.machineId}`, err instanceof Error ? err.message : String(err));
147
+ return { confirmed: false, lease: null };
148
+ }
149
+ }
150
+ /** Interpret a mesh response (accept-ack semantics, Decision 9). */
151
+ interpretResponse(peer, path, sentReqNonce, sentEpoch, data, httpOk) {
152
+ if (!httpOk)
153
+ return { confirmed: false, lease: null };
154
+ const ackCapable = !!peer.meshAckCapable && !!peer.publicKeyPem;
155
+ if (path === '/api/lease/pull') {
156
+ const folded = data?.lease ?? null;
157
+ if (!ackCapable)
158
+ return { confirmed: true, lease: folded }; // legacy 2xx
159
+ const idOk = verifyLeaseAckIdentity(data?.ack, data?.sig, peer.machineId, sentReqNonce, peer.publicKeyPem);
160
+ return { confirmed: idOk, lease: idOk ? folded : null };
161
+ }
162
+ // /api/lease (broadcast) — epoch-equality confirmation.
163
+ if (!ackCapable)
164
+ return { confirmed: true, lease: null }; // legacy 2xx back-compat
165
+ const verdict = verifyLeaseAck(data?.ack, data?.sig, peer.machineId, sentReqNonce, sentEpoch ?? -1, peer.publicKeyPem);
166
+ // 'higher-epoch' is a real takeover signal — NOT a renewal confirmation.
167
+ return { confirmed: verdict === 'confirmed', lease: null };
168
+ }
169
+ /**
170
+ * Hedged race over an ordered endpoint list: fire endpoint[0] immediately, then
171
+ * after hedgeDelayMs fire the rest in parallel; resolve on the FIRST confirmed
172
+ * (aborting the losers), else return the last outcome once all settle.
173
+ */
174
+ async hedge(endpoints, attempt) {
175
+ const controller = new AbortController();
176
+ const hedgeMs = this.d.hedgeDelayMs ?? 1500;
177
+ return new Promise((resolve) => {
178
+ let settled = false;
179
+ let pending = 0;
180
+ let last = { confirmed: false, lease: null };
181
+ const finish = (r) => {
182
+ if (settled)
183
+ return;
184
+ settled = true;
185
+ controller.abort();
186
+ clearTimeout(hedgeTimer);
187
+ resolve(r);
188
+ };
189
+ const fire = (ep) => {
190
+ pending += 1;
191
+ attempt(ep, controller.signal)
192
+ .then((r) => {
193
+ last = r;
194
+ if (r.confirmed)
195
+ finish(r);
196
+ })
197
+ .catch(() => { })
198
+ .finally(() => {
199
+ pending -= 1;
200
+ if (!settled && pending === 0 && !firedRest) {
201
+ // first rope settled unconfirmed before the hedge timer → fire the rest now
202
+ fireRest();
203
+ }
204
+ else if (!settled && pending === 0 && firedRest) {
205
+ finish(last);
206
+ }
207
+ });
208
+ };
209
+ let firedRest = false;
210
+ const fireRest = () => {
211
+ if (firedRest)
212
+ return;
213
+ firedRest = true;
214
+ const rest = endpoints.slice(1);
215
+ if (rest.length === 0) {
216
+ if (pending === 0)
217
+ finish(last);
218
+ return;
219
+ }
220
+ for (const ep of rest)
221
+ fire(ep);
222
+ };
223
+ const hedgeTimer = setTimeout(() => {
224
+ if (!settled)
225
+ fireRest();
226
+ }, hedgeMs);
227
+ // kick off the best rope
228
+ fire(endpoints[0]);
229
+ });
94
230
  }
95
231
  observed() {
96
232
  return { lease: this.lastObserved, lastNonceByHolder: { ...this.lastNonceByHolder } };
@@ -108,20 +244,29 @@ export class HttpLeaseTransport {
108
244
  * machine-auth verification). Keeps only the highest-epoch observed lease and
109
245
  * advances the per-holder nonce watermark (replay detection happens in
110
246
  * FencedLease.acceptTunnelLease which reads this map).
247
+ *
248
+ * multi-transport-mesh-comms — returns the resulting highest observed epoch (or
249
+ * the just-folded lease's epoch), so the /api/lease receiver can sign a
250
+ * freshness-bound accept-ack proving WHAT it folded (Decision 9). When this
251
+ * machine already holds a HIGHER epoch than the broadcast (a takeover the
252
+ * broadcaster hasn't seen), the returned epoch is that higher value — which the
253
+ * caller reads as a stand-down signal, never a confirmation.
111
254
  */
112
255
  recordObserved(lease) {
113
256
  if (!lease || typeof lease.epoch !== 'number')
114
- return;
257
+ return undefined;
115
258
  const prevNonce = this.lastNonceByHolder[lease.holder] ?? -1;
116
259
  // Only accept a strictly-newer nonce for this holder (drop replays here too).
117
260
  if (lease.nonce <= prevNonce && this.lastObserved && this.lastObserved.epoch >= lease.epoch) {
118
- return;
261
+ return this.lastObserved?.epoch;
119
262
  }
120
263
  if (lease.nonce > prevNonce)
121
264
  this.lastNonceByHolder[lease.holder] = lease.nonce;
122
265
  if (!this.lastObserved || lease.epoch >= this.lastObserved.epoch) {
123
266
  this.lastObserved = lease;
124
267
  }
268
+ // The resulting observed epoch = max(what we held, the folded lease).
269
+ return Math.max(this.lastObserved?.epoch ?? lease.epoch, lease.epoch);
125
270
  }
126
271
  /**
127
272
  * Active PULL (Cross-Machine Coherence): GET a peer's current lease over the
@@ -137,37 +282,17 @@ export class HttpLeaseTransport {
137
282
  * returns no lease — proves reachability.
138
283
  */
139
284
  async pullPeer(peer) {
140
- const fetchImpl = this.d.fetchImpl ?? fetch;
141
- try {
142
- const body = {};
143
- const headers = signRequest(this.d.selfMachineId, this.d.signingKeyPem, body, this.d.nextSequence());
144
- const res = await fetchImpl(`${peer.url.replace(/\/$/, '')}/api/lease/pull`, {
145
- method: 'POST',
146
- headers: { 'Content-Type': 'application/json', ...headers },
147
- body: JSON.stringify(body),
148
- // P19 brake: the pull loop's `leasePulling` guard means a hung socket
149
- // would wedge ALL future pulls — abort instead.
150
- signal: AbortSignal.timeout(this.requestTimeoutMs),
151
- });
152
- if (!res || !res.ok) {
153
- this.logFailure(`pull from ${peer.machineId}`, `status ${res?.status}`);
154
- return null;
155
- }
156
- const data = (await res.json().catch(() => null));
157
- // A successful response (even one carrying no lease) proves the medium is live.
158
- this.lastPullOkAt = this.now();
159
- this.logSuccess(`pull from ${peer.machineId}`);
160
- const lease = data?.lease ?? null;
161
- if (lease && typeof lease.epoch === 'number') {
162
- this.recordObserved(lease);
163
- return lease;
164
- }
165
- return null;
166
- }
167
- catch (err) {
168
- this.logFailure(`pull from ${peer.machineId}`, err instanceof Error ? err.message : String(err));
285
+ const outcome = await this.dialPeer(peer, '/api/lease/pull', {}, null);
286
+ if (!outcome.confirmed)
169
287
  return null;
288
+ // A confirmed pull (verified reachability) proves the medium is live.
289
+ this.lastPullOkAt = this.now();
290
+ const lease = outcome.lease;
291
+ if (lease && typeof lease.epoch === 'number') {
292
+ this.recordObserved(lease);
293
+ return lease;
170
294
  }
295
+ return null;
171
296
  }
172
297
  /**
173
298
  * Best-effort fan-out pull of every peer's lease. Failures are advisory (a peer
@@ -181,4 +306,19 @@ export class HttpLeaseTransport {
181
306
  await Promise.all(peers.map((p) => this.pullPeer(p).catch(() => null)));
182
307
  }
183
308
  }
309
+ /** Combine two AbortSignals — aborts when either does (Node 20.3+ AbortSignal.any, with fallback). */
310
+ function mergeSignals(a, b) {
311
+ const anyFn = AbortSignal.any;
312
+ if (typeof anyFn === 'function')
313
+ return anyFn([a, b]);
314
+ const c = new AbortController();
315
+ const onAbort = () => c.abort();
316
+ if (a.aborted || b.aborted)
317
+ c.abort();
318
+ else {
319
+ a.addEventListener('abort', onAbort, { once: true });
320
+ b.addEventListener('abort', onAbort, { once: true });
321
+ }
322
+ return c.signal;
323
+ }
184
324
  //# sourceMappingURL=HttpLeaseTransport.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HttpLeaseTransport.js","sourceRoot":"","sources":["../../src/core/HttpLeaseTransport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HttpLeaseTransport.js","sourceRoot":"","sources":["../../src/core/HttpLeaseTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,sBAAsB,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAC3H,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAqE7D,MAAM,OAAO,kBAAkB;IACZ,CAAC,CAAyB;IACnC,YAAY,GAAuB,IAAI,CAAC;IACxC,iBAAiB,GAA2B,EAAE,CAAC;IAC/C,iBAAiB,GAAG,CAAC,CAAC;IACtB,YAAY,GAAG,CAAC,CAAC;IACR,QAAQ,CAAS;IACjB,gBAAgB,CAAS;IAC1C,6EAA6E;IAC5D,OAAO,CAAqB;IAE7C,YAAY,IAA4B;QACtC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;QACd,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,oBAAoB,IAAI,MAAM,CAAC;QACpD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,MAAM,CAAC;QACxD,IAAI,CAAC,OAAO,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAC;IACtE,CAAC;IAED,uFAAuF;IAC/E,UAAU,CAAC,GAAW,EAAE,MAAc;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,IAAI;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IACO,UAAU,CAAC,GAAW;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,IAAI;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAEO,GAAG;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACpC,CAAC;IACO,GAAG,CAAC,CAAS;QACnB,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,KAAkB;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,4EAA4E;YAC5E,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAC/E,CAAC;QACF,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,KAAK;YAAE,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,MAAM;QACZ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QACnC,OAAO,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5E,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,QAAQ,CACpB,IAAe,EACf,IAAsC,EACtC,QAAiC,EACjC,SAAwB;QAExB,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,QAAS,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACpF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAEpE,MAAM,OAAO,GAAG,KAAK,EAAE,EAAoB,EAAE,MAAmB,EAAE,EAAE;YAClE,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;YACrG,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE;oBACjE,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAE;oBAC3D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oBAC1B,MAAM,EAAE,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;iBACzE,CAAC,CAAC;gBACH,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,IAAK,GAAgB,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC,MAAO,GAAgB,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC5G,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;gBACtF,IAAI,CAAC,CAAC,CAAC,QAAS,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;gBAChG,IAAI,OAAO,CAAC,SAAS;oBAAE,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;;oBAC1E,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,aAAa,CAAC,CAAC;gBAC5E,OAAO,OAAO,CAAC;YACjB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,CAAC,CAAC,QAAS,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;gBACpF,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC1G,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAA0B,EAAE,CAAC;YACjE,CAAC;QACH,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,gFAAgF;IACxE,KAAK,CAAC,UAAU,CACtB,IAAe,EACf,IAAsC,EACtC,QAAiC,EACjC,SAAuB;QAEvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;YACzG,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE;gBACnE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAE;gBAC3D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;gBAC9B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC;aACnD,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,IAAK,GAAgB,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,UAAW,GAAgB,EAAE,MAAM,EAAE,CAAC,CAAC;gBACvF,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YAC3C,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAChD,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,CAAC,MAAO,GAAgB,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAA0C,CAAC;gBACzG,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC;YACzD,CAAC;YACD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClG,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,oEAAoE;IAC5D,iBAAiB,CACvB,IAAe,EACf,IAAsC,EACtC,YAAoB,EACpB,SAAwB,EACxB,IAA4B,EAC5B,MAAe;QAEf,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACtD,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;QAChE,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC;YACnC,IAAI,CAAC,UAAU;gBAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,aAAa;YACzE,MAAM,IAAI,GAAG,sBAAsB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC,YAAsB,CAAC,CAAC;YACrH,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,CAAC;QACD,wDAAwD;QACxD,IAAI,CAAC,UAAU;YAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,yBAAyB;QACnF,MAAM,OAAO,GAAG,cAAc,CAC5B,IAAI,EAAE,GAAG,EACT,IAAI,EAAE,GAAG,EACT,IAAI,CAAC,SAAS,EACd,YAAY,EACZ,SAAS,IAAI,CAAC,CAAC,EACf,IAAI,CAAC,YAAsB,CAC5B,CAAC;QACF,yEAAyE;QACzE,OAAO,EAAE,SAAS,EAAE,OAAO,KAAK,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,KAAK,CACjB,SAA6B,EAC7B,OAAkH;QAElH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC;QAC5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,IAAI,GAAsD,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YAChG,MAAM,MAAM,GAAG,CAAC,CAAoD,EAAE,EAAE;gBACtE,IAAI,OAAO;oBAAE,OAAO;gBACpB,OAAO,GAAG,IAAI,CAAC;gBACf,UAAU,CAAC,KAAK,EAAE,CAAC;gBACnB,YAAY,CAAC,UAAU,CAAC,CAAC;gBACzB,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,EAAoB,EAAE,EAAE;gBACpC,OAAO,IAAI,CAAC,CAAC;gBACb,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC;qBAC3B,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;oBACV,IAAI,GAAG,CAAC,CAAC;oBACT,IAAI,CAAC,CAAC,SAAS;wBAAE,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC7B,CAAC,CAAC;qBACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;qBACf,OAAO,CAAC,GAAG,EAAE;oBACZ,OAAO,IAAI,CAAC,CAAC;oBACb,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;wBAC5C,4EAA4E;wBAC5E,QAAQ,EAAE,CAAC;oBACb,CAAC;yBAAM,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;wBAClD,MAAM,CAAC,IAAI,CAAC,CAAC;oBACf,CAAC;gBACH,CAAC,CAAC,CAAC;YACP,CAAC,CAAC;YACF,IAAI,SAAS,GAAG,KAAK,CAAC;YACtB,MAAM,QAAQ,GAAG,GAAG,EAAE;gBACpB,IAAI,SAAS;oBAAE,OAAO;gBACtB,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACtB,IAAI,OAAO,KAAK,CAAC;wBAAE,MAAM,CAAC,IAAI,CAAC,CAAC;oBAChC,OAAO;gBACT,CAAC;gBACD,KAAK,MAAM,EAAE,IAAI,IAAI;oBAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAClC,CAAC,CAAC;YACF,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;gBACjC,IAAI,CAAC,OAAO;oBAAE,QAAQ,EAAE,CAAC;YAC3B,CAAC,EAAE,OAAO,CAAC,CAAC;YACZ,yBAAyB;YACzB,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;IACxF,CAAC;IAED,WAAW;QACT,iFAAiF;QACjF,4EAA4E;QAC5E,gFAAgF;QAChF,mCAAmC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC5C,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,cAAc,CAAC,KAAkB;QAC/B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QAChE,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7D,8EAA8E;QAC9E,IAAI,KAAK,CAAC,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5F,OAAO,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC;QAClC,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,GAAG,SAAS;YAAE,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QAChF,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YACjE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC5B,CAAC;QACD,sEAAsE;QACtE,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAe;QAC5B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QACpC,sEAAsE;QACtE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC7C,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC3B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC/B,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;CACF;AAUD,sGAAsG;AACtG,SAAS,YAAY,CAAC,CAAc,EAAE,CAAc;IAClD,MAAM,KAAK,GAAI,WAAsE,CAAC,GAAG,CAAC;IAC1F,IAAI,OAAO,KAAK,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,GAAG,IAAI,eAAe,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAChC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO;QAAE,CAAC,CAAC,KAAK,EAAE,CAAC;SACjC,CAAC;QACJ,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC;AAClB,CAAC"}
@@ -119,6 +119,42 @@ export interface LeaseCoordinatorDeps {
119
119
  onSelfSuspend?: (reason: string) => void;
120
120
  /** Fired whenever our effective epoch advances (drives leaseEpochChange → registry push). */
121
121
  onEpochAdvance?: (epoch: number) => void;
122
+ /**
123
+ * F2 (multi-machine-lease-self-heal staleHolderTakeover) — resolved live so a
124
+ * config flip needs no restart. null/disabled ⇒ canAcquire is byte-for-byte the
125
+ * legacy behavior. When enabled, a standby may take over a holder whose signed
126
+ * nonce watermark hasn't advanced for `ttlMs × nonRenewalMissedObservations` of
127
+ * the OBSERVER's own monotonic time (skew-immune; the takeover stays CAS-fenced).
128
+ */
129
+ staleHolderTakeover?: () => {
130
+ enabled: boolean;
131
+ nonRenewalMissedObservations: number;
132
+ } | null;
133
+ /**
134
+ * multi-transport-mesh-comms Layer 3 (soloCaptainHold) — resolved live; DARK by
135
+ * default (null/disabled ⇒ renew() is byte-for-byte today's self-fence). When
136
+ * enabled AND all three preconditions hold, a preferred stationary captain that
137
+ * cannot confirm its renewal over ANY rope HOLDS its lease (same epoch) instead
138
+ * of self-suspending. The preconditions are SIGNALS consumed here, never
139
+ * authority invented here:
140
+ * - isPreferredAwakeAgreed(): this machine is the F4-agreed preferred-awake
141
+ * machine (NOT a raw-config read — the agreement signal from the coordinator).
142
+ * - allPeersPresumedGone(): every peer is presumed-gone by liveness-silence
143
+ * (the EXISTING presumedDeadHolders timeout), i.e. positively aged-out, not
144
+ * merely unreachable this tick.
145
+ * - no higher epoch observed (checked inline against the effective view).
146
+ * The monotonic self-fence stays armed whenever allPeersPresumedGone() is false,
147
+ * so a merely-unreachable-but-recently-alive peer can NEVER keep the captain
148
+ * alive — only a liveness-aged-out one can. store.refresh is NOT used as
149
+ * evidence (a tautology on LocalLeaseStore). Spec: docs/specs/multi-transport-mesh-comms.md.
150
+ */
151
+ soloCaptainHold?: () => {
152
+ enabled: boolean;
153
+ } | null;
154
+ /** F4-agreed preferred-awake signal (consumed by Layer 3 — never the raw config). */
155
+ isPreferredAwakeAgreed?: () => boolean;
156
+ /** True iff EVERY peer is presumed-gone by liveness-silence (Layer 3 gate). */
157
+ allPeersPresumedGone?: () => boolean;
122
158
  logger?: (msg: string) => void;
123
159
  }
124
160
  export declare class LeaseCoordinator {
@@ -143,6 +179,17 @@ export declare class LeaseCoordinator {
143
179
  * while it is not superseded by a higher epoch.
144
180
  */
145
181
  private selfIssued;
182
+ /**
183
+ * F2 (staleHolderTakeover) — per-holder freshness on the OBSERVER's own
184
+ * monotonic clock: the time we last saw that holder's signed nonce watermark
185
+ * ADVANCE (a renewing holder bumps its nonce each renew). Stamped only when a
186
+ * VERIFIED observed lease's nonce strictly exceeds the last we recorded for
187
+ * that holder. `lastObservedNonce` is the per-holder high-water nonce that
188
+ * gates the stamp. Single-clock ⇒ clock-skew immune; the holder cannot forge
189
+ * freshness (the nonce is inside its Ed25519 signature).
190
+ */
191
+ private freshObservedMonoMs;
192
+ private lastObservedNonce;
146
193
  constructor(deps: LeaseCoordinatorDeps);
147
194
  private now;
148
195
  /**
@@ -172,6 +219,25 @@ export declare class LeaseCoordinator {
172
219
  /** The current effective epoch (for stamping writes/sends). */
173
220
  currentEpoch(): number;
174
221
  currentHolder(): string | null;
222
+ /**
223
+ * F4 — is `machineId` the current holder of a LIVE (non-expired, non-released)
224
+ * lease we observe? The deferential-standby health gate: a non-preferred machine
225
+ * defers to its preferred peer ONLY while this is true, so a frozen/down/released
226
+ * preferred never strands coverage (the non-preferred then acquires normally).
227
+ */
228
+ isHolderHealthy(machineId: string): boolean;
229
+ /**
230
+ * multi-transport-mesh-comms Layer 3 — may a preferred stationary captain HOLD
231
+ * its lease (same epoch) instead of self-suspending when no rope confirmed?
232
+ * ALL must hold (each is an EXISTING signal, never authority invented here):
233
+ * (1) the feature is enabled (DARK by default);
234
+ * (2) this machine is the F4-AGREED preferred-awake machine;
235
+ * (3) EVERY peer is presumed-gone by liveness-silence (aged out, not merely
236
+ * unreachable this tick) — the load-bearing "absent vs unreachable" gate;
237
+ * (4) no higher epoch than ours is observed (a real takeover always wins).
238
+ * Fail-closed: a missing dep ⇒ not eligible (today's self-suspend).
239
+ */
240
+ private soloCaptainHoldEligible;
175
241
  /**
176
242
  * The current effective-view signed lease (max of tunnel-observed, git-committed,
177
243
  * and this machine's self-issued renewal), or null. Used to SERVE an active PULL
@@ -199,6 +265,24 @@ export declare class LeaseCoordinator {
199
265
  * win after we relinquish.
200
266
  */
201
267
  relinquish(): void;
268
+ /**
269
+ * F2 — build the StaleHolderTakeoverOpts for `canAcquire`, or `undefined` when
270
+ * the flag is off / the candidate is not a takeable peer (so canAcquire stays
271
+ * byte-for-byte the legacy behavior). Uses this holder's observed freshness on
272
+ * the OBSERVER's own monotonic clock.
273
+ */
274
+ private staleHolderOpts;
275
+ /**
276
+ * F3 — relinquish a lease THIS machine holds AND broadcast a SIGNED tombstone
277
+ * so peers stop deferring to a muted ex-holder's zombie. Called level-triggered
278
+ * by the coordinator when this machine is observe-only yet still the named
279
+ * holder (the 2026-06-19 silent-standby zombie). The tombstone is
280
+ * `released:true` at our epoch with a fresh nonce strictly greater than our last
281
+ * (so a concurrent in-flight renewal cannot out-nonce it) and a past expiry; a
282
+ * higher-epoch normal takeover always strictly dominates it. Idempotent: a no-op
283
+ * (just local relinquish) when we are not the named holder.
284
+ */
285
+ relinquishAndBroadcast(): Promise<void>;
202
286
  /**
203
287
  * Force a ONE-TIME epoch advance to resolve a same-epoch contested tie (spec
204
288
  * §Problem A — the WINNER side, lower `machineId`). Unlike acquireIfEligible(),
@@ -1 +1 @@
1
- {"version":3,"file":"LeaseCoordinator.d.ts","sourceRoot":"","sources":["../../src/core/LeaseCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,IAAI,IAAI;QAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE;YAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC1G;;;;;;;;OAQG;IACH,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;IACrC;;;;;;OAMG;IACH,gBAAgB,CAAC,IAAI,IAAI,CAAC;CAC3B;AAED,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,iFAAiF;IACjF,QAAQ,IAAI;QAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACrF,wDAAwD;IACxD,WAAW,IAAI,OAAO,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjF,+EAA+E;IAC/E,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,wEAAwE;IACxE,mBAAmB,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,kGAAkG;IAClG,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5F,8EAA8E;IAC9E,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,6FAA6F;IAC7F,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAuB;IACzC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAc;IACjC,OAAO,CAAC,YAAY,CAAK;IACzB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,SAAS,CAAS;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,UAAU,CAA4B;gBAElC,IAAI,EAAE,oBAAoB;IAMtC,OAAO,CAAC,GAAG;IAGX;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAIpB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAGnB,OAAO,CAAC,GAAG;IAGX,OAAO,CAAC,SAAS;IAIjB,IAAI,aAAa,IAAI,MAAM,CAE1B;IACD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAkCrB,6EAA6E;IAC7E,UAAU,IAAI,OAAO;IAerB,+DAA+D;IAC/D,YAAY,IAAI,MAAM;IAItB,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B;;;;;;OAMG;IACH,YAAY,IAAI,WAAW,GAAG,IAAI;IAIlC;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,IAAI,IAAI;IAMlB;;;;;;;;;;;OAWG;IACG,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC;IAoBrD;;;OAGG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;;OAKG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC;;;;;OAKG;IACH,iBAAiB,IAAI,WAAW,GAAG,IAAI;IAIvC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,mBAAmB,IAAI,OAAO;IAW9B;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IA6C3C;;;;;;;;;;;;OAYG;IACG,gBAAgB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BpE;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;YA2CjB,SAAS;IAUvB,OAAO,CAAC,SAAS;IAOjB;;;;OAIG;IACH,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI;CAc5D"}
1
+ {"version":3,"file":"LeaseCoordinator.d.ts","sourceRoot":"","sources":["../../src/core/LeaseCoordinator.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,17 @@ export class LeaseCoordinator {
41
41
  * while it is not superseded by a higher epoch.
42
42
  */
43
43
  selfIssued = null;
44
+ /**
45
+ * F2 (staleHolderTakeover) — per-holder freshness on the OBSERVER's own
46
+ * monotonic clock: the time we last saw that holder's signed nonce watermark
47
+ * ADVANCE (a renewing holder bumps its nonce each renew). Stamped only when a
48
+ * VERIFIED observed lease's nonce strictly exceeds the last we recorded for
49
+ * that holder. `lastObservedNonce` is the per-holder high-water nonce that
50
+ * gates the stamp. Single-clock ⇒ clock-skew immune; the holder cannot forge
51
+ * freshness (the nonce is inside its Ed25519 signature).
52
+ */
53
+ freshObservedMonoMs = new Map();
54
+ lastObservedNonce = new Map();
44
55
  constructor(deps) {
45
56
  this.d = deps;
46
57
  this.fl = deps.lease;
@@ -103,9 +114,20 @@ export class LeaseCoordinator {
103
114
  const { [obs.lease.holder]: _self, ...nonceFloor } = obs.lastNonceByHolder;
104
115
  void _self;
105
116
  const decision = this.fl.acceptTunnelLease(obs.lease, git.epoch, nonceFloor);
106
- if (decision.accept && obs.lease.epoch > epoch) {
107
- bestLease = obs.lease;
108
- epoch = obs.lease.epoch;
117
+ if (decision.accept) {
118
+ // F2 freshness stamp (VERIFIED fold-in): a renewing holder bumps its
119
+ // signed nonce each renew (same OR higher epoch), so its watermark
120
+ // advances; a non-renewing holder's stops. Stamp the OBSERVER's own
121
+ // monotonic time when a peer holder's nonce watermark strictly advances.
122
+ const prevNonce = this.lastObservedNonce.get(obs.lease.holder) ?? -1;
123
+ if (obs.lease.holder !== this.selfMachineId && obs.lease.nonce > prevNonce) {
124
+ this.lastObservedNonce.set(obs.lease.holder, obs.lease.nonce);
125
+ this.freshObservedMonoMs.set(obs.lease.holder, this.monotonicNow());
126
+ }
127
+ if (obs.lease.epoch > epoch) {
128
+ bestLease = obs.lease;
129
+ epoch = obs.lease.epoch;
130
+ }
109
131
  }
110
132
  }
111
133
  }
@@ -140,7 +162,50 @@ export class LeaseCoordinator {
140
162
  return this.effectiveView().epoch;
141
163
  }
142
164
  currentHolder() {
143
- return this.effectiveView().lease?.holder ?? null;
165
+ const lease = this.effectiveView().lease;
166
+ // F3 — a RELEASED tombstone declares "epoch N released, not held": it names
167
+ // no live holder, so peers stop deferring to a muted ex-holder's zombie. A
168
+ // higher-epoch normal acquisition still strictly dominates (epoch fold).
169
+ if (!lease || lease.released)
170
+ return null;
171
+ return lease.holder;
172
+ }
173
+ /**
174
+ * F4 — is `machineId` the current holder of a LIVE (non-expired, non-released)
175
+ * lease we observe? The deferential-standby health gate: a non-preferred machine
176
+ * defers to its preferred peer ONLY while this is true, so a frozen/down/released
177
+ * preferred never strands coverage (the non-preferred then acquires normally).
178
+ */
179
+ isHolderHealthy(machineId) {
180
+ const view = this.effectiveView();
181
+ if (!view.lease || view.lease.released || view.lease.holder !== machineId)
182
+ return false;
183
+ return !this.fl.isExpired(view.lease, this.now());
184
+ }
185
+ /**
186
+ * multi-transport-mesh-comms Layer 3 — may a preferred stationary captain HOLD
187
+ * its lease (same epoch) instead of self-suspending when no rope confirmed?
188
+ * ALL must hold (each is an EXISTING signal, never authority invented here):
189
+ * (1) the feature is enabled (DARK by default);
190
+ * (2) this machine is the F4-AGREED preferred-awake machine;
191
+ * (3) EVERY peer is presumed-gone by liveness-silence (aged out, not merely
192
+ * unreachable this tick) — the load-bearing "absent vs unreachable" gate;
193
+ * (4) no higher epoch than ours is observed (a real takeover always wins).
194
+ * Fail-closed: a missing dep ⇒ not eligible (today's self-suspend).
195
+ */
196
+ soloCaptainHoldEligible(ourEpoch) {
197
+ const cfg = this.d.soloCaptainHold?.();
198
+ if (!cfg?.enabled)
199
+ return false;
200
+ if (!this.d.isPreferredAwakeAgreed?.())
201
+ return false;
202
+ if (!this.d.allPeersPresumedGone?.())
203
+ return false;
204
+ // No higher epoch observed than the one we hold (a real takeover dominates).
205
+ const view = this.effectiveView();
206
+ if (view.epoch > ourEpoch)
207
+ return false;
208
+ return true;
144
209
  }
145
210
  /**
146
211
  * The current effective-view signed lease (max of tunnel-observed, git-committed,
@@ -175,6 +240,48 @@ export class LeaseCoordinator {
175
240
  this.d.store.forceLocalExpiry?.();
176
241
  this.log('relinquished self-lease (contested tie-break loser) — winner may now advance to N+1');
177
242
  }
243
+ /**
244
+ * F2 — build the StaleHolderTakeoverOpts for `canAcquire`, or `undefined` when
245
+ * the flag is off / the candidate is not a takeable peer (so canAcquire stays
246
+ * byte-for-byte the legacy behavior). Uses this holder's observed freshness on
247
+ * the OBSERVER's own monotonic clock.
248
+ */
249
+ staleHolderOpts(currentLease) {
250
+ const cfg = this.d.staleHolderTakeover?.();
251
+ if (!cfg?.enabled)
252
+ return undefined;
253
+ if (!currentLease || currentLease.holder === this.selfMachineId)
254
+ return undefined;
255
+ return {
256
+ monotonicNowMs: this.monotonicNow(),
257
+ freshObservedMonoMs: this.freshObservedMonoMs.get(currentLease.holder),
258
+ nonRenewalThresholdMs: this.fl.ttlMs * Math.max(1, cfg.nonRenewalMissedObservations),
259
+ };
260
+ }
261
+ /**
262
+ * F3 — relinquish a lease THIS machine holds AND broadcast a SIGNED tombstone
263
+ * so peers stop deferring to a muted ex-holder's zombie. Called level-triggered
264
+ * by the coordinator when this machine is observe-only yet still the named
265
+ * holder (the 2026-06-19 silent-standby zombie). The tombstone is
266
+ * `released:true` at our epoch with a fresh nonce strictly greater than our last
267
+ * (so a concurrent in-flight renewal cannot out-nonce it) and a past expiry; a
268
+ * higher-epoch normal takeover always strictly dominates it. Idempotent: a no-op
269
+ * (just local relinquish) when we are not the named holder.
270
+ */
271
+ async relinquishAndBroadcast() {
272
+ const view = this.effectiveView();
273
+ if (!view.lease || view.lease.holder !== this.selfMachineId || view.lease.released) {
274
+ // Not the live holder (or already a tombstone) → just clear local state.
275
+ this.relinquish();
276
+ return;
277
+ }
278
+ const tombstone = this.fl.signLease(view.lease.epoch, view.lease.acquiredAt, new Date(this.now()).toISOString(), // past/now expiry — released regardless
279
+ this.nextNonce(), // strictly > our last renewal nonce
280
+ true);
281
+ this.relinquish(); // clear our own self-hold first (forceLocalExpiry preserves the epoch floor)
282
+ await this.broadcast(tombstone);
283
+ this.log(`relinquished + broadcast tombstone for epoch ${view.lease.epoch} (silent-standby release)`);
284
+ }
178
285
  /**
179
286
  * Force a ONE-TIME epoch advance to resolve a same-epoch contested tie (spec
180
287
  * §Problem A — the WINNER side, lower `machineId`). Unlike acquireIfEligible(),
@@ -284,7 +391,7 @@ export class LeaseCoordinator {
284
391
  if (view.lease && view.lease.holder === this.selfMachineId && !this.fl.isExpired(view.lease, this.now())) {
285
392
  return this.renew();
286
393
  }
287
- const decision = this.fl.canAcquire(view.lease, dead, this.now());
394
+ const decision = this.fl.canAcquire(view.lease, dead, this.now(), this.staleHolderOpts(view.lease));
288
395
  if (!decision.can) {
289
396
  this.log(`acquire skipped: ${decision.reason}`);
290
397
  return false;
@@ -304,8 +411,8 @@ export class LeaseCoordinator {
304
411
  if (observedEpoch >= candidate.epoch) {
305
412
  this.log(`CAS lost to epoch ${observedEpoch} (our candidate ${candidate.epoch}) — yielding`);
306
413
  this.emitEpoch(observedEpoch);
307
- // If the winner is a presumed-dead/expired holder we'll retry; else stop.
308
- if (!this.fl.canAcquire(res.observed.lease, dead, this.now()).can)
414
+ // If the winner is a presumed-dead/expired/non-renewing holder we'll retry; else stop.
415
+ if (!this.fl.canAcquire(res.observed.lease, dead, this.now(), this.staleHolderOpts(res.observed.lease)).can)
309
416
  return false;
310
417
  }
311
418
  retries++;
@@ -382,6 +489,21 @@ export class LeaseCoordinator {
382
489
  this.markRenewOk();
383
490
  return true;
384
491
  }
492
+ // ── multi-transport-mesh-comms Layer 3 — safe-by-construction solo-captain hold ──
493
+ // The renewal could not confirm over any rope. BEFORE self-suspending, check the
494
+ // partition floor: a PREFERRED stationary captain whose sole peer is PROVABLY
495
+ // GONE (presumed-gone by liveness-silence) holds its lease (same epoch) instead
496
+ // of thrashing. Gated on F4-agreed-preferred + every-peer-presumed-gone + no
497
+ // higher epoch observed. The hold NEVER advances the epoch or takes over a
498
+ // peer's lease, so even a wrongly-presumed-gone live peer cannot double-write
499
+ // (the intact epoch-CAS + signature fence remains the authority). The monotonic
500
+ // self-fence stays armed whenever the presumed-gone gate is NOT satisfied.
501
+ if (this.soloCaptainHoldEligible(view.epoch)) {
502
+ this.selfIssued = renewed;
503
+ this.markRenewOk(); // hold the SAME epoch — no re-acquire, no inflation
504
+ this.log('solo-captain hold: preferred + all peers presumed-gone + no higher epoch — held lease without medium confirm');
505
+ return true;
506
+ }
385
507
  if (this.monotonicNow() - this.lastRenewOkMonoMs > this.fl.ttlMs) {
386
508
  this.suspended = true;
387
509
  this.d.onSelfSuspend?.(`could not confirm lease over ${this.d.tunnel ? 'tunnel' : 'git'} for > leaseTtlMs (${this.fl.ttlMs}ms, monotonic) — lease lapsed`);