@cortexkit/subc-client 0.19.0 → 0.21.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/README.md CHANGED
@@ -78,6 +78,45 @@ fails loud with an `AuthError` rather than connecting insecurely.
78
78
  - **Connection-file security.** On unix the file must be owner-only (`0600`); a
79
79
  group/world-readable file is rejected, because the key has effectively leaked.
80
80
 
81
+ ### Scoped routes
82
+
83
+ Use a daemon advertising `scopes/v1` and pass a selector to `routeOpen()` or to
84
+ managed `call()` / `callBinary()` options:
85
+
86
+ ```ts
87
+ const scope = {
88
+ owner: { kind: "reserved", module_id: "session-owner" } as const,
89
+ ref: "session-1",
90
+ scopeEpoch: 1,
91
+ };
92
+ const route = await client.routeOpen(target, identity, { scope });
93
+ await client.call("provider", "echo", {}, { scope });
94
+ // Close only this scoped managed route, not the unscoped or another scope's route.
95
+ await client.closeManagedRoute(target, identity, { scope });
96
+ ```
97
+
98
+ The daemon checks who the caller is from its own connection record, not from the request: the caller must be the module that registered the scope (its owner), or a module the owner listed as a carrier on that scope record.
99
+ Passing `scope` does not grant that authority: use the supervised caller's
100
+ `consumerIdentity` (or its default environment identity) as usual. `owner` uses
101
+ the existing `Principal` type; the reserved form above is the normal case, and
102
+ the daemon refuses other owner kinds.
103
+
104
+ The exact wire selector is
105
+ `scope: { owner: { kind: "reserved", module_id: "session-owner" }, ref: "session-1", scope_epoch: 1 }`.
106
+ With no selector, there is no `scope` key. A reserved owner's module id and the
107
+ ref must be non-empty strings, and `scopeEpoch` must be present and a safe
108
+ non-negative integer (zero is valid); invalid selectors fail locally before I/O.
109
+
110
+ Managed routes are cached separately by target, bind and consumer identities,
111
+ reverse capabilities, and the whole scope selector (owner, ref, epoch). Scoped
112
+ and unscoped calls never share a route, nor do different scopes or daemon
113
+ incarnations. Reconnect opens a fresh handle under the same selector.
114
+ `scope_not_synced` and `scope_changed` refusals retain the managed path's retries
115
+ within the caller's deadline. A scope-revocation close (such as `scope_ended` or
116
+ `scope_carrier_removed`) is terminal: neither a later managed call nor a
117
+ reconnect automatically reopens that cache entry. Use a new selector for a new
118
+ session; reload and restart close reasons still permit reopens.
119
+
81
120
  ### Launch nonce
82
121
 
83
122
  A module the daemon spawns proves who it is with a launch nonce. On macOS and
@@ -115,7 +154,9 @@ the environment copy. The environment copy is read only when
115
154
  ## Testing
116
155
 
117
156
  ```sh
118
- bun test # 75 unit/mock tests + 17 RUN_SUBC_LIVE-gated tests
157
+ bun run typecheck
158
+ bun test # unit/mock suite; live tests are gated by RUN_SUBC_LIVE=1
159
+ RUN_SUBC_LIVE=1 bun test tests/live-scoped-open.test.ts
119
160
  ```
120
161
 
121
162
  The live-handshake tests boot the real daemon binary
@@ -124,6 +165,12 @@ byte-identity authority for this client. They skip automatically when the binary
124
165
  is not built; run `cargo build -p subc-core` first (the CI lane does this; the
125
166
  package builds the `ck-subc` executable).
126
167
 
168
+ The scope admission test uses the same supervised `fake-aft-stub` fixture as the
169
+ Rust SDK (built by `cargo build -p subc-core --bins`) to sync an owner's scope and
170
+ observe the real provider bind. Live helpers hard-link the daemon as
171
+ `ckdev-subc` inside the scratch runtime directory before spawning it, and isolate
172
+ all three XDG homes so tests cannot reach the operator's daemon data or config.
173
+
127
174
  ## Layout
128
175
 
129
176
  | File | Responsibility |
package/dist/client.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type ConnectionInfo } from "./connection-file.js";
2
2
  import { AdmissionClass, Priority } from "./envelope.js";
3
+ import type { Principal } from "./provider.js";
3
4
  import { ReverseRequestRegistry, RouteHandle } from "./route-handle.js";
4
5
  export declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
