@cotal-ai/core 0.69.0 → 0.70.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 (91) hide show
  1. package/dist/auth-provider.d.ts +9 -2
  2. package/dist/auth-provider.d.ts.map +1 -1
  3. package/dist/auth-provider.js +10 -0
  4. package/dist/auth-provider.js.map +1 -1
  5. package/dist/channels.js +1 -1
  6. package/dist/channels.js.map +1 -1
  7. package/dist/connector-setup.d.ts +9 -5
  8. package/dist/connector-setup.d.ts.map +1 -1
  9. package/dist/contract-manifest.d.ts +20 -0
  10. package/dist/contract-manifest.d.ts.map +1 -0
  11. package/dist/contract-manifest.js +28 -0
  12. package/dist/contract-manifest.js.map +1 -0
  13. package/dist/endpoint-action.d.ts +3 -0
  14. package/dist/endpoint-action.d.ts.map +1 -1
  15. package/dist/endpoint-action.js +8 -6
  16. package/dist/endpoint-action.js.map +1 -1
  17. package/dist/endpoint-binding.d.ts.map +1 -1
  18. package/dist/endpoint-binding.js +5 -0
  19. package/dist/endpoint-binding.js.map +1 -1
  20. package/dist/endpoint-cluster.d.ts.map +1 -1
  21. package/dist/endpoint-cluster.js +9 -4
  22. package/dist/endpoint-cluster.js.map +1 -1
  23. package/dist/endpoint-contract-store.d.ts +2 -18
  24. package/dist/endpoint-contract-store.d.ts.map +1 -1
  25. package/dist/endpoint-contract-store.js +3 -19
  26. package/dist/endpoint-contract-store.js.map +1 -1
  27. package/dist/endpoint-envelope.d.ts +6 -2
  28. package/dist/endpoint-envelope.d.ts.map +1 -1
  29. package/dist/endpoint-envelope.js +19 -2
  30. package/dist/endpoint-envelope.js.map +1 -1
  31. package/dist/endpoint-error.d.ts +13 -0
  32. package/dist/endpoint-error.d.ts.map +1 -1
  33. package/dist/endpoint-error.js +15 -0
  34. package/dist/endpoint-error.js.map +1 -1
  35. package/dist/endpoint-invoke.d.ts +5 -2
  36. package/dist/endpoint-invoke.d.ts.map +1 -1
  37. package/dist/endpoint-invoke.js +16 -6
  38. package/dist/endpoint-invoke.js.map +1 -1
  39. package/dist/endpoint-records.d.ts +2 -1
  40. package/dist/endpoint-records.d.ts.map +1 -1
  41. package/dist/endpoint-records.js +1 -1
  42. package/dist/endpoint-records.js.map +1 -1
  43. package/dist/endpoint-serve.d.ts.map +1 -1
  44. package/dist/endpoint-serve.js +4 -3
  45. package/dist/endpoint-serve.js.map +1 -1
  46. package/dist/endpoint.d.ts +9 -4
  47. package/dist/endpoint.d.ts.map +1 -1
  48. package/dist/endpoint.js +47 -37
  49. package/dist/endpoint.js.map +1 -1
  50. package/dist/evict.d.ts.map +1 -1
  51. package/dist/evict.js +2 -1
  52. package/dist/evict.js.map +1 -1
  53. package/dist/identity.d.ts +3 -0
  54. package/dist/identity.d.ts.map +1 -1
  55. package/dist/identity.js +5 -0
  56. package/dist/identity.js.map +1 -1
  57. package/dist/kv-scan.d.ts.map +1 -1
  58. package/dist/kv-scan.js +1 -6
  59. package/dist/kv-scan.js.map +1 -1
  60. package/dist/provision.d.ts +23 -24
  61. package/dist/provision.d.ts.map +1 -1
  62. package/dist/provision.js +112 -116
  63. package/dist/provision.js.map +1 -1
  64. package/dist/remote-manager-authority.d.ts +22 -2
  65. package/dist/remote-manager-authority.d.ts.map +1 -1
  66. package/dist/remote-manager-authority.js +23 -15
  67. package/dist/remote-manager-authority.js.map +1 -1
  68. package/dist/resolve.d.ts +15 -2
  69. package/dist/resolve.d.ts.map +1 -1
  70. package/dist/resolve.js +15 -2
  71. package/dist/resolve.js.map +1 -1
  72. package/dist/run-driver-grants.d.ts.map +1 -1
  73. package/dist/run-driver-grants.js +4 -1
  74. package/dist/run-driver-grants.js.map +1 -1
  75. package/dist/run-journal.d.ts.map +1 -1
  76. package/dist/run-journal.js +17 -2
  77. package/dist/run-journal.js.map +1 -1
  78. package/dist/run-record.d.ts +6 -8
  79. package/dist/run-record.d.ts.map +1 -1
  80. package/dist/run-record.js.map +1 -1
  81. package/dist/schema-profile.d.ts +11 -0
  82. package/dist/schema-profile.d.ts.map +1 -1
  83. package/dist/schema-profile.js +13 -2
  84. package/dist/schema-profile.js.map +1 -1
  85. package/dist/secret-fs.d.ts +4 -3
  86. package/dist/secret-fs.d.ts.map +1 -1
  87. package/dist/secret-fs.js +10 -11
  88. package/dist/secret-fs.js.map +1 -1
  89. package/dist/streams.d.ts +2 -2
  90. package/dist/streams.js +2 -2
  91. package/package.json +5 -1
package/dist/provision.js CHANGED
@@ -6,13 +6,13 @@
6
6
  * `@nats-io/jwt`, so there is no dependency on the external `nsc` CLI and the signing
7
7
  * key stays in one place (whoever holds {@link SpaceAuth.account.signingSeed}).
8
8
  *
9
- * Demo-1 stage: out-of-band mint. `cotal up` creates the space's trust material
9
+ * The static mint is out of band: `cotal up` creates the space's trust material
10
10
  * once and writes a `nats-server` config (operator + system account + MEMORY resolver);
11
- * `cotal mint` and the manager load that material and mint per-agent creds files. There
12
- * is no connect-time token exchange yet (that's the later auth-callout stage).
11
+ * `cotal mint` and the manager load that material and mint per-agent creds files. The auth
12
+ * callout mints at connect time through the same {@link permissionsFor}.
13
13
  *
14
- * D5 adds the first credential-death primitive: profile-classified user-JWT lifetimes. Full revocation,
15
- * live eviction, standing-host renewal, and issuance audit still land in later D5 slices.
14
+ * Every credential kind is classified in {@link CREDENTIAL_LIFETIMES}: its lifetime class, default
15
+ * expiry and renewal owner.
16
16
  */
17
17
  import { TTL_RECONCILE_CANARY_KEY, ttlBuckets } from "./streams.js";
18
18
  import { join } from "node:path";
@@ -31,7 +31,7 @@ import { transferReaderGrants, transferWriterGrants } from "./transfer.js";
31
31
  import { recordsBucket, recordSpecKey, recordStatusKey, recordAtomicKey, RECORD_KINDS, GOVERN_HEAD } from "./endpoint-records.js";
32
32
  import { lifecycleHeadKey, uidReservationKey, issuanceGateKey, staticSlotKey, STATIC_SLOT_PREFIX, epgateKey, epcredFamilyPrefix, eprepairKey } from "./lifecycle-state.js";
33
33
  import { rawDigest } from "./canonical.js";
34
- import { credsClaims } from "./identity.js";
34
+ import { credsClaims, isUserNkey } from "./identity.js";
35
35
  import { backupProfilePermissions, restoreProfilePermissions, } from "./backup.js";
36
36
  const FIVE_MINUTES = 5 * 60;
37
37
  /** The broker's pre-auth control-line cap, in bytes (`max_control_line` in the generated config —
@@ -57,7 +57,7 @@ export const CONNECT_ENVELOPE_OVERHEAD_BYTES = 512;
57
57
  * (issue #375's review finding: six distinct 4096-char channels, each individually accepted,
58
58
  * minted a JWT the broker would silently drop). */
59
59
  export const MAX_MINTED_JWT_BYTES = MAX_CONTROL_LINE_BYTES - CONNECT_ENVELOPE_OVERHEAD_BYTES;
60
- /** Bounded lifetime for `standing-renewable` credentials whose renewal owner is ONLINE (D5 slice 5):
60
+ /** Bounded lifetime for `standing-renewable` credentials whose renewal owner is ONLINE:
61
61
  * the holder (or its launcher) re-mints at 75% of the lifetime via the endpoint's creds-source seam,
62
62
  * so a copied cred is broker-dead within a day while renewal never involves an operator. 24h keeps
63
63
  * the remaining-25% loud-failure window at ~6h — wide enough to notice and repair before expiry. */
@@ -66,19 +66,19 @@ export const STANDING_RENEWABLE_TTL_SEC = 24 * 60 * 60;
66
66
  * evictor). They are NOT online-renewable (the $SYS seed dies at end of `up`), so this exp is the
67
67
  * credential-death horizon: a copied observer/evictor cred becomes broker-dead after it, and the
68
68
  * operator is expected to have run a coordinated system-account rotation + broker restart within it
69
- * (the doctor surface warns ahead — slice 6). 30 days balances "copied cred eventually dies" against
69
+ * (the doctor surface warns ahead). 30 days balances "copied cred eventually dies" against
70
70
  * a comfortable monthly rotation cadence; tune here as one named knob. */
71
71
  export const ROTATION_RENEWED_TTL_SEC = 30 * 24 * 60 * 60;
