@cotal-ai/manager 0.78.1 → 0.81.1

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 (38) hide show
  1. package/dist/attach-endpoint.d.ts +10 -10
  2. package/dist/attach-endpoint.d.ts.map +1 -1
  3. package/dist/attach-endpoint.js +9 -9
  4. package/dist/attach-endpoint.js.map +1 -1
  5. package/dist/commands.js +2 -2
  6. package/dist/commands.js.map +1 -1
  7. package/dist/console/app.js +1 -1
  8. package/dist/console/index.html +1 -1
  9. package/dist/console-crypto-shim.d.ts +1 -1
  10. package/dist/console-crypto-shim.js +1 -1
  11. package/dist/console-session-entry.js +1 -1
  12. package/dist/endpoint-evict.d.ts +2 -2
  13. package/dist/endpoint-evict.js +3 -3
  14. package/dist/endpoint-evict.js.map +1 -1
  15. package/dist/manager-service-contract.d.ts +12 -13
  16. package/dist/manager-service-contract.d.ts.map +1 -1
  17. package/dist/manager-service-contract.js +22 -23
  18. package/dist/manager-service-contract.js.map +1 -1
  19. package/dist/manager.d.ts +57 -55
  20. package/dist/manager.d.ts.map +1 -1
  21. package/dist/manager.js +160 -136
  22. package/dist/manager.js.map +1 -1
  23. package/dist/runtime/custodial-pty.js +1 -1
  24. package/dist/runtime/custodial-pty.js.map +1 -1
  25. package/dist/runtime/pty.d.ts.map +1 -1
  26. package/dist/runtime/pty.js +6 -1
  27. package/dist/runtime/pty.js.map +1 -1
  28. package/dist/session/bridge.d.ts +3 -3
  29. package/dist/session/bridge.js +1 -1
  30. package/dist/session/bridge.js.map +1 -1
  31. package/dist/session/establish.d.ts +10 -10
  32. package/dist/session/establish.d.ts.map +1 -1
  33. package/dist/session/establish.js +3 -3
  34. package/dist/session/establish.js.map +1 -1
  35. package/dist/session/index.d.ts +1 -1
  36. package/dist/session/index.js +1 -1
  37. package/dist/session/plane.js +5 -5
  38. package/package.json +12 -12
package/dist/manager.js CHANGED
@@ -23,11 +23,11 @@ import { TranscriptReceiver } from "./transcript-receive.js";
23
23
  import { jetstream, jetstreamManager } from "@nats-io/jetstream";
24
24
  import { Kvm } from "@nats-io/kv";
25
25
  import { recordsBucket, epAuthBucket, ensureAuthorityStores, ensureContractStore, createEndpointStreams, contractStoreContext, publishContractArtifact, contractArtifactCanonicalBytes, standaloneConnectOpts, rawDigest, STANDING_RENEWABLE_TTL_SEC as MANAGED_STATIC_TTL_SEC, newArtifactSigner, RotatingSigner, generationAnchor, sessionsBucket, SESSION_GRANT_MAX_TTL_MS, REMOTE_MANAGER_IDENTITY_NAMES, } from "@cotal-ai/core";
26
- // P2 item 6: the manager's ONE §13.6 session plane — offer mint + one-use redeem + PTY-bridge
26
+ // The manager's ONE §13.6 session plane — offer mint + one-use redeem + PTY-bridge
27
27
  // standup for `attach`, over a dedicated standing session-LEDGER connection (the byte rails ride
28
28
  // per-session credentials on their own short-lived connections).
29
29
  import { ManagerSessionPlane, openSessionLedgerKv } from "./session/index.js";
30
- // P2 item 1 (1a-serve): the manager as an ordinary v0.4 `service` endpoint — the §13.1
30
+ // The manager as an ordinary v0.4 `service` endpoint — the §13.1
31
31
  // endpoint-serve credential subsystem (gate provisioning, registration barrier, mint fence) plus
32
32
  // the register/authorize/serve seams, all driven over a scoped one-shot executor connection.
33
33
  import { provisionEndpointGateOpen, endpointRegistrationBarrier, serveIssuanceGateKv, commitSiblingIssuance, markLedgerRowRevoked, epcredRowKey, epgateKey, parseEndpointGate, readEndpointGateGeneration, registerServingInstance, deregisterServiceInstance, serveEndpoint, bindGoal, createGoal, transitionGoal, commitGoalResult, requestGoalCancel, goalAlreadyTerminal, settleGoalUncertain, readGoalResult, readGoalStatus, readGoalSpec, recordGoalIndex, readGoalIndex, clearGoalIndex, listGoalIndex, mintCheckpoint, resumeCheckpoint, readCheckpointSettle, readCheckpointSpec, expireCheckpoint, GOAL_TERMINAL_STATES, goalRefOf, goalProgressTopic, epeSubject, submissionFingerprint, EpEnvelopeError, lifecycleBlocked, lifecycleBlockedFrom, renderLifecycleBlocked, } from "@cotal-ai/core";
@@ -255,10 +255,10 @@ function parseTurnNote(raw) {
255
255
  return undefined;
256
256
  return { payload: n.payload, deadlineAt: n.deadlineAt, holdEpoch: n.holdEpoch, owner: n.owner, ...(typeof n.holdToken === "string" ? { holdToken: n.holdToken } : {}), ...(typeof n.handoffFrom === "string" ? { handoffFrom: n.handoffFrom } : {}) };
257
257
  }