5
6
  export declare const TIMEOUT_ARBITRATION_GRACE_MS = 50;
@@ -29,7 +30,18 @@ export interface ConsumerIdentity {
29
30
  module_id: string;
30
31
  launch_nonce: string;
31
32
  }
33
+ /** A scope selector; scopeEpoch is required even for the scope's owner. */
34
+ export interface RouteScope {
35
+ /** Owner principal, passed verbatim. The daemon decides which principal kinds may own scopes. */
36
+ owner: Principal;
37
+ /** Opaque, non-empty ref within the owner. */
38
+ ref: string;
39
+ /** Safe non-negative integer, including zero; serialized as scope_epoch. */
40
+ scopeEpoch: number;
41
+ }
32
42
  export interface RouteOpenOptions {
43
+ /** Open under this scope. The caller must be its owner or a listed carrier; use a daemon advertising scopes/v1. Serialized as { owner, ref, scope_epoch }. */
44
+ scope?: RouteScope;
33
45
  /** Optional override for the consumer identity; by default the SUBC_MODULE_ID environment variable and the process's launch nonce (see `launchNonce`) are used when both are non-empty; a refused launch-nonce descriptor counts as no nonce. Set null to send route.open without consumer_identity. */
34
46
  consumerIdentity?: ConsumerIdentity | null;
35
47
  /**
@@ -113,6 +125,8 @@ export interface RequestOptions {
113
125
  signal?: AbortSignal;
114
126
  }
115
127
  export interface ManagedCallOptions extends RequestOptions {
128
+ /** Scope for the cached route and its reconnect reopens. The caller must be the scope's owner or a listed carrier; use a daemon advertising scopes/v1. Each owner/ref/epoch has a separate cache entry. */
129
+ scope?: RouteScope;
116
130
  /** Overrides the per-client identity used for route.open before this call. */
117
131
  identity?: BindIdentity;
118
132
  /** Defaults to management_surface, matching the store/host management APIs. */
@@ -142,6 +156,8 @@ export interface CloseRouteOptions {
142
156
  drain?: boolean;
143
157
  }
144
158
  export interface ManagedCloseRouteOptions extends CloseRouteOptions {
159
+ /** Scope selector used by the cached managed route; omitted selects only an unscoped route. */
160
+ scope?: RouteScope;
145
161
  /** Consumer identity used by the cached managed route. */
146
162
  consumerIdentity?: ConsumerIdentity | null;
147
163
  /** The registry whose derived capability set identifies the cached route. */
@@ -187,6 +203,8 @@ export declare class SubcCallError extends Error {
187
203
  * classify on it and must not have to reach into `cause`.
188
204
  */
189
205
  get detail(): unknown;
206
+ /** Why the route ended. A reason never makes an in-flight call safe to resend. */
207
+ get closeReason(): RouteEndReason | undefined;
190
208
  }
191
209
  /**
192
210
  * A live subscription to a provider's event stream, riding a single held-open
@@ -210,6 +228,7 @@ export declare class SubcError extends Error {
210
228
  * those reasons at the transport boundary.
211
229
  */
212
230
  readonly detail?: unknown | undefined;
231
+ readonly closeReason?: RouteEndReason | undefined;
213
232
  constructor(message: string, code?: string | undefined,
214
233
  /**
215
234
  * Machine-parsable payload from the wire `ErrorBody.detail` field, carried
@@ -217,7 +236,7 @@ export declare class SubcError extends Error {
217
236
  * synapse's certification-refusal reasons); dropping it here would strand
218
237
  * those reasons at the transport boundary.
219
238
  */
220
- detail?: unknown | undefined);
239
+ detail?: unknown | undefined, closeReason?: RouteEndReason | undefined);
221
240
  }