72
- /** D5 profile matrix. This is intentionally centralized so every new mint profile must classify its
72
+ /** The credential lifetime matrix. This is intentionally centralized so every new mint profile must classify its
73
73
  * credential-death behavior instead of silently inheriting non-expiring static creds. */
74
74
  export const CREDENTIAL_LIFETIMES = {
75
75
  agent: { class: "mixed", note: "manager children, foreground spawn/join, and cotal mint static outputs all use this profile; split or repair flow required before default exp" },
76
76
  "manager-caller": { class: "mixed", note: "short-lived user-auth view bound to the bearer expiry and one manager instance" },
77
77
  observer: { class: "static-operator-managed", note: "out-of-band dashboard/audit credential from cotal mint" },
78
78
  admin: { class: "static-operator-managed", note: "out-of-band elevated dashboard/audit credential from cotal mint" },
79
- supervisor: { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "manager's always-on endpoint; the manager holds the DATA seed and self-remints via the endpoint creds source (D5 slice 5 class 1)" },
80
- delivery: { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "server-side Plane-3 daemon; seed-less - the manager re-signs .cotal/delivery.creds for the SAME nkey, requests delivery-admin reloadCreds for explicit adoption, and the endpoint source re-read is only a backstop (D5 slice 5 class 2)" },
81
- "membership-rw": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "membership feed writer; seed-less - the manager re-signs the membership-rw.creds store key for the SAME nkey, the feed adopts it on a 75% preflight-proven renewal timer (its active self-heal), and delivery-admin reloadCreds is the explicit adoption on top (D5 slice 5 class 2)" },
79
+ supervisor: { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "manager's always-on endpoint; the manager holds the DATA seed and self-remints via the endpoint creds source" },
80
+ delivery: { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "server-side Plane-3 daemon; seed-less - the manager re-signs .cotal/delivery.creds for the SAME nkey, requests delivery-admin reloadCreds for explicit adoption, and the endpoint source re-read is only a backstop" },
81
+ "membership-rw": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "membership feed writer; seed-less - the manager re-signs the membership-rw.creds store key for the SAME nkey, the feed adopts it on a 75% preflight-proven renewal timer (its active self-heal), and delivery-admin reloadCreds is the explicit adoption on top" },
82
82
  provisioner: { class: "one-shot", defaultTtlSeconds: FIVE_MINUTES, note: "setup/spawn provisioning window only" },
83
83
  deprovisioner: { class: "one-shot", defaultTtlSeconds: FIVE_MINUTES, note: "target-pinned teardown window only" },
84
84
  "retirement-requester": { class: "one-shot", defaultTtlSeconds: FIVE_MINUTES, note: "one despawn's retirement request window; request+reply only" },
@@ -96,10 +96,10 @@ export const CREDENTIAL_LIFETIMES = {
96
96
  "control-caller-admin": { class: "one-shot", defaultTtlSeconds: FIVE_MINUTES, note: "stop/attach admin control call" },
97
97
  deployer: { class: "one-shot", note: "manifest deploy spans planning/launch/ledger; needs near-expiry guard or remint before default exp" },
98
98
  "endpoint-serve": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "per-instance endpoint serve credential (SPEC 13.9); the managing authority re-mints on renewal and on takeover (new epoch), and the 13.1 barrier revokes the superseded one" },
99
- "goal-writer": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "self-mediated goal-writer for spawn-as-action (P2 item 2); the manager re-mints for the SAME nkey on renewal, disjoint from the serve credential (Q2)" },
100
- "session-caller": { class: "one-shot", defaultTtlSeconds: 24 * 60 * 60, note: "per-session console/CLI caller cred (P2 item 6): rails-only for ONE §13.6 session; TTL-BOUND to the session (the face mints with expiresAt = the session exp; the 24h default is the SESSION_GRANT_MAX_TTL ceiling, never a standing lifetime); NEVER renewed - a new session mints a new cred" },
101
- "session-serving": { class: "one-shot", defaultTtlSeconds: 24 * 60 * 60, note: "per-session SERVING cred (P2 item 6): rails-only for ONE §13.6 session, the mirror of session-caller with the directions swapped; minted at redemption and TTL-BOUND to the session (the 24h default is the SESSION_GRANT_MAX_TTL ceiling, never a standing lifetime); NEVER renewed - a new session mints a new cred, and the session's terminal revokes this one by name" },
102
- "session-ledger": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "manager's session LEDGER (P2 item 6): the dedicated sessions-bucket `session.<id>` rows and NOTHING else - no session rail of any shape. Standing because SPEC 13.6 makes it the durable revocation authority that must survive the serving endpoint; the manager re-mints for the SAME nkey on the half-TTL loop (the goal-writer precedent)" },
99
+ "goal-writer": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "self-mediated goal-writer for spawn-as-action; the manager re-mints for the SAME nkey on renewal, disjoint from the serve credential" },
100
+ "session-caller": { class: "one-shot", defaultTtlSeconds: 24 * 60 * 60, note: "per-session console/CLI caller cred: rails-only for ONE §13.6 session; TTL-BOUND to the session (the face mints with expiresAt = the session exp; the 24h default is the SESSION_GRANT_MAX_TTL ceiling, never a standing lifetime); NEVER renewed - a new session mints a new cred" },
101
+ "session-serving": { class: "one-shot", defaultTtlSeconds: 24 * 60 * 60, note: "per-session SERVING cred: rails-only for ONE §13.6 session, the mirror of session-caller with the directions swapped; minted at redemption and TTL-BOUND to the session (the 24h default is the SESSION_GRANT_MAX_TTL ceiling, never a standing lifetime); NEVER renewed - a new session mints a new cred, and the session's terminal revokes this one by name" },
102
+ "session-ledger": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "manager's session LEDGER: the dedicated sessions-bucket `session.<id>` rows and NOTHING else - no session rail of any shape. Standing because SPEC 13.6 makes it the durable revocation authority that must survive the serving endpoint; the manager re-mints for the SAME nkey on the half-TTL loop (the goal-writer precedent)" },
103
103
  "run-driver": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "one workflow run's driver, per takeover attempt (SPEC 14.6): the hosting manager mints it when it takes the run over and re-mints for the SAME nkey on renewal; a new takeover mints a new one" },
104
104
  "run-mediator": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "manager", note: "trusted workflow host operations, bound to one run and attempt; kept on the hosting process's connection" },
105
105
  "run-operator": { class: "one-shot", defaultTtlSeconds: 60, note: "one served run-status / run-ps / run-answer call (SPEC 14.3): the hosting manager mints it per call on its own connection, never the serve rails; 60s bounds a copied cred to a minute" },
@@ -107,10 +107,10 @@ export const CREDENTIAL_LIFETIMES = {
107
107
  "run-admitter": { class: "one-shot", defaultTtlSeconds: 60, note: "one hosted run's admission record create, or its revocation marker (SPEC 14.8); 60s bounds a copied cred to a minute" },
108
108
  "transfer-writer": { class: "one-shot", defaultTtlSeconds: FIVE_MINUTES, note: "one carried resume per CLI call: one object's chunk and meta subjects in one instance's transfer bucket" },
109
109
  "transfer-reader": { class: "one-shot", defaultTtlSeconds: FIVE_MINUTES, note: "one transcript-receive or sweep over the minting instance's own transfer bucket" },
110
- "endpoint-evictor": { class: "one-shot", defaultTtlSeconds: 60, note: "one re-registration's verify-evict window (P2 item 3): a scoped delivery-admin caller that kicks+verifies the SUPERSEDED serve family before the epoch advances; 60s bounds a copied cred to a minute" },
110
+ "endpoint-evictor": { class: "one-shot", defaultTtlSeconds: 60, note: "one re-registration's verify-evict window: a scoped delivery-admin caller that kicks+verifies the SUPERSEDED serve family before the epoch advances; 60s bounds a copied cred to a minute" },
111
111
  "remote-manager": { class: "standing-renewable", defaultTtlSeconds: STANDING_RENEWABLE_TTL_SEC, renewalOwner: "auth-service", note: "the scoped remote manager lifecycle: own lease/presence plus same-owner agent provisioning; issued only by the typed supervise protocol, never by cotal mint or a raw view/profile string" },
112
112
  "membership-observer": { class: "rotation-renewed", defaultTtlSeconds: ROTATION_RENEWED_TTL_SEC, renewalOwner: "system-account rotation", note: "$SYS-account CONNZ observer; NOT online-renewable ($SYS seed dies at `up`) - bounded exp, renewed only by rotateSystemAccount + broker restart; doctor warns near expiry" },
113
- "connection-evictor": { class: "rotation-renewed", defaultTtlSeconds: ROTATION_RENEWED_TTL_SEC, renewalOwner: "system-account rotation", note: "$SYS-account KICK-only live-eviction cred (D5 slice 4); same rotation-renewed posture as the observer" },
113
+ "connection-evictor": { class: "rotation-renewed", defaultTtlSeconds: ROTATION_RENEWED_TTL_SEC, renewalOwner: "system-account rotation", note: "$SYS-account KICK-only live-eviction cred; same rotation-renewed posture as the observer" },
114
114
  };
115
115
  // RUNTIME integrity (the afa715b class): the matrix and every policy freeze at module load
116
116
  // (a post-import `defaultTtlSeconds = undefined` would otherwise mint a NON-EXPIRING credential
@@ -198,8 +198,8 @@ export function stripSpaceAuth(auth) {
198
198
  };
199
199
  }
