@cortexkit/subc-client 0.16.0 → 0.17.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.
package/dist/client.d.ts CHANGED
@@ -4,7 +4,8 @@ import { ReverseRequestRegistry, RouteHandle } from "./route-handle.js";
4
4
  export declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
5
5
  export declare const TIMEOUT_ARBITRATION_GRACE_MS = 50;
6
6
  export declare const LIVENESS_PROBE_WINDOW_MS = 2000;
7
- export declare const ROUTE_OPEN_RETRY_DEADLINE_MS = 30000;
7
+ export declare const ROUTE_OPEN_RETRY_DEADLINE_MS = 90000;
8
+ export declare const MAX_ROUTE_OPENS_IN_FLIGHT = 8;
8
9
  export declare const SUBC_MODULE_ID_ENV = "SUBC_MODULE_ID";
9
10
  export declare const SUBC_LAUNCH_NONCE_ENV = "SUBC_LAUNCH_NONCE";
10
11
  export interface BindIdentity {
@@ -229,12 +230,23 @@ export interface ConnectOptions {
229
230
  reconnectBackoff?: ReconnectBackoff;
230
231
  /** Injectable sleep for timer-free reconnect tests. */
231
232
  sleep?: (ms: number) => Promise<void>;
233
+ /**
234
+ * Injectable clock (milliseconds) for the route.open retry deadline. Tests pair
235
+ * it with `sleep` so a minute-long module restart runs in fake time.
236
+ */
237
+ now?: () => number;
238
+ /**
239
+ * Injectable random source in [0, 1) for route.open retry jitter, so tests can
240
+ * seed it. Defaults to Math.random.
241
+ */
242
+ random?: () => number;
232
243
  /**
233
244
  * How long managed calls keep retrying route.open in-place on retryable
234
245
  * refusals (module_reloading, module_warming, target_unavailable, …) before
235
- * settling not_sent. This deadline is the ONLY binder on those retries —
236
- * module reloads legitimately take tens of seconds (the daemon's drain alone
237
- * defaults to 30s), so the default matches the daemon's drain ceiling.
246
+ * settling not_sent. This deadline and the call's own timeoutMs (when set) are
247
+ * the only binders on those retries: a module restart legitimately keeps its
248
+ * routes refused for about a minute (drain, stop, boot), so the default is
249
+ * ROUTE_OPEN_RETRY_DEADLINE_MS.
238
250
  */
239
251
  routeOpenRetryDeadlineMs?: number;
240
252
  /**
@@ -305,9 +317,11 @@ export declare class SubcClient {
305
317
  private closeStarted;
306
318
  private reconnecting;
307
319
  private generation;
320
+ private routeOpenGateInstance;
308
321
  private readerActive;
309
322
  private constructor();
310
323
  get conn(): ConnectionInfo;
324
+ private get routeOpenGate();
311
325
  /** Read the connection file, connect, authenticate, and start the read loop. */
312
326
  static connect(opts: ConnectOptions): Promise<SubcClient>;
313
327
  /** List modules subc knows about (channel-0 catalog.list). */
@@ -321,8 +335,14 @@ export declare class SubcClient {
321
335
  resolveProvider(capability: string): Promise<string>;
322
336
  /** Resolve every catalog claimant in deterministic module-id order. */
323
337
  resolveProviders(capability: string): Promise<string[]>;
324
- /** Open a route and return its connection-bound immutable handle. */
338
+ /**
339
+ * Open a route and return its connection-bound immutable handle. At most
340
+ * MAX_ROUTE_OPENS_IN_FLIGHT opens are outstanding at once; further calls wait
341
+ * their turn.
342
+ */
325
343
  routeOpen(target: RouteTarget, identity: BindIdentity, opts?: RouteOpenOptions): Promise<RouteHandle>;
344
+ /** One route.open exchange. The caller holds a route-open gate slot. */
345
+ private sendRouteOpen;
326
346
  /** Send a data-plane request on exactly the supplied route generation. */
327
347
  request(handle: RouteHandle, body: unknown, opts?: RequestOptions): Promise<unknown>;
328
348
  /**
@@ -382,7 +402,15 @@ export declare class SubcClient {
382
402
  private managedRequest;
383
403
  private sendManaged;
384
404
  private cachedRouteHandle;
405
+ private awaitOpeningUntil;
385
406
  private openCachedRoute;
407
+ /**
408
+ * The not_sent error for a route.open whose retry deadline ran out. Its code
409
+ * and cause are the most recent refusal, as they always were; its message
410
+ * describes the most informative refusal seen, so a module that was reloading
411
+ * is not reported as admission pressure on the client's own connection.
412
+ */
413
+ private routeOpenRetryExhausted;
386
414
  private lastInboundAtMs;
387
415
  private livenessProbe;
388
416
  /**
@@ -488,6 +516,16 @@ export declare function isConsumerReconnectTransient(err: unknown): boolean;
488
516
  * classification parity.
489
517
  */
490
518
  export declare function isRetryableRouteOpenCode(code: string | undefined): boolean;
519
+ export declare const UNKNOWN_CHANNEL = "unknown_channel";
520
+ export declare const STALE_ROUTE_EPOCH = "stale_route_epoch";
521
+ /** Whether to evict this route, reopen it, and resend once. A consumer deriving
522
+ * custody, provider, or suspect verdicts from route death owns its own code list.
523
+ * Kept byte-identical to subc-protocol error_codes::is_established_route_dead.
524
+ * The origin bit is recorded but not enforced until every daemon consumers can
525
+ * meet sets it on these frames (landed and deployed); requiring it sooner would
526
+ * stop a new SDK from evicting genuine stale routes on older daemons.
527
+ */
528
+ export declare function isEstablishedRouteDead(_flags: number, code: string | undefined): boolean;
491
529
  export declare function connectionFileExists(path: string): Promise<boolean>;
492
530
  /** Validate the exact capability-grammar identifier before catalog I/O. */
493
531
  export declare function isValidCapabilityIdentifier(identifier: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -44,14 +44,22 @@ const DEADLINE_NO_DROP_CODE = "deadline_exceeded_no_drop_observed";
44
44
  // A retryable route.open rejection (target booting / reloading / momentarily
45
45
  // absent) is retried in-place against the same connection up to this deadline
46
46
  // before it is surfaced as not_sent. Mirrors subc-client-rs
47
- // DEFAULT_ROUTE_RETRY_DEADLINE so a target that is briefly unavailable at daemon
48
- // restart recovers without a misleading terminal error.
49
- // Sized against the daemon's route.bind relay timeout (12s default): a single
50
- // load-stalled bind relay consumes ~12s of this budget before the daemon even
51
- // rejects with module_timeout, so the deadline must leave room for MULTIPLE
52
- // full relay waits or one slow bind exhausts the whole retry clock. 30s allows
53
- // ~2 full relay timeouts plus backoff before surfacing not_sent.
54
- export const ROUTE_OPEN_RETRY_DEADLINE_MS = 30_000;
47
+ // DEFAULT_ROUTE_RETRY_DEADLINE so a target that is unavailable while it restarts
48
+ // recovers without a misleading terminal error.
49
+ // Sized against a real module restart, not a single bind: the daemon drains the
50
+ // module's routes (up to 30s), waits for the old process to stop (up to its stop
51
+ // budget, 25s by default), then boots the new one. A measured prefrontal-core
52
+ // restart kept route.open refused for 62.5s end to end, which a 30s budget gave
53
+ // up on halfway through. 90s covers that window with room for a slow boot. A
54
+ // call that sets its own timeoutMs still stops retrying at that timeout.
55
+ export const ROUTE_OPEN_RETRY_DEADLINE_MS = 90_000;
56
+ // The most route.open requests this client keeps outstanding on one connection.
57
+ // Mirrors the daemon's MAX_PENDING_ROUTE_OPENS_PER_CONNECTION
58
+ // (crates/subc-daemon/src/server.rs): the daemon refuses every open beyond that
59
+ // many with a retryable target_unavailable, so sending more at once only
60
+ // manufactures refusals. Extra opens wait here, first come first served, and the
61
+ // wait counts against the same retry deadline as the refusals do.
62
+ export const MAX_ROUTE_OPENS_IN_FLIGHT = 8;
55
63
  // Once a header arrives, its body must follow promptly; bound it so a truncated
56
64
  // frame cannot wedge the read loop forever.
57
65
  const BODY_READ_TIMEOUT_MS = 30_000;
@@ -115,6 +123,9 @@ export class SubcError extends Error {
115
123
  this.detail = detail;
116
124
  }
117
125
  }
126
+ // The wire flags belong to the frame, not the public error API. Keep them with
127
+ // that error across managed-call wrapping so Phase 2 can enforce origin here.
128
+ const errorFrameFlags = new WeakMap();
118
129
  function requireBinaryBody(body) {
119
130
  if (body instanceof Uint8Array)
120
131
  return body;
@@ -158,6 +169,85 @@ export function routeCloseReason(push) {
158
169
  return undefined;
159
170
  return parseRouteCloseReason(push.body.reason);
160
171
  }
172
+ /**
173
+ * First-come-first-served limit on the route.open requests one client has
174
+ * outstanding. A slot is held from just before the open is written until its
175
+ * answer, or its failure, settles. The client holds one connection at a time,
176
+ * and replacing it fails every open still in flight on the old one, so one gate
177
+ * per client is a per-connection limit.
178
+ */
179
+ class RouteOpenGate {
180
+ limit;
181
+ inFlight = 0;
182
+ waiters = [];
183
+ constructor(limit) {
184
+ this.limit = limit;
185
+ }
186
+ /**
187
+ * Resolve with a release function once a slot is free, or with null when
188
+ * `timeoutMs` passes first. Without a timeout the caller waits until a slot
189
+ * frees, which happens as each open in flight settles.
190
+ */
191
+ acquire(timeoutMs) {
192
+ if (this.inFlight < this.limit && this.waiters.length === 0) {
193
+ this.inFlight += 1;
194
+ return Promise.resolve(this.releaser());
195
+ }
196
+ if (timeoutMs !== undefined && timeoutMs <= 0)
197
+ return Promise.resolve(null);
198
+ return new Promise((resolve) => {
199
+ let timer;
200
+ const waiter = (release) => {
201
+ if (timer !== undefined)
202
+ clearTimeout(timer);
203
+ resolve(release);
204
+ };
205
+ this.waiters.push(waiter);
206
+ if (timeoutMs !== undefined) {
207
+ timer = setTimeout(() => {
208
+ const index = this.waiters.indexOf(waiter);
209
+ if (index === -1)
210
+ return;
211
+ this.waiters.splice(index, 1);
212
+ resolve(null);
213
+ }, timeoutMs);
214
+ }
215
+ });
216
+ }
217
+ releaser() {
218
+ let released = false;
219
+ return () => {
220
+ if (released)
221
+ return;
222
+ released = true;
223
+ // Hand the slot straight to the oldest waiter, so a newcomer cannot take
224
+ // it between this release and that waiter resuming.
225
+ const next = this.waiters.shift();
226
+ if (next)
227
+ next(this.releaser());
228
+ else
229
+ this.inFlight -= 1;
230
+ };
231
+ }
232
+ }
233
+ /**
234
+ * The route.open refusals one retry loop has seen: the most recent one, and the
235
+ * one that best explains why the target was unreachable. When the deadline runs
236
+ * out, the error describes the best one. After a module restart the most recent
237
+ * refusal is often admission pressure ("8 binds in flight"), which points a
238
+ * reader at the client's concurrency when the module was simply down.
239
+ */
240
+ class RouteOpenRefusals {
241
+ best;
242
+ last;
243
+ record(refusal) {
244
+ this.last = refusal;
245
+ // At equal rank the newer refusal wins: it describes the target's latest state.
246
+ if (!this.best || routeOpenRefusalRank(refusal) >= routeOpenRefusalRank(this.best)) {
247
+ this.best = refusal;
248
+ }
249
+ }
250
+ }
161
251
  export class SubcClient {
162
252
  sock;
163
253
  currentConn;
@@ -173,6 +263,7 @@ export class SubcClient {
173
263
  closeStarted = false;
174
264
  reconnecting = null;
175
265
  generation = 1;
266
+ routeOpenGateInstance;
176
267
  // True while the read loop is actively reading/dispatching a frame off the
177
268
  // current socket (between reading a header and finishing its dispatch). The
178
269
  // timeout arbitration reads it to decide whether a just-fired timeout should
@@ -187,6 +278,11 @@ export class SubcClient {
187
278
  get conn() {
188
279
  return this.currentConn;
189
280
  }
281
+ // Created on first use, so a client assembled without running its constructor
282
+ // (as the unit tests do) still paces its route.opens.
283
+ get routeOpenGate() {
284
+ return (this.routeOpenGateInstance ??= new RouteOpenGate(MAX_ROUTE_OPENS_IN_FLIGHT));
285
+ }
190
286
  /** Read the connection file, connect, authenticate, and start the read loop. */
191
287
  static async connect(opts) {
192
288
  const normalized = normalizeConnectOptions(opts);
@@ -227,8 +323,23 @@ export class SubcClient {
227
323
  .map((module) => module.module_id)
228
324
  .sort();
229
325
  }
230
- /** Open a route and return its connection-bound immutable handle. */
326
+ /**
327
+ * Open a route and return its connection-bound immutable handle. At most
328
+ * MAX_ROUTE_OPENS_IN_FLIGHT opens are outstanding at once; further calls wait
329
+ * their turn.
330
+ */
231
331
  async routeOpen(target, identity, opts = {}) {
332
+ // Without a timeout the gate always grants a slot eventually.
333
+ const release = (await this.routeOpenGate.acquire());
334
+ try {
335
+ return await this.sendRouteOpen(target, identity, opts);
336
+ }
337
+ finally {
338
+ release();
339
+ }
340
+ }
341
+ /** One route.open exchange. The caller holds a route-open gate slot. */
342
+ async sendRouteOpen(target, identity, opts = {}) {
232
343
  const consumerIdentity = routeOpenConsumerIdentity(opts);
233
344
  const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry();
234
345
  reverseRequests.seal();
@@ -323,7 +434,7 @@ export class SubcClient {
323
434
  // request was in flight. The daemon's contract for the code is
324
435
  // NOT-FORWARDED — dropped before delivery — so the retry is safe by
325
436
  // construction, and the remedy is identical: evict, re-open, resend once.
326
- const deadBindCode = err.code === "unknown_channel" || err.code === "stale_route_epoch";
437
+ const deadBindCode = isEstablishedRouteDead(err.cause instanceof SubcError ? (errorFrameFlags.get(err.cause) ?? 0) : 0, err.code);
327
438
  if (deadBindCode && !retriedUnknownChannel && !this.closeStarted) {
328
439
  retriedUnknownChannel = true;
329
440
  this.evictRouteHandle(routeHandle);
@@ -738,17 +849,41 @@ export class SubcClient {
738
849
  }
739
850
  if (cached.handle && this.isLiveHandle(cached.handle))
740
851
  return cached.handle;
852
+ // The retries end at the retry deadline or at the call's own timeoutMs,
853
+ // whichever comes first. Without timeoutMs the call has no overall deadline
854
+ // here: the default request timeout bounds only the response wait.
855
+ const startedAt = this.opts.now();
856
+ const callDeadline = opts.timeoutMs === undefined ? undefined : startedAt + opts.timeoutMs;
741
857
  if (!cached.opening) {
742
- cached.opening = this.openCachedRoute(cached).finally(() => {
858
+ const retryDeadline = startedAt + this.opts.routeOpenRetryDeadlineMs;
859
+ const deadline = callDeadline === undefined ? retryDeadline : Math.min(retryDeadline, callDeadline);
860
+ cached.opening = this.openCachedRoute(cached, deadline).finally(() => {
743
861
  cached.opening = null;
744
862
  });
863
+ return cached.opening;
745
864
  }
746
- return cached.opening;
865
+ // Another call is already opening this route, on its own deadline. Share its
866
+ // result, but never wait past this call's own timeout for it.
867
+ if (callDeadline === undefined)
868
+ return cached.opening;
869
+ return this.awaitOpeningUntil(cached.opening, callDeadline);
870
+ }
871
+ awaitOpeningUntil(opening, deadline) {
872
+ return new Promise((resolve, reject) => {
873
+ const timer = setTimeout(() => reject(this.notSentCallError("call deadline elapsed waiting for another call's route.open")), Math.max(0, deadline - this.opts.now()));
874
+ opening.then((handle) => {
875
+ clearTimeout(timer);
876
+ resolve(handle);
877
+ }, (error) => {
878
+ clearTimeout(timer);
879
+ reject(error);
880
+ });
881
+ });
747
882
  }
748
- async openCachedRoute(cached) {
749
- const routeRetryDeadline = Date.now() + this.opts.routeOpenRetryDeadlineMs;
883
+ async openCachedRoute(cached, deadline) {
750
884
  let routeRetryDelay = this.opts.reconnectBackoff.baseMs;
751
885
  let routeRetryAttempt = 0;
886
+ const refusals = new RouteOpenRefusals();
752
887
  for (;;) {
753
888
  if (cached.closed)
754
889
  throw this.routeClosedDuringOpen();
@@ -760,11 +895,27 @@ export class SubcClient {
760
895
  }
761
896
  if (cached.handle && this.isLiveHandle(cached.handle))
762
897
  return cached.handle;
898
+ // Waiting for a free slot spends the same deadline as retrying refusals.
899
+ const release = await this.routeOpenGate.acquire(Math.max(0, deadline - this.opts.now()));
900
+ if (!release)
901
+ throw this.routeOpenRetryExhausted(cached.moduleId, routeRetryAttempt, refusals);
902
+ let outcome;
763
903
  try {
764
- const handle = await this.routeOpen(cached.target, cached.identity, {
765
- consumerIdentity: cached.consumerIdentity ?? null,
766
- reverseRequests: cached.reverseRequests,
767
- });
904
+ outcome = {
905
+ handle: await this.sendRouteOpen(cached.target, cached.identity, {
906
+ consumerIdentity: cached.consumerIdentity ?? null,
907
+ reverseRequests: cached.reverseRequests,
908
+ }),
909
+ };
910
+ }
911
+ catch (error) {
912
+ outcome = { error };
913
+ }
914
+ finally {
915
+ release();
916
+ }
917
+ if ("handle" in outcome) {
918
+ const { handle } = outcome;
768
919
  if (cached.closed) {
769
920
  this.liveRoutes.delete(handle.channel);
770
921
  this.sendRouteGoodbye(handle);
@@ -773,37 +924,55 @@ export class SubcClient {
773
924
  cached.handle = handle;
774
925
  return handle;
775
926
  }
776
- catch (error) {
777
- if (error instanceof SubcCallError && error.code === "route_closed")
778
- throw error;
779
- if (!this.closeStarted && isConsumerReconnectTransient(error)) {
780
- try {
781
- await this.reconnectAfterDrop(error);
782
- }
783
- catch (reconnectError) {
784
- throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectError);
785
- }
786
- continue;
927
+ const { error } = outcome;
928
+ if (error instanceof SubcCallError && error.code === "route_closed")
929
+ throw error;
930
+ if (!this.closeStarted && isConsumerReconnectTransient(error)) {
931
+ try {
932
+ await this.reconnectAfterDrop(error);
787
933
  }
788
- if (!this.closeStarted && error instanceof SubcError && isRetryableRouteOpenCode(error.code)) {
789
- // The deadline is the ONLY binder here. An attempt cap used to share
790
- // this condition, and because the capped backoff sums to ~3.1s it
791
- // strictly dominated the 30s deadline — the advertised reload
792
- // patience was never delivered, so every module restart whose reload
793
- // exceeded ~3s failed managed callers with module_reloading. Module
794
- // reloads legitimately take tens of seconds (drain alone defaults to
795
- // 30s); the backoff cap below bounds retry pressure instead.
796
- routeRetryAttempt += 1;
797
- if (Date.now() < routeRetryDeadline) {
798
- await this.opts.sleep(routeRetryDelay);
799
- routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
800
- continue;
801
- }
802
- throw this.notSentCallError(`route.open failed for module ${cached.moduleId}: ${error.code} (retry deadline exhausted after ${routeRetryAttempt} attempts)`, error);
934
+ catch (reconnectError) {
935
+ throw this.notSentRecoveryError("route.open was not sent and reconnect failed", reconnectError);
936
+ }
937
+ continue;
938
+ }
939
+ if (!this.closeStarted && error instanceof SubcError && isRetryableRouteOpenCode(error.code)) {
940
+ // The deadline is the ONLY binder here. An attempt cap used to share
941
+ // this condition, and because the capped backoff sums to ~3.1s it
942
+ // strictly dominated the deadline — the advertised reload patience was
943
+ // never delivered, so every module restart whose reload exceeded ~3s
944
+ // failed managed callers with module_reloading. A restart legitimately
945
+ // keeps routes refused for about a minute; the backoff cap below bounds
946
+ // retry pressure instead.
947
+ routeRetryAttempt += 1;
948
+ refusals.record(error);
949
+ const remaining = deadline - this.opts.now();
950
+ if (remaining > 0) {
951
+ // Every route on a connection is closed together when its module
952
+ // drains, so without jitter they all retry in lock step and arrive at
953
+ // the daemon as one burst each round.
954
+ await this.opts.sleep(Math.min(equalJitter(routeRetryDelay, this.opts.random), remaining));
955
+ routeRetryDelay = Math.min(routeRetryDelay * 2, this.opts.reconnectBackoff.capMs);
956
+ continue;
803
957
  }
804
- throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error);
958
+ throw this.routeOpenRetryExhausted(cached.moduleId, routeRetryAttempt, refusals);
805
959
  }
960
+ throw this.terminalCallError(`route.open failed for module ${cached.moduleId}`, error);
961
+ }
962
+ }
963
+ /**
964
+ * The not_sent error for a route.open whose retry deadline ran out. Its code
965
+ * and cause are the most recent refusal, as they always were; its message
966
+ * describes the most informative refusal seen, so a module that was reloading
967
+ * is not reported as admission pressure on the client's own connection.
968
+ */
969
+ routeOpenRetryExhausted(moduleId, attempts, refusals) {
970
+ const { best, last } = refusals;
971
+ if (!best || !last) {
972
+ return this.notSentCallError(`route.open for module ${moduleId} waited until its deadline for one of ${MAX_ROUTE_OPENS_IN_FLIGHT} route.open slots on this connection`);
806
973
  }
974
+ const recent = last === best ? "" : `; the most recent refusal was ${describeRouteOpenRefusal(last)}`;
975
+ return new SubcCallError("not_sent", `route.open failed for module ${moduleId}: ${describeRouteOpenRefusal(best)} (retry deadline exhausted after ${attempts} attempts${recent})`, last.code, last);
807
976
  }
808
977
  // Stamped by dispatch() on every inbound frame; read by the liveness probe.
809
978
  lastInboundAtMs = 0;
@@ -1247,7 +1416,9 @@ export class SubcClient {
1247
1416
  errorFromFrame(frame) {
1248
1417
  try {
1249
1418
  const parsed = JSON.parse(Buffer.from(frame.body).toString("utf8"));
1250
- return new SubcError(parsed.message ?? "subc error", parsed.code, parsed.detail);
1419
+ const error = new SubcError(parsed.message ?? "subc error", parsed.code, parsed.detail);
1420
+ errorFrameFlags.set(error, frame.header.flags);
1421
+ return error;
1251
1422
  }
1252
1423
  catch {
1253
1424
  return new SubcError(Buffer.from(frame.body).toString("utf8") || "subc error");
@@ -1398,6 +1569,67 @@ export function isRetryableRouteOpenCode(code) {
1398
1569
  code === "target_unavailable" ||
1399
1570
  code === "module_timeout");
1400
1571
  }
1572
+ /**
1573
+ * "Equal jitter": half the delay is kept and the other half is random, so
1574
+ * retries spread out while still backing off. `random` returns a value in [0, 1).
1575
+ */
1576
+ function equalJitter(delayMs, random) {
1577
+ const half = delayMs / 2;
1578
+ return half + random() * half;
1579
+ }
1580
+ // The daemon's reasons for refusing a route.open because too many binds are
1581
+ // already in flight: on the client's connection, or towards the target module
1582
+ // (crates/subc-daemon/src/control.rs, route_open_capacity_refusal and
1583
+ // route_open_target_capacity_refusal). Both are sent as target_unavailable.
1584
+ const ROUTE_OPEN_ADMISSION_PRESSURE_REASONS = new Set(["open_admission_full", "target_binds_full"]);
1585
+ // Matches the messages of those same admission-pressure refusals. The daemon
1586
+ // currently logs the reason but leaves it out of the refusal's detail, so the
1587
+ // message is the only way to recognise them.
1588
+ const ROUTE_OPEN_ADMISSION_PRESSURE_MESSAGE = /route\.open binds in flight|route\.bind relays in flight/;
1589
+ function refusalReason(refusal) {
1590
+ const detail = refusal.detail;
1591
+ if (typeof detail !== "object" || detail === null || !("reason" in detail))
1592
+ return undefined;
1593
+ const reason = detail.reason;
1594
+ return typeof reason === "string" ? reason : undefined;
1595
+ }
1596
+ /**
1597
+ * How much a route.open refusal says about why the target was unreachable,
1598
+ * highest first: the module was changing state (reloading or warming); a
1599
+ * delegation was not registered; the daemon was refusing for admission pressure
1600
+ * (too many binds in flight); anything else.
1601
+ */
1602
+ function routeOpenRefusalRank(refusal) {
1603
+ if (refusal.code === "module_reloading" || refusal.code === "module_warming")
1604
+ return 3;
1605
+ const reason = refusalReason(refusal);
1606
+ if (refusal.code === "delegation_not_registered" || reason === "delegation_not_registered")
1607
+ return 2;
1608
+ if (refusal.code === "target_unavailable") {
1609
+ const admissionPressure = reason === undefined
1610
+ ? ROUTE_OPEN_ADMISSION_PRESSURE_MESSAGE.test(refusal.message)
1611
+ : ROUTE_OPEN_ADMISSION_PRESSURE_REASONS.has(reason);
1612
+ if (admissionPressure)
1613
+ return 1;
1614
+ }
1615
+ return 0;
1616
+ }
1617
+ function describeRouteOpenRefusal(refusal) {
1618
+ const reason = refusalReason(refusal);
1619
+ return `${refusal.code ?? "refused"}${reason === undefined ? "" : ` (reason ${reason})`}: ${refusal.message}`;
1620
+ }
1621
+ export const UNKNOWN_CHANNEL = "unknown_channel";
1622
+ export const STALE_ROUTE_EPOCH = "stale_route_epoch";
1623
+ /** Whether to evict this route, reopen it, and resend once. A consumer deriving
1624
+ * custody, provider, or suspect verdicts from route death owns its own code list.
1625
+ * Kept byte-identical to subc-protocol error_codes::is_established_route_dead.
1626
+ * The origin bit is recorded but not enforced until every daemon consumers can
1627
+ * meet sets it on these frames (landed and deployed); requiring it sooner would
1628
+ * stop a new SDK from evicting genuine stale routes on older daemons.
1629
+ */
1630
+ export function isEstablishedRouteDead(_flags, code) {
1631
+ return code === UNKNOWN_CHANNEL || code === STALE_ROUTE_EPOCH;
1632
+ }
1401
1633
  export async function connectionFileExists(path) {
1402
1634
  try {
1403
1635
  await fs.access(path);
@@ -1415,6 +1647,8 @@ function normalizeConnectOptions(opts) {
1415
1647
  targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
1416
1648
  reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
1417
1649
  sleep: opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
1650
+ now: opts.now ?? Date.now,
1651
+ random: opts.random ?? Math.random,
1418
1652
  routeOpenRetryDeadlineMs: opts.routeOpenRetryDeadlineMs ?? ROUTE_OPEN_RETRY_DEADLINE_MS,
1419
1653
  timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS,
1420
1654
  livenessProbeWindowMs: opts.livenessProbeWindowMs ?? LIVENESS_PROBE_WINDOW_MS,