222
241
  export interface ConnectOptions {
223
242
  connectionFile: string;
@@ -266,15 +285,11 @@ export interface ConnectOptions {
266
285
  */
267
286
  timeoutArbitrationGraceMs?: number;
268
287
  /**
269
- * Observer for daemon-originated channel-0 control pushes (`route.closing`,
270
- * `route.closed`, and any op added later). Purely advisory: the daemon's
271
- * load-bearing route-death signal remains the GOODBYE frame, and nothing in
272
- * the client's own route lifecycle consumes these. The contract is the wire
273
- * contract verbatim -- unrecognized ops still arrive here (callers ignore
274
- * what they don't know, per the MUST-ignore clause), a push that fails to
275
- * parse as JSON is dropped without surfacing, and an observer throw is
276
- * swallowed like every other caller callback so it cannot fail the read loop
277
- * or unrelated requests.
288
+ * Observer for parsed daemon control pushes, including unrecognized ops which
289
+ * callers should ignore. Malformed JSON is dropped and observer exceptions are
290
+ * swallowed so they cannot fail unrelated requests. The client records route
291
+ * reasons before notifying the observer, but closes routes only on the separate
292
+ * GOODBYE frame, never on a control push.
278
293
  */
279
294
  onControlPush?: (push: ControlPush) => void;
280
295
  }
@@ -286,9 +301,11 @@ export interface ControlPush {
286
301
  body: Record<string, unknown>;
287
302
  }
288
303
  /** A known route-close reason, excluding forward-compatible unknown values. */
289
- export type KnownRouteCloseReason = "reload" | "restart" | "disable" | "crash" | "capability_denied";
304
+ export type KnownRouteCloseReason = "reload" | "restart" | "disable" | "crash" | "capability_denied" | "scope_ended" | "scope_carrier_removed" | "scope_delegation_changed" | "scope_parent_ended";
290
305
  /** A route-close reason decoded from a daemon control push. */
291
306
  export type RouteCloseReason = KnownRouteCloseReason | "unknown";
307
+ /** Why a route ended. Even a planned closure can leave a call's outcome unknown. */
308
+ export type RouteEndReason = RouteCloseReason | "closed_by_caller" | "connection_lost";
292
309
  /** Whether the close reason alone permits reopening a route automatically. */
293
310
  export type RouteCloseDisposition = "may_reopen" | "must_not_reopen";
294
311
  /**
@@ -311,6 +328,9 @@ export declare class SubcClient {
311
328
  private readonly lateResponses;
312
329
  private readonly routes;
313
330
  private readonly liveRoutes;
331
+ private readonly routeModules;
332
+ private readonly routeEndReasons;
333
+ private readonly legacyChannelReasons;
314
334
  private connectionToken;
315
335
  private ingressEpochDropCount;
316
336
  private closedErr;
@@ -339,6 +359,7 @@ export declare class SubcClient {
339
359
  * Open a route and return its connection-bound immutable handle. At most
340
360
  * MAX_ROUTE_OPENS_IN_FLIGHT opens are outstanding at once; further calls wait
341
361
  * their turn.
362
+ * A scoped open requires the caller to be the scope's owner or a listed carrier.
342
363
  */
343
364
  routeOpen(target: RouteTarget, identity: BindIdentity, opts?: RouteOpenOptions): Promise<RouteHandle>;
344
365
  /** One route.open exchange. The caller holds a route-open gate slot. */
@@ -348,6 +369,8 @@ export declare class SubcClient {
348
369
  /**
349
370
  * Managed route + request convenience. Opens and caches a route for the module,
350
371
  * reconnecting and re-opening cached routes after connection drops.
372
+ * Scoped routes are isolated by owner/ref/epoch and require owner or carrier authority.
373
+ * Terminal scope close reasons prevent automatic reopens under the same selector.
351
374
  */
352
375
  call<Response = unknown>(moduleId: string, method: string, params?: unknown, opts?: ManagedCallOptions): Promise<Response>;
353
376
  /**
@@ -460,6 +483,7 @@ export declare class SubcClient {
460
483
  private reopenCachedRoutes;
461
484
  private timeoutMessage;
462
485
  private routeClosedDuringOpen;
486
+ private endedCachedRoute;
463
487
  private readLoop;
464
488
  private dispatch;
465
489
  /**
@@ -478,6 +502,9 @@ export declare class SubcClient {
478
502
  private sendReverseReply;
479
503
  private errorFromFrame;
480
504
  private evictRouteHandle;
505
+ private recordRouteEnd;
506
+ private preventRouteReopen;
507
+ private routeEndReason;
481
508
  private failHandle;
482
509
  private fail;
483
510
  private notSentCallError;
@@ -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
@@ -107,10 +107,16 @@ export class SubcCallError extends Error {
107
107
  get detail() {
108
108
  return this.cause instanceof SubcError ? this.cause.detail : undefined;
109
109
  }
110
+ /** Why the route ended. A reason never makes an in-flight call safe to resend. */
111
+ get closeReason() {
112
+ return this.cause instanceof SubcError || this.cause instanceof SubcCallError
113
+ ? this.cause.closeReason : undefined;
114
+ }
110
115
  }
111
116
  export class SubcError extends Error {
112
117
  code;
113
118
  detail;
119
+ closeReason;
114
120
  constructor(message, code,
115
121
  /**
116
122
  * Machine-parsable payload from the wire `ErrorBody.detail` field, carried
@@ -118,10 +124,11 @@ export class SubcError extends Error {
118
124
  * synapse's certification-refusal reasons); dropping it here would strand
119
125
  * those reasons at the transport boundary.
120
126
  */
121
- detail) {
127
+ detail, closeReason) {
122
128
  super(message);
123
129
  this.code = code;
124
130
  this.detail = detail;
131
+ this.closeReason = closeReason;
125
132
  }
126
133
  }
127
134
  // The wire flags belong to the frame, not the public error API. Keep them with
@@ -146,6 +153,10 @@ export function parseRouteCloseReason(reason) {
146
153
  case "disable":
147
154
  case "crash":
148
155
  case "capability_denied":
156
+ case "scope_ended":
157
+ case "scope_carrier_removed":
158
+ case "scope_delegation_changed":
159
+ case "scope_parent_ended":
149
160
  return reason;
150
161
  default:
151
162
  return "unknown";
@@ -160,6 +171,10 @@ export function classifyRouteCloseReason(reason) {
160
171
  case "disable":
161
172
  case "crash":
162
173
  case "capability_denied":
174
+ case "scope_ended":
175
+ case "scope_carrier_removed":
176
+ case "scope_delegation_changed":
177
+ case "scope_parent_ended":
163
178
  case "unknown":
164
179
  return "must_not_reopen";
165
180
  }
@@ -258,6 +273,9 @@ export class SubcClient {
258
273
  lateResponses = new Map();
259
274
  routes = new Map();
260
275
  liveRoutes = new Map();
276
+ routeModules = new Map();
277
+ routeEndReasons = new Map();
278
+ legacyChannelReasons = new Map();
261
279
  connectionToken = newConnectionToken();
262
280
  ingressEpochDropCount = 0;
263
281
  closedErr = null;
@@ -328,12 +346,14 @@ export class SubcClient {
328
346
  * Open a route and return its connection-bound immutable handle. At most
329
347
  * MAX_ROUTE_OPENS_IN_FLIGHT opens are outstanding at once; further calls wait
330
348
  * their turn.
349
+ * A scoped open requires the caller to be the scope's owner or a listed carrier.
331
350
  */
332
351
  async routeOpen(target, identity, opts = {}) {
352
+ const scope = validatedRouteScope(opts.scope);
333
353
  // Without a timeout the gate always grants a slot eventually.
334
354
  const release = (await this.routeOpenGate.acquire());
335
355
  try {
336
- return await this.sendRouteOpen(target, identity, opts);
356
+ return await this.sendRouteOpen(target, identity, { ...opts, scope });
337
357
  }
338
358
  finally {
339
359
  release();
@@ -341,6 +361,7 @@ export class SubcClient {
341
361
  }
342
362
  /** One route.open exchange. The caller holds a route-open gate slot. */
343
363
  async sendRouteOpen(target, identity, opts = {}) {
364
+ const scope = validatedRouteScope(opts.scope);
344
365
  const consumerIdentity = routeOpenConsumerIdentity(opts);
345
366
  const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry();
346
367
  reverseRequests.seal();
@@ -351,6 +372,7 @@ export class SubcClient {
351
372
  identity,
352
373
  ...(consumerIdentity ? { consumer_identity: consumerIdentity } : {}),
353
374
  ...(consumerCapabilities.length > 0 ? { consumer_capabilities: consumerCapabilities } : {}),
375
+ ...(scope ? { scope: { owner: scope.owner, ref: scope.ref, scope_epoch: scope.scopeEpoch } } : {}),
354
376
  });
355
377
  let installed = null;
356
378
  const install = (frame) => {
@@ -361,6 +383,7 @@ export class SubcClient {
361
383
  throw new SubcError(`route.open returned no route handle: ${JSON.stringify(parsed)}`);
362
384
  }
363
385
  installed = this.installRoute(parsed.route_channel, parsed.route_epoch, reverseRequests);
386
+ this.routeModules.set(parsed.route_channel, target.module_id);
364
387
  return true;
365
388
  };
366
389
  const closeLateRoute = (frame) => {
@@ -371,7 +394,7 @@ export class SubcClient {
371
394
  if (typeof parsed.route_channel !== "number" || typeof parsed.route_epoch !== "number")
372
395
  return;
373
396
  const lateHandle = this.installRoute(parsed.route_channel, parsed.route_epoch);
374
- this.failHandle(lateHandle, new SubcError("late route.open was closed", "route_closed"));
397
+ this.failHandle(lateHandle, new SubcError("late route.open was closed", "route_closed", undefined, "closed_by_caller"));
375
398
  this.liveRoutes.delete(lateHandle.channel);
376
399
  this.sendRouteGoodbye(lateHandle, true);
377
400
  }
@@ -397,6 +420,8 @@ export class SubcClient {
397
420
  /**
398
421
  * Managed route + request convenience. Opens and caches a route for the module,
399
422
  * reconnecting and re-opening cached routes after connection drops.
423
+ * Scoped routes are isolated by owner/ref/epoch and require owner or carrier authority.
424
+ * Terminal scope close reasons prevent automatic reopens under the same selector.
400
425
  */
401
426
  async call(moduleId, method, params, opts = {}) {
402
427
  if (opts.binary) {
@@ -611,14 +636,14 @@ export class SubcClient {
611
636
  }
612
637
  if (opts.drain)
613
638
  await this.drainUnaryOnHandle(handle);
614
- this.failHandle(handle, new SubcError("route closed by closeRoute", "route_closed"));
639
+ this.failHandle(handle, new SubcError("route closed by closeRoute", "route_closed", undefined, "closed_by_caller"));
615
640
  if (this.liveRoutes.get(handle.channel) === handle)
616
641
  this.liveRoutes.delete(handle.channel);
617
642
  this.sendRouteGoodbye(handle);
618
643
  }
619
644
  /** Close a cached managed route by its route-open identity tuple. */
620
645
  async closeManagedRoute(target, identity, opts = {}) {
621
- const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts), (opts.reverseRequests ?? new ReverseRequestRegistry()).capabilities());
646
+ const key = routeCacheKey(target, identity, routeOpenConsumerIdentity(opts), (opts.reverseRequests ?? new ReverseRequestRegistry()).capabilities(), validatedRouteScope(opts.scope));
622
647
  const cached = this.routes.get(key);
623
648
  if (!cached)
624
649
  return;
@@ -715,13 +740,15 @@ export class SubcClient {
715
740
  };
716
741
  pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, channel, corr, ms), ms);
717
742
  this.pending.set(key, pending);
718
- if (signal)
719
- this.attachCancelSignal(signal, key, handle, corr, priority);
720
743
  writeBorrowed(this.sock, encodeFrame(frame), Date.now() + ms).catch((error) => {
721
744
  const current = this.pending.get(key);
722
745
  if (current)
723
746
  this.rejectPending(key, current, error instanceof Error ? error : new SubcError(String(error)));
724
747
  });
748
+ // Queue REQUEST first: an already-aborted signal emits CANCEL immediately,
749
+ // and the daemon can only cancel a correlation it has already received.
750
+ if (signal)
751
+ this.attachCancelSignal(signal, key, handle, corr, priority);
725
752
  });
726
753
  }
727
754
  /**
@@ -813,8 +840,6 @@ export class SubcClient {
813
840
  };
814
841
  pending.timer = setTimeout(() => this.arbitrateTimeout(key, pending, handle.channel, corr, ms), ms);
815
842
  this.pending.set(key, pending);
816
- if (signal)
817
- this.attachCancelSignal(signal, key, handle, corr, priority);
818
843
  const write = writeTrackedBorrowed(this.sock, encodeFrame(frame), Date.now() + ms);
819
844
  handedToSocket = write.queued;
820
845
  write.completed.catch((error) => {
@@ -822,9 +847,13 @@ export class SubcClient {
822
847
  if (current)
823
848
  this.rejectPending(key, current, error instanceof Error ? error : new SubcError(String(error)));
824
849
  });
850
+ // Preserve REQUEST/CANCEL order even when the signal was already aborted.
851
+ if (signal && write.queued)
852
+ this.attachCancelSignal(signal, key, handle, corr, priority);
825
853
  });
826
854
  }
827
855
  async cachedRouteHandle(moduleId, opts) {
856
+ const scope = validatedRouteScope(opts.scope);
828
857
  const identity = opts.identity ?? this.opts.identity;
829
858
  if (!identity) {
830
859
  throw new SubcCallError("terminal", "managed call requires a BindIdentity in SubcClient.connect({ identity }) or call(..., { identity })", "missing_identity");
@@ -833,7 +862,7 @@ export class SubcClient {
833
862
  const consumerIdentity = routeOpenConsumerIdentity(opts);
834
863
  const reverseRequests = opts.reverseRequests ?? new ReverseRequestRegistry();
835
864
  reverseRequests.seal();
836
- const key = routeCacheKey(target, identity, consumerIdentity, reverseRequests.capabilities());
865
+ const key = routeCacheKey(target, identity, consumerIdentity, reverseRequests.capabilities(), scope);
837
866
  let cached = this.routes.get(key);
838
867
  if (!cached) {
839
868
  cached = {
@@ -841,6 +870,7 @@ export class SubcClient {
841
870
  moduleId,
842
871
  target,
843
872
  identity,
873
+ scope,
844
874
  consumerIdentity,
845
875
  reverseRequests,
846
876
  handle: null,
@@ -848,6 +878,8 @@ export class SubcClient {
848
878
  };
849
879
  this.routes.set(key, cached);
850
880
  }
881
+ if (cached.endReason !== undefined)
882
+ throw this.endedCachedRoute(cached.endReason);
851
883
  if (cached.handle && this.isLiveHandle(cached.handle))
852
884
  return cached.handle;
853
885
  // The retries end at the retry deadline or at the call's own timeoutMs,
@@ -888,6 +920,8 @@ export class SubcClient {
888
920
  for (;;) {
889
921
  if (cached.closed)
890
922
  throw this.routeClosedDuringOpen();
923
+ if (cached.endReason !== undefined)
924
+ throw this.endedCachedRoute(cached.endReason);
891
925
  try {
892
926
  await this.ensureConnectedForManaged();
893
927
  }
@@ -904,6 +938,7 @@ export class SubcClient {
904
938
  try {
905
939
  outcome = {
906
940
  handle: await this.sendRouteOpen(cached.target, cached.identity, {
941
+ scope: cached.scope,
907
942
  consumerIdentity: cached.consumerIdentity ?? null,
908
943
  reverseRequests: cached.reverseRequests,
909
944
  }),
@@ -1149,10 +1184,11 @@ export class SubcClient {
1149
1184
  }
1150
1185
  for (const key of routeKeys) {
1151
1186
  const cached = this.routes.get(key);
1152
- if (!cached || cached.closed)
1187
+ if (!cached || cached.closed || cached.endReason !== undefined)
1153
1188
  continue;
1154
1189
  try {
1155
1190
  const handle = await this.routeOpen(cached.target, cached.identity, {
1191
+ scope: cached.scope,
1156
1192
  consumerIdentity: cached.consumerIdentity ?? null,
1157
1193
  reverseRequests: cached.reverseRequests,
1158
1194
  });
@@ -1182,7 +1218,12 @@ export class SubcClient {
1182
1218
  return `request on ${where} ${channel} corr ${corr} timed out after ${ms}ms`;
1183
1219
  }
1184
1220
  routeClosedDuringOpen() {
1185
- return new SubcCallError("not_sent", "route was closed before route.open completed", "route_closed");
1221
+ const cause = new SubcError("route was closed before route.open completed", "route_closed", undefined, "closed_by_caller");
1222
+ return new SubcCallError("not_sent", cause.message, cause.code, cause);
1223
+ }
1224
+ endedCachedRoute(reason) {
1225
+ const cause = new SubcError(`cached route closed by subc (${reason}); must not reopen`, "route_closed", undefined, reason);
1226
+ return this.terminalCallError(cause.message, cause);
1186
1227
  }
1187
1228
  async readLoop(sock, generation) {
1188
1229
  try {
@@ -1222,12 +1263,12 @@ export class SubcClient {
1222
1263
  if (frame.header.channel === 0 && frame.header.ty === FrameType.Push) {
1223
1264
  // Daemon-originated control push (route.closing / route.closed / future
1224
1265
  // ops). Never matches a pending (corr is daemon-chosen), never an error
1225
- // path: unparseable bodies and absent observers both drop silently per
1226
- // the wire contract's MUST-ignore clause, and an observer throw is
1266
+ // path: unparseable bodies drop silently. Reasons are recorded even without
1267
+ // an observer, and an observer throw is
1227
1268
  // swallowed for the same reason as onProgress below -- a caller callback
1228
1269
  // must not fail the read loop.
1229
1270
  const observer = this.opts.onControlPush;
1230
- if (observer) {
1271
+ {
1231
1272
  let parsed = null;
1232
1273
  try {
1233
1274
  const body = this.parseJson(frame);
@@ -1238,8 +1279,9 @@ export class SubcClient {
1238
1279
  // Unparseable control push: ignored by contract.
1239
1280
  }
1240
1281
  if (parsed) {
1282
+ this.recordRouteEnd(parsed);
1241
1283
  try {
1242
- observer(parsed);
1284
+ observer?.(parsed);
1243
1285
  }
1244
1286
  catch {
1245
1287
  // Observer's own throw, on its own stack; the stream must survive.
@@ -1320,7 +1362,8 @@ export class SubcClient {
1320
1362
  // so it stays kind=outcome_unknown -- the same class as a mid-flight socket
1321
1363
  // drop, and never the not_sent/unknown_channel class that call() retries.
1322
1364
  // The code says WHICH route ended, not that it is safe to send again.
1323
- this.failHandle(handle, new SubcError("route closed by subc (GOODBYE)", "route_closed"));
1365
+ this.failHandle(handle, new SubcError("route closed by subc (GOODBYE)", "route_closed", undefined, this.routeEndReason(handle.channel)));
1366
+ this.preventRouteReopen(handle.channel, this.routeEndReason(handle.channel));
1324
1367
  if (this.liveRoutes.get(handle.channel) === handle)
1325
1368
  this.liveRoutes.delete(handle.channel);
1326
1369
  this.evictRouteHandle(handle);
@@ -1431,6 +1474,48 @@ export class SubcClient {
1431
1474
  cached.handle = null;
1432
1475
  }
1433
1476
  }
1477
+ recordRouteEnd(push) {
1478
+ const reason = routeCloseReason(push);
1479
+ if (reason === undefined)
1480
+ return;
1481
+ if ("channels" in push.body) {
1482
+ if (Array.isArray(push.body.channels)) {
1483
+ for (const channel of push.body.channels) {
1484
+ if (typeof channel !== "number" || !Number.isInteger(channel) || channel < 0 || channel > 65535)
1485
+ continue;
1486
+ const final = push.op === "route.closed";
1487
+ if (final || !this.routeEndReasons.get(channel)?.final) {
1488
+ this.routeEndReasons.set(channel, { reason, final });
1489
+ if (final)
1490
+ this.preventRouteReopen(channel, reason);
1491
+ }
1492
+ }
1493
+ }
1494
+ }
1495
+ else if (typeof push.body.module_id === "string") {
1496
+ for (const [channel, module] of this.routeModules) {
1497
+ if (module === push.body.module_id) {
1498
+ this.legacyChannelReasons.set(channel, reason);
1499
+ if (push.op === "route.closed")
1500
+ this.preventRouteReopen(channel, reason);
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ preventRouteReopen(channel, reason) {
1506
+ if (classifyRouteCloseReason(reason) !== "must_not_reopen")
1507
+ return;
1508
+ for (const cached of this.routes.values()) {
1509
+ if (cached.handle?.channel === channel)
1510
+ cached.endReason = reason;
1511
+ }
1512
+ }
1513
+ routeEndReason(channel) {
1514
+ const specific = this.routeEndReasons.get(channel);
1515
+ if (specific)
1516
+ return specific.reason;
1517
+ return this.legacyChannelReasons.get(channel) ?? "unknown";
1518
+ }
1434
1519
  failHandle(handle, error) {
1435
1520
  for (const [key, pending] of this.pending) {
1436
1521
  if (pending.handle && sameRouteHandle(pending.handle, handle))
@@ -1438,10 +1523,15 @@ export class SubcClient {
1438
1523
  }
1439
1524
  }
1440
1525
  fail(err) {
1526
+ const routeError = err instanceof SubcError && err.closeReason ? err
1527
+ : new SubcError(err.message, errorCode(err), undefined, this.closeStarted ? "closed_by_caller" : "connection_lost");
1441
1528
  if (!this.closedErr)
1442
1529
  this.closedErr = err;
1530
+ this.routeEndReasons.clear();
1531
+ this.legacyChannelReasons.clear();
1532
+ this.routeModules.clear();
1443
1533
  for (const [key, pending] of this.pending) {
1444
- this.rejectPending(key, pending, err);
1534
+ this.rejectPending(key, pending, pending.handle ? routeError : err);
1445
1535
  }
1446
1536
  }
1447
1537
  notSentCallError(message, cause) {
@@ -1468,6 +1558,9 @@ export class SubcClient {
1468
1558
  }
1469
1559
  installRoute(channel, epoch, reverseRequests = new ReverseRequestRegistry()) {
1470
1560
  const handle = createRouteHandle(channel, epoch, this.connectionToken, reverseRequests);
1561
+ this.routeEndReasons.delete(channel);
1562
+ this.legacyChannelReasons.delete(channel);
1563
+ this.routeModules.delete(channel);
1471
1564
  this.liveRoutes.set(channel, handle);
1472
1565
  return handle;
1473
1566
  }
@@ -1565,6 +1658,9 @@ export function isRetryableRouteOpenCode(code) {
1565
1658
  // A capability deny is policy, never a transient target-availability failure.
1566
1659
  if (code === "capability_forbidden")
1567
1660
  return false;
1661
+ // Decoding a flow stamp alone does not promise flow behaviour.
1662
+ if (code === "target_flow_unsupported")
1663
+ return false;
1568
1664
  return (code === "module_reloading" ||
1569
1665
  code === "module_warming" ||
1570
1666
  code === "target_unavailable" ||
@@ -1681,12 +1777,36 @@ export function isValidCapabilityIdentifier(identifier) {
1681
1777
  const numericVersion = Number(version);
1682
1778
  return Number.isSafeInteger(numericVersion) && numericVersion >= 1 && numericVersion <= 0xffff_ffff;
1683
1779
  }
1684
- function routeCacheKey(target, identity, consumerIdentity, consumerCapabilities) {
1780
+ function routeCacheKey(target, identity, consumerIdentity, consumerCapabilities, scope) {
1685
1781
  const consumerPart = consumerIdentity
1686
1782
  ? `${consumerIdentity.module_id}\0${consumerIdentity.launch_nonce}`
1687
1783
  : "";
1688
1784
  const capabilitiesPart = [...consumerCapabilities].sort().join("\0");
1689
- return `${target.kind}\0${target.module_id}\0${identity.project_root}\0${identity.harness}\0${identity.session}\0${consumerPart}\0${capabilitiesPart}`;
1785
+ // A JSON tuple keeps opaque refs (including embedded separators) distinct.
1786
+ const scopePart = scope
1787
+ ? JSON.stringify([scope.owner.kind, scope.owner.kind === "reserved" ? scope.owner.module_id : null, scope.ref, scope.scopeEpoch])
1788
+ : "";
1789
+ return `${target.kind}\0${target.module_id}\0${identity.project_root}\0${identity.harness}\0${identity.session}\0${consumerPart}\0${capabilitiesPart}\0${scopePart}`;
1790
+ }
1791
+ /** Validate before any route-open I/O, and snapshot caller-owned mutable values for reopens. */
1792
+ function validatedRouteScope(scope) {
1793
+ if (scope === undefined)
1794
+ return undefined;
1795
+ if (!scope || typeof scope.owner !== "object" || !scope.owner ||
1796
+ !["reserved", "direct", "unverified"].includes(scope.owner.kind) ||
1797
+ (scope.owner.kind === "reserved" && (typeof scope.owner.module_id !== "string" || scope.owner.module_id.length === 0))) {
1798
+ throw new SubcError("scope.owner must be a Principal with a non-empty reserved module_id", "invalid_scope");
1799
+ }
1800
+ if (typeof scope.ref !== "string" || scope.ref.length === 0) {
1801
+ throw new SubcError("scope.ref must be a non-empty string", "invalid_scope");
1802
+ }
1803
+ if (scope.scopeEpoch === undefined) {
1804
+ throw new SubcError("scope.scopeEpoch is required", "scope_epoch_required");
1805
+ }
1806
+ if (!Number.isSafeInteger(scope.scopeEpoch) || scope.scopeEpoch < 0) {
1807
+ throw new SubcError("scope.scopeEpoch must be a safe non-negative integer", "invalid_scope");
1808
+ }
1809
+ return { owner: { ...scope.owner }, ref: scope.ref, scopeEpoch: scope.scopeEpoch };
1690
1810
  }
1691
1811
  function routeOpenConsumerIdentity(opts = {}) {
1692
1812
  if (opts.consumerIdentity !== undefined)