200
200
  /** Rotate the DATA-account signing key and re-issue the data-account JWT so the old data signer is no
201
- * longer trusted by the broker once it loads the returned auth. This does NOT rotate the system account:
202
- * persisted `membership-observer` creds remain valid until the system-account renewal/rotation slice. */
201
+ * longer trusted by the broker once it loads the returned auth. This does NOT rotate the system account
202
+ * (that is {@link rotateSystemAccount}): persisted `membership-observer` creds stay valid. */
203
203
  export async function rotateDataAccountSigningKey(auth) {
204
204
  if (!auth.operator.seed || !auth.account.seed)
205
205
  throw new Error("rotateDataAccountSigningKey: full operator/account seed material is required (a stripped signer cannot rotate trust)");
@@ -291,7 +291,7 @@ export async function createSpaceAccountAuth(broker, space) {
291
291
  }
292
292
  /** Generate a fresh operator → account(+signing key) → system-account chain for a space.
293
293
  * The single-space composition of {@link createBrokerAuth} + {@link createSpaceAccountAuth}: one
294
- * broker whose only tenant is this space, which is exactly the pre-W4 shape. */
294
+ * broker whose only tenant is this space. */
295
295
  export async function createSpaceAuth(space) {
296
296
  const broker = await createBrokerAuth(space);
297
297
  const spaceAccount = await createSpaceAccountAuth(broker, space);
@@ -372,7 +372,7 @@ export async function provisionAgentDurables(provisioner, pr, opts = {}) {
372
372
  // reissueAcl — rides THIS mint: allowSubscribe was just baked into the user JWT above. Separate
373
373
  // from commitAcl so an ordinary registry writer cannot raise the ceiling by passing a flag
374
374
  // (SPEC §9.6). Not crypto-bound to the JWT bytes — process discipline that this call stays next
375
- // to the mint (ACL-authority panel residual).
375
+ // to the mint.
376
376
  if (opts.durableMembership !== false) {
377
377
  await provisioner.reissueAcl(principalKey(pr.owner, pr.actor).key, uid, allowSubscribe);
378
378
  }
@@ -492,7 +492,7 @@ async function releaseIssuance(space, profile, pr, opts, perms, exp, credentialI
492
492
  * lifetime builders. It signs with the space account's signing key alone, so a host that holds
493
493
  * only that key passes no placeholder broker trust. */
494
494
  export async function mintPublicUserJwt(auth, publicId, profile, opts) {
495
- if (!/^U[A-Z2-7]{55}$/.test(publicId))
495
+ if (!isUserNkey(publicId))
496
496
  throw new Error("mintPublicUserJwt: publicId must be a user nkey");
497
497
  if (!["remote-manager", "endpoint-serve", "goal-writer", "session-ledger", "session-serving", "retirement-requester", "run-driver", "run-mediator", "run-operator", "transfer-reader"].includes(profile))
498
498
  throw new Error(`mintPublicUserJwt: profile "${profile}" is not part of the closed remote manager protocol`);
@@ -540,7 +540,7 @@ const ISSUABLE_PROFILES = new Set(["agent", "control-caller-privileged", "contro
540
540
  /** Build the NATS user permission object for a profile: a default-deny allow-list scoped to
541
541
  * exactly what each profile does. Every profile is now enumerated least-privilege — the former
542
542
  * allow-all `manager` is gone (its roles split across supervisor/provisioner/operator/purger and the
543
- * PR 1.5 CLI-surface profiles). Subject/stream/durable names come from the shared builders so the ACLs
543
+ * CLI-surface profiles). Subject/stream/durable names come from the shared builders so the ACLs
544
544
  * can't drift from the wire layout.
545
545
  *
546
546
  * PRINCIPAL-PARAMETERIZED + MODE-AGNOSTIC (owner+actor grammar): `pr` carries the owner+actor wire
@@ -572,11 +572,11 @@ export function permissionsFor(profile, space, pr, opts) {
572
572
  if (profile === "membership-rw")
573
573
  return membershipRwPermissions(space, pr); // scoped graph-feed reader/writer
574
574
  if (profile === "supervisor")
575
- return supervisorPermissions(space, pr); // always-on daemon (closure (ii) gate)
575
+ return supervisorPermissions(space, pr); // always-on daemon
576
576
  if (profile === "provisioner")
577
- return provisionerPermissions(space, pr); // ephemeral onboarding authority (closure (ii))
577
+ return provisionerPermissions(space, pr); // ephemeral onboarding authority
578
578
  if (profile === "deprovisioner") {
579
- // Ephemeral, TARGET-PINNED teardown (#159 B) — the counterpart to `provisioner`. The target is a
579
+ // Ephemeral, TARGET-PINNED teardown — the counterpart to `provisioner`. The target is a
580
580
  // full principal dot-form for user-mode agents, or a bare static/dev actor id (keyed under
581
581
  // DEV_OWNER) — see {@link deprovisionTargetPrincipal}.
582
582
  if (!opts.deprovisionTarget)
@@ -584,7 +584,7 @@ export function permissionsFor(profile, space, pr, opts) {
584
584
  return deprovisionerPermissions(space, pr, opts.deprovisionTarget);
585
585
  }
586
586
  if (profile === "retirement-requester") {
587
- // Ephemeral request+reply on the AUTH ENDPOINT rail (#29 piece 3; moved off `ctl` by #350):
587
+ // Ephemeral request+reply on the AUTH ENDPOINT rail:
588
588
  // publish EXACTLY this caller triple's own request subject for the ONE target it names +
589
589
  // subscribe its own reply-plane filter and inbox. No store reads, no barrier/scanner/plane
590
590
  // authority - the requester only asks; the auth plane holds every executing right and
@@ -654,7 +654,7 @@ export function permissionsFor(profile, space, pr, opts) {
654
654
  return { pub: { allow: g.publish }, sub: { allow: g.subscribe } };
655
655
  }
656
656
  if (profile === "endpoint-evictor") {
657
- // P2 item 3 (slice 3a): a SCOPED delivery-admin caller for ONE re-registration's verify-evict.
657
+ // A SCOPED delivery-admin caller for ONE re-registration's verify-evict.
658
658
  // Publish EXACTLY this credential's OWN delivery-admin control subject + $JS.API.INFO; subscribe
659
659
  // its own reply subtree + inbox. NO lease, presence, store read, consumer, KV, or executing
660
660
  // right — the daemon does the $SYS scan/KICK (subject-gated authority, like the supervisor evictor
@@ -679,7 +679,7 @@ export function permissionsFor(profile, space, pr, opts) {
679
679
  return goalWriterPermissions(space, pr, opts.goalWriter);
680
680
  }
681
681
  if (profile === "purger")
682
- return purgerPermissions(space, pr); // ephemeral history-purge (closure (ii))
682
+ return purgerPermissions(space, pr); // ephemeral history-purge
683
683
  if (profile === "backup") {
684
684
  if (!opts.backup)
685
685
  throw new Error("permissionsFor: backup requires opts.backup");
@@ -691,27 +691,27 @@ export function permissionsFor(profile, space, pr, opts) {
691
691
  return restoreProfilePermissions(space, pr.connId, opts.restore);
692
692
  }
693
693
  if (profile === "operator")
694
- return operatorPermissions(space, pr); // human-CLI client (send/dm/ask) (closure (ii))
694
+ return operatorPermissions(space, pr); // human-CLI client (send/dm/ask)
695
695
  if (profile === "probe")
696
- return probePermissions(pr); // connect-only liveness/auth preflight (PR 1.5)
696
+ return probePermissions(pr); // connect-only liveness/auth preflight
697
697
  if (profile === "channel-writer")
698
- return channelWriterPermissions(space, pr); // channel-registry writes (PR 1.5)
698
+ return channelWriterPermissions(space, pr); // channel-registry writes
699
699
  if (profile === "channel-purger")
700
- return channelPurgerPermissions(space, pr); // channel-writer + CHAT purge (PR 1.5)
700
+ return channelPurgerPermissions(space, pr); // channel-writer + CHAT purge
701
701
  if (profile === "teardown")
702
- return teardownPermissions(space, pr, opts.transferStreams ?? []); // sole STREAM.DELETE holder (PR 1.5)
702
+ return teardownPermissions(space, pr, opts.transferStreams ?? []); // sole STREAM.DELETE holder
703
703
  if (profile === "control-caller-privileged")
704
- return controlCallerPermissions(space, pr, "privileged", opts); // ps/start reads (PR 1.5)
704
+ return controlCallerPermissions(space, pr, "privileged", opts); // ps/start reads
705
705
  if (profile === "control-caller-admin")
706
- return controlCallerPermissions(space, pr, "admin", opts); // any-mode stop/attach (PR 1.5)
706
+ return controlCallerPermissions(space, pr, "admin", opts); // any-mode stop/attach
707
707
  if (profile === "deployer")
708
- return deployerPermissions(space, pr, opts.controlTier ?? "admin", opts); // spawn -f deploy authority (PR 1.5; user-mode view rides privileged)
708
+ return deployerPermissions(space, pr, opts.controlTier ?? "admin", opts); // spawn -f deploy authority (user-mode view rides privileged)
709
709
  if (profile === "session-caller")
710
- return sessionCallerPermissions(space, pr, opts.sessionCaller); // one §13.6 session's caller rails (P2 item 6)
710
+ return sessionCallerPermissions(space, pr, opts.sessionCaller); // one §13.6 session's caller rails
711
711
  if (profile === "session-serving")
712
- return sessionServingPermissions(space, pr, opts.sessionServing); // one §13.6 session's SERVING rails (P2 item 6)
712
+ return sessionServingPermissions(space, pr, opts.sessionServing); // one §13.6 session's SERVING rails
713
713
  if (profile === "session-ledger")
714
- return sessionLedgerPermissions(space, pr); // the dedicated session ledger, no rails (P2 item 6)
714
+ return sessionLedgerPermissions(space, pr); // the dedicated session ledger, no rails
715
715
  if (profile === "run-driver") {
716
716
  if (!opts.runDriver)
717
717
  throw new Error("permissionsFor: run-driver requires opts.runDriver ({endpoint, runId, takeoverId, instanceId, epoch} of the ONE run and attempt it drives)");
@@ -839,7 +839,7 @@ export function permissionsFor(profile, space, pr, opts) {
839
839
  unicastSubject(space, "*", "*", pr.owner, pr.actor), // inst.*.*.<o>.<a> — DM any instance, as me
840
840
  anycastSubject(space, "*", pr.owner, pr.actor), // svc.*.<o>.<a> — anycast any role, as me
841
841
  // Self stop/despawn rides the v0.4 ep baseline (`stop` self-mode) — the manager `ctl` rail is
842
- // deleted (1d). The delivery-daemon rail below is a separate service (Plane-3), kept.
842
+ // deleted. The delivery-daemon rail below is a separate service (Plane-3), kept.
843
843
  // ctl.delivery.<o>.<a> — request a durable backstop join/leave/list from the SERVER-SIDE delivery
844
844
  // daemon (NOT the manager). The reply rides this same subtree (`ctl.delivery.<o>.<a>.reply.<n>`, in
845
845
  // sub.allow below) so the daemon can answer without broad inbox-publish — see CONTROL_DELIVERY.
@@ -927,7 +927,7 @@ export function permissionsFor(profile, space, pr, opts) {
927
927
  pubAllow.push(`$JS.API.STREAM.INFO.${TASK}`, `$JS.API.CONSUMER.INFO.${TASK}.${svcD}`, `$JS.API.CONSUMER.MSG.NEXT.${TASK}.${svcD}`, `$JS.ACK.${TASK}.${svcD}.>`);
928
928
  }
929
929
  // Spawn / admin capability control reach rides the v0.4 ep rows below (the manager `ctl` rail is
930
- // deleted, 1d) — the spawn set (owner-mode manager lifecycle) and the admin instrument set
930
+ // deleted) — the spawn set (owner-mode manager lifecycle) and the admin instrument set
931
931
  // (any-mode + manager.admin family) are added to the ep caller rows, not a ctl subject.
932
932
  // v0.4 endpoint rails (SPEC §13.9 caller rows). EVERY agent gets the Appendix-B BASELINE set
933
933
  // (wildcard describe + delivery join/leave/list + self-mode lifecycle + the reply rail), keyed
@@ -975,7 +975,7 @@ export function permissionsFor(profile, space, pr, opts) {
975
975
  epSub.push(s);
976
976
  }
977
977
  if (opts.capabilities?.includes("admin"))
978
- // The admin capability's ep mirror (the 1c grant-migration table): the v0.3 `ctl.<admin>`
978
+ // The admin capability's ep mirror: the v0.3 `ctl.<admin>`
979
979
  // subject above grants the FULL admin-tier op reach, so its holder gets the admin instrument
980
980
  // set on the ep rails — any-mode despawn/attach + the `manager.admin` family + the reads. In
981
981
  // user mode this is the ledger `admin` scope arriving via the callout, the broker-enforced
@@ -1032,7 +1032,7 @@ export function permissionsFor(profile, space, pr, opts) {
1032
1032
  // addressed elsewhere.
1033
1033
  const livenessReplies = LIVENESS_PLANES.map((plane) => `${livenessSubject(space, plane, pr.owner, pr.actor)}.>`);
1034
1034
  // Manager control replies ride the v0.4 ep reply rail (in `epSub`, keyed on the caller triple) —
1035
- // the `ctl.<tier>.<id>.reply.>` subtrees are gone with the ctl rail (1d).
1035
+ // the `ctl.<tier>.<id>.reply.>` subtrees are gone with the ctl rail.
1036
1036
  return { pub: { allow: pubAllow, deny: pubDeny }, sub: { allow: [inbox, deliveryReplies, ...livenessReplies, ...subChat, ...epSub] } };
1037
1037
  }
1038
1038
  /** One seat's manager control view. It carries no agent messaging or delivery surface, and every
@@ -1064,10 +1064,10 @@ function managerCallerPermissions(space, pr, opts) {
1064
1064
  sub: { allow: [`_INBOX_${pr.connId}.>`, ...rows.sub] },
1065
1065
  };
1066
1066
  }
1067
- /** The long-lived SUPERVISOR permission set (closure (ii), residual 2) — the always-on manager daemon
1068
- * (`manager.ts` `this.ep`), carved down from the former allow-all `manager`. THIS is the cred whose
1069
- * STANDING breadth was the residual-2 gate: tightening it removes the always-on DM/DLV body-read AND the
1070
- * stream-admin tamper from the one connection that never goes away. It does exactly three things — serve
1067
+ /** The long-lived SUPERVISOR permission set — the always-on manager daemon
1068
+ * (`manager.ts` `this.ep`), carved down from the former allow-all `manager`. Its breadth is
1069
+ * STANDING, so tightening it removes the always-on DM/DLV body-read AND the stream-admin tamper
1070
+ * from the one connection that never goes away. It does exactly three things — serve
1071
1071
  * the three lifecycle control tiers (bounded replies), hold the singleton manager lease, and publish +
1072
1072
  * watch presence (the roster) — and nothing else. Provisioning (DM/DLV/TASK consumer-create + ACL
1073
1073
  * writes) moves to the EPHEMERAL `provisioner` (opened per-spawn); destructive history-purge moves to the
@@ -1080,7 +1080,7 @@ function managerCallerPermissions(space, pr, opts) {
1080
1080
  function supervisorPermissions(space, pr) {
1081
1081
  const PKV = `KV_${presenceBucket(space)}`, MKV = `KV_${managerBucket(space)}`;
1082
1082
  const SUP_DLVKV = `KV_${deliveryBucket(space)}`;
1083
- // 1d: the supervisor no longer serves the manager control tiers — the manager's control surface
1083
+ // The supervisor no longer serves the manager control tiers — the manager's control surface
1084
1084
  // is its v0.4 `service` endpoint, served on a SEPARATE connection under its own `endpoint-serve`
1085
1085
  // credential (its rails are that credential's grant, not the supervisor's). The supervisor now
1086
1086
  // holds only the lease, presence, and the ONE delivery-admin call.
@@ -1089,18 +1089,17 @@ function supervisorPermissions(space, pr) {
1089
1089
  allow: [
1090
1090
  "$JS.API.INFO",
1091
1091
  // Per-instance manager liveness lease (managerBucket, pre-created at `cotal up`): OPEN-ONLY bind +
1092
- // CAS this instance's own `lease.<instanceId>` key (acquire/renew/release) + read the subtree. P2
1093
- // item 3 demoted the per-space singleton to per-instance keys, so the write grant spans `lease.*`
1094
- // (every instance of this space shares this one supervisor principal — the isolation between
1095
- // instances is the logical-id/CAS boundary, not a cred boundary). NO STREAM.CREATE (pre-created),
1096
- // DELETE, or PURGE.
1092
+ // CAS this instance's own `lease.<instanceId>` key (acquire/renew/release) + read the subtree. The
1093
+ // lease is per instance, so the write grant spans `lease.*` (every instance of this space
1094
+ // shares this one supervisor principal — the isolation between instances is the logical-id/CAS
1095
+ // boundary, not a cred boundary). NO STREAM.CREATE (pre-created), DELETE, or PURGE.
1097
1096
  `$JS.API.STREAM.INFO.${MKV}`,
1098
1097
  `$JS.API.STREAM.MSG.GET.${MKV}`, // readManagerLease (last_by_subj lease.*) + CAS-conflict kv.get
1099
1098
  `$KV.${managerBucket(space)}.${MANAGER_LEASE_KEY}.*`, // this instance's lease.<id> key (create/update/delete = $KV publishes)
1100
1099
  // #1634: the per-space daemon-credential renewal lease, the CAS that picks ONE renewal owner
1101
1100
  // when several managers share the daemon's store. Same bucket, its own key outside `lease.*`.
1102
1101
  `$KV.${managerBucket(space)}.${MANAGER_RENEWAL_LEASE_KEY}`,
1103
- // Presence: publish OWN key + watch the roster. Own key only (no peer-key forge — residual 3); no
1102
+ // Presence: publish OWN key + watch the roster. Own key only (no peer-key forge); no
1104
1103
  // presence-stream purge/delete (no force-offline tamper). No presence kv.get (roster is the in-memory
1105
1104
  // watch cache + sweep), so no STREAM.MSG.GET on presence.
1106
1105
  `$KV.${presenceBucket(space)}.${principalKey(pr.owner, pr.actor).key}`,
@@ -1108,8 +1107,8 @@ function supervisorPermissions(space, pr) {
1108
1107
  `$JS.API.CONSUMER.CREATE.${PKV}.>`, // kv.watch ordered consumer (roster)
1109
1108
  `$JS.API.CONSUMER.INFO.${PKV}.>`,
1110
1109
  "$JS.FC.>", // ordered-consumer flow control
1111
- // The ONE control service the supervisor CALLS (D5 slice 5): the delivery daemon's privileged
1112
- // admin rail — the manager is the class-2 renewal owner, and after re-signing the daemon creds
1110
+ // The ONE control service the supervisor CALLS: the delivery daemon's privileged
1111
+ // admin rail — the manager is the daemon's renewal owner, and after re-signing the daemon creds
1113
1112
  // files it requests `reloadCreds` here so adoption is an explicit, auditable event. Self-scoped
1114
1113
  // request subject (its own owner+actor slots), bounded reply subtree in sub.allow below.
1115
1114
  controlServiceSubject(space, CONTROL_DELIVERY_ADMIN, pr.owner, pr.actor),
@@ -1138,8 +1137,8 @@ function supervisorPermissions(space, pr) {
1138
1137
  },
1139
1138
  sub: {
1140
1139
  // Own reply inbox + the delivery-admin reply subtree for its OWN requests. NO chat/inst/dlv
1141
- // native sub (the supervisor reads no feed), NO manager control-tier serve (1d: that moved to
1142
- // the endpoint-serve credential), NO broad `$JS.>`/`$KV.>` (the residual-2 read/admin path is gone).
1140
+ // native sub (the supervisor reads no feed), NO manager control-tier serve (that is
1141
+ // the endpoint-serve credential's), NO broad `$JS.>`/`$KV.>`.
1143
1142
  //
1144
1143
  // PLUS the manager-plane liveness SERVE filter (#1577): `live.manager.*.*`, queue-grouped, so
1145
1144
  // any credentialed peer's presence probe reaches the lease holder. This is a serve
@@ -1247,7 +1246,7 @@ function remoteManagerPermissions(space, pr, pin) {
1247
1246
  },
1248
1247
  };
1249
1248
  }
1250
- /** The human-CLI OPERATOR permission set (closure (ii), residual 2) — the ephemeral key the headless
1249
+ /** The human-CLI OPERATOR permission set — the ephemeral key the headless
1251
1250
  * client commands mint (`cotal send dm|msg|ask`, `cotal dm`, `personas list --running`, via
1252
1251
  * `openTransient`). It does exactly what those do: POST as itself (chat/DM/anycast — self-scoped, can
1253
1252
  * never forge another actor), and READ the public roster (presence) + the channel registry to resolve a
@@ -1290,7 +1289,7 @@ function operatorPermissions(space, pr) {
1290
1289
  sub: { allow: [`_INBOX_${pr.connId}.>`] },
1291
1290
  };
1292
1291
  }
1293
- /** Connect-only PROBE (PR 1.5) — the liveness/auth preflight (`preflight.ts preflightTarget`, minted on
1292
+ /** Connect-only PROBE — the liveness/auth preflight (`preflight.ts preflightTarget`, minted on
1294
1293
  * ~every CLI command that resolves a mesh). `probeConnect` opens a connection to prove the broker is up
1295
1294
  * and the creds are accepted, then closes it — it performs NO pub/sub. So the tightest possible grant:
1296
1295
  * deny ALL publish, subscribe only to the own reply inbox. A leaked probe cred can open a socket and do
@@ -1298,7 +1297,7 @@ function operatorPermissions(space, pr) {
1298
1297
  function probePermissions(pr) {
1299
1298
  return { pub: { deny: [">"] }, sub: { allow: [`_INBOX_${pr.connId}.>`] } };
1300
1299
  }
1301
- /** CHANNEL-WRITER (PR 1.5) — edits the channel registry ONLY: `cotal channels set/default` and the
1300
+ /** CHANNEL-WRITER — edits the channel registry ONLY: `cotal channels set/default` and the
1302
1301
  * `spawn -f` new-channel seed (`seedChannelRegistry`). It VALUE-writes `$KV.<channelBucket>` (a channel's
1303
1302
  * config key) and read-before-writes it. NO stream data, NO other bucket, NO chat/DM — a leaked
1304
1303
  * channel-writer can only rewrite channel config, never post, read a body, or tear a stream down. */
@@ -1319,7 +1318,7 @@ function channelWriterPermissions(space, pr) {
1319
1318
  sub: { allow: [`_INBOX_${pr.connId}.>`] },
1320
1319
  };
1321
1320
  }
1322
- /** CHANNEL-PURGER (PR 1.5) — the `cotal web` dashboard's ONLY write path: delete a channel
1321
+ /** CHANNEL-PURGER — the `cotal web` dashboard's ONLY write path: delete a channel
1323
1322
  * (`clearChannel` = filtered `STREAM.PURGE.CHAT` to drop the channel's messages + a `$KV.<channelBucket>`
1324
1323
  * key delete). Pre-minted once by `web` so the account signing seed falls out of scope; the dashboard's
1325
1324
  * READ side runs on the separate read-only `admin` cred. = channel-writer + the scoped CHAT purge. */
@@ -1342,8 +1341,8 @@ function channelPurgerPermissions(space, pr) {
1342
1341
  sub: { allow: [`_INBOX_${pr.connId}.>`] },
1343
1342
  };
1344
1343
  }
1345
- /** TEARDOWN (PR 1.5) — `cotal down -f` space teardown. The SOLE cred that keeps `STREAM.DELETE` (the
1346
- * face-b tamper verb). `down -f` is multi-step: `connectProbe` (presence-watch + channel-registry read)
1344
+ /** TEARDOWN — `cotal down -f` space teardown. The SOLE cred that keeps `STREAM.DELETE` (the
1345
+ * tamper verb). `down -f` is multi-step: `connectProbe` (presence-watch + channel-registry read)
1347
1346
  * → invoke the manager's `ps` + any-mode `despawn` over the ep rails to politely stop the managed
1348
1347
  * agents → `deleteChannels`
1349
1348
  * (channel-registry key delete + CHAT purge) → `deleteSpace` (STREAM.DELETE every owned stream/bucket).
@@ -1352,7 +1351,7 @@ function channelPurgerPermissions(space, pr) {
1352
1351
  * can delete a stream; a leaked teardown can wipe a space you own + stop its agents (that IS its job),
1353
1352
  * nothing else. Minted ephemerally per teardown from the local trust material (same-checkout `down -f`). */
1354
1353
  function teardownPermissions(space, pr, transferStreams) {
1355
- // The ep-rail mirror of the admin deploy tier (1c.2c): teardown reads `ps` and stops owned agents
1354
+ // The ep-rail mirror of the admin deploy tier: teardown reads `ps` and stops owned agents
1356
1355
  // it did not spawn (any-mode despawn) - the admin instrument set. Lifecycle-keyed, so a uid is
1357
1356
  // required at mint (fail-loud).
1358
1357
  const ep = instrumentEpRows(space, pr, "admin");
@@ -1360,7 +1359,7 @@ function teardownPermissions(space, pr, transferStreams) {
1360
1359
  const PKV = `KV_${presenceBucket(space)}`, CHKV = `KV_${channelBucket(space)}`;
1361
1360
  // deleteSpace() deletes EVERY stream + KV bucket setup creates; each needs INFO (jsm existence)
1362
1361
  // + DELETE. This is the ONLY cred that
1363
- // holds STREAM.DELETE (face-b isolated here). This list and deleteSpace()'s own array must agree:
1362
+ // holds STREAM.DELETE. This list and deleteSpace()'s own array must agree:
1364
1363
  // a stream in one and not the other is either an undeletable leak or a grant for nothing.
1365
1364
  const del = [
1366
1365
  CHAT, dmStream(space), taskStream(space), inboxStream(space), dlvStream(space),
@@ -1390,7 +1389,7 @@ function teardownPermissions(space, pr, transferStreams) {
1390
1389
  `$JS.API.CONSUMER.INFO.${CHKV}.>`,
1391
1390
  "$JS.FC.>", // ordered-consumer flow control
1392
1391
  // Stop the managed agents over the v0.4 ep rails only (ps + any-mode despawn) — the admin
1393
- // instrument set. The manager `ctl` rail is deleted (1d).
1392
+ // instrument set. The manager `ctl` rail is deleted.
1394
1393
  ...ep.pub,
1395
1394
  ...del,
1396
1395
  // deleteChannels/clearChannel: purge the channel's chat messages + delete its registry key.
@@ -1399,16 +1398,16 @@ function teardownPermissions(space, pr, transferStreams) {
1399
1398
  ],
1400
1399
  },
1401
1400
  // Own inbox (connectProbe presence-watch delivery + JS API responses) + the ep reply rail (the
1402
- // ps + any-mode despawn calls reply there). The `ctl.admin.<id>.reply.>` subtree is gone (1d).
1401
+ // ps + any-mode despawn calls reply there). The `ctl.admin.<id>.reply.>` subtree is gone.
1403
1402
  sub: { allow: [`_INBOX_${pr.connId}.>`, ...ep.sub] },
1404
1403
  };
1405
1404
  }
1406
- /** CONTROL-CALLER (PR 1.5; ep-only since 1d) — the operator's lifecycle commands
1405
+ /** CONTROL-CALLER (ep rails only) — the operator's lifecycle commands
1407
1406
  * (`cotal ps/start/stop/attach`, `manager/commands.ts`). It invokes the manager's v0.4 service
1408
1407
  * endpoint and reads the bounded reply on the ep reply rail. That is ALL — no `$JS`, no `$KV`,
1409
1408
  * no chat/DM: it forges nothing, reads no body.
1410
1409
  *
1411
- * The tiers stay SPLIT because the BROKER grant is load-bearing (the 1c decision): an any-mode
1410
+ * The tiers stay SPLIT because the BROKER grant is load-bearing: an any-mode
1412
1411
  * despawn/attach row *is* cross-agent reach — the manager maps mode `any` to its admin
1413
1412
  * authorization path, so which ROWS an instrument holds is the tier boundary. Therefore:
1414
1413
  * • `control-caller-privileged` (ps/start) holds the manager reads + untargeted `spawn` +
@@ -1420,11 +1419,11 @@ function teardownPermissions(space, pr, transferStreams) {
1420
1419
  * disconnect, from the local signing seed); on a user mesh the manager's serve-time ledger
1421
1420
  * re-check sits on top. */
1422
1421
  function controlCallerPermissions(space, pr, epTier, opts = {}) {
1423
- // 1d: the manager `ctl` rail is gone — an operator instrument holds ONLY its v0.4 ep rows (the
1422
+ // The manager `ctl` rail is gone — an operator instrument holds ONLY its v0.4 ep rows (the
1424
1423
  // tier-matched request set, the reply rail, describe, the one epc fetch). The `epTier` selects
1425
1424
  // privileged (ps/start reads) vs admin (any-mode stop/attach) exactly as the ctl tier did.
1426
1425
  //
1427
- // B6 / `--on <instanceId>`: these instruments are ONE-SHOT, minted per control call, and the
1426
+ // `--on <instanceId>`: these instruments are ONE-SHOT, minted per control call, and the
1428
1427
  // resolve that pins the instance happens BEFORE the mint. So the caller can hand the exact
1429
1428
  // instance id down and get the exact `ep.inst.<endpoint>.<iid>.<command>` row for THIS invocation
1430
1429
  // and nothing else — the least-privilege issuance, with no standing wildcard anywhere. The
@@ -1434,17 +1433,17 @@ function controlCallerPermissions(space, pr, epTier, opts = {}) {
1434
1433
  const ep = instrumentEpRows(space, pr, epTier, opts.endpointCapabilities ?? [], opts);
1435
1434
  return {
1436
1435
  // The PRIVILEGED tier (the `cotal ps` instrument) also carries the SCOPED §13.9 records read the
1437
- // class scatter's freeze rides (P2 item 3): `freezeExpectedSet` enumerates `svc.<endpoint>.*.spec`
1436
+ // class scatter's freeze rides: `freezeExpectedSet` enumerates `svc.<endpoint>.*.spec`
1438
1437
  // and LEADER-reads each frozen slot's svc spec/status before it scatters `ps` on the `all` rail.
1439
1438
  // The admin tier (stop/attach) never scatters, so it gets no records read.
1440
1439
  pub: { allow: epTier === "privileged" ? [...ep.pub, ...scatterFreezeReadRows(space)] : ep.pub },
1441
1440
  sub: { allow: [`_INBOX_${pr.connId}.>`, ...ep.sub] },
1442
1441
  };
1443
1442
  }
1444
- /** The SCOPED §13.9 records-read rows the class-scatter freeze rides (P2 item 3, `cotal ps`): the
1443
+ /** The SCOPED §13.9 records-read rows the class-scatter freeze rides (`cotal ps`): the
1445
1444
  * `svc.*` enumeration consumer + the leader-served per-slot spec/status read of the endpoint's
1446
- * `svc` registry — a READ of exactly the service-registration keys, no write, no other bucket. A
1447
- * new D32 matrix row. The keyed Direct Get is subject-PINNED to `svc.>`; the enumeration consumer
1445
+ * `svc` registry — a READ of exactly the service-registration keys, no write, no other bucket.
1446
+ * The keyed Direct Get is subject-PINNED to `svc.>`; the enumeration consumer
1448
1447
  * and the leader `STREAM.MSG.GET` are STREAM-scoped because the requested key rides the PAYLOAD
1449
1448
  * (which a subject grant cannot narrow) — the SAME NAMED RESIDUAL every records reader already
1450
1449
  * accepts (the provisioner, the lifecycle/serve executors): for this EPHEMERAL one-shot instrument's
@@ -1468,12 +1467,10 @@ function scatterFreezeReadRows(space) {
1468
1467
  `$JS.API.DIRECT.GET.KV_${REC}.$KV.${REC}.svc.>`,
1469
1468
  ];
1470
1469
  }
1471
- /** The v0.4 ep-rail rows of an operator INSTRUMENT credential (the 1c grant-migration table's
1472
- * admin row): the tier-matched {@link operatorInstrumentCapabilities} request rows + the caller's
1473
- * reply rail, the wildcard `describe` form, and the ONE subject-scoped §13.7 contract-store fetch
1474
- * row (the same shape the agent baseline holds; the D32 audit's single exemption). These mirror
1475
- * the instrument's ctl tier onto the ep rails during dual-serve; at 1d the ctl row disappears and
1476
- * these ARE the instrument. The caller triple pins the instrument's own mint-time lifecycle uid
1470
+ /** The v0.4 ep-rail rows of an operator INSTRUMENT credential: the tier-matched
1471
+ * {@link operatorInstrumentCapabilities} request rows + the caller's reply rail, the wildcard
1472
+ * `describe` form, and the ONE subject-scoped §13.7 contract-store fetch row (the same shape the
1473
+ * agent baseline holds). No ctl row exists, so these ARE the instrument. The caller triple pins the instrument's own mint-time lifecycle uid
1477
1474
  * ({@link MintPrincipal.lifecycleUid}) — REQUIRED here: without it the reply rail cannot be pinned
1478
1475
  * and the mint fails loud rather than emit a triple-less (unfenced) caller surface. `extra` lets a
1479
1476
  * profile append its tier-refined additions (the user-mode deployer's owner-equality `launch`). */
@@ -1549,7 +1546,7 @@ function endpointServePermissions(space, pr, opts) {
1549
1546
  sub: { allow: [...rows.sub, `_INBOX_${pr.connId}.>`] },
1550
1547
  };
1551
1548
  }
1552
- /** DEPLOYER (PR 1.5) — the `cotal spawn -f` manifest-deploy authority. `spawn -f` drives ONE
1549
+ /** DEPLOYER — the `cotal spawn -f` manifest-deploy authority. `spawn -f` drives ONE
1553
1550
  * `connectProbe` endpoint that both READS live state (roster/presence watch, channel registry,
1554
1551
  * membership feed, manager-singleton lease) AND invokes the running manager's `launch` + `ps`
1555
1552
  * readiness over the v0.4 ep rails. Those interleave on one connection, so a strict 3-connection
@@ -1572,7 +1569,7 @@ function deployerPermissions(space, pr, epTier = "admin", opts = {}) {
1572
1569
  // set; the user-mode deployer VIEW (privileged) carries the privileged set PLUS an untargeted
1573
1570
  // `launch` row — its launch stays owner-equality-authorized (the manager's ledger-derived admin
1574
1571
  // flag is false for a spawn-scoped deployer), exactly the v0.3 user-mode privileged-tier launch.
1575
- // B6 / `--on`: the per-invocation pin APPENDS to this profile's standing set, never replaces it -
1572
+ // `--on`: the per-invocation pin APPENDS to this profile's standing set, never replaces it -
1576
1573
  // the privileged deployer view keeps its owner-equality `launch` row and additionally gets the one
1577
1574
  // exact `ep.inst.<endpoint>.<iid>.<command>` row for the instance this deploy resolved.
1578
1575
  const pinned = opts.endpointCapabilities ?? [];
@@ -1609,7 +1606,7 @@ function deployerPermissions(space, pr, epTier = "admin", opts = {}) {
1609
1606
  ...kvPointRead(MGRKV), // manager-singleton lease keyed read (waitManagerReady) — point-get, NO write, NO watch
1610
1607
  ...kvPointRead(DLVKV), // delivery-lease keyed read (preserve-state quiescence proof) — point-get, NO write, NO watch
1611
1608
  "$JS.FC.>", // ordered-consumer flow control
1612
- // 1d: launch + ps readiness ride the v0.4 ep rows only (the manager `ctl` rail is gone).
1609
+ // Launch + ps readiness ride the v0.4 ep rows only (the manager `ctl` rail is gone).
1613
1610
  // Static deploys carry the admin instrument set; the user-mode deployer VIEW carries the
1614
1611
  // privileged set + an owner-equality `launch` row (the manager's ledger-derived admin flag
1615
1612
  // is false for a spawn-scoped deployer, so its launch stays owner-equality-authorized).
@@ -1620,7 +1617,7 @@ function deployerPermissions(space, pr, epTier = "admin", opts = {}) {
1620
1617
  sub: { allow: [`_INBOX_${pr.connId}.>`, ...ep.sub] },
1621
1618
  };
1622
1619
  }
1623
- /** The ephemeral PURGER permission set (closure (ii), residual 2) — minted per-purge inside the daemon's
1620
+ /** The ephemeral PURGER permission set — minted per-purge inside the daemon's
1624
1621
  * `opPurge` and `cotal history clear`. Isolates the DESTRUCTIVE history-purge grant
1625
1622
  * (`STREAM.PURGE.CHAT` + `STREAM.PURGE.DM`) off the always-on supervisor: `--dms` purges the DM stream,
1626
1623
  * exactly the grant the supervisor must not hold. It PURGES but never READS — no DM/chat consumer, no
@@ -1635,12 +1632,12 @@ function purgerPermissions(space, pr) {
1635
1632
  `$JS.API.STREAM.PURGE.${DM}`, // clearSpaceHistory includeDms — the isolated DM-purge grant
1636
1633
  ],
1637
1634
  // NOTE: this profile does NOT cover `clearChannel` (web/`down -f` channel-delete) — that also does a
1638
- // `$KV.<channelBucket>.<ch>` registry delete this cred lacks; it stays on the broad operator/CLI cred.
1635
+ // `$KV.<channelBucket>.<ch>` registry delete this cred lacks, which `channel-purger` and `teardown` hold.
1639
1636
  },
1640
1637
  sub: { allow: [`_INBOX_${pr.connId}.>`] },
1641
1638
  };
1642
1639
  }
1643
- /** The ephemeral PROVISIONER permission set (closure (ii), residual 2) — the onboarding authority,
1640
+ /** The ephemeral PROVISIONER permission set — the onboarding authority,
1644
1641
  * carved off the long-lived manager. Minted short-lived for per-spawn provisioning (pre-create each
1645
1642
  * agent's bind-only DM/DLV/TASK durables + record its read ACL via `commitAcl`) — the daemon opens it per
1646
1643
  * spawn (`manager.ts withProvisioner`). It is ALSO the cred that creates the space's streams + KV buckets
@@ -1654,8 +1651,7 @@ function purgerPermissions(space, pr) {
1654
1651
  * create a DM/DLV consumer can stream the bodies). That is exactly why it is split OFF the always-on
1655
1652
  * supervisor and made EPHEMERAL: the daemon opens a provisioner connection per spawn and drains it
1656
1653
  * immediately, so the surface exists only for the provisioning window, not as a standing target. The
1657
- * cred is MEMORY-ONLY (never written to `.cotal`) and now carries a short profile-default `exp`; signer
1658
- * rotation, live eviction, and full revocation are later D5 slices.
1654
+ * cred is MEMORY-ONLY (never written to `.cotal`) and carries a short profile-default `exp`.
1659
1655
  *
1660
1656
  * `$JS` is an ENUMERATED allow-list, never `$JS.>`: STREAM.CREATE + INFO for the space streams/buckets,
1661
1657
  * DM/DLV/TASK consumer CREATE/DURABLE.CREATE/INFO — and deliberately NO `MSG.NEXT`/`MSG.GET`/`ACK` on
@@ -1685,9 +1681,9 @@ function provisionerPermissions(space, pr) {
1685
1681
  // STREAM.CREATE + INFO for each (idempotent setup at `cotal up`; CREATE is create-if-matching, INFO covers
1686
1682
  // the client's existence checks). NO DELETE/PURGE — provisioning never tears a stream down.
1687
1683
  // The §13.7 CONTRACT store (EPC) joins the list for the static manager's start-time
1688
- // `ensureContractStore` (P2 item 1, 1c): create-or-verify only — the provisioner holds no
1684
+ // `ensureContractStore`: create-or-verify only — the provisioner holds no
1689
1685
  // artifact-publish grant on it (publication rides the scoped endpoint-serve executor).
1690
- // The seven §13.12 ENDPOINT streams join the list (P2 item 2): spawn-as-action makes the manager
1686
+ // The seven §13.12 ENDPOINT streams join the list: spawn-as-action makes the manager
1691
1687
  // the first EPF (goal facts) + EPE (progress) writer, and nothing provisioned the endpoint streams
1692
1688
  // before (no manager code wrote to them), so `createEndpointStreams` now runs at the manager's
1693
1689
  // start-time ensure over this provisioner. Create-or-verify only (idempotent, fail-loud on drift);
@@ -1764,7 +1760,7 @@ function provisionerPermissions(space, pr) {
1764
1760
  `$JS.API.DIRECT.GET.KV_${aclBucket(space)}.>`, // keyed get: `.>` (the key rides the subject)
1765
1761
  `$JS.API.STREAM.MSG.GET.KV_${channelBucket(space)}`,
1766
1762
  `$JS.API.DIRECT.GET.KV_${channelBucket(space)}.>`, // keyed get: `.>` (the key rides the subject)
1767
- // The Unit B static-manager start path: `ensureAuthorityStores` UPDATEs the records store's
1763
+ // The static-manager start path: `ensureAuthorityStores` UPDATEs the records store's
1768
1764
  // deny-flags exactly once at fresh creation (create → update → verify), and the boot
1769
1765
  // reconciliation sweep enumerates the manager's slot rows (`keys()` → an ordered consumer)
1770
1766
  // then reads each slot BODY (phase/uid/actor) to plan resume — the reads ride the
@@ -1840,7 +1836,7 @@ function runAdmitterPermissions(space, pr, pin) {
1840
1836
  };
1841
1837
  }
1842
1838
  /** The ephemeral, LIFECYCLE-PINNED §13.1 state-write permission set for the STATIC manager's
1843
- * lifecycle executor (Unit B). One credential per lifecycle OPERATION (activation, terminal,
1839
+ * lifecycle executor. One credential per lifecycle OPERATION (activation, terminal,
1844
1840
  * renewal ledger append): every grant names exactly ONE incarnation's keys — the alias head,
1845
1841
  * the uid reservation, the manager slot row, the issuance gate, and the `cred.<uid>.>` ledger
1846
1842
  * family — so a leaked executor cred can move one incarnation's state machine and nothing else.
@@ -1868,7 +1864,7 @@ function lifecycleExecutorPermissions(space, pr, pin) {
1868
1864
  // grant names exactly one of this incarnation's keys.
1869
1865
  ...recordKeys.map((k) => `$KV.${REC}.${k}`),
1870
1866
  // Auth-store CAS writes — this incarnation's gate + its cred-ledger family (renewals
1871
- // append rows here; the terminal's B1 revoke CASes them).
1867
+ // append rows here; the terminal's revoke CASes them).
1872
1868
  `$KV.${AUTH}.${issuanceGateKey(pin.lifecycleUid)}`,
1873
1869
  `$KV.${AUTH}.cred.${pin.lifecycleUid}.>`,
1874
1870
  // Keyed Direct Get reads of the same records keys (key-pinned) for direct-aware read
@@ -1885,16 +1881,16 @@ function lifecycleExecutorPermissions(space, pr, pin) {
1885
1881
  sub: { allow: [`_INBOX_${pr.connId}.>`] },
1886
1882
  };
1887
1883
  }
1888
- /** The SELF-MEDIATED goal-writer profile (P2 item 2, spawn-as-action): exactly
1884
+ /** The SELF-MEDIATED goal-writer profile (spawn-as-action): exactly
1889
1885
  * {@link goalWriterGrants} for ITS endpoint — the goal bind + terminal facts, the goal-record KV
1890
1886
  * writes, and the leader-served fencing reads — plus the connection-scoped reply inbox. Disjoint
1891
- * from the endpoint's serve credential (Q2): a serve connection carries none of these rows, so it
1887
+ * from the endpoint's serve credential: a serve connection carries none of these rows, so it
1892
1888
  * is broker-denied every goal write. */
1893
1889
  function goalWriterPermissions(space, pr, pin) {
1894
1890
  const g = goalWriterGrants(space, pin.endpoint, pr.connId);
1895
1891
  return { pub: { allow: g.publish }, sub: { allow: g.subscribe } };
1896
1892
  }
1897
- /** The console/CLI per-session CALLER rows (P2 item 6): RAILS-ONLY for ONE §13.6 session — pub the
1893
+ /** The console/CLI per-session CALLER rows: RAILS-ONLY for ONE §13.6 session — pub the
1898
1894
  * session's epoch-pinned `in` rail, sub its `out` rail plus the caller's own reply inbox, and
1899
1895
  * NOTHING else. Deliberately NO KV, NO JetStream API, NO store: the caller drives the terminal over
1900
1896
  * the two core-only eps subjects and never reads the session ledger, so there is no subject-blind
@@ -1909,7 +1905,7 @@ function sessionCallerPermissions(space, pr, pin) {
1909
1905
  sub: { allow: [epsSubject(space, pin.endpoint, pin.sessionId, pin.epoch, "out"), `_INBOX_${pr.connId}.>`] },
1910
1906
  };
1911
1907
  }
1912
- /** The manager's per-session SERVING rows (P2 item 6): the EXACT mirror of
1908
+ /** The manager's per-session SERVING rows: the EXACT mirror of
1913
1909
  * {@link sessionCallerPermissions} with the directions swapped — sub the ONE session's epoch-pinned
1914
1910
  * `in` rail (caller→serving), pub its `out` rail (serving→caller), plus the connection-scoped reply
1915
1911
  * inbox, and NOTHING else. Same asymmetry §13.6 states: "the caller publishes `in` and subscribes
@@ -1932,7 +1928,7 @@ function sessionServingPermissions(space, pr, pin) {
1932
1928
  sub: { allow: [epsSubject(space, pin.endpoint, pin.sessionId, pin.epoch, "in"), `_INBOX_${pr.connId}.>`] },
1933
1929
  };
1934
1930
  }
1935
- /** The manager's SESSION-LEDGER rows (P2 item 6): the DEDICATED sessions-bucket rows and nothing
1931
+ /** The manager's SESSION-LEDGER rows: the DEDICATED sessions-bucket rows and nothing
1936
1932
  * else — no session rail of any shape. Needs no pin: the grant carries no endpoint, epoch, or
1937
1933
  * session component, because §13.6's durable revocation authority is per-space, not per-session
1938
1934
  * (it must still be able to resolve and revoke a row after the endpoint that served it is gone).
@@ -1942,10 +1938,10 @@ function sessionLedgerPermissions(space, pr) {
1942
1938
  const g = sessionLedgerGrants(space, pr.connId);
1943
1939
  return { pub: { allow: g.publish }, sub: { allow: g.subscribe } };
1944
1940
  }
1945
- /** The ephemeral, ENDPOINT-INSTANCE-PINNED endpoint-serve executor permission set (P2 item 1,
1946
- * 1a-serve): the manager mints this per registration/serve-mint op and drives the endpoint
1941
+ /** The ephemeral, ENDPOINT-INSTANCE-PINNED endpoint-serve executor permission set:
1942
+ * the manager mints this per registration/serve-mint op and drives the endpoint
1947
1943
  * registration barrier's `epgate` CAS + the mint fence's `epcred` stage/revoke THROUGH it — never
1948
- * its standing seed/supervisor connection (critic #1's manager-specific "no seed shortcut"). Every
1944
+ * its standing seed/supervisor connection. Every
1949
1945
  * WRITE is key-pinned to exactly ONE (endpoint, instanceId): the gate `epgate.<ep>.<iid>`, its
1950
1946
  * serving ledger family `epcred.<ep>.<iid>.>`, and the registration's two records keys (the
1951
1947
  * instance's `svc` spec + the endpoint's governance head — `registerServiceInstance` drives the
@@ -1963,7 +1959,7 @@ function endpointServeExecutorPermissions(space, pr, pin) {
1963
1959
  const repairKey = eprepairKey(pin.endpoint, pin.instanceId);
1964
1960
  // The registration writes this ONE instance's spec key plus the endpoint's governance head
1965
1961
  // (`registerServiceInstance` PHASE 1/3b: the slot-take + promote ride the SAME executor), and this
1966
- // instance's own svc STATUS key (P2 item 3: the manager writes its CONVERGED `ready` status so it
1962
+ // instance's own svc STATUS key (the manager writes its CONVERGED `ready` status so it
1967
1963
  // is a §13.5 scatter member — `freezeExpectedSet` requires a status caught up to the current
1968
1964
  // registration; the write is epoch-fenced by `writeServiceStatus`).
1969
1965
  const recordKeys = [
@@ -1983,7 +1979,7 @@ function endpointServeExecutorPermissions(space, pr, pin) {
1983
1979
  `$KV.${AUTH}.${repairKey}`,
1984
1980
  `$KV.${AUTH}.${credPrefix}.>`,
1985
1981
  ...recordKeys.map((k) => `$KV.${REC}.${k}`),
1986
- // §13.7 contract-artifact publication (P2 item 1, 1c): the registration publishes the
1982
+ // §13.7 contract-artifact publication: the registration publishes the
1987
1983
  // endpoint's cluster document, closure manifests, and schema roots to the EPC store so
1988
1984
  // callers can fetch-verify-compile the registered digests. A digest subject is a SINGLE
1989
1985
  // hex token (`epc.<64hex>`), so the grant is the single-token `epc.*` form (matching
@@ -2023,7 +2019,7 @@ function endpointServeExecutorPermissions(space, pr, pin) {
2023
2019
  sub: { allow: [`_INBOX_${pr.connId}.>`] },
2024
2020
  };
2025
2021
  }
2026
- /** The ephemeral, TARGET-PINNED DEPROVISIONER permission set (#159 Part B) — the teardown counterpart
2022
+ /** The ephemeral, TARGET-PINNED DEPROVISIONER permission set — the teardown counterpart
2027
2023
  * to {@link provisionerPermissions}, minted per departed agent inside the manager's `deprovision` tail
2028
2024
  * (`withProvisioner`-style: a fresh scoped cred per teardown is cheap). It deletes exactly the
2029
2025
  * dev/static principal footprint the provisioner created for ONE agent: that agent's two bind-only
@@ -2174,7 +2170,7 @@ function deliveryPermissions(space, pr) {
2174
2170
  // the `.reply.>` leaf so the daemon can't publish to the request subjects themselves — tighter than a
2175
2171
  // blanket `ctl.delivery.>` (fact-check precision, review panel). The caller slots widened to `.*.*`.
2176
2172
  `${p}.ctl.delivery.*.*.reply.>`,
2177
- // The privileged delivery-admin rail (D5 slice 5/6): same replies-only shape. Requests reach the
2173
+ // The privileged delivery-admin rail: same replies-only shape. Requests reach the
2178
2174
  // daemon on the sub below; only the supervisor cred can PUBLISH them (nats-server is the boundary).
2179
2175
  `${p}.ctl.delivery-admin.*.*.reply.>`,
2180
2176
  // LIVENESS REPLIES for the DELIVERY plane (#1577) — same replies-only shape as the two control
@@ -2255,7 +2251,7 @@ export async function mintMembershipObserverCreds(auth, identity, opts = {}) {
2255
2251
  throw new Error("mintMembershipObserverCreds: no in-memory system-account signing seed - the observer can only be minted from a system account that is being (re)provisioned, because the $SYS seed is never persisted. Rotate the system account to mint a fresh one (`cotal down` then `cotal up --rotate-sys`); a plain re-`up` reuses the existing account and its existing creds.");
2256
2252
  const signer = fromSeed(new TextEncoder().encode(auth.sys.signingSeed));
2257
2253
  const perms = membershipObserverPermissions(auth.account.pub);
2258
- // Bounded exp (D5 slice 5): the observer is `rotation-renewed` — it carries the matrix's default
2254
+ // Bounded exp: the observer is `rotation-renewed` — it carries the matrix's default
2259
2255
  // lifetime so a copied cred becomes broker-dead, but there is NO online renewal (the $SYS seed is
2260
2256
  // gone after `up`); renewal is a coordinated system-account rotation + restart.
2261
2257
  const validDates = userValidDates("membership-observer", opts);
@@ -2263,7 +2259,7 @@ export async function mintMembershipObserverCreds(auth, identity, opts = {}) {
2263
2259
  const creds = fmtCreds(userJwt, fromSeed(new TextEncoder().encode(identity.seed)));
2264
2260
  return new TextDecoder().decode(creds);
2265
2261
  }
2266
- /** The KICK-ONLY connection-evictor permission set (D5 slice 4) — a SYSTEM-account user that can do
2262
+ /** The KICK-ONLY connection-evictor permission set — a SYSTEM-account user that can do
2267
2263
  * exactly ONE thing: `$SYS.REQ.SERVER.*.KICK` (disconnect a live client by cid). It CANNOT read
2268
2264
  * CONNZ (discovery stays on the separate observer cred — never one broad sys user that both
2269
2265
  * enumerates and kills), touch any other `$SYS` verb, or reach another account's data. A leaked
@@ -2280,14 +2276,14 @@ function connectionEvictorPermissions() {
2280
2276
  sub: { allow: ["_INBOX.>"] },
2281
2277
  };
2282
2278
  }
2283
- /** Mint the scoped `connection-evictor` creds — the kick-only SYSTEM-account user D5 slice 4's live
2284
- * eviction holds. Same mint-only-at-provision property as the observer (the $SYS seed is in-memory
2279
+ /** Mint the scoped `connection-evictor` creds — the kick-only SYSTEM-account user for live
2280
+ * eviction. Same mint-only-at-provision property as the observer (the $SYS seed is in-memory
2285
2281
  * only), same fail-loud when it's absent. Paired with the observer at `up`. */
2286
2282
  export async function mintConnectionEvictorCreds(auth, identity, opts = {}) {
2287
2283
  if (!auth.sys.signingSeed)
2288
2284
  throw new Error("mintConnectionEvictorCreds: no in-memory system-account signing seed - the evictor can only be minted from a system account that is being (re)provisioned, because the $SYS seed is never persisted. Rotate the system account to mint a fresh one (`cotal down` then `cotal up --rotate-sys`); a plain re-`up` reuses the existing account and its existing creds.");
2289
2285
  const signer = fromSeed(new TextEncoder().encode(auth.sys.signingSeed));
2290
- // Bounded exp (D5 slice 5): `rotation-renewed`, same posture as the observer above.
2286
+ // Bounded exp: `rotation-renewed`, same posture as the observer above.
2291
2287
  const validDates = userValidDates("connection-evictor", opts);
2292
2288
  const userJwt = await encodeUser("connection-evictor", fromPublic(identity.id), fromPublic(auth.sys.pub), connectionEvictorPermissions(), { signer, ...validDates });
2293
2289
  const creds = fmtCreds(userJwt, fromSeed(new TextEncoder().encode(identity.seed)));
@@ -2357,7 +2353,7 @@ function renderTlsBlock(transport) {
2357
2353
  * THIS broker's operator before it is preloaded: rendering a foreign-signed account would either
2358
2354
  * refuse broker boot or, worse, advertise a tenant the broker cannot actually authenticate.
2359
2355
  *
2360
- * NOTE (W4): the MEMORY resolver is one static whole-broker map, so every mutation rewrites all of
2356
+ * NOTE: the MEMORY resolver is one static whole-broker map, so every mutation rewrites all of
2361
2357
  * it. Concurrent add/remove of spaces needs a broker-authoritative inventory with generation/CAS
2362
2358
  * and atomic promotion above this function; this renderer is deliberately pure. */
2363
2359
  export function serverConfig(broker, spaces, opts) {
@@ -2374,7 +2370,7 @@ export function serverConfig(broker, spaces, opts) {
2374
2370
  }
2375
2371
  const port = opts.port ?? 4222;
2376
2372
  const host = opts.host ?? "127.0.0.1";
2377
- // The websocket listener (item 6): LOCALHOST by default, no_tls for the dev loopback. Emitted only
2373
+ // The websocket listener: LOCALHOST by default, no_tls for the dev loopback. Emitted only
2378
2374
  // when wsPort is set — a broker with no console session client opens no ws surface.
2379
2375
  const websocket = opts.wsPort === undefined ? "" : `websocket {
2380
2376
  host: ${opts.wsHost ?? "127.0.0.1"}