258
- /** A turn relay's key in the manager's maps: the caller triple and goal id the goal plane stores
259
- * the turn under, because a goal id is the caller's own (SPEC 13.6 item 1) and two callers may
260
- * pick the same one. Every part is a subject token, so the dotted join is unambiguous. */
261
- function turnKey(ref) {
258
+ /** A goal's key in the manager's maps: the caller triple and goal id the goal plane stores the
259
+ * goal under, because a goal id is the caller's own (SPEC 13.6 item 1) and two callers may pick
260
+ * the same one. Every part is a subject token, so the dotted join is unambiguous. */
261
+ function goalKey(ref) {
262
262
  return `${ref.caller.owner}.${ref.caller.actor}.${ref.caller.uid}.${ref.goalId}`;
263
263
  }
264
264
  /** A turn hold's token, DERIVED (same recipe as the runtime's pause tokens) from the relay key, so
@@ -329,13 +329,13 @@ const STORE_CHALLENGE_TIMEOUT_MS = 5_000;
329
329
  export class Manager {
330
330
  space;
331
331
  servers;
332
- /** P2 item 6: the broker ws listener port (loopback) `cotal up` allocated, for the console session
332
+ /** The broker ws listener port (loopback) `cotal up` allocated, for the console session
333
333
  * client's wsUrl. Undefined ⇒ no console session client (POST /session 503s). */
334
334
  wsPort;
335
335
  name;
336
336
  workspaceRoot;
337
337
  eventsRequired;
338
- /** P2 item 6: the operator-set global live-session ceiling (see {@link ManagerOptions.maxSessions}). */
338
+ /** The operator-set global live-session ceiling (see {@link ManagerOptions.maxSessions}). */
339
339
  maxSessions;
340
340
  /** The ONE secret store for every kind this manager touches (daemon-cred remint + agent kinds).
341
341
  * See {@link ManagerOptions.secretStore}. */
@@ -401,7 +401,7 @@ export class Manager {
401
401
  * never reused across restarts) — the endpoint's presence key AND the `managerInstance` audit
402
402
  * coordinate every static activation records. */
403
403
  managerLifecycleUid = mintLifecycleUid();
404
- /** The persisted LOGICAL instance id (SPEC 13.6 item 7, P2 item 3): STABLE across restart, so a
404
+ /** The persisted LOGICAL instance id (SPEC 13.6 item 7): STABLE across restart, so a
405
405
  * restart re-registers the SAME id with an ADVANCED epoch through the §13.1 gate (the successor
406
406
  * fences the predecessor's epoch — the (i) fence bites on a real restart). It is the registration
407
407
  * instanceId, the served-status id, the goal spec's executor.instanceId, the epe route, and the
@@ -412,19 +412,19 @@ export class Manager {
412
412
  * {@link provisionEndpointGateOpen} idempotent (no core barrier change) and gives verified
413
413
  * eviction a stable target (the predecessor's connections under this principal). Set in start(). */
414
414
  managerServeIdentity;
415
- /** P2 item 1 (1a-serve): the manager's v0.4 service-endpoint serve state — the serve handle +
415
+ /** The manager's v0.4 service-endpoint serve state — the serve handle +
416
416
  * its dedicated connection, the STABLE serve identity (renewals re-mint the same nkey), the
417
417
  * branded serve grant, and the CURRENT credential (the connection's authenticator reads it on
418
418
  * every (re)connect, so a renewal is adopted without re-registration). Absent on open meshes,
419
- * in user mode (the named 1a follow-up), and before registration completes. */
419
+ * in user mode, and before registration completes. */
420
420
  serviceServe;
421
421
  /** #1577: serve connections whose transport is down while the client reconnects them. Such a
422
422
  * connection is open (`isClosed()` is false under unbounded reconnects) yet the broker holds
423
423
  * none of its rails, so the liveness responder must not grade it `bound`. Keyed by the
424
424
  * connection, so a re-dial that swaps in a fresh one starts from its own state. */
425
425
  serveTransportDown = new WeakSet();
426
- /** P2 item 2 (spawn-as-action): the SELF-MEDIATED goal-writer connection + ActionContext — a
427
- * standing connection DISJOINT from the serve credential (Q2), scoped to exactly this endpoint's
426
+ /** The spawn-as-action SELF-MEDIATED goal-writer connection + ActionContext — a
427
+ * standing connection DISJOINT from the serve credential, scoped to exactly this endpoint's
428
428
  * goal bind/terminal facts + goal-record writes ({@link goalWriterGrants}). Auth mode mints the
429
429
  * `goal-writer` cred; an open mesh uses a bare connection (no credential system to mint from).
430
430
  * `gate` (auth mode) is the own-issuance-gate READER for the own-gate currency belt — the
@@ -442,31 +442,31 @@ export class Manager {
442
442
  * live) and stashed here for {@link startGoalWriter} to build the standing connection from. */
443
443
  goalWriterIdentity;
444
444
  goalWriterCreds;
445
- /** P2 item 6: the manager's ONE §13.6 session plane — offer mint + one-use redeem + PTY-bridge
445
+ /** The manager's ONE §13.6 session plane — offer mint + one-use redeem + PTY-bridge
446
446
  * standup for `attach`. The face's establisher and the CLI attach handler both call THIS one
447
447
  * plane; the manager never constructs a second. Undefined until {@link startSessionPlane}. */
448
448
  sessionPlane;
449
- /** P2 item 6: the standing session-LEDGER connection + its mutable creds holder (the authenticator
449
+ /** The standing session-LEDGER connection + its mutable creds holder (the authenticator
450
450
  * presents the refreshed cred on the next reconnect after a half-TTL renewal — the goal-writer
451
451
  * precedent). Auth mode only; an open mesh runs the plane over a bare connection. */
452
452
  sessionLedgerConn;
453
453
  /** Renews the session signing key long before its window closes. A key that expires unattended
454
454
  * takes the whole session plane down until the manager is restarted, which kills live sessions. */
455
455
  sessionKeyRenewTimer;
456
- /** P2 item 6: credentialId → the nkey that credential was minted for, for the live per-session
456
+ /** Maps credentialId → the nkey that credential was minted for, for the live per-session
457
457
  * SERVING credentials. The §13.1 ledger row records the holder principal, and the row is written
458
458
  * at stage time (after the mint), so the two steps need this one hop. Entries are dropped at
459
459
  * revoke; a session that never staged drops its entry when the manager exits. */
460
460
  sessionServingKeys = new Map();
461
- /** P2 item 6: the STABLE session-LEDGER identity (auth mode) — minted once at registration
461
+ /** The STABLE session-LEDGER identity (auth mode) — minted once at registration
462
462
  * alongside the serve + goal-writer identities; a renewal re-mints the SAME nkey with a fresh
463
463
  * bounded exp and re-stages its distinct credId into the §13.1 revocation family. The current
464
464
  * credential is minted INSIDE {@link registerManagerService}'s run block and stashed here. */
465
465
  sessionLedgerIdentity;
466
466
  sessionLedgerCreds;
467
- /** P2 item 2: the acceptance replied for each in-flight goalId this incarnation accepted, so an
468
- * idempotent same-goalId retry serves the IDENTICAL acceptance (same allocated name/triple) without
469
- * a second spawn. Durable cross-incarnation reconstruction rides the goal index; here the
467
+ /** The acceptance replied for each in-flight goal this incarnation accepted, by {@link goalKey},
468
+ * so an idempotent same-goalId retry serves the IDENTICAL acceptance (same allocated name/triple)
469
+ * without a second spawn. Durable cross-incarnation reconstruction rides the goal index; here the
470
470
  * live map covers same-incarnation retries, with the committed result fact as the fallback. */
471
471
  goalAcceptances = new Map();
472
472
  /** The boot reconcile of the durable goal index runs ONCE at start (a
@@ -474,12 +474,12 @@ export class Manager {
474
474
  * Spawn-as-action REFUSES to accept until it completes, so the sweep never races a live goal's
475
475
  * acceptance (settling one mid-flight would steal its real terminal). */
476
476
  goalReconcileDone = false;
477
- /** P2 item 2 (M4): the live spawn goal ref for each managed agent name, so a despawn MID-GOAL
477
+ /** The live spawn goal ref for each managed agent name, so a despawn MID-GOAL
478
478
  * drives the cancel path (transition -> cancel terminal). Cleared when the goal terminalizes. */
479
479
  agentGoals = new Map();
480
480
  /**
481
481
  * The turn relay's same-incarnation idempotency map ({@link goalAcceptances}'s twin), by
482
- * {@link turnKey}: a same-goal retry serves the identical acceptance; cross-incarnation retries
482
+ * {@link goalKey}: a same-goal retry serves the identical acceptance; cross-incarnation retries
483
483
  * rebuild from the goal-index entry (its acceptance floor + note).
484
484
  *
485
485
  * One entry per turn this incarnation accepted: the acceptance a duplicate submission is served
@@ -501,7 +501,7 @@ export class Manager {
501
501
  * window would hear `not-found` again.
502
502
  */
503
503
  turnAcceptances = new Map();
504
- /** Every relayed turn awaiting its seat's yield, by {@link turnKey}. The seat's `turn-pending` pull
504
+ /** Every relayed turn awaiting its seat's yield, by {@link goalKey}. The seat's `turn-pending` pull
505
505
  * scans it; the deadline sweep drives expiry; a seat reap stamps its entries `seatDiedAt`, which
506
506
  * the deadline terminal carries as `agentDownAt` so the run reads that death as L4002.
507
507
  * Rebuilt at boot from goal-index entries carrying a turn note. */
@@ -681,7 +681,7 @@ export class Manager {
681
681
  this.attach = new AttachEndpoint(() => this.list(),
682
682
  // Initial /feed replay for a connecting console: the current peer roster.
683
683
  () => [{ event: "roster", data: this.ep?.getRoster() ?? [] }], opts.consolePort ?? 0,
684
- // P2 item 6: the console's mesh §13.6 session establisher — injected ONLY when a broker ws
684
+ // The console's mesh §13.6 session establisher — injected ONLY when a broker ws
685
685
  // listener exists (cotal up allocated a wsPort). Never a second plane; it drives THE plane.
686
686
  opts.wsPort !== undefined ? (name) => this.establishConsoleSession(name) : undefined,
687
687
  // Loopback unless the OPERATOR said otherwise. A broker *dial* address is not a manager *bind*
@@ -889,7 +889,7 @@ export class Manager {
889
889
  throw new Error(`space "${this.space}" has user-auth state on disk but no mesh registry entry - a user-mode manager needs the authoritative record (\`cotal up\` writes it before the control plane); \`cotal up --user-auth\` this space, or remove the stale ${userAuthStateDir(this.workspaceRoot, this.space)}`);
890
890
  if (!this.remoteAuthority && this.userMode && !this.auth)
891
891
  throw new Error(`space "${this.space}" has user-auth state but no auth.json under ${authDir(this.workspaceRoot)} - the pre-flip manager still needs the space trust bundle; re-run \`cotal up --user-auth\` here`);
892
- // P2 item 3 (SPEC 13.6 item 7): the LOGICAL instance id + serve identity PERSIST across restart
892
+ // SPEC 13.6 item 7: the LOGICAL instance id + serve identity PERSIST across restart
893
893
  // (a space-scoped manager identity file under .cotal). A restart re-registers the SAME id with an
894
894
  // ADVANCED epoch (the successor fences the predecessor); a fresh mint over a malformed file is
895
895
  // refused loud (no-fallbacks - a restart never silently becomes a fresh instance). A second
@@ -978,7 +978,7 @@ export class Manager {
978
978
  this.ep.on("presence-view", () => this.logSeatMeshTransitions());
979
979
  await this.ep.start();
980
980
  await this.ep.setActivity(`supervisor (${this.runtimeKind})`);
981
- // Per-instance liveness lease (P2 item 3 — the old per-space singleton is DEMOTED per D9). Acquire
981
+ // Per-instance liveness lease (the old per-space singleton is DEMOTED). Acquire
982
982
  // THIS logical instance's own key (atomic CAS create). A DIFFERENT instance (a second manager in a
983
983
  // second workspace root) has a distinct id ⇒ a distinct key ⇒ it coexists; the create THROWS only
984
984
  // when the SAME instance id is already live (a same-root double-start, or a restart racing the
@@ -1035,7 +1035,7 @@ export class Manager {
1035
1035
  const startupReconcile = this.auth && !this.userMode ? this.reconcileStaticLifecycles() : undefined;
1036
1036
  if (startupReconcile)
1037
1037
  void startupReconcile.catch((e) => console.error(`! ${STARTUP_RECONCILING}: ${rejectionText(e)} - no per-alias retry could be planned; a later manager start re-reads unfinished durable terminals`));
1038
- // P2 item 1 (1d): the manager serves NO ctl tiers - its whole control surface is the v0.4
1038
+ // The manager serves NO ctl tiers - its whole control surface is the v0.4
1039
1039
  // service endpoint registered below. The old three-tier rail (self/manager/admin) is deleted;
1040
1040
  // `ctl.delivery`/`ctl.delivery-admin` (the delivery daemon) and `ctl.auth-admin` (the auth
1041
1041
  // plane) are separate services and keep their rails.
@@ -1101,8 +1101,8 @@ export class Manager {
1101
1101
  // the fence before it can publish a fresh service registration after shutdown.
1102
1102
  if (this.staticReconcileStopping)
1103
1103
  return;
1104
- // P2 item 1: register the manager as an ordinary v0.4 `service` endpoint (SPEC §13.7/§13.9)
1105
- // and serve its typed command surface on the ep rails - since 1d the ONLY control door, in
1104
+ // Register the manager as an ordinary v0.4 `service` endpoint (SPEC §13.7/§13.9)
1105
+ // and serve its typed command surface on the ep rails - the ONLY control door, in
1106
1106
  // EVERY mesh mode. Static + user meshes mint the scoped executor + endpoint-serve credential;
1107
1107
  // an open mesh runs the same gate/registration ceremony over bare connections and never mints
1108
1108
  // (there is no credential system - the broker enforces nothing, matching the old open-mesh ctl
@@ -1110,10 +1110,10 @@ export class Manager {
1110
1110
  await this.registerManagerService();
1111
1111
  if (this.staticReconcileStopping)
1112
1112
  return;
1113
- // P2 item 2: stand up the standing goal-writer connection for spawn-as-action — AFTER
1113
+ // Stand up the standing goal-writer connection for spawn-as-action — AFTER
1114
1114
  // registration (it writes this endpoint's goal facts/records), disjoint from the serve cred.
1115
1115
  await this.startGoalWriter();
1116
- // P2 item 6: stand up the ONE §13.6 session plane for `attach` — AFTER registration too (it
1116
+ // Stand up the ONE §13.6 session plane for `attach` — AFTER registration too (it
1117
1117
  // rides the serve grant's epoch + the family-staged session-ledger cred), on its own standing
1118
1118
  // connection disjoint from both the serve and goal-writer creds.
1119
1119
  await this.startSessionPlane();
@@ -1483,7 +1483,7 @@ export class Manager {
1483
1483
  }
1484
1484
  }
1485
1485
  }
1486
- // P2 item 1 (checklist 7): the manager is the `endpoint-serve` renewal owner for its OWN
1486
+ // The manager is the `endpoint-serve` renewal owner for its OWN
1487
1487
  // service credential — re-mint the SAME serve identity with a fresh bounded exp THROUGH the
1488
1488
  // §13.1 mint fence over a scoped one-shot executor (every renewal stages a distinct ledger
1489
1489
  // row and wins the gate CAS; never the standing connection). The serve connection's
@@ -1529,7 +1529,7 @@ export class Manager {
1529
1529
  console.error(`! goal-writer renewal: ${rejectionText(e)} - spawn-as-action stops accepting at this cred's expiry unless the manager restarts`);
1530
1530
  }
1531
1531
  }
1532
- // P2 item 6: the manager is also the session-ledger's renewal owner — re-mint the SAME nkey
1532
+ // The manager is also the session-ledger's renewal owner — re-mint the SAME nkey
1533
1533
  // with a fresh bounded exp AND re-stage its new credId into the §13.1 family, through the
1534
1534
  // scoped executor. Without this the standing session-ledger connection dies at its TTL and
1535
1535
  // `attach` stops establishing sessions until a restart. The connection's authenticator presents
@@ -2644,7 +2644,7 @@ export class Manager {
2644
2644
  return { ok: false, error: rejectionText(e) };
2645
2645
  }
2646
2646
  }
2647
- /** The ONE shared control-admission chokepoint (P2 item 1, checklist 3/8) BOTH dispatch doors
2647
+ /** The ONE shared control-admission chokepoint BOTH dispatch doors
2648
2648
  * run — the v0.3 `ctl` door ({@link handle}) and the v0.4 `ep` service handlers
2649
2649
  * ({@link serveGated}): the maintenance/resume fence (`beginLifecycle`: a resume-pending or
2650
2650
  * non-active manager accepts no ordinary control work) and then the F5(a) membership gate
@@ -2679,7 +2679,7 @@ export class Manager {
2679
2679
  admission.release();
2680
2680
  }
2681
2681
  }
2682
- /** The ep door's ADMIN flag for a caller (the 1c tier refinement). Static mesh: `true` — the
2682
+ /** The ep door's ADMIN flag for a caller. Static mesh: `true` — the
2683
2683
  * admin-grade rows (any-mode despawn/attach, the `manager.admin` family, `launch`) are minted
2684
2684
  * only into operator instruments (§13.2: `any` is operator-policy-mintable; the agent/spawn
2685
2685
  * rollups never carry them), so REACHING the handler is holding the admin tier, exactly as
@@ -2688,9 +2688,9 @@ export class Manager {
2688
2688
  * subject-parsed caller tuple to its host-owned authorization callback, with no participant-ledger
2689
2689
  * fallback. The same fresh authority drives {@link psOwnerFilter}, so a revoked scope demotes the
2690
2690
  * very next call even on a still-valid bearer. Local ledger read failures authorize nothing;
2691
- * remote host-state faults throw and fail the operation closed. NAMED RESIDUAL (critic,
2692
- * 1c.2b): the static `true` has no serve-time
2693
- * re-check — a LEAKED static admin instrument keeps its reach until the credential's bounded
2691
+ * remote host-state faults throw and fail the operation closed.
2692
+ * NAMED RESIDUAL: the static `true` has no serve-time re-check — a LEAKED static admin
2693
+ * instrument keeps its reach until the credential's bounded
2694
2694
  * TTL (the one-shot 5-minute profile), the same static-revoke≠reconnect-death class ruled
2695
2695
  * across this campaign; static revocation is the TTL, not a ledger. */
2696
2696
  async epAdminReach(caller) {
@@ -2796,15 +2796,15 @@ export class Manager {
2796
2796
  if (accepted.by !== agent.name)
2797
2797
  throw new EpEnvelopeError("permission-denied", `run-answer amend is allowed to ${agent.name} only for an answer recorded under its own name; this step's accepted answer is ${JSON.stringify(accepted.by)}'s`);
2798
2798
  }
2799
- /** The v0.4 typed command table (P2 item 1, slice 1b): every ordinary handler runs the SHARED
2799
+ /** The v0.4 typed command table: every ordinary handler runs the SHARED
2800
2800
  * admission chokepoint ({@link serveGated}) and then delegates to the SAME op core the ctl
2801
- * door dispatches (checklist 8: one core, two thin doors). The resume/preservation family
2801
+ * door dispatches (one core, two thin doors). The resume/preservation family
2802
2802
  * deliberately BYPASSES serveGated — exactly as it sits before {@link admitControl} on the ctl
2803
2803
  * door (those ops must run while `resumeRequired` fences ordinary work) — riding its own state
2804
- * fences; its ep gate is the admin-grade `manager.admin` capability grant (the 1b rule: static
2804
+ * fences; its ep gate is the admin-grade `manager.admin` capability grant (static
2805
2805
  * admin-class commands are capability-gated + untargeted, never a fabricated ledger mode).
2806
2806
  *
2807
- * TIER SEMANTICS on the ep door (the 1c grant-migration table): the tier lives in the CALLER'S
2807
+ * TIER SEMANTICS on the ep door: the tier lives in the CALLER'S
2808
2808
  * GRANT, refined per-op exactly as the ctl doors refine their subject tier. Owner-mode
2809
2809
  * `despawn`/`attach` keep the privileged semantics (`admin=false`, own-domain via
2810
2810
  * {@link authorizeNamed}) — every spawn-capable agent holds those rows. ANY-mode requests are
@@ -2828,13 +2828,13 @@ export class Manager {
2828
2828
  const callerOf = (ctx) => principalKey(ctx.subject.caller.owner, ctx.subject.caller.actor).key;
2829
2829
  // A ctl-core failure reply becomes the §13.3 structured error the serve boundary publishes.
2830
2830
  // The data half of a failure reply (e.g. a degraded resume result) rides the error MESSAGE
2831
- // only — the item-2 action model gives failures a typed channel.
2831
+ // only — the action model gives failures a typed channel.
2832
2832
  const unwrap = (r) => {
2833
2833
  if (!r.ok)
2834
2834
  throw new EpEnvelopeError("failed-precondition", r.error ?? "the operation failed");
2835
2835
  return r.data;
2836
2836
  };
2837
- // The admin-family serve gate (1c.2c, security4's hardening): every `manager.admin`-class
2837
+ // The admin-family serve gate: every `manager.admin`-class
2838
2838
  // command re-checks operator reach AT SERVE TIME - static: true (the mint boundary already
2839
2839
  // gates the rows to instruments); user mesh: the caller's CURRENT ledger scope must still
2840
2840
  // carry `admin` ({@link epAdminReach}'s fresh read), so a revoked scope demotes the very next
@@ -2942,8 +2942,8 @@ export class Manager {
2942
2942
  throw new EpEnvelopeError(persona.error.startsWith("no persona") ? "not-found" : "failed-precondition", persona.error);
2943
2943
  return { agent: persona.agent };
2944
2944
  }),
2945
- // P2 item 2: `spawn` is an ACTION - accept a goal + reply the acceptance floor payload, drive
2946
- // progress + terminal off-handler (no ~30s block). The blocking reply path is gone (pin 8).
2945
+ // `spawn` is an ACTION - accept a goal + reply the acceptance floor payload, drive
2946
+ // progress + terminal off-handler (no ~30s block). The blocking reply path is gone.
2947
2947
  // #373: arming the event plane (events: true, or the omission that arms it by default)
2948
2948
  // follows owner-domain reach on a user mesh. Resolve the caller's admin tier once for
2949
2949
  // the residual cross-owner case; opStart decides before connector resolution or grant
@@ -3013,7 +3013,7 @@ export class Manager {
3013
3013
  // deployer bearer would then bypass owner-equality (operator launch) despite the view holding
3014
3014
  // no admin rows. Uniform owner-equality removes that divergence in the least-privilege
3015
3015
  // direction.
3016
- // P2 item 2 (ruling 3): manifest `launch` is an ACTION through the SAME chokepoint as spawn -
3016
+ // Manifest `launch` is an ACTION through the SAME chokepoint as spawn -
3017
3017
  // the manifest resolve + owner-equality authz run in opLaunch's accept path, then the goal
3018
3018
  // drives progress + terminal. The acceptance floor is the allocated identity + goal coords.
3019
3019
  launch: (ctx) => this.serveGated(ctx, () => this.serveSpawnGoal(ctx, (h) => this.opLaunch(args(ctx), callerOf(ctx), false, h, ctx.subject.route))),
@@ -3624,7 +3624,7 @@ export class Manager {
3624
3624
  rmSync(a.restart.sessionStatePath, { force: true });
3625
3625
  if (a.seatHome)
3626
3626
  rmSync(a.seatHome, { recursive: true, force: true });
3627
- // P2 item 6 (pin 4): end any live §13.6 attach session bound to THIS incarnation with the honest
3627
+ // End any live §13.6 attach session bound to THIS incarnation with the honest
3628
3628
  // `target-despawn` reason. Fires once per agent on every free path (despawn / self-stop / reap /
3629
3629
  // exit) via the `agents` guard above; a no-op when no plane or no live session for the target.
3630
3630
  this.sessionPlane?.endForTarget(a.name, a.lifecycleUid, "target-despawn");
@@ -3973,9 +3973,14 @@ export class Manager {
3973
3973
  console.error(`despawn ${a.name}: the agent's retirement completed; the name is free for reuse`);
3974
3974
  }
3975
3975
  }
3976
- else {
3976
+ else if (cur) {
3977
3977
  console.error(`despawn ${a.name}: retirement confirmed for a prior lifecycle of "${a.name}"; the current hold is left intact`);
3978
3978
  }
3979
+ else {
3980
+ // No hold stands, as after an orphaned spawn's rollback: that lifecycle was never despawned and
3981
+ // has no successor, so this line names neither.
3982
+ console.error(`retire ${a.name}: lifecycle ${a.lifecycleUid} retired; the name had no hold to clear`);
3983
+ }
3979
3984
  }
3980
3985
  /** The teardown's ASYNC BROKER PHASE: mint the ephemeral target-pinned deprovisioner cred and
3981
3986
  * delete the agent's broker footprint (dm_/dlv_ durables + read-ACL row). Split from
@@ -4397,7 +4402,7 @@ export class Manager {
4397
4402
  }
4398
4403
  return live;
4399
4404
  }
4400
- /** THE single name-liveness predicate both the hard-pinned collision refuse (M6, P2 item 2) and
4405
+ /** THE single name-liveness predicate both the hard-pinned collision refuse and
4401
4406
  * uniqueName's numbering consult, so they can never drift: a name is taken if this manager
4402
4407
  * reserves/manages/retires it OR a roster-live occupant already holds it. Pass a pre-built
4403
4408
  * {@link liveRosterNames} set when checking many names in one allocation. */
@@ -4671,9 +4676,9 @@ export class Manager {
4671
4676
  }
4672
4677
  /** The launch fields the host supplies rather than the seat. Spawn and resume both take them from
4673
4678
  * here, so a resumed seat launches under the same host policy, `eventsRequired` included, as the
4674
- * same seat spawned fresh. */
4675
- hostLaunchFields(agent, shareTools, harness) {
4676
- const cotalConfig = loadCotalConfig(this.workspaceRoot);
4679
+ * same seat spawned fresh. The caller passes the cotal config it judged the launch by, so the
4680
+ * servers and env allowlist come from the contents its checks read. */
4681
+ hostLaunchFields(cotalConfig, agent, shareTools, harness) {
4677
4682
  return {
4678
4683
  space: this.space,
4679
4684
  servers: this.servers,
@@ -5024,6 +5029,17 @@ export class Manager {
5024
5029
  if (this.userMode)
5025
5030
  return { ok: false, error: "supervise is a restart policy this host cannot enforce: a user-mode seat has no static slot to keep the incarnation owned across a process death" };
5026
5031
  }
5032
+ // One read of the cotal config per spawn: the delegated refusal, the model policy and the launch
5033
+ // fields below all take this value, so the awaits between the policy check and the launch cannot
5034
+ // admit the seat under one file and launch it with another's servers and env allowlist. Read per
5035
+ // spawn, so a policy edit reaches the next spawn without a restart.
5036
+ let cotalConfig;
5037
+ try {
5038
+ cotalConfig = loadCotalConfig(this.workspaceRoot);
5039
+ }
5040
+ catch (e) {
5041
+ return { ok: false, error: rejectionText(e) };
5042
+ }
5027
5043
  // A delegated seat starts outside this host from values alone, so a choice only this host can
5028
5044
  // honour is refused here, before enrollment, and named rather than dropped.
5029
5045
  if (this.requiredRuntime.spawnDelegated) {
@@ -5042,7 +5058,7 @@ export class Manager {
5042
5058
  return { ok: false, error: `${delegatedBy}, so it cannot reopen a session held on this host (continuity: exact)` };
5043
5059
  if (typeof opts.cwd === "string" && opts.cwd !== "")
5044
5060
  return { ok: false, error: `${delegatedBy}, so it cannot run in a directory on this host's filesystem (cwd); the seat runs in its runtime resource's own directory` };
5045
- const shared = Object.keys(connectorServers(loadCotalConfig(this.workspaceRoot), agent, opts.shareTools));
5061
+ const shared = Object.keys(connectorServers(cotalConfig, agent, opts.shareTools));
5046
5062
  if (shared.length)
5047
5063
  return { ok: false, error: `${delegatedBy}, so it cannot share MCP servers that run on this host (${shared.join(", ")}); pass --share-tools none` };
5048
5064
  }
@@ -5160,22 +5176,16 @@ export class Manager {
5160
5176
  // #581: the operator's per-role model allowlist, judged on the EFFECTIVE role and model resolved
5161
5177
  // above, before any reserve or mint. This is where the launch is performed, so no caller can
5162
5178
  // skip it, and a definition pinned to a stale model (or to none) is refused here instead of
5163
- // serving on it. Read per spawn, so a policy edit reaches the next spawn without a restart.
5164
- let policyRefusal;
5165
- try {
5166
- policyRefusal = modelPolicyRefusal(loadCotalConfig(this.workspaceRoot), {
5167
- persona: opts.resolved ? `manifest agent "${ref}"` : `persona "${ref}" (${configPath})`,
5168
- role, model, variant,
5169
- // A manifest launch carries its own declared model/variant in these options
5170
- // (launchAgentToStartOpts), so there they are the definition's field, never a flag.
5171
- modelFlag: !opts.resolved && opts.model !== undefined,
5172
- variantFlag: !opts.resolved && opts.variant !== undefined,
5173
- launchOptions,
5174
- });
5175
- }
5176
- catch (e) {
5177
- return { ok: false, error: rejectionText(e) };
5178
- }
5179
+ // serving on it.
5180
+ const policyRefusal = modelPolicyRefusal(cotalConfig, {
5181
+ persona: opts.resolved ? `manifest agent "${ref}"` : `persona "${ref}" (${configPath})`,
5182
+ role, model, variant,
5183
+ // A manifest launch carries its own declared model/variant in these options
5184
+ // (launchAgentToStartOpts), so there they are the definition's field, never a flag.
5185
+ modelFlag: !opts.resolved && opts.model !== undefined,
5186
+ variantFlag: !opts.resolved && opts.variant !== undefined,
5187
+ launchOptions,
5188
+ });
5179
5189
  if (policyRefusal)
5180
5190
  return { ok: false, error: policyRefusal };
5181
5191
  // The alias-reuse gate (#29 piece 3): a name whose previous agent is still retiring REFUSES
@@ -5230,9 +5240,9 @@ export class Manager {
5230
5240
  // unconditional: a half-wired endpoint without the seam must fail loud here, not silently
5231
5241
  // allocate off a pre-snapshot roster.
5232
5242
  await this.ep.waitForPresenceSnapshot();
5233
- // M6 (P2 item 2 spawn-as-action): a HARD-PINNED name — an imperative `--name`/identity override
5243
+ // Spawn-as-action: a HARD-PINNED name — an imperative `--name`/identity override
5234
5244
  // or a manifest-declared name (opts.resolved) — that collides with a LIVE/provisioning/reserved
5235
- // incarnation REFUSES loud at accept, BEFORE any reserve/mint/bind (pin 1), never a silent `_2`
5245
+ // incarnation REFUSES loud at accept, BEFORE any reserve/mint/bind, never a silent `_2`
5236
5246
  // suffix (so an address-by-triple caller's pinned name can't be re-pointed). A PERSONA-DERIVED
5237
5247
  // base name (no pin) keeps uniqueName's collision numbering, so multi-peer `spawn reviewer` twice
5238
5248
  // still yields reviewer + reviewer_2. The alias-reuse gate above is orthogonal and already fired.
@@ -5243,7 +5253,7 @@ export class Manager {
5243
5253
  // this manager's agents/reserved/retiring PLUS the roster-live set) - a hard-pinned name
5244
5254
  // colliding with ANY live incarnation (managed, unmanaged foreground/connector, or another
5245
5255
  // manager's agent) refuses cleanly at accept, rather than minting the collision and black-
5246
- // holing on the broker/auth refusal (item 3: a pinned name live under another manager MUST refuse).
5256
+ // holing on the broker/auth refusal (a pinned name live under another manager MUST refuse).
5247
5257
  if (this.nameInUse(identityName))
5248
5258
  return { ok: false, error: `the name "${identityName}" is hard-pinned (${opts.resolved ? "manifest-declared" : "--name/identity override"}) but is already held by a live incarnation (managed here, an unmanaged foreground/connector session, or another manager's agent); a pinned same-name collision refuses at accept - pick another name or despawn the existing one` };
5249
5259
  name = identityName;
@@ -5285,11 +5295,11 @@ export class Manager {
5285
5295
  // before anything recorded how to address them, so a crash in that window left a live seat
5286
5296
  // outside every manager and the successor retired the slot over it.
5287
5297
  const custody = this.reserveCustody();
5288
- // ACCEPT SEAM (P2 item 2 spawn-as-action): the incarnation identity is minted and NOTHING has
5298
+ // ACCEPT SEAM (spawn-as-action): the incarnation identity is minted and NOTHING has
5289
5299
  // been provisioned yet — the action serve path binds the goal + replies the acceptance HERE. A
5290
5300
  // throw (bind conflict / duplicate goalId) aborts the spawn before provisioning: the catch below
5291
5301
  // returns the failure and the finally releases the reserve, so a refused accept leaves zero
5292
- // footprint (pin 1). The hosted enrollment arm is the exception, below. Blocking callers
5302
+ // footprint. The hosted enrollment arm is the exception, below. Blocking callers
5293
5303
  // (roster boot) pass no hooks and this is a no-op.
5294
5304
  // The ALLOCATED agent's addressing triple (the acceptance floor names what was actually
5295
5305
  // allocated, never the requested-but-unallocated name). Static/open key on DEV_OWNER + the
@@ -5462,7 +5472,7 @@ export class Manager {
5462
5472
  : undefined;
5463
5473
  const manifestSha256 = manifestPath ? this.fileDigest(manifestPath) : undefined;
5464
5474
  const launchOpts = {
5465
- ...this.hostLaunchFields(agent, opts.shareTools, harness),
5475
+ ...this.hostLaunchFields(cotalConfig, agent, opts.shareTools, harness),
5466
5476
  name,
5467
5477
  role,
5468
5478
  // User mode: the principal IS the identity (the endpoint derives card.id from owner+actor);
@@ -5521,7 +5531,7 @@ export class Manager {
5521
5531
  spec.env = { ...spec.env, COTAL_MANAGER_INSTANCE: this.managerInstanceId };
5522
5532
  handle = await this.spawnCustodied(name, spec, cwd, custody);
5523
5533
  }
5524
- hooks?.onLaunched?.(); // P2 item 2: the "launched" progress edge (process spawned, pre-presence)
5534
+ hooks?.onLaunched?.(); // The "launched" progress edge (process spawned, pre-presence)
5525
5535
  const managed = {
5526
5536
  name,
5527
5537
  role,
@@ -5688,7 +5698,7 @@ export class Manager {
5688
5698
  // OMIT an absent role: the goal terminal commits this data through the strict
5689
5699
  // canonicalJson (undefined never coerces to null, SPEC 13.6), so a role-less spawn would
5690
5700
  // otherwise fail its succeeded terminal. The CLI/connector already render an absent role as
5691
- // "no role", so dropping the key preserves the reply (P2 item 2, surfaced by readiness:live).
5701
+ // "no role", so dropping the key preserves the reply (surfaced by readiness:live).
5692
5702
  const okData = { name, agent, id: managed.id, mode: handle.kind, lifecycleUid, ...(role !== undefined ? { role } : {}), ...(opts.eventsNotice !== undefined ? { eventsNotice: opts.eventsNotice } : {}) };
5693
5703
  await hooks?.onOutcome?.({ kind: "succeeded", data: okData });
5694
5704
  return { ok: true, data: okData };
@@ -6179,7 +6189,7 @@ export class Manager {
6179
6189
  }
6180
6190
  try {
6181
6191
  const launchOpts = {
6182
- ...this.hostLaunchFields(entry.launch.connector, entry.launch.shareTools, harness),
6192
+ ...this.hostLaunchFields(loadCotalConfig(this.workspaceRoot), entry.launch.connector, entry.launch.shareTools, harness),
6183
6193
  name: entry.name,
6184
6194
  role: entry.role,
6185
6195
  id: authority.id,
@@ -6635,7 +6645,7 @@ export class Manager {
6635
6645
  return { ok: false, error: `no agent "${name}"` };
6636
6646
  return this.despawnCore(a, caller, admin, args.graceful !== false);
6637
6647
  }
6638
- /** The ONE named-terminal core both doors share (P2 item 1, checklist 8): the ctl named `stop`
6648
+ /** The ONE named-terminal core both doors share: the ctl named `stop`
6639
6649
  * and the v0.4 targeted `despawn` are the same terminal — authorize by the shared policy
6640
6650
  * ({@link authorizeNamed}: own-child / owner-domain on privileged, any on admin), stop, track.
6641
6651
  * The ep door runs the SAME two pieces separately so a policy denial surfaces as the §13.3
@@ -6653,14 +6663,15 @@ export class Manager {
6653
6663
  despawnAuthorized(a, graceful, trackNonAdmin, caller) {
6654
6664
  this.stopHandle(a, graceful);
6655
6665
  this.trackStoppedHandle(a, trackNonAdmin, { kind: "stopped-requested", requester: caller });
6656
- void this.cancelAgentGoal(a.name, graceful ? "graceful" : "terminate"); // M4: cancel a live spawn goal
6666
+ void this.cancelAgentGoal(a.name, graceful ? "graceful" : "terminate"); // Cancel a live spawn goal
6657
6667
  return { ok: true, data: { name: a.name, stopped: true, graceful } };
6658
6668
  }
6659
6669
  /** Retire one agent this manager launched under a delegated user intent, through the host
6660
6670
  * (SPEC 13.16). It sends the user's retirement intent for the UID of the running slot or its
6661
- * retirement hold, and only on `retired: true` for that exact target stops the slot and frees the
6662
- * name; every other answer leaves the slot running or the name held. It never calls the holder's
6663
- * own prepare or requester. */
6671
+ * retirement hold, and only on `retired: true` for that exact target stops the slot, shreds the
6672
+ * seat's local secret family and frees the name; every other answer leaves the slot running or
6673
+ * the name held, and a failed shred keeps the name held. It never calls the holder's own prepare
6674
+ * or requester. */
6664
6675
  async retireDelegatedAgent(name, intentId) {
6665
6676
  const execute = this.remoteAuthority?.executeDelegatedUserIntent;
6666
6677
  if (!execute)
@@ -6696,6 +6707,17 @@ export class Manager {
6696
6707
  const slot = this.agents.get(name);
6697
6708
  if (slot?.lifecycleUid === target.lifecycleUid)
6698
6709
  this.despawnAuthorized(slot, true, false, `delegated retirement ${intentId}`);
6710
+ // The host owns the grant and the footprint, but the secret family enrollUserAgent wrote here
6711
+ // is this participant's, and no teardown arm of a delegated seat removes it.
6712
+ const unshredded = [];
6713
+ await this.shredUserSecrets(unshredded, (live ?? held?.target)?.secretPaths ?? agentLifecycleSecretFilePaths(this.workspaceRoot, this.space, name, target.lifecycleUid));
6714
+ if (unshredded.length) {
6715
+ const error = `the host retired "${name}" at ${target.lifecycleUid}, but cleanup failed: ${unshredded.join("; ")}; the name stays held until a retried retirement intent removes it`;
6716
+ const hold = this.retiring.get(name);
6717
+ if (hold?.target.lifecycleUid === target.lifecycleUid)
6718
+ hold.lastError = error;
6719
+ return { ok: false, error };
6720
+ }
6699
6721
  this.confirmRetirement({ id: principalKey(target.owner, target.actor).key, name, lifecycleUid: target.lifecycleUid });
6700
6722
  return { ok: true, data: { name, lifecycleUid: target.lifecycleUid, retired: true } };
6701
6723
  }
@@ -6808,7 +6830,7 @@ export class Manager {
6808
6830
  await nc.drain().catch(() => nc.close());
6809
6831
  }
6810
6832
  }
6811
- /** 1d open-mesh counterpart of {@link withEndpointServeExecutor}: an OPEN mesh has no
6833
+ /** The open-mesh counterpart of {@link withEndpointServeExecutor}: an OPEN mesh has no
6812
6834
  * credential system, so there is no scoped executor to mint - the same §13.1 gate/records
6813
6835
  * writes ride a bare one-shot connection (the broker enforces nothing on an open mesh; the
6814
6836
  * ceremony still produces the real gate, epoch, and registration the serve rails run on). */
@@ -6829,7 +6851,7 @@ export class Manager {
6829
6851
  await nc.drain().catch(() => nc.close());
6830
6852
  }
6831
6853
  }
6832
- /** The served manager-level health summary (1a's one read-only command). */
6854
+ /** The served manager-level health summary. */
6833
6855
  managerStatusData() {
6834
6856
  return {
6835
6857
  instanceId: this.managerInstanceId,
@@ -6936,7 +6958,7 @@ export class Manager {
6936
6958
  })().catch(() => this.serveTransportDown.add(nc));
6937
6959
  let handle;
6938
6960
  try {
6939
- // The 1b typed surface + the derived `describe`. The descriptor stays PUBLIC in static
6961
+ // The typed surface + the derived `describe`. The descriptor stays PUBLIC in static
6940
6962
  // mode: the broker grant (who holds each command's request-publish row) is the
6941
6963
  // load-bearing authority tier, and a static single-operator mesh leaks nothing by listing
6942
6964
  // command names; the trusted per-caller `view(caller)` scoping joins the user-mode
@@ -7029,8 +7051,8 @@ export class Manager {
7029
7051
  await this.stop();
7030
7052
  process.exit(1);
7031
7053
  }
7032
- /** P2 item 1: register the manager as an ordinary v0.4 `service` endpoint and serve its typed
7033
- * command surface on the ep rails - since 1d the manager's ONLY control door. On an AUTH mesh
7054
+ /** Register the manager as an ordinary v0.4 `service` endpoint and serve its typed
7055
+ * command surface on the ep rails - the manager's ONLY control door. On an AUTH mesh
7034
7056
  * the whole credential path is the SAME one an ordinary endpoint traverses (the enforcement
7035
7057
  * test that keeps "ordinary" honest): provision the §13.1 issuance gate, drive the
7036
7058
  * registration BARRIER's gate CAS, then release the serve credential only on the mint FENCE's
@@ -7065,7 +7087,7 @@ export class Manager {
7065
7087
  console.error(`remote manager service endpoint activated: ${MANAGER_ENDPOINT}/${this.managerInstanceId} (epoch ${state.grant.epoch})`);
7066
7088
  return;
7067
7089
  }
7068
- // The §13.7 contract store is REGISTRATION's dependency, ensured here MODE-NEUTRALLY (1c.2c):
7090
+ // The §13.7 contract store is REGISTRATION's dependency, ensured here MODE-NEUTRALLY:
7069
7091
  // it used to ride the static-only lifecycle reconcile, so a USER-mode manager registered
7070
7092
  // against an absent stream and its artifact publish died no-responders (live-repro'd). A
7071
7093
  // provisioner one-shot creates-or-verifies it (config-B immutability incl. the shadowed-legacy
@@ -7075,7 +7097,7 @@ export class Manager {
7075
7097
  const provCreds = auth ? await mintCreds(auth, newIdentity(), "provisioner") : undefined;
7076
7098
  const provNc = await this.dial({ ...standaloneConnectOpts({ creds: provCreds, /* not yet wired to a recorded transport */ tls: false }), maxReconnectAttempts: 0 });
7077
7099
  try {
7078
- // P2 item 2: the manager now WRITES goal facts (EPF) + progress events (EPE), so the §13.12
7100
+ // The manager now WRITES goal facts (EPF) + progress events (EPE), so the §13.12
7079
7101
  // endpoint streams must exist. Nothing provisioned them before spawn-as-action (no endpoint
7080
7102
  // wrote to EPF/EPE), so the manager ensures the full set here over the provisioner (whose
7081
7103
  // STREAM.CREATE now covers them), idempotently - createEndpointStreams is a superset of
@@ -7103,7 +7125,7 @@ export class Manager {
7103
7125
  const authority = {
7104
7126
  authorize: (name, owner) => ({ authorized: name === MANAGER_ENDPOINT && owner === DEV_OWNER, revision: 0 }),
7105
7127
  };
7106
- // The STABLE serve identity (P2 item 3): the PERSISTED serve nkey, reused across restart so the
7128
+ // The STABLE serve identity: the PERSISTED serve nkey, reused across restart so the
7107
7129
  // gate binds the SAME principal (§13.1 serving-principal binding) - provisionEndpointGateOpen
7108
7130
  // stays idempotent and verified eviction has a stable target. Renewals re-mint the same nkey
7109
7131
  // with a fresh bounded exp; a restart re-provisions the same (idempotent) gate + re-registers.
@@ -7114,7 +7136,7 @@ export class Manager {
7114
7136
  // The STABLE goal-writer identity — a SIBLING credential in the same §13.1 family
7115
7137
  // (not the gate's bound serving principal), so the run block can family-stage it.
7116
7138
  this.goalWriterIdentity = siblings.goalWriter;
7117
- // P2 item 6: the STABLE session-LEDGER identity — another SIBLING in the SAME §13.1 family, so
7139
+ // The STABLE session-LEDGER identity — another SIBLING in the SAME §13.1 family, so
7118
7140
  // the takeover barrier revokes a deposed manager's ledger cred alongside its goal-writer. The
7119
7141
  // per-session serving creds join the same family, each with its own fresh identity.
7120
7142
  this.sessionLedgerIdentity = siblings.sessionLedger;
@@ -7135,17 +7157,17 @@ export class Manager {
7135
7157
  }
7136
7158
  };
7137
7159
  const publishAndProvision = async ({ authKv, nc: execNc }) => {
7138
- // §13.7 contract-artifact publication (1c): every schema root + its closure manifest, plus
7160
+ // §13.7 contract-artifact publication: every schema root + its closure manifest, plus
7139
7161
  // the cluster document + ITS manifest, land in the EPC store BEFORE the registration that
7140
7162
  // advertises their digests — so a caller can always fetch-verify-compile a registered
7141
- // digest (the item-5 generic-invoke read path). Create-only + content-addressed: a retry
7163
+ // digest (the generic-invoke read path). Create-only + content-addressed: a retry
7142
7164
  // or a same-artifact republish is an idempotent lost-CAS. The registration itself still
7143
7165
  // verifies against the in-memory copies (the manager is the author).
7144
7166
  const storeCtx = await contractStoreContext(execNc, this.space);
7145
7167
  for (const value of [...managerContractArtifactValues(), artifacts.document, artifacts.manifest])
7146
7168
  await publishContractArtifact(storeCtx, contractArtifactCanonicalBytes(value));
7147
- // §13.1 pre-registration (checklist 1): the issuance gate, born open@gen0 bound to the serve
7148
- // principal — provisioned ONCE, on the FIRST registration. On a RESTART (P2 item 3) the gate
7169
+ // §13.1 pre-registration: the issuance gate, born open@gen0 bound to the serve
7170
+ // principal — provisioned ONCE, on the FIRST registration. On a RESTART the gate
7149
7171
  // already EXISTS (advanced past gen0 by the prior registration), so re-provisioning the gen0
7150
7172
  // row would conflict "foreign content"; the persisted instanceId makes this a TAKEOVER, and
7151
7173
  // registerServiceInstance below freezes + re-registers the EXISTING gate (advancing the epoch
@@ -7156,7 +7178,7 @@ export class Manager {
7156
7178
  };
7157
7179
  const completeRegistration = async ({ recordsKv, authKv, nc: execNc }) => {
7158
7180
  await publishAndProvision({ recordsKv, authKv, nc: execNc });
7159
- // P2 item 3 (slice 3a): on an AUTH mesh a RE-registration (restart of the persisted instanceId)
7181
+ // On an AUTH mesh a RE-registration (restart of the persisted instanceId)
7160
7182
  // must VERIFY-EVICT the superseded serve family BEFORE the epoch advances (§13.1 "old authority
7161
7183
  // dies before new authority is visible"). Inject the SCOPED delivery-admin evictor; the OPEN
7162
7184
  // mesh mints no serve family, so no evictor (the empty-family path never consults it and a
@@ -7186,7 +7208,7 @@ export class Manager {
7186
7208
  // authKv (the fence is live), so its credId lands in `epcred.<e>.<iid>` and the takeover
7187
7209
  // barrier revokes it. Open mesh: no mint (no credential system; the goal-writer conn is bare).
7188
7210
  const goalWriterCreds = auth ? await this.mintAndStageGoalWriter(authKv) : undefined;
7189
- // P2 item 6: mint + family-stage the session-LEDGER credential HERE too (same executor, same
7211
+ // Mint + family-stage the session-LEDGER credential HERE too (same executor, same
7190
7212
  // fence, same §13.1 family), so takeover revokes a deposed manager's ledger connection. The
7191
7213
  // per-session SERVING credentials are minted later, one per redemption, into the SAME family.
7192
7214
  // Open mesh: no mint (no credential system; the ledger connection stays bare).
@@ -7249,7 +7271,7 @@ export class Manager {
7249
7271
  const auth = this.auth;
7250
7272
  const identity = this.goalWriterIdentity;
7251
7273
  // The issuance gate + §13.1 revocation family are keyed by the REGISTRATION instanceId
7252
- // (the persisted logical id, item 3's split), NOT the per-process lifecycleUid — the barrier
7274
+ // (the persisted logical id), NOT the per-process lifecycleUid — the barrier
7253
7275
  // enumerates `epcred.<e>.<managerInstanceId>`, so the goal-writer must stage into that family.
7254
7276
  const iid = this.managerInstanceId;
7255
7277
  const creds = await mintCreds(auth, identity, "goal-writer", { goalWriter: { endpoint: MANAGER_ENDPOINT } });
@@ -7287,8 +7309,8 @@ export class Manager {
7287
7309
  });
7288
7310
  nc.closed().then((err) => { void this.onGoalWriterConnectionClosed(err ?? undefined); });
7289
7311
  gw.nc = nc;
7290
- // The (i) fence resolver (SPEC 13.6 P2 item 3): resolve an executing instance's CURRENT gate
7291
- // epoch. This manager reconciles only ITS OWN goals (security pin 4), so it resolves its own
7312
+ // The (i) fence resolver (SPEC 13.6): resolve an executing instance's CURRENT gate
7313
+ // epoch. This manager reconciles only ITS OWN goals, so it resolves its own
7292
7314
  // registration instanceId to this incarnation's serve-grant epoch; a foreign/retired instance
7293
7315
  // is `null` (no current terminal to surface). A successor incarnation carries an ADVANCED epoch
7294
7316
  // here, so its reads pick the current-epoch subject and the predecessor's terminal is fenced out.
@@ -7341,7 +7363,7 @@ export class Manager {
7341
7363
  return;
7342
7364
  console.error("! manager goal-writer could not be re-dialed; leaving the credential to the next renewal pass");
7343
7365
  }
7344
- /** P2 item 2 (spawn-as-action): stand up the standing self-mediated goal-writer connection +
7366
+ /** Spawn-as-action: stand up the standing self-mediated goal-writer connection +
7345
7367
  * ActionContext. Mode-dual, mirroring {@link registerManagerService}: an AUTH mesh uses the
7346
7368
  * scoped `goal-writer` credential already minted + family-STAGED inside registration's run block
7347
7369
  * ({@link mintAndStageGoalWriter} — DISJOINT grant from the serve cred, SHARED §13.1 revocation
@@ -7375,7 +7397,7 @@ export class Manager {
7375
7397
  catch { /* best effort */ }
7376
7398
  }
7377
7399
  }
7378
- /** P2 item 6: mint the standing `session-ledger` credential and STAGE it into this instance's
7400
+ /** Mint the standing `session-ledger` credential and STAGE it into this instance's
7379
7401
  * §13.1 revocation family (`epcred.<e>.<iid>`), over the passed executor's `authKv` — EXACTLY the
7380
7402
  * {@link mintAndStageGoalWriter} pattern, under the same open-and-commit fence.
7381
7403
  *
@@ -7388,7 +7410,7 @@ export class Manager {
7388
7410
  async mintAndStageSessionLedger(authKv) {
7389
7411
  const auth = this.auth;
7390
7412
  const identity = this.sessionLedgerIdentity;
7391
- // Registration instanceId (item 3's persisted logical id), not the per-process lifecycleUid:
7413
+ // Registration instanceId (the persisted logical id), not the per-process lifecycleUid:
7392
7414
  // the barrier enumerates `epcred.<e>.<managerInstanceId>`, so the ledger cred joins that family.
7393
7415
  const iid = this.managerInstanceId;
7394
7416
  const fence = serveIssuanceGateKv(authKv, this.space, { endpoint: MANAGER_ENDPOINT, instanceId: iid });
@@ -7455,7 +7477,7 @@ export class Manager {
7455
7477
  return;
7456
7478
  console.error("! manager session-ledger could not be re-dialed; leaving the credential to the next renewal pass");
7457
7479
  }
7458
- /** P2 item 6: stand up the ONE §13.6 session plane on its own standing connection. Mode-dual,
7480
+ /** Stand up the ONE §13.6 session plane on its own standing connection. Mode-dual,
7459
7481
  * mirroring {@link startGoalWriter}: an AUTH mesh presents the scoped `session-ledger` cred
7460
7482
  * already minted + family-staged inside registration's run block ({@link mintAndStageSessionLedger});
7461
7483
  * an OPEN mesh uses a bare connection (no credential system to mint from). The connection presents
@@ -7506,10 +7528,10 @@ export class Manager {
7506
7528
  const keyId = rotating.current().keyId;
7507
7529
  this.sessionPlane = new ManagerSessionPlane({
7508
7530
  space: this.space,
7509
- // The session's serving identity is the persisted REGISTRATION instanceId (item 3), not the
7531
+ // The session's serving identity is the persisted REGISTRATION instanceId, not the
7510
7532
  // per-process lifecycleUid: a restarted manager re-registers the SAME logical instanceId with
7511
7533
  // an ADVANCED epoch, so a client re-attaches by the same instance while the epoch fences the
7512
- // old incarnation's sessions (item 6's restart-refusal composed with item 3's addressing).
7534
+ // old incarnation's sessions.
7513
7535
  serving: { instanceId: this.managerInstanceId, epoch: serveEpoch },
7514
7536
  // Read through the rotator on EVERY use rather than capturing a key: signing takes the newest
7515
7537
  // generation, and resolution accepts any generation still inside its overlap so an artifact
@@ -7538,7 +7560,7 @@ export class Manager {
7538
7560
  console.error(`manager session plane standing (endpoint ${MANAGER_ENDPOINT}, epoch ${serveEpoch}, ${(this.auth || this.remoteAuthority) ? "scoped session-ledger cred, §13.1 family-staged" : "open/bare"})`);
7539
7561
  }
7540
7562
  /**
7541
- * The per-session SERVING credential seam (P2 item 6, SPEC 13.6): the manager mints, gate-stages,
7563
+ * The per-session SERVING credential seam (SPEC 13.6): the manager mints, gate-stages,
7542
7564
  * connects and revokes ONE credential per live session, replacing a standing credential that held
7543
7565
  * `eps.manager.*.<epoch>.{in,out}` and so reached every live session's bytes at its epoch.
7544
7566
  *
@@ -7713,11 +7735,12 @@ export class Manager {
7713
7735
  await nc.drain().catch(() => nc.close());
7714
7736
  }
7715
7737
  }
7716
- // Single-manager item 2: EVERY inherited entry belongs to a DEAD predecessor (only one manager
7717
- // at a time), so all are reconciled. The `iid` field is the hook item-3's multi-instance sweep
7738
+ // Single-manager: EVERY inherited entry belongs to a DEAD predecessor (only one manager
7739
+ // at a time), so all are reconciled. The `iid` field is the hook the multi-instance sweep
7718
7740
  // filters on (skip a goal whose accepting `iid` is a still-LIVE sibling — never settle its goal).
7719
7741
  for (const entry of entries) {
7720
- if (this.goalAcceptances.has(entry.ref.goalId) || this.turnAcceptances.has(turnKey(entry.ref)))
7742
+ const key = goalKey(entry.ref);
7743
+ if (this.goalAcceptances.has(key) || this.turnAcceptances.has(key))
7721
7744
  continue; // never settle a goal THIS incarnation drives
7722
7745
  try {
7723
7746
  // A note marks a TURN entry: its relay is rebuilt (the hold is its bounded ending), never
@@ -7788,9 +7811,9 @@ export class Manager {
7788
7811
  const t = setTimeout(() => { settle().catch((e) => console.error(`! goal reconcile settle ${ref.goalId}: ${rejectionText(e)}`)); }, remaining + 100);
7789
7812
  t.unref?.();
7790
7813
  }
7791
- /** P2 item 2: publish a goal PROGRESS event on the caller-scoped epe subtree, over the SERVE
7814
+ /** Publish a goal PROGRESS event on the caller-scoped epe subtree, over the SERVE
7792
7815
  * connection (which holds the `epe.<e>.<iid>.<epoch>.>` egress grant; the goal-writer deliberately
7793
- * does not). The terminal rides a final event `phase:"terminal"` (Q1 — the caller follows epe to
7816
+ * does not). The terminal rides a final event `phase:"terminal"` (the caller follows epe to
7794
7817
  * the terminal; the durable result fact + inspect/ps are the reconcile authority). A dropped event
7795
7818
  * is non-fatal (the terminal is authoritative in the journal). */
7796
7819
  emitGoalProgress(ref, epoch, event) {
@@ -7838,13 +7861,13 @@ export class Manager {
7838
7861
  if (observed.processEpoch !== epoch)
7839
7862
  throw new EpEnvelopeError("expired", `the manager's issuance gate epoch is ${observed.processEpoch} but this goal was accepted under epoch ${epoch}; a superseded incarnation never commits a goal terminal (SPEC 13.6)`);
7840
7863
  }
7841
- /** Serve `spawn`/`launch` as an ACTION (P2 item 2). Authz already ran in {@link serveGated}. The
7864
+ /** Serve `spawn`/`launch` as an ACTION. Authz already ran in {@link serveGated}. The
7842
7865
  * accept path runs INLINE on the handler ({@link startAgent} with hooks): the goal binds + the
7843
- * acceptance replies the moment the identity is minted, BEFORE any provision (pin 1), or on the
7866
+ * acceptance replies the moment the identity is minted, BEFORE any provision, or on the
7844
7867
  * hosted enrollment arm once the host has enrolled the agent; progress and the terminal are driven
7845
7868
  * OFF-handler, so the ~30s readiness wait no longer blocks the reply.
7846
7869
  * Returns the acceptance floor payload {name, owner, actor, uid, goalId, fingerprint, executor}
7847
- * (the ALLOCATED identity). goalId = the request id (env.id, Q3). */
7870
+ * (the ALLOCATED identity). goalId = the request id (env.id). */
7848
7871
  async serveSpawnGoal(ctx, run) {
7849
7872
  if (this.execution === "none")
7850
7873
  throw new EpEnvelopeError("unimplemented", this.executionRefusal());
@@ -7858,14 +7881,15 @@ export class Manager {
7858
7881
  const goalId = ctx.request.id;
7859
7882
  const { fingerprint } = submissionFingerprint(ctx.request, ctx.subject);
7860
7883
  const ref = goalRefOf(ctx.subject, goalId);
7884
+ const key = goalKey(ref);
7861
7885
  const executor = { lifecycleUid: this.managerInstanceId, epoch: this.serviceServe?.grant.epoch ?? 0 };
7862
7886
  const epoch = executor.epoch;
7863
7887
  const acceptedAt = Date.now();
7864
7888
  // Idempotent same-goalId retry (a client re-send): serve the IDENTICAL acceptance without
7865
- // re-running the accept path — so a HARD-PINNED retry does not trip the M6 same-name refuse and no
7889
+ // re-running the accept path — so a HARD-PINNED retry does not trip the same-name refuse and no
7866
7890
  // name is re-allocated. Same-incarnation rides the live map; the create-only bindGoal in onAccepted
7867
7891
  // still fences a CONCURRENT same-goalId race (the loser aborts and serves the winner's acceptance).
7868
- const prior = this.goalAcceptances.get(goalId);
7892
+ const prior = this.goalAcceptances.get(key);
7869
7893
  if (prior !== undefined) {
7870
7894
  if (prior.fingerprint !== fingerprint)
7871
7895
  throw new EpEnvelopeError("failed-precondition", `goal "${goalId}" was accepted under a different submission; one goalId never carries two specs (SPEC 13.6)`);
@@ -7969,15 +7993,15 @@ export class Manager {
7969
7993
  // No claim needed here: `ownsGoal` is still false, so the commit path refuses this attempt.
7970
7994
  throw new EpEnvelopeError("failed-precondition", `goal "${goalId}" was accepted by instance "${idx.existing.iid}"; that instance's acceptance is served and this attempt provisions nothing (SPEC 13.6)`);
7971
7995
  }
7972
- // Bind AFTER the accept-path checks (M6/capacity/persona) + identity mint, BEFORE any provision:
7973
- // a create-only CAS per goalId (pin 1 — a refused accept above left zero bind, zero reserve).
7996
+ // Bind AFTER the accept-path checks (name/capacity/persona) + identity mint, BEFORE any provision:
7997
+ // a create-only CAS per goalId (a refused accept above left zero bind, zero reserve).
7974
7998
  const b = await bindGoal(gw.ctx, ref, fingerprint);
7975
7999
  if (!b.bound) {
7976
8000
  if (b.existing.fingerprint !== fingerprint)
7977
8001
  throw new EpEnvelopeError("failed-precondition", `goal "${goalId}" is already bound to a different submission; one goalId never carries two specs (SPEC 13.6)`);
7978
8002
  // Lost a concurrent same-goalId race: serve the winner's acceptance and abort THIS provision
7979
8003
  // (no second spawn). The throw unwinds to the finally, which releases this attempt's reserve.
7980
- acceptance = this.goalAcceptances.get(goalId) ?? await this.cachedSpawnAcceptance(ref, goalId, fingerprint, executor);
8004
+ acceptance = this.goalAcceptances.get(key) ?? await this.cachedSpawnAcceptance(ref, goalId, fingerprint, executor);
7981
8005
  resolveAccept(acceptance);
7982
8006
  // No claim needed here either. This attempt lost the CAS, so `ownsGoal` is still false and
7983
8007
  // the single check in `onOutcome` refuses it. Before that check existed this site had to
@@ -8001,8 +8025,8 @@ export class Manager {
8001
8025
  readinessDeadlineMs: readinessTimeoutMs,
8002
8026
  });
8003
8027
  acceptance = { name, owner: agentTriple.owner, actor: agentTriple.actor, uid: agentTriple.uid, goalId, fingerprint, readinessDeadlineMs: readinessTimeoutMs, executor };
8004
- this.goalAcceptances.set(goalId, acceptance);
8005
- this.agentGoals.set(name, ref); // M4: a despawn of this name mid-goal drives the cancel path
8028
+ this.goalAcceptances.set(key, acceptance);
8029
+ this.agentGoals.set(name, ref); // A despawn of this name mid-goal drives the cancel path
8006
8030
  resolveAccept(acceptance);
8007
8031
  this.emitGoalProgress(ref, epoch, { phase: "handoff" });
8008
8032
  },
@@ -8015,7 +8039,7 @@ export class Manager {
8015
8039
  onTerminalDeferred: () => { terminalEntered = true; },
8016
8040
  });
8017
8041
  bg.then((reply) => {
8018
- // Refused BEFORE onAccepted (M6 hard-pin collision, capacity, persona-not-found) — no goal bound.
8042
+ // Refused BEFORE onAccepted (hard-pin collision, capacity, persona-not-found) — no goal bound.
8019
8043
  if (acceptance === undefined) {
8020
8044
  const details = reply.details;
8021
8045
  rejectAccept(new EpEnvelopeError("failed-precondition", reply.error ?? "spawn refused at accept", details));
@@ -8107,7 +8131,7 @@ export class Manager {
8107
8131
  const goalId = ctx.request.id;
8108
8132
  const { fingerprint } = submissionFingerprint(ctx.request, ctx.subject);
8109
8133
  const ref = goalRefOf(ctx.subject, goalId);
8110
- const key = turnKey(ref);
8134
+ const key = goalKey(ref);
8111
8135
  const executor = { lifecycleUid: this.managerInstanceId, epoch: this.serviceServe?.grant.epoch ?? 0 };
8112
8136
  const acceptedAt = Date.now();
8113
8137
  const prior = this.turnAcceptances.get(key)?.acceptance;
@@ -8366,7 +8390,7 @@ export class Manager {
8366
8390
  const raw = (ctx.request.args ?? {});
8367
8391
  const goalId = String(raw.goalId);
8368
8392
  const ref = goalRefOf(ctx.subject, goalId);
8369
- const key = turnKey(ref);
8393
+ const key = goalKey(ref);
8370
8394
  const p = this.pendingTurns.get(key);
8371
8395
  if (p === undefined) {
8372
8396
  const ended = await readGoalResult(gw.ctx, ref);
@@ -8407,7 +8431,7 @@ export class Manager {
8407
8431
  const gw = this.goalWriter;
8408
8432
  if (!gw)
8409
8433
  return;
8410
- const key = turnKey(p.ref);
8434
+ const key = goalKey(p.ref);
8411
8435
  if (!this.pendingTurns.delete(key))
8412
8436
  return;
8413
8437
  this.markTurnLatchDropped(key);
@@ -8581,7 +8605,7 @@ export class Manager {
8581
8605
  console.error(`turn reconcile ${p.goalId}: its deadline hold was never minted (the accept crashed before it); left unsettled`);
8582
8606
  return;
8583
8607
  }
8584
- const key = turnKey(p.ref);
8608
+ const key = goalKey(p.ref);
8585
8609
  this.pendingTurns.set(key, p);
8586
8610
  // THE ACCEPTANCE TOO, or the adopted turn's answer is never remembered: `rememberSettledTurn`
8587
8611
  // writes only against an acceptance this incarnation holds, and adoption rebuilt the pending
@@ -8605,12 +8629,12 @@ export class Manager {
8605
8629
  console.error(`turn reconcile ${p.goalId}: pending relay to ${p.seat.name}/${p.seat.uid} adopted (deadline ${p.deadlineAt})`);
8606
8630
  this.ensureTurnSweep();
8607
8631
  }
8608
- /** M4 (settle race): a despawn MID-GOAL drives the goal's cancel terminal - transition to
8632
+ /** Settle race: a despawn MID-GOAL drives the goal's cancel terminal - transition to
8609
8633
  * `cancelling`, then commit the `cancel` cause on the goal-writer connection. First-terminal-fact
8610
8634
  * wins: if the readiness outcome already committed (succeeded/failed/uncertain) the transition or
8611
8635
  * the create-only commit loses gracefully and the readiness terminal stands. Fire-and-forget from
8612
8636
  * despawn (the process teardown is authoritative for the agent; this settles the GOAL honestly).
8613
- * Cancel rides the despawn's own authorizeNamed reach (pin 5) - there is no cancel-by-goalId. */
8637
+ * Cancel rides the despawn's own authorizeNamed reach - there is no cancel-by-goalId. */
8614
8638
  async cancelAgentGoal(name, mode) {
8615
8639
  const gw = this.goalWriter;
8616
8640
  const ref = this.agentGoals.get(name);
@@ -9161,12 +9185,12 @@ export class Manager {
9161
9185
  retiredSlots++;
9162
9186
  continue;
9163
9187
  }
9164
- // 3b-2 RECONCILE OWNERSHIP (multi-manager-per-space): a manager adjudicates ONLY the non-retired
9188
+ // RECONCILE OWNERSHIP (multi-manager-per-space): a manager adjudicates ONLY the non-retired
9165
9189
  // rows THIS logical instance owns. A SIBLING manager's active/provisioning row is LEFT UNTOUCHED —
9166
9190
  // sweep-terminalizing it would destroy the sibling's live agent (the historical all-agents-kill
9167
- // hazard, now cross-instance). A legacy row (pre-3b-2, no owner recorded) predates multi-manager,
9191
+ // hazard, now cross-instance). A legacy row (no owner recorded) predates multi-manager,
9168
9192
  // so this manager is its legitimate single-manager-past successor and reconciles it. An orphaned
9169
- // sibling row is reclaimed only by an explicit operator CAS takeover (ruling 1), never here.
9193
+ // sibling row is reclaimed only by an explicit operator CAS takeover, never here.
9170
9194
  if (ownedBySibling(row, this.managerInstanceId)) {
9171
9195
  preservedForeign++;
9172
9196
  continue;
@@ -9608,7 +9632,7 @@ export class Manager {
9608
9632
  throw new EpEnvelopeError("unavailable", `input for seat "${a.name}" failed: runtime accepted ${String(bytes)} of ${intendedBytes} bytes`);
9609
9633
  return { name: a.name, bytes };
9610
9634
  }
9611
- /** The post-authorization attach effect (P2 item 6): mint the holder-bound §13.6 offer, redeem it
9635
+ /** The post-authorization attach effect: mint the holder-bound §13.6 offer, redeem it
9612
9636
  * through the ONE session plane (one-use CAS + presenter-equality), and stand up the PTY bridge —
9613
9637
  * atomically. The reply is the SIGNED grant (no ws:// URL, non-bearer, never logged); the caller
9614
9638
  * redeems it over the mesh with a per-session rails-only cred it mints itself. Only streamable
@@ -9650,7 +9674,7 @@ export class Manager {
9650
9674
  const carried = a.launch.resumed?.host;
9651
9675
  return { ok: true, data: { grant, ...(carried ? { resumedFrom: { host: carried, source: a.launch.resumed.source } } : {}) } };
9652
9676
  }
9653
- /** P2 item 6: the console's mesh §13.6 session establisher (backing `POST /session/<name>` on the
9677
+ /** The console's mesh §13.6 session establisher (backing `POST /session/<name>` on the
9654
9678
  * loopback face). Drives THE ONE plane — same establishAttach as the ep `attach` command — with
9655
9679
  * the loopback OPERATOR as holder (same-host trust boundary), then hands the browser everything it
9656
9680
  * needs to open the caller rail over the broker ws listener: the holder-bound grant, a per-session