@cotal-ai/connector-core 0.116.1 → 0.116.2

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.
@@ -1,8 +1,8 @@
1
1
  /** The installed Cotal version, for stamping the orientation card and other surfaces. */
2
- export const DOCS_VERSION = "0.116.1";
2
+ export const DOCS_VERSION = "0.116.2";
3
3
  export function loadDocsBundle() {
4
4
  return {
5
- "version": "0.116.1",
5
+ "version": "0.116.2",
6
6
  "generatedFrom": "docs/*.md + SPEC.md + spec/cotal-lang.md + spec/cotal.schema.json",
7
7
  "pages": [
8
8
  {
@@ -171,7 +171,7 @@ export function loadDocsBundle() {
171
171
  "kind": "Concept (informative)",
172
172
  "category": "Concept",
173
173
  "summary": "Cotal once had a privileged control rail: a fixed set of named service tiers (self / manager / admin / delivery) on their own ctl.",
174
- "body": "# The control surface\n\n> **Concept** (informative) · **For:** operators and client authors who want to know how the manager and other daemons are driven · **Normative:** [SPEC §13](../SPEC.md#13-endpoint-control-surface-v04)\n\nCotal once had a privileged control rail: a fixed set of named service tiers\n(`self` / `manager` / `admin` / `delivery`) on their own `ctl.*` subjects, with the manager\nas a special case the broker recognised by name. That rail is gone. Everything that serves\nstructured commands now, the manager, the delivery daemon, a wrapped MCP server, a\nthird-party service, is an ordinary **endpoint**: a daemon that registers a service\nidentity, publishes its contracts, and answers `describe`. `manager` is an endpoint name\nlike any other; no subject, envelope, or grant in this surface knows it specially. The\nmanager is a service on the mesh, not an authority over it: it holds only the capability\nrows its callers grant it, and serves over a scoped credential.\n\nOne part of the old rail is still served in the reference implementation. The delivery daemon\nanswers agents' durable join, leave and membership-list requests on `ctl.delivery.<owner>.<actor>`\nand the manager's admin requests on `ctl.delivery-admin.<owner>.<actor>`\n([delivery daemon](delivery-daemon.md)). [SPEC §13.11](../SPEC.md#1311-the-hard-cut) retires every\n`ctl` subject and §7 places the durable join on the `delivery` endpoint, so these two rails are\nimplementation residue the spec does not define.\n\nFor a starting point across the integration interfaces, see the [API reference](api-reference.md).\n\n## The `ep` rails\n\nOne kind, `ep`, carries every request under a mode token that says where the request\nroutes, never which verb it is (the verb rides the envelope): `one` (queue-group\nanycast, one and only one class member), `all` (scatter, every instance), and `inst` (one instance by its\nstable address). Replies come back on a `reply` rail keyed to the serving instance and its\nepoch. Around these sit the sibling planes the composites use: per-goal events, timers,\nsessions, and the journal that holds durable facts. Every request carries the caller as\nthree forge-locked tokens, `owner`, `actor`, and lifecycle `uid`, plus an unguessable\nnonce, so the broker polices who is calling in the subject grammar itself. See\n[SPEC §13.2](../SPEC.md#132-grammar) for the grammar and [§13.5](../SPEC.md#135-verbs) for\nthe verbs (`call`, `cast`, `watch`, `claim`, `scatter`).\n\n## Lifecycle identity\n\nA principal `owner.actor` is a reusable routing alias: a despawn frees the actor name and a\nlater spawn may legitimately reuse it, so the alias alone is never authority. Two further\ncoordinates make an identity durable: a **lifecycle uid**, an unguessable, never-reused id\nfor one managed lifecycle under a principal, and a **process epoch**, the fenced ownership\nepoch of the process currently animating it, advanced on every restart or takeover. At most\none live epoch owns an identity, and a superseded epoch must stop serving. Durables and\ncredentials key on the lifecycle uid, not the reusable name, which is what lets a\nsupervised restart recover the same lifecycle instead of minting a new one. See\n[SPEC §13.1](../SPEC.md#131-lifecycle-identity) and [identity & auth](identity-and-auth.md).\n\n## Service discovery\n\nNo client has compile-time knowledge of any endpoint's commands. `cotal describe\n<endpoint>` resolves a registered endpoint's command set off the wire: the reserved\n`describe` command answers the registered contract digests, the schemas are fetched from the\nspace's content-addressed contract store, recompiled, and verified against those digests.\nEach command prints with its capability class and targeting shape. `cotal invoke <endpoint>\n<command> --args '<json>'` then calls one command by name, validating the arguments as they\nwill be sent (JSON drops a key whose value is undefined) against the fetched input schema before\npublish. A refusal at that check means nothing was sent, and it is marked `not-executed`. An\nendpoint that refuses a request before running the command states `not-executed` in the reply's\n`error.outcome` too, for example on a wrong envelope version, sender, contract digest or target\nmode, or a body that does not parse. A refusal the command itself raises carries only the\noutcome it states. A refusal that does not serialize comes back as `internal`, and one too large\nto publish as `resource-exhausted`, and both keep that outcome. A\nsigned-in user invokes the same surface through their bearer, and the broker enforces each\ncommand's existing capability grant. A manager alias supplied through `--name` resolves through\nits name-keyed `inspect` command, so an authorized targeted call does not need the manager-wide\n`ps` enumeration grant. Every built-in manager command uses this\nsame trust chain, so there is nothing the built-ins can reach that a described contract cannot. The registered\n`auth` endpoint is describable the same way `manager` is: `cotal describe auth` lists\n`retire-lifecycle` and its exact-mode target shape.\nSee [SPEC §13.7](../SPEC.md#137-contracts-and-discovery) and [cli.md](cli.md).\n\nThe manager's `vitals` command reports one invocation-time sample of host CPU count and load,\navailable and total memory, and bounded local filesystem capacity. It is untargeted but resolves to\none exact Manager instance. The separate `manager.vitals` capability is issued only when the actor\nscope contains `machine-vitals`; `spawn`, `run` and `admin` do not imply it. The response contains\nmount points and aggregate byte counts, never device paths, remote endpoints, process data, command\nlines, environment values or persisted history. Unsupported measurement refuses without a partial\nor zero-valued fallback.\n\nThe manager's `resolve-cwd` command is in the `manager.spawn` capability class. It accepts an\nabsolute path on that manager's host and returns its canonical directory plus the host name. It\nrefuses a relative, missing or non-directory path with `failed-precondition`; it creates nothing.\n`spawn` applies the same check at admission, before any credentials or durables are minted. It is\nminted beside `spawn` in the operator instruments, which are the caller on a static mesh, and in a\n`spawn` holder's `manager-caller` view. The standing agent `spawn` capability does not carry it.\nA runtime that delegates seats outside the manager's host cannot use a host cwd. Its manager\nrefuses `resolve-cwd` with `failed-precondition` before any filesystem lookup, with the same\nexecution-mode refusal for every path. It returns no host name or canonical path.\n\nThe manager's `resolve-agent` command is minted beside `spawn` in the spawn capability and the\noperator instruments. It accepts the persona fields `spawn` takes (`name`, `config`, `agent`,\n`defaultAgent`) and returns `{agent}`, the harness `spawn` on that manager would launch: the flag,\nthen the persona's `agent:` pin, then the caller's default, then the manager's own default. It loads\nthe persona with the same visibility check as `spawn` and launches nothing. A detached `--resume`\nwithout `--agent` asks it before carrying a session, and a manager that does not serve it refuses\nthe call.\n\nOn a delegated runtime, both `resolve-agent` and `spawn` refuse an explicit persona `config`\nbefore any lookup of that path. Absolute, relative and bare-name config overrides receive the\nsame `failed-precondition` refusal. Select a named catalog persona through `name` instead.\nLocally executing managers retain their config-path behavior. A resolved manifest uses its own\nvalidated, host-materialized persona resource and is not a caller-selected config override.\n\n`spawn` refuses an empty or whitespace-only value in any of its optional string fields, such as\n`role`, `agent` or `identity`, with `bad-request` naming the field. To take the persona file's value,\nomit the field.\n\n### Inspecting a managed name\n\nManager `inspect` keeps its successful response as the live managed-agent row. A live hit does\nnot read durable lifecycle state, so a temporary records-store failure cannot break inspection of\nan agent the manager currently holds.\n\nOn a live miss, a static manager point-reads its durable slot row. A name with no slot, or a slot\nwhose phase is `retired`, remains `not-found`. A nonterminal slot returns\n`failed-precondition` with `error.details[].kind =\nai.cotal.manager.static-slot-observation`. The detail carries the slot's `slotPhase`,\n`owner`, `actor`, `slotLifecycleUid`, `cleanupComplete` when recorded, and `slotRevision`. It\nthen carries the separate lifecycle head's `headState`, `headOp` when present,\n`headLifecycleUid`, and `headRevision`. Head fields are absent when provisioning has not written\nthe lifecycle head yet.\nThe error message carries the same diagnostic summary so string-only operator paths do not hide\nthe structured detail.\n\nA slot row records the manager instance that owns it. In a space with more than one manager, the\nclass queue can hand `inspect` to an instance that does not host the name. When the row names a\ndifferent instance and is not `retired`, the miss returns `failed-precondition` with the same\ndetail plus `ownerInstanceId`, which names the only manager that can act on it. The message names\nboth instances, so a caller that reads only the string can tell it from `not-found`. A sibling's\n`retired` row remains `not-found`. A named `cotal_despawn` resolves its target through this read\nand cannot address an instance, so it asks again until the owning instance answers, up to 16\ntimes.\n\nThe slot is read before the head. These records do not form one atomic snapshot, so the detail\nalso carries `readOrder: [\"slot\", \"head\"]` and `consistency: \"ordered-not-atomic\"`. A head can\nadvance between the reads. The issuance gate is not projected because the retirement operation\nneeded for this diagnosis is already recorded on the head, and reading a third record would add\nanother non-atomic edge without changing the per-name result.\n\nIf either durable read fails or exceeds its bound, the miss returns `unavailable` with\n`ai.cotal.manager.static-slot-read-failed` rather than claiming the name is absent. That detail\nnames the inspected `name`, the failed `record` (`slot`, `head`, or `slot-or-head` when the layer\ncannot distinguish them), and `operation: \"read\"`. User-auth managers do not own `mgrslot` rows,\nso their inspect misses remain live-map reads.\n\nFor Linux custodied seats, retirement requires the runtime's process-exit evidence before\nfreeing the alias or deleting its credentials and delivery state. Socket loss alone is not\nproof of exit. The runtime retains the record captured at launch or adoption so a clean\ncustodian exit can unlink its file without losing the recorded boot and process identities.\nIf the file is missing, reaping uses that retained record and the existing kernel identity\nchecks. An unknown reference without either record refuses cleanup. Reused process ids\nare never signalled on the strength of the old record.\n\n### Listing the durable slots\n\nManager `slots` (`manager.read`, untargeted) lists the durable static slot rows this manager\nowns. Only static managers hold these rows: a user-mode or open manager answers\n`failed-precondition`, and a manager whose durable store is not standing answers `unavailable`.\nEach row carries the same `readOrder` and `consistency` fields `inspect` uses, because the list\nis read the same way: torn across rows as well as within each row's slot/head pair.\nWith no arguments, retired rows remain excluded. From manager cluster revision 32,\n`{names: [\"worker\"], includeRetired: true}` point-reads up to 100 distinct aliases and\nincludes their retired rows. An absent or sibling-owned slot is omitted, not reported\nas retired. Each returned row retains its principal, lifecycle UID, slot/head revisions,\nphase and any native cleanup-complete fact. Consumers must match every requested\nincarnation; a missing live row or an accepted stop is not a retirement result.\n`live` reflects the manager's live roster at render time, not the durable row. A slot row\nis never deleted, so a row whose latest operation is a DEL or PURGE marker is corruption:\nthe list answers `unavailable` naming that row, as `inspect` does for its name.\n\n### Static chat sessions\n\nFrom manager cluster revision 34, a static manager admits chat sessions with\n`chat-session-open` and ends them with `chat-session-retire`. Both are untargeted and in the\n`manager.chat` class. Only operator instruments carry their rows; the `spawn` and `run`\ncapabilities do not. A user-mode or open manager refuses both with `unimplemented`.\n\n`chat-session-open` takes `{subscribe, allowSubscribe, allowPublish, label, ttl, sealTo}`. The\nthree lists are a spawn's, under a spawn's rules: `subscribe` is the session's initial channels,\n`allowSubscribe` its read ceiling (empty means `subscribe`, and `subscribe` must lie within it),\nand `allowPublish` its post list (empty means none). Each may be omitted. A session can join any\nchannel under its ceiling, patterns included. A concrete event channel of another principal is\nrefused, as it is for a spawn. The manager draws a `chat_<26 base32>` alias and a fresh nkey\nidentity, runs the static slot activation, provisions the session's DM and DELIVER durables and\nACL row, and mints an agent-profile leaf with no role, capabilities, endpoint rows or issuance.\nThe leaf expires after `ttl` seconds, at most 900, and is never renewed. Because the leaf is not\nan issuance, the manager writes its credential ledger row itself before the credential leaves the\nprocess, and that row is what retirement marks revoked and verify-evicts.\n\n`sealTo` is a one-time curve public key (`X…`) the caller mints and keeps the private half of. The\nreply is `{alias, actor, lifecycleUid, expiresAt, sealer, sealed}`: `actor` is the nkey the\nbroker authenticates, `alias` names the slot, and `expiresAt` is in epoch milliseconds. The\ncredential is not in the reply in the clear. `sealed` is base64url, sealed to `sealTo` from the\none-time `sealer` key with the NATS xkey format, and opens to the credential bound to the space,\nthe admitting manager instance and every field of the reply. A generic invoke, an agent or a\nbrowser sees only that ciphertext. The chat adapter opens it once, refuses it unless every bound\nfield matches, and keeps the credential in memory.\n\n`chat-session-retire` takes `{alias, actor, lifecycleUid}` and runs the static terminal. It refuses\nbefore any effect unless the alias is a chat alias whose slot this manager instance owns at that\nuid and actor. It answers `retired`, `alreadyRetired`, or `failed` with a `retirement pending:`\nreason while the slot stays held. Retirement marks the credential's ledger row revoked, verifies\nthat the session's principal has no broker connection left, tears down its broker footprint and\nretires the slot. A static mesh has no broker-side credential revocation, so a copy of the leaf\ncan still connect with the permissions it carries until its expiry. An ordinary spawn refuses any\nname that starts with `chat_`.\n\nThe manager that admitted a session retires it at its expiry when nothing retired it sooner, so a\nlost reply or an abandoned client does not hold the slot. Its stop retires every session it still\nholds, with or without its agents, and names each one it could not retire; a stop that preserves\nthe manager's state leaves them. Its own startup sweep never retires a session it is admitting or\nholds. A session that none of these retired stays held until the next start of that manager\ninstance.\n\n## Spawn is a goal\n\nLong-running commands are **actions** ([SPEC §13.6](../SPEC.md#136-composites)): the caller\nsubmits with a client-generated `goalId` and a request fingerprint, the endpoint records a\ndurable accept or reject decision, progress rides per-goal events, and the work ends in one\nterminal outcome (`succeeded`, `failed`, `cancelled`, `expired`, or `uncertain`). Spawn is\nthe reference case. Rather than block the caller for up to 30 seconds while an agent comes\nup, the manager accepts the goal and returns the allocated identity at once:\n\n```json\n{\n \"name\": \"reviewer_2\",\n \"owner\": \"u_...\", \"actor\": \"reviewer_2\", \"uid\": \"...\",\n \"goalId\": \"...\", \"fingerprint\": \"...\",\n \"readinessDeadlineMs\": 30000,\n \"executor\": { \"lifecycleUid\": \"...\", \"epoch\": 3 }\n}\n```\n\nThe `uid` is the lifecycle the agent runs at. On a participant manager whose host enrolls its\nagents, the host picks that uid, so the manager accepts the goal only after the host has answered.\nA host refusal there refuses the spawn, and no goal is bound.\n\nResubmitting the same `goalId` returns the same acceptance. A `goalId` belongs to the caller that\nsubmitted it, so another caller's spawn under the same id is its own goal with its own\nacceptance. A sibling instance or a restarted one\nanswers it from the identity the accepting instance recorded before it replied, owner included.\nWhen that record names no owner because an older manager wrote it, the resubmission is refused\n`unavailable`. Once the goal has ended, the accepting manager keeps its acceptance for five more\nminutes. After that, and at any other instance, the resubmission is answered from the goal's\nterminal and never accepted again: a `succeeded` terminal names the agent, so it returns the same\nacceptance, and any other outcome refuses it `failed-precondition` with that terminal attached.\n\nThe name is the one actually allocated: a persona-derived collision is auto-numbered\n(`reviewer`, then `reviewer_2`), while a hard-pinned `--name` that collides with a live\nagent is refused at accept, before anything is minted. Auto-numbering never hands out a numbered\nname it has already issued in that manager process, even after the agent holding it is gone, so\na collision takes the next number. Only numbering consults that history: a hard-pinned `--name`,\nor a persona whose own name is a numbered string, takes that name whenever it is free, and\nnumbering does not skip a string such a spawn held before. The triple plus `goalId` let the\ncaller follow progress (connector handoff, process launched, presence join) and reconcile\nlater against the exact instance that accepted. Presence within the manager's default\n30-second readiness window, or a connector's declared bounded window, settles the goal\n`succeeded`; an early process exit is `failed`; the window passing with neither is `uncertain`,\na bounded, durable outcome that a later `ps` or status read settles against the live roster.\n`uncertain` is a real terminal outcome, not an absence and not a silent hang. It carries the\ndiagnosis of whoever owned the deadline: for a launch that\nnames the agent and says to inspect it rather than re-issue, since re-issuing after a launch\nthat in fact succeeded mints a duplicate. A follower keeps the acceptance as the data of any\nterminal other than `succeeded`, so `cotal_spawn` returns an uncertain launch as a pending result\ninstead of an error: it names the allocated agent, its id, and its manager, and tells the calling\nagent to watch the roster. A committer that supplies no diagnosis falls back to\n\"the success signal did not arrive within the readiness deadline\". The agent's own eventual\nstate is then observable on its presence record.\n\nThe acceptance carries that exact `readinessDeadlineMs`. A synchronous follower treats its own\nrequest deadline as a floor and waits through the accepted readiness budget plus delivery margin,\nso a connector-specific slow boot cannot be reported as a caller timeout while the manager is\nstill legitimately waiting for its terminal.\n\nThe manager keeps a spawn or launch exception's error code and details when turning it\ninto a refusal. Failed `ControlReply` values keep their code and details at the serving\nboundary. A host enrollment refusal that proves nothing was executed also keeps its\ncode in the public `Manager.startAgent` reply after staged-secret cleanup. A reply\nwithout a code remains `failed-precondition`.\n\nA spawn that is **refused** because a lifecycle barrier already holds the actor (a frozen\nissuance gate, a retiring alias, a retired uid) is not a wait-timeout. The manager already\nknows the blocked op (`registration` / `retirement` / `activation` / `takeover`), the `opId`\nholding it, and the remedy when one exists (`retry`, `cotal reconcile-gate`). The detail\ncarries `headState` (`active` / `retiring` / `retired`) only when the refusing site read the\nlifecycle head, and `gateState` (`frozen` / `retired`) only when it read the issuance gate. A\ngate frozen by a takeover or a registration says nothing about the head, so that refusal\ncarries `gateState=frozen` and no `headState`. Those facts ride `error.details[]` as\n`kind = ai.cotal.ep.lifecycle-blocked` and are also appended to the error string, so a\ncaller that only prints `error.message` still sees them. The CLI and the connector tools hand a\nrefusal on in one shape, so `cotal spawn --detach` keeps the same code, details, rendered facts\nand acceptance data as `cotal_spawn`. A connector that collapses the\nrefusal to \"startup failed (unknown)\" or a SPEC 13.6 wait-timeout is hiding a knowable\nstate, not reporting a missing one.\n\n## Instance routing\n\nA space can run more than one manager. Each manager persists a stable logical instance id\nacross restarts and advances its process epoch when it comes back, so callers address a\nspecific manager without caring which process currently serves it. A start serves only at the\nepoch its own registration committed, never at the epoch of a later start of the same instance.\nOn a static mesh or from an unbound open caller, an untargeted spawn rides class anycast\n(any manager may accept, and the acceptance records which one did). An open managed seat's\npersona definition, list, show and spawn tools default to its launching manager. Its generic\nmanager describe and self-targeted invoke use that launch address too. An explicit existing\npersona or spawn selector still selects that instance. Static credential grants and user-auth\nissuer selection are unchanged. The library's `describeService` accepts an optional `instanceId`;\na pinned describe does not read or populate the endpoint-only class cache.\n`cotal spawn <persona> --detach --on <instance>` and `cotal_spawn(instance: \"<instance>\")`\npin one instance by its exact id, as `--on` does for `cotal ps`, `cotal models` and every hosted\n`cotal run` verb, and `instance` for `cotal_run`, `cotal_persona` and `cotal_personas`. A foreground CLI spawn has no manager to pin and refuses the\nflag. An MCP pin that does not resolve is refused without falling back to class anycast. There are no ordinal\naliases and no short forms: wherever a display names an instance you can address, it prints\nthe whole id, because both surfaces take nothing else.\n\nOn a user-auth mesh, manager commands obtain a short-lived `manager-caller` view from the\nexchange. It authorizes one concrete manager instance using the caller's current actor grant and\nthe host's registered service records. Discovery and invocation both use that instance's `inst`\nroute. This view grants no registry scan or class queue. It adds no command capability except the\nthree reads a launch needs: a view whose actor holds `spawn` may call `status`, `models` and\n`resolve-cwd` on that instance, subject to the execution-mode limit above. A `run`-only or no-scope view may not, and `ps` and `slots` stay with\n`admin`. A user mesh's co-located manager answers every owner's view, so its `status` counts only the\ncaller's own seats, as `ps` would list them, unless the caller holds `admin`. An absent,\nambiguous or unauthorized selection refuses before the command is sent. An ambiguous one lists the\nowner's live manager instance ids and names the caller's way to pick one: `--on <instanceId>` for\nthe CLI, `--manager-instance <instanceId>` for `cotal agent-bearer --manager-call`, and the\n`instance` argument for an agent's tools.\nA pin changes routing, not the caller's grant.\n\nManaged launches carry `COTAL_MANAGER_INSTANCE` so their tools address the manager that launched\nthem; a tool's `instance` argument must name that same manager. The `cotal` commands run from their\nshell select it too, unless `--on` names another instance. Existing unbound sessions can use the exchange's unique authorized selection without\nreplacing their actor or conversation. The connector uses a separate control connection; the\nstanding message connection and its credential source are unchanged. Accepted spawn goals are\nfollowed on that renewing connection, using its existing caller-scoped progress grant, so a long\nreadiness budget does not depend on the short-lived control credential. The follower confirms its\nprogress subscription with the broker before submitting on the separate connection. A caller still\nchecks the resolved instance and epoch, and never retries an ambiguous mutation outcome.\n\nThe manager's `goal-result` command accepts `{goalId}` and returns `{goalId, result?}`. It reads\nonly the authenticated caller's owner, actor and lifecycle through the manager's separate trusted\ngoal-writer connection. The caller receives an attributed reply, never a raw JetStream reader\ngrant. Each read is admitted by the connection's broker-enforced command grant. A live user-auth\nconnection remains bounded by its bearer expiry after revocation; a renewed connection is checked\nagainst fresh authority. There is no separate per-read ledger check. An absent `result` means no\nterminal is recorded; it does not prove the goal is running or permit another submission. The\nexisting trusted goal-writer's leader-served EPF read is space-wide at the broker; the handler\nconfines it to this endpoint and caller triple.\n\nThe manager's reserved `cancel` command accepts `{goalId, mode?}` and returns `{goalId, state}`.\nIt is served for a turn the manager relays. The goal is the authenticated caller's own, so a caller\nwithdraws only a turn it submitted. The turn ends `cancelled`, its seat is not shown it again, and a\nlater yield of it is answered with that terminal. A goal that already ended is refused\n`failed-precondition` with its cached outcome attached, and a goal this manager does not relay is\nrefused without being changed. So is a second cancel that arrives while a first is still ending the\nturn; a first that fails leaves the turn pending unless something ended it meanwhile. A workflow\nrun sends it for the turn, ask attempt or escalation of a branch it cancelled.\n\nA followed mutation requires a manager whose attributed describe includes `goal-result`. Update\nthe manager, issuer and client together before using that recovery path. Reloading an issuer alone\ncannot change an already-running participant manager. Recovery re-resolves the accepting instance's\nepoch, preserves the caller lifecycle and validates the result against the accepted goal and any\nacceptance fingerprint. Stopping the caller ends its observation, not the already accepted goal.\n\nA followed call resolves the endpoint within its deadline before the submission starts, so a\nrefused or unanswered describe surfaces as its own error. On a user-auth mesh that preparation also\nobtains the caller's `manager-caller` view and opens its connection, and a failure there surfaces\nunchanged. The control connection uses the remaining preparation deadline, including time spent\nobtaining the bearer, rather than a separate two-second limit. A deadline that passes during those\nsteps reports that the request was not run. The\ndescribe then spends what is left of the deadline, so a describe that draws no reply still reports\nitself as unanswered.\nA describe or command publish that the broker refuses reports `not-executed`.\nCancellation before submission reports `not-executed`. Once submission starts, cancellation or a\nlost reply reports an unknown outcome unless an attributed refusal proves otherwise. A received\nrefusal remains a refusal even when stop races it. Local failures do not invent responder identities.\nThe follower owns its subscription, timers and read cancellation signal. Reconciliation begins\nbefore the wait deadline, and late read completions cannot settle an expired observation. Its read\ncallback receives the accepting caller triple, remaining budget and abort signal; borrowed bearer\ncommands and control connections use that signal. An in-flight dial that finishes after cancellation\ncloses without publishing. A local reply-subscription failure prevents publication and is observed\nby the same request promise, including when the transport is closing or draining. Request\ncancellation does not revoke or resubmit the accepted operation.\n\n\"Only one manager per space\" is not the current invariant. A split topology that keeps the\nbroker host manager-free is still a topology choice: `cotal up --no-manager` on that host starts no\nmanager, and `cotal supervise --server` runs the manager elsewhere ([Run a mesh](run-a-mesh.md)).\nA broker host that already runs a manager stops it only after `✓ manager up` in\n`.cotal/manager.<spaceKey>.log` (detach stdout listing `manager` is pidfile liveness, not a\nteardown boundary). A controller stack stops it with\n`cotal service stop stack-manager --space <s> --yes`; a legacy stack has no command that stops only\nits manager. Extra live managers are addressable, not an error.\n\nThe reserved `describe` bootstrap is the one request the resolver may repeat while waiting: it is\nread-only, it is re-published under the same request binding, and every attempt stays inside the\noriginal deadline. This covers the startup window where Core NATS discards the first request before\nthe manager has subscribed. If the connection closes while the resolver waits, the describe fails\ncleanly instead of throwing from the retry timer. The resolved command is never repeated by this\nreadiness behavior.\n\nThe describe and the contract store reads after it share the resolver's one deadline, so a slow\nstore read fails the resolve with `deadline-exceeded` when that deadline expires. `cotal invoke` passes its\n`--timeout` as that deadline (default 10000 ms) and gives the reply what the resolve leaves of it.\n`cotal describe` has no `--timeout` and passes 10000 ms. Cancelling a\nresolve settles a store read in flight instead of waiting for it to return. When one store read\nfails, the resolve fails with it and fetches no further command contracts; fetches already under\nway finish on their own.\n\nThe resolve and the invoke are separate trips through the same anycast queue, so in a\nmulti-manager space an unpinned call can land on an instance the caller did not resolve. Every\ncall carries the incarnation it resolved against, and a manager that is not that incarnation\n**refuses before running the command**, so the failure an operator sees says the command did\nnot run, and re-issuing it cannot duplicate the effect. That is the difference that matters for\na mutation: the older behaviour detected the mismatch on the reply, after the manager had\nalready acted, and could only tell you to go and check. `--on` still matters for reaching a\nspecific manager (`ps`, `stop`, `attach`, `spawn --detach`), but it is no longer what stands\nbetween a split and a duplicated spawn. Against a manager older than this fence the refusal is\nstill after the fact, and its message says so. The re-issue is automatic only when the refusal\nstates `not-executed` in its `outcome` field; a refusal that omits the field, or states\n`unknown`, is surfaced to the caller instead of repaired, because neither proves the command did\nnot run. The CLI's manager commands, `cotal invoke`, the `cotal run` verbs and the manager row of\n`cotal status` re-describe and re-issue an unpinned call after each such refusal, up to 16 times,\nso a split reaches the operator only when every attempt split. A hosted run's own manager calls\nuse the same bound. A pinned call is never re-issued. An agent's own manager\ntools, such as `cotal_spawn` and `cotal_despawn`, re-describe and re-issue with the same bound,\nincluding the goal-result read that follows a spawn to its outcome.\n\nAn unpinned targeted call, such as `cotal_despawn` or a hosted run's turn relay, can also reach a\nmanager that does not host its target, because each manager resolves targets against the agents\nit runs. That manager refuses with `expired` and `not-executed` and says it holds no mapping for\nthe target, and the same re-issue repairs it within the same bound. An agent that no manager hosts\nstill ends in that refusal once the re-issues run out. A pinned call gets the refusal of the\ninstance it named.\n\nA verified Manager `status` reply includes `host`, the answering process's host name, and\n`version`, the running `@cotal-ai/manager` package version captured when its module loaded.\nThese fields are advisory display metadata. They do not select a Manager, authorize a caller\nor determine placement. Use the verified responder's `instanceId` for attribution. Clients\nmust accept status payloads that omit either field and leave the missing value unknown.\nThe optional fields advance the Manager cluster revision to 28.\n\nA manager whose boot inventory marked every declared connector unavailable does not subscribe\n`spawn` or `launch` on the class `one` rail. Those commands stay on scatter and on this\ninstance's `inst` rail, so a sibling that can launch them can take an unpinned spawn, and a\ncaller that pins this instance with `--on` still gets a named harness refusal. `describe`\nstill lists the commands: the instance rail serves them, and `describe` itself stays on the\nclass rail (SPEC 13.7). An unpinned `spawn` can therefore bind-fence: `describe` may land on\nthe skip member while `spawn` lands on a sibling, the command was not run, and the caller\nre-issues or pins `--on`. `status` reports `classSpawn: false` when that skip is in effect.\nWhen no manager takes the class queue, the broker answers an unpinned `spawn` with no\nresponders, and the caller classifies that `not-executed` (SPEC 13.3).\nA manager that can launch some connectors keeps the class rail. If the queue hands it a\nharness its inventory marked unavailable, the refusal names `--on` because the standing serve\ncredential cannot read sibling inventories. Pin the capable instance (the whole id, as `ps`\nprints it).\n\n`ps` and\n`status` become a **scatter** across every registered instance: the caller freezes the\nexpected set from the service registry, invokes each under a shared deadline, and merges the\nresults with per-instance attribution. A non-answering instance is labelled as registered\nwith no answer within the deadline, never silently omitted. See [SPEC §13.5](../SPEC.md#135-verbs) (scatter) and [cli.md](cli.md).\n\nThe expected set comes from the **registry**, which records registration rather than liveness.\nAn instance that crashes never deregisters, so it stays in the set and the gather has nothing\nleft to wait for but an answer that cannot come. It pays the whole deadline, on every scatter,\nindefinitely. A scatter can therefore be given a per-instance liveness probe: when the broker\nitself reports that an instance holds no subscription on its own instance rail, the gather stops\nwaiting for it. Only that affirmative report counts. A lapsed presence entry, a probe that timed\nout, and a probe that failed are all *absence of evidence*, and treating any of them as death\nwould turn a slow correct answer into a fast wrong one, so they leave the full deadline standing.\nNothing about the outcome changes either way: an instance that did not answer is still\nunreachable, still surfaced, and the scatter is still not complete.\n\nThe probe is supplied by the **caller**, not invented by the scatter. Asking about an instance is\na publish on that instance's rail, and a credential that holds no row for it is refused by the\nbroker asynchronously, while the publish itself returns normally. The probe verb watches for that\nrefusal and raises it as `permission-denied` naming the rail, so it is never mistaken for a quiet\ninstance, and it never burns the probe budget waiting out a refusal. Only the layer that\nminted the credential knows which ids it may ask about, so that layer asks about those and no\nothers. `cotal ps` freezes the class on its first connection, re-mints an instrument pinned only\nto the frozen ids, and scatters on a second; a refusal the broker raises anyway is printed and\nthe instance's row says the probe was refused, which is a fact about the credential, not about\nthe instance.\n\nThis does not help against an instance that is **connected but not answering**. A hung manager\nholds its subscriptions, so it is indistinguishable from a slow one, and it still costs the full\ndeadline. That is the correct result, not a gap in the probe.\n\n### Deregistration\n\nA probe makes a dead registration cheap to skip; it does not remove it. Removal is the\nregistration's own exit, and there are two explicit routes to it\n([SPEC §13.5](../SPEC.md#135-verbs): a deleted `svc` spec *is* the deregistration).\n\nA manager that stops cleanly removes its own registration, so an ordinary shutdown leaves no stale\nrow. The delete is pinned to the registration revision that process wrote. When a successor has\nregistered the same instance since then, the stop logs that and leaves the successor's registration\nalone. It refuses that delete while this instance holds the endpoint governance slot at the live\nissuance-gate generation (a registration still completing its reopen). A leftover slot whose\ngeneration is behind that live generation is not in-flight and does not block the stop. A manager\nthat cannot renew or read its lease keeps serving, stays registered, and retries. If another process\nholds the same instance key, that process has taken the instance over, so this one logs the conflict\nand exits without deregistering, leaving the successor's registration alone.\n\nA restart that died *mid-registration* is a different residue: the issuance gate stays frozen under\nthat op. The successor completes the dead registration on boot when the freeze-holder is\naffirmatively gone under a complete CONNZ sweep (the same composition as\n[`cotal reconcile-gate`](cli.md#reconcile-gate)). A committed spec write is finished under that\nsame freeze; only a definite no-commit abort-reopens and then runs the normal takeover.\nOnce that reopen commits, the registration has completed: a governance slot it then fails to release\nis left behind the live generation, as on a normal registration, and does not fail the restart.\nIt does not invent a TTL and it does not start a new freeze over a still-held one.\n\nThat residue has a second half, and it is the endpoint governance slot rather than the gate. Every\nregistration takes the endpoint-wide slot before it publishes its spec and holds it until its own\ngate reopens, which is what serializes registration for the endpoint. An instance that stopped\nbetween those two points leaves the slot held with no registration behind it, so the endpoint\nrefuses new registrations while nothing is actually in flight. The slot is stamped with the\ngeneration of the gate its holder had frozen when it took it, and a slot is promoted only at that\nsame generation. So once the holder's gate has reopened past the stamp, the slot can never be\npromoted by anyone, and the next registration for that endpoint replaces it. That reclaim is part of\nan ordinary start and needs no operator step.\n\nA slot whose holder's gate is still at the stamped generation is a registration that is genuinely in\nflight, and it keeps refusing. The two states read differently only in the holder's gate coordinate,\nso reopening that gate is what separates them: the holder's own restart heals it on boot, and\n[`cotal reconcile-gate`](cli.md#reconcile-gate) is the operator's route when the boot path cannot\nrun. The registration path is the slot's only writer, and neither repair command writes it.\nA registration that cannot read the holder's gate at all refuses, because an unreadable gate does\nnot distinguish the two states either. Each of these refusals carries\n`kind = ai.cotal.ep.foreign-slot-held` in `error.details[]` with the holder's instance id and the\n`condition` that refused: `in-flight` for a holder gate still at the stamp, or `no-seam`,\n`unreadable`, `garbled` or `behind` when the registration could not read that gate or read it below\nthe stamp. A remote manager asks its host to reconcile the holder only on `in-flight`, the one\ncondition a gate repair can clear.\n\nFor the instance that cannot cooperate, an operator names it:\n`cotal endpoint deregister <endpoint> <full-instance-id>`\n([cli.md](cli.md#endpoint-deregister)). It removes the\nrecord only on the same evidence `cotal ps` acts on: the broker reporting nothing subscribed on\nthat instance's own rail. It refuses if the instance answers a describe, refuses if the probe could\nnot run at all, and refuses if the instance is merely quiet, because a hung process still holds its\nsubscriptions and is therefore not affirmed gone. It also refuses while that instance holds the\nendpoint governance slot at the live issuance-gate generation (a registration still completing);\na leftover slot behind that generation is not in-flight and does not block. Nothing sweeps the\nregistry on an age threshold or on silence.\nAn instance that is deregistered while it is merely wedged re-registers over the tombstone on its\nnext start, which is what makes the operator's decision a recoverable one.\n\n## Attach sessions\n\n`cotal attach` no longer returns a `ws://127.0.0.1` URL. It creates a one-use, holder-bound\nsession offer: the manager mints a token bound to the caller, the target lifecycle, its own\ninstance id and epoch, and an expiry, and replies with a session id and expiry only, no URL\nand no secret in the reply. The CLI redeems the offer over the mesh (a second redeem is\nrefused). On a registered open mesh that redeem is a bare connection, the same path other\ncontrol commands already use; on a static-auth mesh it is still a session-caller credential\nminted from the resolved root's seed. On a user-auth mesh the CLI holds no seed: it exchanges its\nlogin and the grant for a `session-caller` view bearer, and the callout mints the same caller rails\nwith the grant's expiry. Terminal bytes then stream on core-NATS session subjects\nscoped to the two parties. Backpressure is a bounded in-flight window with an explicit drop notice, never\nsilent loss; a late attach still repaints the full screen from a replayed terminal\nsnapshot. Close, expiry, target despawn, and a manager restart are distinct, surfaced end\nstates: a restarted manager's successor refuses the old epoch's sessions. `cotal attach`\nreconnects when its link dies by asking the manager for a new session\n([CLI](cli.md#managed-seats)).\n\n## Seat input\n\n`attach` is a stream, so it is the wrong shape for a program that wants to send one line: it\nholds a session open and expects a terminal at the caller's end. The `input` command is the\nother half. One authorized call writes text into a running seat's terminal as if it had been\ntyped there, and answers with the seat and the number of bytes delivered.\n\nIt exists for **harness commands**. A line beginning with `/` (`/compact`, `/clear`, `/model`)\nis neither chat nor an event: the agent's own harness handles it, and the keyboard is the only\nway in. An external control surface that can already read a seat's turns and talk to it still\ncannot drive it without this.\n\nThe op is targeted, rides the `manager.lifecycle` capability, and declares authz modes `owner`\nand `any`, the row shape `attach` and `despawn` already carry, checked by the same authorization.\nEnter is appended unless the caller suppresses it, and nothing is echoed back, since the resulting\nturns already have somewhere to go.\n\n**Who may call it is narrower than either of those**, and the reasoning is worth stating because\nthe natural assumption is wrong. `despawn` and `attach` are granted to anything holding `spawn`;\n`input` is granted only to operator credentials. The tempting argument for treating them alike is\nthat an attach session's `write` already reaches the same terminal, so `input` adds nothing. It\ndoes not reach it: an attach yields a signed session offer, and redeeming one needs a per-session\ncredential minted from the space signing seed, which no agent holds. So `input` would be new\nauthority, and the own-owner rule that bounds `despawn` covers every seat under an owner rather\nthan only the ones a caller launched. Killing a peer is denial; typing into a peer is control of\nit. The write therefore sits with the credential that is already the administrative authority for\nthe domain.\n\nOnly a runtime that owns the child's input stream can serve it. The `pty` runtime does; the\nexternal terminal runtimes attach to a process they do not own, and there the command refuses\nand names the runtime rather than dropping the keystroke. A seat that is not running refuses for\nits own reason, and the two are distinguishable, so a caller can tell \"this will never work\"\nfrom \"not right now\". Both refusals carry `not-executed`, because nothing was typed. A write the\nruntime rejects once delivery has started states no outcome, so a caller reads it as `unknown`.\nThe manager's other control refusals follow the same rule: one raised before the command's first\neffect, such as a denied caller, a stale target or a missing persona file, carries `not-executed`.\nSee [cli.md](cli.md#input).\n\n## Grants\n\nThere is no broad control credential. A caller holds one capability row per command it is\nallowed to send, and minting maps each named capability to the request subjects it needs and no\nothers. The manager serves over a scoped serve credential that can answer and\nreply but cannot, for instance, write another endpoint's records or forge a goal terminal;\nthe goal-fact writer and the session writer are separate, narrowly scoped credentials the\nbroker fences by subject. Authorization is checked at the serving boundary, and for actions\nit linearises at acceptance: a spawn refused there mints no reservation and leaves no\nprocess. See [SPEC §13.9](../SPEC.md#139-authority-boundary) and\n[identity & auth](identity-and-auth.md).\n\nA carried resume transcript never rides the rails. The operator-only `transcript-receive` command\nanswers whether to upload and hands back a one-time claim for `spawn`, and the bytes travel through\nthe target instance's own transfer bucket under two one-shot credentials: a writer the operator\nmints for that one transcript, and a reader the target instance mints for its own bucket, or that\nthe host issues a remote manager through its `transferReader` authority operation.\n\n## See also\n\n- [Architecture](architecture.md), where the manager and the wire fit in the whole system.\n- [CLI](cli.md), for `describe`, `invoke`, `spawn`, `ps`, `status`, `attach`, and `input`.\n- [SPEC §13](../SPEC.md#13-endpoint-control-surface-v04), the normative contract.\n"
174
+ "body": "# The control surface\n\n> **Concept** (informative) · **For:** operators and client authors who want to know how the manager and other daemons are driven · **Normative:** [SPEC §13](../SPEC.md#13-endpoint-control-surface-v04)\n\nCotal once had a privileged control rail: a fixed set of named service tiers\n(`self` / `manager` / `admin` / `delivery`) on their own `ctl.*` subjects, with the manager\nas a special case the broker recognised by name. That rail is gone. Everything that serves\nstructured commands now, the manager, the delivery daemon, a wrapped MCP server, a\nthird-party service, is an ordinary **endpoint**: a daemon that registers a service\nidentity, publishes its contracts, and answers `describe`. `manager` is an endpoint name\nlike any other; no subject, envelope, or grant in this surface knows it specially. The\nmanager is a service on the mesh, not an authority over it: it holds only the capability\nrows its callers grant it, and serves over a scoped credential.\n\nOne part of the old rail is still served in the reference implementation. The delivery daemon\nanswers agents' durable join, leave and membership-list requests on `ctl.delivery.<owner>.<actor>`\nand the manager's admin requests on `ctl.delivery-admin.<owner>.<actor>`\n([delivery daemon](delivery-daemon.md)). [SPEC §13.11](../SPEC.md#1311-the-hard-cut) retires every\n`ctl` subject and §7 places the durable join on the `delivery` endpoint, so these two rails are\nimplementation residue the spec does not define.\n\nFor a starting point across the integration interfaces, see the [API reference](api-reference.md).\n\n## The `ep` rails\n\nOne kind, `ep`, carries every request under a mode token that says where the request\nroutes, never which verb it is (the verb rides the envelope): `one` (queue-group\nanycast, one and only one class member), `all` (scatter, every instance), and `inst` (one instance by its\nstable address). Replies come back on a `reply` rail keyed to the serving instance and its\nepoch. Around these sit the sibling planes the composites use: per-goal events, timers,\nsessions, and the journal that holds durable facts. Every request carries the caller as\nthree forge-locked tokens, `owner`, `actor`, and lifecycle `uid`, plus an unguessable\nnonce, so the broker polices who is calling in the subject grammar itself. See\n[SPEC §13.2](../SPEC.md#132-grammar) for the grammar and [§13.5](../SPEC.md#135-verbs) for\nthe verbs (`call`, `cast`, `watch`, `claim`, `scatter`).\n\n## Lifecycle identity\n\nA principal `owner.actor` is a reusable routing alias: a despawn frees the actor name and a\nlater spawn may legitimately reuse it, so the alias alone is never authority. Two further\ncoordinates make an identity durable: a **lifecycle uid**, an unguessable, never-reused id\nfor one managed lifecycle under a principal, and a **process epoch**, the fenced ownership\nepoch of the process currently animating it, advanced on every restart or takeover. At most\none live epoch owns an identity, and a superseded epoch must stop serving. Durables and\ncredentials key on the lifecycle uid, not the reusable name, which is what lets a\nsupervised restart recover the same lifecycle instead of minting a new one. See\n[SPEC §13.1](../SPEC.md#131-lifecycle-identity) and [identity & auth](identity-and-auth.md).\n\n## Service discovery\n\nNo client has compile-time knowledge of any endpoint's commands. `cotal describe\n<endpoint>` resolves a registered endpoint's command set off the wire: the reserved\n`describe` command answers the registered contract digests, the schemas are fetched from the\nspace's content-addressed contract store, recompiled, and verified against those digests.\nEach command prints with its capability class and targeting shape. `cotal invoke <endpoint>\n<command> --args '<json>'` then calls one command by name, validating the arguments as they\nwill be sent (JSON drops a key whose value is undefined) against the fetched input schema before\npublish. A refusal at that check means nothing was sent, and it is marked `not-executed`. An\nendpoint that refuses a request before running the command states `not-executed` in the reply's\n`error.outcome` too, for example on a wrong envelope version, sender, contract digest or target\nmode, or a body that does not parse. A refusal the command itself raises carries only the\noutcome it states. A refusal that does not serialize comes back as `internal`, and one too large\nto publish as `resource-exhausted`, and both keep that outcome. A\nsigned-in user invokes the same surface through their bearer, and the broker enforces each\ncommand's existing capability grant. A manager alias supplied through `--name` resolves through\nits name-keyed `inspect` command, so an authorized targeted call does not need the manager-wide\n`ps` enumeration grant. Every built-in manager command uses this\nsame trust chain, so there is nothing the built-ins can reach that a described contract cannot. The registered\n`auth` endpoint is describable the same way `manager` is: `cotal describe auth` lists\n`retire-lifecycle` and its exact-mode target shape.\nSee [SPEC §13.7](../SPEC.md#137-contracts-and-discovery) and [cli.md](cli.md).\n\nThe manager's `vitals` command reports one invocation-time sample of host CPU count and load,\navailable and total memory, and bounded local filesystem capacity. It is untargeted but resolves to\none exact Manager instance. The separate `manager.vitals` capability is issued only when the actor\nscope contains `machine-vitals`; `spawn`, `run` and `admin` do not imply it. The response contains\nmount points and aggregate byte counts, never device paths, remote endpoints, process data, command\nlines, environment values or persisted history. Unsupported measurement refuses without a partial\nor zero-valued fallback.\n\nThe manager's `resolve-cwd` command is in the `manager.spawn` capability class. It accepts an\nabsolute path on that manager's host and returns its canonical directory plus the host name. It\nrefuses a relative, missing or non-directory path with `failed-precondition`; it creates nothing.\n`spawn` applies the same check at admission, before any credentials or durables are minted. It is\nminted beside `spawn` in the operator instruments, which are the caller on a static mesh, and in a\n`spawn` holder's `manager-caller` view. The standing agent `spawn` capability does not carry it.\nA runtime that delegates seats outside the manager's host cannot use a host cwd. Its manager\nrefuses `resolve-cwd` with `failed-precondition` before any filesystem lookup, with the same\nexecution-mode refusal for every path. It returns no host name or canonical path.\n\nThe manager's `resolve-agent` command is minted beside `spawn` in the spawn capability and the\noperator instruments. It accepts the persona fields `spawn` takes (`name`, `config`, `agent`,\n`defaultAgent`) and returns `{agent}`, the harness `spawn` on that manager would launch: the flag,\nthen the persona's `agent:` pin, then the caller's default, then the manager's own default. It loads\nthe persona with the same visibility check as `spawn` and launches nothing. A detached `--resume`\nwithout `--agent` asks it before carrying a session, and a manager that does not serve it refuses\nthe call.\n\nOn a delegated runtime, both `resolve-agent` and `spawn` refuse an explicit persona `config`\nbefore any lookup of that path. Absolute, relative and bare-name config overrides receive the\nsame `failed-precondition` refusal. Select a named catalog persona through `name` instead.\nLocally executing managers retain their config-path behavior. A resolved manifest uses its own\nvalidated, host-materialized persona resource and is not a caller-selected config override.\n\n`spawn` refuses an empty or whitespace-only value in any of its optional string fields, such as\n`role`, `agent` or `identity`, with `bad-request` naming the field. To take the persona file's value,\nomit the field.\n\n### Inspecting a managed name\n\nManager `inspect` keeps its successful response as the live managed-agent row. A live hit does\nnot read durable lifecycle state, so a temporary records-store failure cannot break inspection of\nan agent the manager currently holds.\n\nOn a live miss, a static manager point-reads its durable slot row. A name with no slot, or a slot\nwhose phase is `retired`, remains `not-found`. A nonterminal slot returns\n`failed-precondition` with `error.details[].kind =\nai.cotal.manager.static-slot-observation`. The detail carries the slot's `slotPhase`,\n`owner`, `actor`, `slotLifecycleUid`, `cleanupComplete` when recorded, and `slotRevision`. It\nthen carries the separate lifecycle head's `headState`, `headOp` when present,\n`headLifecycleUid`, and `headRevision`. Head fields are absent when provisioning has not written\nthe lifecycle head yet.\nThe error message carries the same diagnostic summary so string-only operator paths do not hide\nthe structured detail.\n\nA slot row records the manager instance that owns it. In a space with more than one manager, the\nclass queue can hand `inspect` to an instance that does not host the name. When the row names a\ndifferent instance and is not `retired`, the miss returns `failed-precondition` with the same\ndetail plus `ownerInstanceId`, which names the only manager that can act on it. The message names\nboth instances, so a caller that reads only the string can tell it from `not-found`. A sibling's\n`retired` row remains `not-found`. A named `cotal_despawn` resolves its target through this read\nand cannot address an instance, so it asks again until the owning instance answers, up to 16\ntimes.\n\nThe slot is read before the head. These records do not form one atomic snapshot, so the detail\nalso carries `readOrder: [\"slot\", \"head\"]` and `consistency: \"ordered-not-atomic\"`. A head can\nadvance between the reads. The issuance gate is not projected because the retirement operation\nneeded for this diagnosis is already recorded on the head, and reading a third record would add\nanother non-atomic edge without changing the per-name result.\n\nIf either durable read fails or exceeds its bound, the miss returns `unavailable` with\n`ai.cotal.manager.static-slot-read-failed` rather than claiming the name is absent. That detail\nnames the inspected `name`, the failed `record` (`slot`, `head`, or `slot-or-head` when the layer\ncannot distinguish them), and `operation: \"read\"`. User-auth managers do not own `mgrslot` rows,\nso their inspect misses remain live-map reads.\n\nFor Linux custodied seats, retirement requires the runtime's process-exit evidence before\nfreeing the alias or deleting its credentials and delivery state. Socket loss alone is not\nproof of exit. The runtime retains the record captured at launch or adoption so a clean\ncustodian exit can unlink its file without losing the recorded boot and process identities.\nIf the file is missing, reaping uses that retained record and the existing kernel identity\nchecks. An unknown reference without either record refuses cleanup. Reused process ids\nare never signalled on the strength of the old record.\n\n### Listing the durable slots\n\nManager `slots` (`manager.read`, untargeted) lists the durable static slot rows this manager\nowns. Only static managers hold these rows: a user-mode or open manager answers\n`failed-precondition`, and a manager whose durable store is not standing answers `unavailable`.\nEach row carries the same `readOrder` and `consistency` fields `inspect` uses, because the list\nis read the same way: torn across rows as well as within each row's slot/head pair.\nWith no arguments, retired rows remain excluded. From manager cluster revision 32,\n`{names: [\"worker\"], includeRetired: true}` point-reads up to 100 distinct aliases and\nincludes their retired rows. An absent or sibling-owned slot is omitted, not reported\nas retired. Each returned row retains its principal, lifecycle UID, slot/head revisions,\nphase and any native cleanup-complete fact. Consumers must match every requested\nincarnation; a missing live row or an accepted stop is not a retirement result.\n`live` reflects the manager's live roster at render time, not the durable row. A slot row\nis never deleted, so a row whose latest operation is a DEL or PURGE marker is corruption:\nthe list answers `unavailable` naming that row, as `inspect` does for its name.\n\n### Static chat sessions\n\nFrom manager cluster revision 34, a static manager admits chat sessions with\n`chat-session-open` and ends them with `chat-session-retire`. Both are untargeted and in the\n`manager.chat` class. Only operator instruments carry their rows; the `spawn` and `run`\ncapabilities do not. A user-mode or open manager refuses both with `unimplemented`.\n\n`chat-session-open` takes `{subscribe, allowSubscribe, allowPublish, label, ttl, sealTo}`. The\nthree lists are a spawn's, under a spawn's rules: `subscribe` is the session's initial channels,\n`allowSubscribe` its read ceiling (empty means `subscribe`, and `subscribe` must lie within it),\nand `allowPublish` its post list (empty means none). Each may be omitted. A session can join any\nchannel under its ceiling, patterns included. A concrete event channel of another principal is\nrefused, as it is for a spawn. The manager draws a `chat_<26 base32>` alias and a fresh nkey\nidentity, runs the static slot activation, provisions the session's DM and DELIVER durables and\nACL row, and mints an agent-profile leaf with no role, capabilities, endpoint rows or issuance.\nThe leaf expires after `ttl` seconds, at most 900, and is never renewed. Because the leaf is not\nan issuance, the manager writes its credential ledger row itself before the credential leaves the\nprocess, and that row is what retirement marks revoked and verify-evicts.\n\n`sealTo` is a one-time curve public key (`X…`) the caller mints and keeps the private half of. The\nreply is `{alias, actor, lifecycleUid, expiresAt, sealer, sealed}`: `actor` is the nkey the\nbroker authenticates, `alias` names the slot, and `expiresAt` is in epoch milliseconds. The\ncredential is not in the reply in the clear. `sealed` is base64url, sealed to `sealTo` from the\none-time `sealer` key with the NATS xkey format, and opens to the credential bound to the space,\nthe admitting manager instance and every field of the reply. A generic invoke, an agent or a\nbrowser sees only that ciphertext. The chat adapter opens it once, refuses it unless every bound\nfield matches, and keeps the credential in memory.\n\n`chat-session-retire` takes `{alias, actor, lifecycleUid}` and runs the static terminal. It refuses\nbefore any effect unless the alias is a chat alias whose slot this manager instance owns at that\nuid and actor. It answers `retired`, `alreadyRetired`, or `failed` with a `retirement pending:`\nreason while the slot stays held. Retirement marks the credential's ledger row revoked, verifies\nthat the session's principal has no broker connection left, tears down its broker footprint and\nretires the slot. A static mesh has no broker-side credential revocation, so a copy of the leaf\ncan still connect with the permissions it carries until its expiry. An ordinary spawn refuses any\nname that starts with `chat_`.\n\nThe manager that admitted a session retires it at its expiry when nothing retired it sooner, so a\nlost reply or an abandoned client does not hold the slot. Its stop retires every session it still\nholds, with or without its agents, and names each one it could not retire; a stop that preserves\nthe manager's state leaves them. Its own startup sweep never retires a session it is admitting or\nholds. A session that none of these retired stays held until the next start of that manager\ninstance.\n\n## Persona write observation\n\nAn unanswered `define-persona` command does not prove the persona was not written. The\n`cotal_persona` tool reports that write outcome as unknown and tells the caller to read it with\n`cotal_personas` on the same manager before acting. The write may still land after the wait ends,\nso a missing readback alone does not make another definition safe. A failed describe, broker\nno-responders answer or explicit pre-effect refusal remains a failure, not an unknown write.\n\n## Spawn is a goal\n\nLong-running commands are **actions** ([SPEC §13.6](../SPEC.md#136-composites)): the caller\nsubmits with a client-generated `goalId` and a request fingerprint, the endpoint records a\ndurable accept or reject decision, progress rides per-goal events, and the work ends in one\nterminal outcome (`succeeded`, `failed`, `cancelled`, `expired`, or `uncertain`). Spawn is\nthe reference case. Rather than block the caller for up to 30 seconds while an agent comes\nup, the manager accepts the goal and returns the allocated identity at once:\n\n```json\n{\n \"name\": \"reviewer_2\",\n \"owner\": \"u_...\", \"actor\": \"reviewer_2\", \"uid\": \"...\",\n \"goalId\": \"...\", \"fingerprint\": \"...\",\n \"readinessDeadlineMs\": 30000,\n \"executor\": { \"lifecycleUid\": \"...\", \"epoch\": 3 }\n}\n```\n\nThe `uid` is the lifecycle the agent runs at. On a participant manager whose host enrolls its\nagents, the host picks that uid, so the manager accepts the goal only after the host has answered.\nA host refusal there refuses the spawn, and no goal is bound.\n\nResubmitting the same `goalId` returns the same acceptance. A `goalId` belongs to the caller that\nsubmitted it, so another caller's spawn under the same id is its own goal with its own\nacceptance. A sibling instance or a restarted one\nanswers it from the identity the accepting instance recorded before it replied, owner included.\nWhen that record names no owner because an older manager wrote it, the resubmission is refused\n`unavailable`. Once the goal has ended, the accepting manager keeps its acceptance for five more\nminutes. After that, and at any other instance, the resubmission is answered from the goal's\nterminal and never accepted again: a `succeeded` terminal names the agent, so it returns the same\nacceptance, and any other outcome refuses it `failed-precondition` with that terminal attached.\n\nThe name is the one actually allocated: a persona-derived collision is auto-numbered\n(`reviewer`, then `reviewer_2`), while a hard-pinned `--name` that collides with a live\nagent is refused at accept, before anything is minted. Auto-numbering never hands out a numbered\nname it has already issued in that manager process, even after the agent holding it is gone, so\na collision takes the next number. Only numbering consults that history: a hard-pinned `--name`,\nor a persona whose own name is a numbered string, takes that name whenever it is free, and\nnumbering does not skip a string such a spawn held before. The triple plus `goalId` let the\ncaller follow progress (connector handoff, process launched, presence join) and reconcile\nlater against the exact instance that accepted. Presence within the manager's default\n30-second readiness window, or a connector's declared bounded window, settles the goal\n`succeeded`; an early process exit is `failed`; the window passing with neither is `uncertain`,\na bounded, durable outcome that a later `ps` or status read settles against the live roster.\n`uncertain` is a real terminal outcome, not an absence and not a silent hang. It carries the\ndiagnosis of whoever owned the deadline: for a launch that\nnames the agent and says to inspect it rather than re-issue, since re-issuing after a launch\nthat in fact succeeded mints a duplicate. A follower keeps the acceptance as the data of any\nterminal other than `succeeded`, so `cotal_spawn` returns an uncertain launch as a pending result\ninstead of an error: it names the allocated agent, its id, and its manager, and tells the calling\nagent to watch the roster. A committer that supplies no diagnosis falls back to\n\"the success signal did not arrive within the readiness deadline\". The agent's own eventual\nstate is then observable on its presence record.\n\nThe acceptance carries that exact `readinessDeadlineMs`. A synchronous follower treats its own\nrequest deadline as a floor and waits through the accepted readiness budget plus delivery margin,\nso a connector-specific slow boot cannot be reported as a caller timeout while the manager is\nstill legitimately waiting for its terminal.\n\nThe manager keeps a spawn or launch exception's error code and details when turning it\ninto a refusal. Failed `ControlReply` values keep their code and details at the serving\nboundary. A host enrollment refusal that proves nothing was executed also keeps its\ncode in the public `Manager.startAgent` reply after staged-secret cleanup. A reply\nwithout a code remains `failed-precondition`.\n\nA spawn that is **refused** because a lifecycle barrier already holds the actor (a frozen\nissuance gate, a retiring alias, a retired uid) is not a wait-timeout. The manager already\nknows the blocked op (`registration` / `retirement` / `activation` / `takeover`), the `opId`\nholding it, and the remedy when one exists (`retry`, `cotal reconcile-gate`). The detail\ncarries `headState` (`active` / `retiring` / `retired`) only when the refusing site read the\nlifecycle head, and `gateState` (`frozen` / `retired`) only when it read the issuance gate. A\ngate frozen by a takeover or a registration says nothing about the head, so that refusal\ncarries `gateState=frozen` and no `headState`. Those facts ride `error.details[]` as\n`kind = ai.cotal.ep.lifecycle-blocked` and are also appended to the error string, so a\ncaller that only prints `error.message` still sees them. The CLI and the connector tools hand a\nrefusal on in one shape, so `cotal spawn --detach` keeps the same code, details, rendered facts\nand acceptance data as `cotal_spawn`. A connector that collapses the\nrefusal to \"startup failed (unknown)\" or a SPEC 13.6 wait-timeout is hiding a knowable\nstate, not reporting a missing one.\n\n## Instance routing\n\nA space can run more than one manager. Each manager persists a stable logical instance id\nacross restarts and advances its process epoch when it comes back, so callers address a\nspecific manager without caring which process currently serves it. A start serves only at the\nepoch its own registration committed, never at the epoch of a later start of the same instance.\nOn a static mesh or from an unbound open caller, an untargeted spawn rides class anycast\n(any manager may accept, and the acceptance records which one did). An open managed seat's\npersona definition, list, show and spawn tools default to its launching manager. Its generic\nmanager describe and self-targeted invoke use that launch address too. An explicit existing\npersona or spawn selector still selects that instance. Static credential grants and user-auth\nissuer selection are unchanged. The library's `describeService` accepts an optional `instanceId`;\na pinned describe does not read or populate the endpoint-only class cache.\n`cotal spawn <persona> --detach --on <instance>` and `cotal_spawn(instance: \"<instance>\")`\npin one instance by its exact id, as `--on` does for `cotal ps`, `cotal models` and every hosted\n`cotal run` verb, and `instance` for `cotal_run`, `cotal_persona` and `cotal_personas`. A foreground CLI spawn has no manager to pin and refuses the\nflag. An MCP pin that does not resolve is refused without falling back to class anycast. There are no ordinal\naliases and no short forms: wherever a display names an instance you can address, it prints\nthe whole id, because both surfaces take nothing else.\n\nOn a user-auth mesh, manager commands obtain a short-lived `manager-caller` view from the\nexchange. It authorizes one concrete manager instance using the caller's current actor grant and\nthe host's registered service records. Discovery and invocation both use that instance's `inst`\nroute. This view grants no registry scan or class queue. It adds no command capability except the\nthree reads a launch needs: a view whose actor holds `spawn` may call `status`, `models` and\n`resolve-cwd` on that instance, subject to the execution-mode limit above. A `run`-only or no-scope view may not, and `ps` and `slots` stay with\n`admin`. A user mesh's co-located manager answers every owner's view, so its `status` counts only the\ncaller's own seats, as `ps` would list them, unless the caller holds `admin`. An absent,\nambiguous or unauthorized selection refuses before the command is sent. An ambiguous one lists the\nowner's live manager instance ids and names the caller's way to pick one: `--on <instanceId>` for\nthe CLI, `--manager-instance <instanceId>` for `cotal agent-bearer --manager-call`, and the\n`instance` argument for an agent's tools.\nA pin changes routing, not the caller's grant.\n\nManaged launches carry `COTAL_MANAGER_INSTANCE` so their tools address the manager that launched\nthem; a tool's `instance` argument must name that same manager. The `cotal` commands run from their\nshell select it too, unless `--on` names another instance. Existing unbound sessions can use the exchange's unique authorized selection without\nreplacing their actor or conversation. The connector uses a separate control connection; the\nstanding message connection and its credential source are unchanged. Accepted spawn goals are\nfollowed on that renewing connection, using its existing caller-scoped progress grant, so a long\nreadiness budget does not depend on the short-lived control credential. The follower confirms its\nprogress subscription with the broker before submitting on the separate connection. A caller still\nchecks the resolved instance and epoch, and never retries an ambiguous mutation outcome.\n\nThe manager's `goal-result` command accepts `{goalId}` and returns `{goalId, result?}`. It reads\nonly the authenticated caller's owner, actor and lifecycle through the manager's separate trusted\ngoal-writer connection. The caller receives an attributed reply, never a raw JetStream reader\ngrant. Each read is admitted by the connection's broker-enforced command grant. A live user-auth\nconnection remains bounded by its bearer expiry after revocation; a renewed connection is checked\nagainst fresh authority. There is no separate per-read ledger check. An absent `result` means no\nterminal is recorded; it does not prove the goal is running or permit another submission. The\nexisting trusted goal-writer's leader-served EPF read is space-wide at the broker; the handler\nconfines it to this endpoint and caller triple.\n\nThe manager's reserved `cancel` command accepts `{goalId, mode?}` and returns `{goalId, state}`.\nIt is served for a turn the manager relays. The goal is the authenticated caller's own, so a caller\nwithdraws only a turn it submitted. The turn ends `cancelled`, its seat is not shown it again, and a\nlater yield of it is answered with that terminal. A goal that already ended is refused\n`failed-precondition` with its cached outcome attached, and a goal this manager does not relay is\nrefused without being changed. So is a second cancel that arrives while a first is still ending the\nturn; a first that fails leaves the turn pending unless something ended it meanwhile. A workflow\nrun sends it for the turn, ask attempt or escalation of a branch it cancelled.\n\nA followed mutation requires a manager whose attributed describe includes `goal-result`. Update\nthe manager, issuer and client together before using that recovery path. Reloading an issuer alone\ncannot change an already-running participant manager. Recovery re-resolves the accepting instance's\nepoch, preserves the caller lifecycle and validates the result against the accepted goal and any\nacceptance fingerprint. Stopping the caller ends its observation, not the already accepted goal.\n\nA followed call resolves the endpoint within its deadline before the submission starts, so a\nrefused or unanswered describe surfaces as its own error. On a user-auth mesh that preparation also\nobtains the caller's `manager-caller` view and opens its connection, and a failure there surfaces\nunchanged. The control connection uses the remaining preparation deadline, including time spent\nobtaining the bearer, rather than a separate two-second limit. A deadline that passes during those\nsteps reports that the request was not run. The\ndescribe then spends what is left of the deadline, so a describe that draws no reply still reports\nitself as unanswered.\nA describe or command publish that the broker refuses reports `not-executed`.\nCancellation before submission reports `not-executed`. Once submission starts, cancellation or a\nlost reply reports an unknown outcome unless an attributed refusal proves otherwise. A received\nrefusal remains a refusal even when stop races it. Local failures do not invent responder identities.\nThe follower owns its subscription, timers and read cancellation signal. Reconciliation begins\nbefore the wait deadline, and late read completions cannot settle an expired observation. Its read\ncallback receives the accepting caller triple, remaining budget and abort signal; borrowed bearer\ncommands and control connections use that signal. An in-flight dial that finishes after cancellation\ncloses without publishing. A local reply-subscription failure prevents publication and is observed\nby the same request promise, including when the transport is closing or draining. Request\ncancellation does not revoke or resubmit the accepted operation.\n\n\"Only one manager per space\" is not the current invariant. A split topology that keeps the\nbroker host manager-free is still a topology choice: `cotal up --no-manager` on that host starts no\nmanager, and `cotal supervise --server` runs the manager elsewhere ([Run a mesh](run-a-mesh.md)).\nA broker host that already runs a manager stops it only after `✓ manager up` in\n`.cotal/manager.<spaceKey>.log` (detach stdout listing `manager` is pidfile liveness, not a\nteardown boundary). A controller stack stops it with\n`cotal service stop stack-manager --space <s> --yes`; a legacy stack has no command that stops only\nits manager. Extra live managers are addressable, not an error.\n\nThe reserved `describe` bootstrap is the one request the resolver may repeat while waiting: it is\nread-only, it is re-published under the same request binding, and every attempt stays inside the\noriginal deadline. This covers the startup window where Core NATS discards the first request before\nthe manager has subscribed. If the connection closes while the resolver waits, the describe fails\ncleanly instead of throwing from the retry timer. The resolved command is never repeated by this\nreadiness behavior.\n\nThe describe and the contract store reads after it share the resolver's one deadline, so a slow\nstore read fails the resolve with `deadline-exceeded` when that deadline expires. `cotal invoke` passes its\n`--timeout` as that deadline (default 10000 ms) and gives the reply what the resolve leaves of it.\n`cotal describe` has no `--timeout` and passes 10000 ms. Cancelling a\nresolve settles a store read in flight instead of waiting for it to return. When one store read\nfails, the resolve fails with it and fetches no further command contracts; fetches already under\nway finish on their own.\n\nThe resolve and the invoke are separate trips through the same anycast queue, so in a\nmulti-manager space an unpinned call can land on an instance the caller did not resolve. Every\ncall carries the incarnation it resolved against, and a manager that is not that incarnation\n**refuses before running the command**, so the failure an operator sees says the command did\nnot run, and re-issuing it cannot duplicate the effect. That is the difference that matters for\na mutation: the older behaviour detected the mismatch on the reply, after the manager had\nalready acted, and could only tell you to go and check. `--on` still matters for reaching a\nspecific manager (`ps`, `stop`, `attach`, `spawn --detach`), but it is no longer what stands\nbetween a split and a duplicated spawn. Against a manager older than this fence the refusal is\nstill after the fact, and its message says so. The re-issue is automatic only when the refusal\nstates `not-executed` in its `outcome` field; a refusal that omits the field, or states\n`unknown`, is surfaced to the caller instead of repaired, because neither proves the command did\nnot run. The CLI's manager commands, `cotal invoke`, the `cotal run` verbs and the manager row of\n`cotal status` re-describe and re-issue an unpinned call after each such refusal, up to 16 times,\nso a split reaches the operator only when every attempt split. A hosted run's own manager calls\nuse the same bound. A pinned call is never re-issued. An agent's own manager\ntools, such as `cotal_spawn` and `cotal_despawn`, re-describe and re-issue with the same bound,\nincluding the goal-result read that follows a spawn to its outcome.\n\nAn unpinned targeted call, such as `cotal_despawn` or a hosted run's turn relay, can also reach a\nmanager that does not host its target, because each manager resolves targets against the agents\nit runs. That manager refuses with `expired` and `not-executed` and says it holds no mapping for\nthe target, and the same re-issue repairs it within the same bound. An agent that no manager hosts\nstill ends in that refusal once the re-issues run out. A pinned call gets the refusal of the\ninstance it named.\n\nA verified Manager `status` reply includes `host`, the answering process's host name, and\n`version`, the running `@cotal-ai/manager` package version captured when its module loaded.\nThese fields are advisory display metadata. They do not select a Manager, authorize a caller\nor determine placement. Use the verified responder's `instanceId` for attribution. Clients\nmust accept status payloads that omit either field and leave the missing value unknown.\nThe optional fields advance the Manager cluster revision to 28.\n\nA manager whose boot inventory marked every declared connector unavailable does not subscribe\n`spawn` or `launch` on the class `one` rail. Those commands stay on scatter and on this\ninstance's `inst` rail, so a sibling that can launch them can take an unpinned spawn, and a\ncaller that pins this instance with `--on` still gets a named harness refusal. `describe`\nstill lists the commands: the instance rail serves them, and `describe` itself stays on the\nclass rail (SPEC 13.7). An unpinned `spawn` can therefore bind-fence: `describe` may land on\nthe skip member while `spawn` lands on a sibling, the command was not run, and the caller\nre-issues or pins `--on`. `status` reports `classSpawn: false` when that skip is in effect.\nWhen no manager takes the class queue, the broker answers an unpinned `spawn` with no\nresponders, and the caller classifies that `not-executed` (SPEC 13.3).\nA manager that can launch some connectors keeps the class rail. If the queue hands it a\nharness its inventory marked unavailable, the refusal names `--on` because the standing serve\ncredential cannot read sibling inventories. Pin the capable instance (the whole id, as `ps`\nprints it).\n\n`ps` and\n`status` become a **scatter** across every registered instance: the caller freezes the\nexpected set from the service registry, invokes each under a shared deadline, and merges the\nresults with per-instance attribution. A non-answering instance is labelled as registered\nwith no answer within the deadline, never silently omitted. See [SPEC §13.5](../SPEC.md#135-verbs) (scatter) and [cli.md](cli.md).\n\nThe expected set comes from the **registry**, which records registration rather than liveness.\nAn instance that crashes never deregisters, so it stays in the set and the gather has nothing\nleft to wait for but an answer that cannot come. It pays the whole deadline, on every scatter,\nindefinitely. A scatter can therefore be given a per-instance liveness probe: when the broker\nitself reports that an instance holds no subscription on its own instance rail, the gather stops\nwaiting for it. Only that affirmative report counts. A lapsed presence entry, a probe that timed\nout, and a probe that failed are all *absence of evidence*, and treating any of them as death\nwould turn a slow correct answer into a fast wrong one, so they leave the full deadline standing.\nNothing about the outcome changes either way: an instance that did not answer is still\nunreachable, still surfaced, and the scatter is still not complete.\n\nThe probe is supplied by the **caller**, not invented by the scatter. Asking about an instance is\na publish on that instance's rail, and a credential that holds no row for it is refused by the\nbroker asynchronously, while the publish itself returns normally. The probe verb watches for that\nrefusal and raises it as `permission-denied` naming the rail, so it is never mistaken for a quiet\ninstance, and it never burns the probe budget waiting out a refusal. Only the layer that\nminted the credential knows which ids it may ask about, so that layer asks about those and no\nothers. `cotal ps` freezes the class on its first connection, re-mints an instrument pinned only\nto the frozen ids, and scatters on a second; a refusal the broker raises anyway is printed and\nthe instance's row says the probe was refused, which is a fact about the credential, not about\nthe instance.\n\nThis does not help against an instance that is **connected but not answering**. A hung manager\nholds its subscriptions, so it is indistinguishable from a slow one, and it still costs the full\ndeadline. That is the correct result, not a gap in the probe.\n\n### Deregistration\n\nA probe makes a dead registration cheap to skip; it does not remove it. Removal is the\nregistration's own exit, and there are two explicit routes to it\n([SPEC §13.5](../SPEC.md#135-verbs): a deleted `svc` spec *is* the deregistration).\n\nA manager that stops cleanly removes its own registration, so an ordinary shutdown leaves no stale\nrow. The delete is pinned to the registration revision that process wrote. When a successor has\nregistered the same instance since then, the stop logs that and leaves the successor's registration\nalone. It refuses that delete while this instance holds the endpoint governance slot at the live\nissuance-gate generation (a registration still completing its reopen). A leftover slot whose\ngeneration is behind that live generation is not in-flight and does not block the stop. A manager\nthat cannot renew or read its lease keeps serving, stays registered, and retries. If another process\nholds the same instance key, that process has taken the instance over, so this one logs the conflict\nand exits without deregistering, leaving the successor's registration alone.\n\nA restart that died *mid-registration* is a different residue: the issuance gate stays frozen under\nthat op. The successor completes the dead registration on boot when the freeze-holder is\naffirmatively gone under a complete CONNZ sweep (the same composition as\n[`cotal reconcile-gate`](cli.md#reconcile-gate)). A committed spec write is finished under that\nsame freeze; only a definite no-commit abort-reopens and then runs the normal takeover.\nOnce that reopen commits, the registration has completed: a governance slot it then fails to release\nis left behind the live generation, as on a normal registration, and does not fail the restart.\nIt does not invent a TTL and it does not start a new freeze over a still-held one.\n\nThat residue has a second half, and it is the endpoint governance slot rather than the gate. Every\nregistration takes the endpoint-wide slot before it publishes its spec and holds it until its own\ngate reopens, which is what serializes registration for the endpoint. An instance that stopped\nbetween those two points leaves the slot held with no registration behind it, so the endpoint\nrefuses new registrations while nothing is actually in flight. The slot is stamped with the\ngeneration of the gate its holder had frozen when it took it, and a slot is promoted only at that\nsame generation. So once the holder's gate has reopened past the stamp, the slot can never be\npromoted by anyone, and the next registration for that endpoint replaces it. That reclaim is part of\nan ordinary start and needs no operator step.\n\nA slot whose holder's gate is still at the stamped generation is a registration that is genuinely in\nflight, and it keeps refusing. The two states read differently only in the holder's gate coordinate,\nso reopening that gate is what separates them: the holder's own restart heals it on boot, and\n[`cotal reconcile-gate`](cli.md#reconcile-gate) is the operator's route when the boot path cannot\nrun. The registration path is the slot's only writer, and neither repair command writes it.\nA registration that cannot read the holder's gate at all refuses, because an unreadable gate does\nnot distinguish the two states either. Each of these refusals carries\n`kind = ai.cotal.ep.foreign-slot-held` in `error.details[]` with the holder's instance id and the\n`condition` that refused: `in-flight` for a holder gate still at the stamp, or `no-seam`,\n`unreadable`, `garbled` or `behind` when the registration could not read that gate or read it below\nthe stamp. A remote manager asks its host to reconcile the holder only on `in-flight`, the one\ncondition a gate repair can clear.\n\nFor the instance that cannot cooperate, an operator names it:\n`cotal endpoint deregister <endpoint> <full-instance-id>`\n([cli.md](cli.md#endpoint-deregister)). It removes the\nrecord only on the same evidence `cotal ps` acts on: the broker reporting nothing subscribed on\nthat instance's own rail. It refuses if the instance answers a describe, refuses if the probe could\nnot run at all, and refuses if the instance is merely quiet, because a hung process still holds its\nsubscriptions and is therefore not affirmed gone. It also refuses while that instance holds the\nendpoint governance slot at the live issuance-gate generation (a registration still completing);\na leftover slot behind that generation is not in-flight and does not block. Nothing sweeps the\nregistry on an age threshold or on silence.\nAn instance that is deregistered while it is merely wedged re-registers over the tombstone on its\nnext start, which is what makes the operator's decision a recoverable one.\n\n## Attach sessions\n\n`cotal attach` no longer returns a `ws://127.0.0.1` URL. It creates a one-use, holder-bound\nsession offer: the manager mints a token bound to the caller, the target lifecycle, its own\ninstance id and epoch, and an expiry, and replies with a session id and expiry only, no URL\nand no secret in the reply. The CLI redeems the offer over the mesh (a second redeem is\nrefused). On a registered open mesh that redeem is a bare connection, the same path other\ncontrol commands already use; on a static-auth mesh it is still a session-caller credential\nminted from the resolved root's seed. On a user-auth mesh the CLI holds no seed: it exchanges its\nlogin and the grant for a `session-caller` view bearer, and the callout mints the same caller rails\nwith the grant's expiry. Terminal bytes then stream on core-NATS session subjects\nscoped to the two parties. Backpressure is a bounded in-flight window with an explicit drop notice, never\nsilent loss; a late attach still repaints the full screen from a replayed terminal\nsnapshot. Close, expiry, target despawn, and a manager restart are distinct, surfaced end\nstates: a restarted manager's successor refuses the old epoch's sessions. `cotal attach`\nreconnects when its link dies by asking the manager for a new session\n([CLI](cli.md#managed-seats)).\n\n## Seat input\n\n`attach` is a stream, so it is the wrong shape for a program that wants to send one line: it\nholds a session open and expects a terminal at the caller's end. The `input` command is the\nother half. One authorized call writes text into a running seat's terminal as if it had been\ntyped there, and answers with the seat and the number of bytes delivered.\n\nIt exists for **harness commands**. A line beginning with `/` (`/compact`, `/clear`, `/model`)\nis neither chat nor an event: the agent's own harness handles it, and the keyboard is the only\nway in. An external control surface that can already read a seat's turns and talk to it still\ncannot drive it without this.\n\nThe op is targeted, rides the `manager.lifecycle` capability, and declares authz modes `owner`\nand `any`, the row shape `attach` and `despawn` already carry, checked by the same authorization.\nEnter is appended unless the caller suppresses it, and nothing is echoed back, since the resulting\nturns already have somewhere to go.\n\n**Who may call it is narrower than either of those**, and the reasoning is worth stating because\nthe natural assumption is wrong. `despawn` and `attach` are granted to anything holding `spawn`;\n`input` is granted only to operator credentials. The tempting argument for treating them alike is\nthat an attach session's `write` already reaches the same terminal, so `input` adds nothing. It\ndoes not reach it: an attach yields a signed session offer, and redeeming one needs a per-session\ncredential minted from the space signing seed, which no agent holds. So `input` would be new\nauthority, and the own-owner rule that bounds `despawn` covers every seat under an owner rather\nthan only the ones a caller launched. Killing a peer is denial; typing into a peer is control of\nit. The write therefore sits with the credential that is already the administrative authority for\nthe domain.\n\nOnly a runtime that owns the child's input stream can serve it. The `pty` runtime does; the\nexternal terminal runtimes attach to a process they do not own, and there the command refuses\nand names the runtime rather than dropping the keystroke. A seat that is not running refuses for\nits own reason, and the two are distinguishable, so a caller can tell \"this will never work\"\nfrom \"not right now\". Both refusals carry `not-executed`, because nothing was typed. A write the\nruntime rejects once delivery has started states no outcome, so a caller reads it as `unknown`.\nThe manager's other control refusals follow the same rule: one raised before the command's first\neffect, such as a denied caller, a stale target or a missing persona file, carries `not-executed`.\nSee [cli.md](cli.md#input).\n\n## Grants\n\nThere is no broad control credential. A caller holds one capability row per command it is\nallowed to send, and minting maps each named capability to the request subjects it needs and no\nothers. The manager serves over a scoped serve credential that can answer and\nreply but cannot, for instance, write another endpoint's records or forge a goal terminal;\nthe goal-fact writer and the session writer are separate, narrowly scoped credentials the\nbroker fences by subject. Authorization is checked at the serving boundary, and for actions\nit linearises at acceptance: a spawn refused there mints no reservation and leaves no\nprocess. See [SPEC §13.9](../SPEC.md#139-authority-boundary) and\n[identity & auth](identity-and-auth.md).\n\nA carried resume transcript never rides the rails. The operator-only `transcript-receive` command\nanswers whether to upload and hands back a one-time claim for `spawn`, and the bytes travel through\nthe target instance's own transfer bucket under two one-shot credentials: a writer the operator\nmints for that one transcript, and a reader the target instance mints for its own bucket, or that\nthe host issues a remote manager through its `transferReader` authority operation.\n\n## See also\n\n- [Architecture](architecture.md), where the manager and the wire fit in the whole system.\n- [CLI](cli.md), for `describe`, `invoke`, `spawn`, `ps`, `status`, `attach`, and `input`.\n- [SPEC §13](../SPEC.md#13-endpoint-control-surface-v04), the normative contract.\n"
175
175
  },
176
176
  {
177
177
  "slug": "dashboard-api",
@@ -368,7 +368,7 @@ export function loadDocsBundle() {
368
368
  ],
369
369
  "spec": {
370
370
  "title": "Cotal Wire Specification",
371
- "body": "# Cotal Wire Specification\n\n> **Status:** Draft, v0.5 (pre-1.0). This document is the normative wire contract. Libraries\n> (including the reference TypeScript implementation) are thin clients over it; where a\n> client disagrees with this document, this document wins.\n>\n> **Layered authority.** Message *shapes* are defined by the machine-readable schema,\n> [`spec/cotal.schema.json`](spec/cotal.schema.json) (§5); this document's prose defines\n> *semantics*: routing, delivery guarantees, presence, authorization, and conformance. For\n> the reference implementation's operator surfaces (the CLI, the `cotal_*` tools), see the\n> [Reference docs](docs/README.md#reference); those describe the TypeScript implementation,\n> not this contract.\n>\n> **Editors:** Cotal maintainers. **Last updated:** 2026-10-19. Changes are tracked in\n> [Appendix D](#appendix-d-change-log); versioning rules are §11.\n>\n> **v0.5 binding revision: workflow runs.** A deployment MAY host **durable workflow runs**: programs\n> in the Cotal workflow language ([`spec/cotal-lang.md`](spec/cotal-lang.md), normative and\n> incorporated by reference) whose every effect is recorded in a per-run **step journal** so a run\n> resumes on any host by re-execution against its journal (§14). The revision adds one per-space\n> stream (`WFJ_<space>`, one subject per run, an append-only journal fenced by the run's own subject\n> sequence), four core record kinds (`run`, `answer`, `notice`, `migration`), a per-run driver grant\n> family, and the language reference; it changes no existing kind, subject, grant row or shipped\n> datum, so it is **additive** under §11: a v0.4 participant that ignores §14 conforms to v0.4\n> unchanged, and the advertised `protocolVersion` targets `0.5` once the v0.4 migration completes and\n> the §14 plane is served. Language semantics carry their own version (`languageVersion`, pinned on\n> every run record) and move independently of the wire version.\n>\n> **v0.3 binding revision: owner+actor identity.** An instance's wire identity moves from a single\n> id (the connection nkey, used as the sender token everywhere) to a two-token **principal**\n> `(owner, actor)` (§2): the human/account owner and the agent actor become distinct routing tokens,\n> so every subject carries the sender as `<owner>.<actor>` (§3), and grants, durables, presence, and\n> `from.id` re-key onto the principal (§6, §8, §9). The connection nkey survives only as the transport\n> credential, keying the per-connection reply inbox `_INBOX_<connId>` (§2, §10); the wire identity and\n> the connection credential are now distinct. Cross-owner **and** same-owner cross-actor forge/read\n> isolation is a normative confinement property (§9). `parseSubject` splits the tokens; a well-formed\n> split is necessary but not sufficient: a reader additionally rejects a non-principal owner token\n> (e.g. an old-shape alias carrying a raw nkey) at the surfacing boundary (§3, §9). The owner-token\n> *format* (`u_` + 26 base32-lower) is normative; its *derivation* from an owner's identity (login →\n> auth callout, or another identity adapter) is a pluggable edge, not fixed by this contract. This\n> supersedes the v0.2/early-v0.3 single-id grammar. As with the live-delivery revision, the advertised\n> wire `protocolVersion` (§6, §11) is the migration's normative target, not a claim that every surface\n> has cut over.\n>\n> **v0.4 binding revision: endpoint control surface.** Structured command traffic moves from the v0\n> `ctl` control rail to one standardized, typed, discoverable endpoint surface (§13): class +\n> instance + scatter rails with per-command broker enforcement, a versioned envelope, three\n> delivery contracts (ephemeral / record / journal), normative composites (action, checkpoint,\n> guard, capability handle, session), content-addressed contracts with governed traits, and\n> lifecycle identity (§13.1) extending §2/§6/§8. This is an intentional **hard cut** (§11,\n> §13.11): the v0 control grammar, envelope, and authority tiers are deleted, not dual-served.\n> The advertised `protocolVersion` targets `0.4` at the completion of this revision's migration;\n> `1.0` remains reserved as a later stability declaration, not part of this revision.\n>\n> **v0.3 binding revision: channel live delivery.** Channel *live* delivery moves from a single\n> mediated JetStream live-tail durable (`chat_<id>`) to native core-NATS subscriptions bounded by\n> `sub.allow`, with durability provided by an explicit per-channel `live`/`durable` delivery class\n> (§4, §7, §8). Join/leave becomes a direct subscribe/unsubscribe with no privileged mediation,\n> and channel membership moves off consumer topology to a privileged-written registry (§7). This\n> supersedes the v0.2 single-durable live-tail. The reference implementation migrates additively\n> (the legacy durable and the new core-sub path coexist behind `id` dedup until the legacy path is\n> removed), but that migration path is not itself normative. The advertised wire `protocolVersion`\n> (§6, §11) stays `0.2` until the core-sub behaviour ships; this revision is the normative target the\n> migration converges to, and the additive `deliveryClass` field is backward-compatible meanwhile.\n\nThe key words MUST, MUST NOT, REQUIRED, SHALL, SHOULD, SHOULD NOT, MAY, and OPTIONAL in\nthis document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119)\nand [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174).\n\nSections 3 to 7 define the transport-agnostic Cotal contract. Sections 8 to 10 define\nthe NATS + JetStream binding (v0). A conformant deployment implements one binding; the\nNATS binding is the only one defined today. External specifications this document relies on\nare listed in Appendix C.\n\n---\n\n## 1. Scope and terminology\n\nCotal is a wire interface for software, especially AI agents, to coordinate in real time\nas lateral peers in a shared pub/sub space, not as nodes in an orchestrator tree.\n\n- **Space**: an isolated coordination context. One space is one tenant boundary; messages\n in one space are not visible in another. NATS binding: one space = one account.\n- **Instance**: a connected participant, identified by a stable **instance id**. Also called\n an endpoint.\n- **Agent node**: an instance whose `kind` is `agent`, versus a plain `endpoint` such as an\n observer, logger, or dashboard.\n- **Peer**: any other instance in the same space.\n- **Channel**: a named multicast topic within a space, dotted and hierarchical.\n- **Service**: an anycast role reached by name (`svc`, §4).\n- **Endpoint (control surface)**: a daemon that registers a service identity, publishes\n typed contracts, and serves commands on the endpoint rails (§13).\n- **Broker**: the message router for a space. v0 assumes a single trusted broker.\n- **Delivery message**: a multicast, unicast, or anycast `CotalMessage`.\n- **Endpoint request**: a typed request/reply command addressed to an endpoint class or\n instance on the `ep` rails (§13). The v0 `ctl` control rail is deleted (§13.11).\n\n---\n\n## 2. Identity\n\nAn instance's wire identity is a **principal** = a pair of routing tokens `(owner, actor)`:\n\n- **`owner`**: the account that owns the instance: the human (or organization) an agent acts on\n behalf of. In an authenticated deployment it is a derived **owner token** (`u_` followed by 26\n base32-lower characters), a namespaced, nkey-disjoint token deterministically derived from the\n owner's stable identity (e.g. an IdP subject) by the deployment's identity adapter; the wire\n contract fixes the token *format*, not the derivation mechanism, which is a pluggable edge. In open\n dev mode the owner is the literal `local`.\n- **`actor`**: the instance's own handle within that owner (its agent id). Distinct actors under one\n owner are distinct principals and are confined from one another (§9), so one human's two agents\n cannot forge or read as each other.\n\nEach token is sanitized to `[A-Za-z0-9_]` (see §3) with `-` additionally reserved as the form\nseparator, so a principal has two unambiguous serializations: the **dot-form** `<owner>.<actor>` and\nthe **dash-form** `<owner>-<actor>`. The same principal MUST appear identically as: the\n`AgentCard.id` (§6, dot-form), the sender tokens in subjects (§3), the message `from.id` (§5,\ndot-form), the presence key (§6, dot-form), and the per-instance durable names (§8, dash-form).\n\n**The principal is distinct from the connection credential.** In the authenticated NATS binding the\nconnecting user is still an Ed25519 nkey (base32, 56 chars, prefix `U`, e.g. `UAQG...`), stable for\nthe lifetime of the connection, but it is **not** the wire identity. The nkey authenticates the\ntransport and scopes only the per-connection reply inbox `_INBOX_<connId>.>` (§10); the principal\nthat keys every subject, grant, and durable is carried by the minted grant, not by the nkey. This\nseparation is what lets a login (§9) mint a fresh connection whose nkey the client never sees while\nthe principal stays stable across reconnects.\n\n- A client that authenticates with a static credential MUST adopt the principal that credential's\n grant names; if a principal is also set explicitly (via the card) it MUST match, else the client\n MUST fail before publish.\n- A client that authenticates through the auth callout (user mode, §9) cannot know its connection\n nkey before connecting, so it chooses its own reply-inbox nonce (`connId`) and derives its\n principal from its bearer; the broker's minted grant, not the client's self-read, is the\n boundary.\n- Open dev mode MAY use `local` as the owner and an opaque stable actor, but open mode is outside\n the security claims in §9 and is not a conformant authenticated deployment.\n\nFuture binding, not v0: portable `did:key` identity plus signed envelopes so authenticity\nsurvives an untrusted relay. See the threat model in [docs/security.md](docs/security.md).\n\n---\n\n## 3. Subject layout\n\nEvery wire subject is rooted at `cotal.<space>`. `<space>` and every routing token except a role\nare sanitized: any character outside `[A-Za-z0-9_-]` maps to `_`. Sanitization is lossy; tokens\nMUST NOT be decoded back into display names.\n\nThe **sender** of every delivery is a principal (§2), carried as **two adjacent tokens**\n`<owner>.<actor>`. Routed kinds (`inst`) also carry the recipient principal as two tokens.\n\n| Purpose | Subject | Sender tokens | Delivery |\n| --- | --- | --- | --- |\n| Multicast | `cotal.<space>.chat.<owner>.<actor>.<channel...>` | 3–4 | §4 multicast |\n| Unicast | `cotal.<space>.inst.<recipOwner>.<recipActor>.<sndOwner>.<sndActor>` | 5–6 | §4 unicast |\n| Anycast | `cotal.<space>.svc.<role>.<owner>.<actor>` | 4–5 | §4 anycast |\n| Endpoint rails | `cotal.<space>.ep.<one\\|all\\|inst\\|reply>.…`, `cotal.<space>.ep<c\\|e\\|f\\|j\\|r\\|t\\|w\\|s>.…` | see §13.2 | §13 control surface |\n| Plane liveness | `cotal.<space>.live.<plane>.<owner>.<actor>` | 4-5 | §6.1 request/reply |\n| Trace | `cotal.<space>.trace.<instance>` | n/a | reserved |\n\nToken indexing is zero-based on `subject.split(\".\")`: `cotal` = 0, `<space>` = 1,\n`<kind>` = 2. The sender principal is recovered as the dot-form `<owner>.<actor>` (= the message\n`from.id`, §5), so a guard comparing `from.id` to the subject sender uses one value.\n\n**Two-token sender, and its asymmetry.** A reader MUST locate the sender by kind:\n\n- `chat`: sender owner at token 3, actor at token 4; the channel is everything after, tokens 5+,\n so it may be hierarchical (`team.backend`).\n- `svc`: route target at token 3; sender owner at token 4, actor at token 5.\n- `ep`: per-mode arities with the caller as the trailing identity tokens; §13.2 defines them.\n- `inst`: recipient owner+actor at tokens 3–4; sender owner+actor at tokens 5–6.\n\nThe two-token sender is what lets a native publish grant **forge-lock** the sender suffix (e.g.\n`inst.*.*.<myOwner>.<myActor>` permits a DM to anyone but only *as me*), so the broker enforces\nsender authenticity and a receiver need not re-verify a payload claim. A subject that does not match\none of these shapes (wrong prefix or wrong per-kind arity) MUST be treated as having no sender and\nMUST NOT be read as a delivery. `parseSubject` **splits only**: it recovers the tokens but does not\nvalidate that `<owner>` is a well-formed owner token; trust comes from the broker's forge-locked\ngrant, and a reader that surfaces content additionally rejects a non-principal owner token at the\nsurfacing boundary (§9). Reference implementation: `parseSubject` in\n`packages/core/src/subjects.ts`.\n\n**Channel tokens.** A channel is dotted; each segment is sanitized. The literal wildcards\n`*` and `>` are preserved only as whole segments for subscription and allow-list patterns;\n`>` is valid only as the final segment. A publish target MUST be concrete, with no `*` or\n`>`; a subscription MAY be wildcard. A channel is at most 4096 characters in total\n(`MAX_CHANNEL_LENGTH`): every grant line a channel mints rides the minted credential's\nCONNECT line (§13.9), so an unbounded channel is an unbounded connect.\n\n**Role tokens.** A role is an address, so it is never sanitized: it MUST be one\n`[A-Za-z0-9_-]` token. A client MUST refuse any other spelling, for the role it holds and for an\nanycast target, because a rewrite would route distinct spellings to one queue while the message\nkept the spelling sent. An anycast target MUST be concrete: `*` is valid only in subscribe and\nallow patterns such as `svc.*.<owner>.<actor>`.\n\n**Reserved prefixes.** Application messages MUST NOT use subjects beginning with `$JS.`,\n`$KV.`, `$SYS.`, `$O.`, or `_INBOX.`. (`$O.` is the Object Store data/meta subject prefix\nper ADR-20, `$O.<bucket>.C.>` / `$O.<bucket>.M.>`; `OBJ_<bucket>` is a stream NAME, not a\nsubject prefix.)\n\n---\n\n## 4. Delivery modes\n\n| Mode | Routing field | Semantics |\n| --- | --- | --- |\n| multicast | `channel` | delivered to every subscriber of the channel |\n| unicast | `to` | delivered to the named instance's inbox |\n| anycast | `toService` | delivered to one consumer of the named role |\n\nExactly one of `channel`, `to`, or `toService` MUST be set on a `CotalMessage` (§5).\n\n**Authenticated delivery kind.** A receiver MUST derive \"how was this addressed to me\"\nfrom the delivering subject kind (`chat` -> `channel`, `inst` -> `dm`, `svc` ->\n`anycast`), not from payload routing fields, which are advisory. (\"Delivery kind\", the\naddressing axis, is distinct from a channel's `live`/`durable` **delivery class**, §7.) A peer can put your id in\npayload `to`, but cannot publish on your private unicast subject. Reference:\n`MessageMeta.kind`.\n\n**Delivery guarantee: `live` and `durable` classes.** Channel delivery has two classes, fixed\nper channel and wire-observable (§7); the guarantee is defined here, its NATS realization is the\nbinding in §8. A receiver MUST derive its effective class from channel config (§7), not from\nper-message metadata (`MessageMeta` need not carry it); it MUST NOT assume one class.\n\n- **`live`** is native broker-subscription delivery and is **at-most-once**: a message reaches\n only the instances subscribed to the channel at publish time. An instance that is disconnected,\n busy, or not yet joined does not receive that message live and has no claim to the live copy\n later. There is no per-subscriber redelivery of the live copy.\n- **`durable`** is `live` plus a per-subscriber durable backstop and is **at-least-once for\n current members within retention**: the message is also retained for each member and delivered on\n that member's next connection or turn, remaining pending until acked. A crash or `ack_wait` expiry\n redelivers the durable copy. At-least-once is bounded by the channel's retention / `replayWindow`\n (§7): a message evicted by retention before ack may be lost; the guarantee is not unbounded.\n\nUnicast (`to`) and anycast (`toService`) are at-least-once via their own DM/TASK consumers (§8);\nthey have no channel membership and are not subject to the per-channel delivery-class mechanism. An\n`@mention` (§5) on a `live` channel additionally writes a durable copy to each mentioned target\n**authorized to read that channel** (its `allowSubscribe` covers the channel), so an authorized but\noffline target still receives it; an `@mention` MUST NOT deliver channel content to a target outside\nits read ACL. Durable mention routing resolves each lowercased name to a unique current instance id\nfrom presence at publish time; an ambiguous (multiple live matches) or unresolvable name yields no\ndurable copy, and authorization is checked against the resolved id's current `allowSubscribe`. A\ntarget authorized for a channel is **mention-reachable** there whether or not it is currently joined; this is intentional (an `@mention` can pull an authorized peer in) and is distinct\nfrom membership; a client SHOULD distinguish \"joined\" (actively subscribed) from \"readable /\nmention-reachable\" (in `allowSubscribe`) so an unjoined channel is not treated as \"cannot reach me\nhere.\"\n\nA message delivered both live and durable is **one logical delivery**: receivers MUST deduplicate\nby `id` across classes (§8); the durable copy owns ack/commit; and a previously seen `id` MUST NOT\nbe treated as authorization for a later durable copy (for example one that arrives after a leave).\nReceiver deduplication MUST NOT use the empty string as a key. Two received messages MUST NOT be\ntreated as one logical delivery solely because both carry `id: \"\"`; each otherwise-deliverable\nmessage remains independently deliverable. Because live, backfill, and durable copies with\n`id: \"\"` cannot be correlated by wire identity, an at-least-once path may surface the same logical\nmessage more than once. The existing §5 obligation for publishers to supply a unique string id is\nunchanged. An absent or non-string id remains a malformed envelope.\nReceivers MUST tolerate the `live` gap and rely on the `durable` backstop for catch-up on\n`durable` channels. Malformed JSON, spoofed sender payloads, and unparseable delivery subjects are\npermanent anomalies and MUST be terminated, not retried.\n\n**Ordering.** Cotal does not define global ordering across modes, channels, or consumers.\nImplementations MUST NOT depend on cross-subject ordering. Per-consumer delivery is ordered\nby the backing stream except where redelivery or explicit backfill interleaves older\nmessages.\n\n---\n\n## 5. Envelopes\n\nDelivery messages are UTF-8 JSON objects with this shape (`CotalMessage`):\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `id` | string | MUST | unique message id; NATS binding also uses it as `Nats-Msg-Id` |\n| `ts` | number | MUST | epoch ms |\n| `space` | string | MUST | space name |\n| `from` | `EndpointRef` | MUST | `{ id, name, role? }` |\n| `channel` | string | one-of | multicast target |\n| `to` | string | one-of | unicast target instance id |\n| `toService` | string | one-of | anycast target role |\n| `mentions` | string[] | MAY | lowercased peer names; wakes the mentioned peer. On a `live` channel it also routes a durable copy to each mentioned target authorized to read that channel (§4); it never delivers content outside the target's read ACL and is not a routing substitute for `channel`/`to` |\n| `parts` | `Part[]` | MUST | content |\n| `replyTo` | string | MAY | id of the message replied to |\n| `contextId` | string | MAY | thread/conversation correlation id |\n\n`Part` is one of the three core shapes, or an extension object whose `kind` is namespaced\nas described in §11:\n\n- `{ \"kind\": \"text\", \"text\": string }`\n- `{ \"kind\": \"data\", \"data\": <any JSON value> }`\n- `{ \"kind\": \"artifact\", \"name\": string, \"mediaType\": string, \"digest\": string, \"size\": number }`\n- `{ \"kind\": \"<reverse-DNS extension kind>\", ... }`\n\nA `data` part's `data` MUST be a JSON value at every depth; a publisher MUST refuse the part\nrather than serialize a value JSON cannot represent, naming the offending member's path (a\ntop-level `undefined` serializes to a keyless `{\"kind\":\"data\"}` object, and `NaN`, a `Date`,\nor a class instance would be silently rewritten rather than refused).\n\nAn `artifact` part REFERENCES bytes held outside the message. `digest` MUST be\n`sha256:<lowercase hex>` over the raw bytes and is the artifact's identity; the part carries no\nlocation, so resolution is the receiver's. `name`, `mediaType`, and `size` are the publisher's\nclaims: a receiver MUST NOT allocate from `size`, and MUST verify fetched bytes against `digest`\nbefore use.\n\n`EndpointRef` is `{ \"id\": string, \"name\": string, \"role\"?: string }`.\n\nOn receive, a client MUST verify `from.id` equals the subject sender (§3). On mismatch, a\nmissing `from`, or an unparseable delivery subject, the message MUST be rejected and never\nredelivered.\n\nEndpoint requests and replies (the control surface) use the versioned typed envelope of\n§13.3 (`EndpointRequest`/`EndpointReply`); they are not Cotal delivery messages. The v0\n`ControlRequest`/`ControlReply` shapes are deleted (§13.11).\n\nReceivers MUST ignore unknown object fields. Unknown conformant extension `Part.kind` values\nMUST be ignored unless the receiver explicitly supports that extension. Bare unrecognized\ncore-kind values are not conformant. Messages MUST fit the broker's configured maximum payload;\nbytes that do not fit move out of the message and are referenced by an `artifact` part (above).\nThe transport that serves those bytes is not defined by this document.\n\n**Schema.** The JSON Schema (draft-07) at\n[`spec/cotal.schema.json`](spec/cotal.schema.json) is **authoritative for message shapes**:\na conformant delivery message MUST validate against it, and where this document's field\ntables and the schema diverge on a shape, the schema wins. Delivery *semantics* (routing,\nguarantees, rejection) are defined by this document's prose. The schema is generated from\nthe reference source, [`packages/core/src/types.ts`](packages/core/src/types.ts)\n(`pnpm gen:schema`), and committed; `pnpm check:docsbundle` fails when the committed file\ndiffers from the generator's output. The published copy lives at\n`https://docs.cotal.ai/cotal.schema.json`.\n\n**Rejection reasons.** The three permanent anomalies in §4 are terminated, never redelivered.\nThese reason tokens are advisory (for logs and error surfaces); the action is uniform:\n\n| Reason | Trigger |\n| --- | --- |\n| `malformed-subject` | the delivery subject does not parse (§3) |\n| `sender-mismatch` | `from` is missing, or `from.id` does not equal the subject sender (§5) |\n| `malformed-json` | the payload is not valid UTF-8 JSON |\n\n---\n\n## 6. Presence and discovery\n\nPresence is a per-space directory keyed by instance id. NATS binding: JetStream KV bucket\n`cotal_presence_<space>` (§8).\n\n`Presence`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `card` | `AgentCard` | MUST | identity record |\n| `status` | `PresenceStatus` | MUST | `idle`, `waiting`, `working`, or `offline` |\n| `condition` | `PresenceCondition` | MAY | harness-reported structured condition. Missing means nothing was reported. A connector relays the harness signal and MUST NOT infer a condition itself |\n| `environment` | string | MAY | opaque reference whose meaning belongs to the provider that issued it. Core MUST NOT parse it |\n| `activity` | string | MAY | freeform current activity |\n| `statusSince` | number | MAY | epoch ms when the instance entered its current `status` and `activity`. A change to either moves it; a heartbeat or a repeated report does not, so `ts` dates liveness and `statusSince` dates the report. An offline record MUST NOT carry it: an observer that derives `offline` from a stale `ts` does not know when the peer left |\n| `activitySince` | number | MAY | epoch ms when the current `activity` was set. A status change or a heartbeat does not move it, so an activity left behind while the status flips every turn still reads as old |\n| `activeAt` | number | MAY | epoch ms of the last work progress the harness reported, such as a token or a tool call. Missing means the connector reports none. `ts` is the heartbeat, so a live instance whose turn stopped advancing keeps a fresh `ts` and an old `activeAt`. A connector relays the harness's events and carries the value on its next heartbeat |\n| `attention` | `AttentionMode` | MAY | global attention mode: `open` \\| `dnd` \\| `focus`. Advisory observability; `open`/absent ⇒ receives everything. Reset: `open` published on `SessionStart`, removed on the offline sweep |\n| `lifecycleUid` | string | MUST in auth mode from v0.4 | the current managed-lifecycle UID (§13.1); distinguishes a live instance from a same-name successor. Advisory for display; authority checks use the trusted lifecycle mapping, not presence |\n| `runtime` | `PresenceRuntime` | MAY | the OS process holding this record's mesh connection, as that process observed itself: `{ id, startedAt, source }`. `id` is an opaque CSPRNG token minted once per (OS process, `lifecycleUid`) scope and MUST NOT be reused or span two lifecycle UIDs. A new process or lifecycle scope MUST get a new id. `startedAt` is the epoch ms that OS process started, read in-process (`performance.timeOrigin`), shared by all endpoints in the process. A lifecycle registered later carries the process's age, not its lifecycle age. It MUST NOT date a launch request, registration, heartbeat, activity, separate parent or model harness process. `source` is the closed set `endpoint-process`; an observer treats any other value as unsupported. Status, activity, heartbeats and in-process reconnects within the scope leave it unchanged. An offline record keeps it, so `now - startedAt` dates a running process only while the record is live. It carries no pid, host, path, command line or environment. Missing means not reported, never zero |\n| `channelModes` | `Record<string, ChannelMode>` | MAY | per-channel attention overrides (`ChannelMode` = `quiet` \\| `muted`), keyed by concrete channel name. Advisory, **not** access control (the broker still authorises and delivers); a receive-side preference, reset on restart |\n| `ts` | number | MUST | epoch ms of last heartbeat |\n\n`AgentCard`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `id` | string | MUST | instance id (§2) |\n| `name` | string | MUST | display name; at most 128 characters (`MAX_NAME_LENGTH`, refused at the shared validator; an unbounded name rides the CONNECT line until the broker drops it silently, §13.9) |\n| `kind` | `agent` or `endpoint` | MUST | participation class |\n| `role` | string | MAY | service role |\n| `description` | string | MAY | one-line summary |\n| `tags` | string[] | MAY | capability tags |\n| `skills` | `AgentSkill[]` | MAY | `{ id, name, description? }` |\n| `meta` | object | MAY | free-form display metadata. Reserved flat string keys are `connector` (host harness name), `model` (pinned model), `provider` (effective provider serving the model, connector-reported), `host` (self-reported machine), `cwd`, `repo`, `branch`, `head`, `sessionKind`, `sessionId`, and `terminal` (`stream` or `none`, whether a terminal attaches to the seats this manager starts). All are advisory only |\n| `protocolVersion` | string | MUST from v0.4 | wire version spoken (§11); `\"0.4\"` for this revision. Advertisement is the marker at the v0.4 reachability boundary (§13.11): a participant that omits it is pre-0.4 (omission means the pre-0.4 line, where the field was optional) and MUST NOT be addressed on the `ep` rails. A change signal, not negotiation |\n\nAn instance MUST refresh its own presence entry on the heartbeat interval, default 2000 ms.\nThe liveness window defaults to 6000 ms. A peer whose `ts` is older than the liveness window\nis considered `offline`.\n\nLive clients MUST NOT heartbeat as `offline`. A graceful disconnect MAY publish one final\n`offline` presence record. Observers MUST also derive `offline` from stale timestamps and\nfrom KV delete/purge events. Offline peers MAY remain in local rosters for observability.\nAn instance MUST write only its own presence key, and the key MUST equal `card.id`.\nReaders MUST drop a record whose `card.id` differs from its KV key, whose `card.name` or\n`status` does not have the type given above, whose `ts` is not a finite number, whose\n`card.role`, `activity` or `attention` is present and not a string, or whose `condition` is present\nand is not an object with a string `code`, and SHOULD report the rejection on their recoverable\ndiagnostic path. A `condition` of `null`, a bare string or an object with no `code` is dropped.\nA reader that kept a record whose `ts` is missing or text such as `\"nope\"` could not age it past the liveness window, so it would\nshow its peer live after the key expired. Readers print the string fields as text, and an object\nsuch as `{\"toString\":null,\"valueOf\":null}` throws when converted, so one kept row would fail every\nreader's roster.\n\nA watch delivers every member's heartbeat to every watcher, so a space of K watching members moves\nK² deliveries per heartbeat interval. A participant that needs the roster only when it acts (an\nagent resolving a DM target, checking an `@mention`, listing who is present) SHOULD read it on\ndemand instead: batched Direct Gets over `$KV.cotal_presence_<space>.>` (`next_by_subj`, paged), which\nbind no consumer. A read applies the reader rules above, and a record whose `ts` is older than the\nliveness window reads `offline`. Only a read that completed supports an absence verdict; a failed\nread MUST NOT be reported as \"no such peer\". Observers that act on liveness transitions\n(supervision, delivery `@mention` resolution, dashboards) watch.\n\n`PresenceCondition`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `code` | `PresenceConditionCode` | MUST | `rate_limit` \\| `overloaded` \\| `auth` \\| `billing` \\| `budget` \\| `context` \\| `model` \\| `request` \\| `server` \\| `retrying` \\| `approval` \\| `input` \\| `failed` |\n| `source` | string | MAY | harness-native value, relayed verbatim |\n| `message` | string | MAY | free text from the harness |\n| `since` | number | MAY | epoch ms when the condition began |\n\n### 6.1 Plane liveness\n\nA credentialed peer MAY ask whether the manager plane or the delivery plane has a bound\nresponder in its space. The question is presence only. It does not read either lease bucket,\nand the peer does not need to own the plane it asks about.\n\n**Planes.** The set of planes is closed: `manager` and `delivery`. A client MUST refuse any\nother plane before it publishes anything.\n\n**Subjects.**\n\n| Purpose | Subject |\n| --- | --- |\n| Request | `cotal.<space>.live.<plane>.<owner>.<actor>` |\n| Reply | `cotal.<space>.live.<plane>.<owner>.<actor>.reply.<nonce>` |\n| Responder serve filter | `cotal.<space>.live.<plane>.*.*`, queue group `live.<plane>` |\n| Responder reply grant | `cotal.<space>.live.<plane>.*.*.reply.>` |\n\n`<owner>.<actor>` is the asking principal (§2). The plane rides the subject so a credential can\nbe scoped to one plane by the broker. A `live` subject is not a delivery: `parseSubject`\nrecovers no sender from it, and a reader MUST NOT treat it as one.\n\n**Request.** The body is empty. The caller names a reply subject under its own request subject,\n`<request>.reply.<nonce>`, with a fresh nonce per probe. A responder MUST drop, without\nanswering, any request whose reply target is absent or is not under `<request subject>.reply.`.\nIt SHOULD report that drop on its recoverable diagnostic path. It MUST NOT report it on a\nchannel that can end the process, and it keeps serving.\n\n**Reply.** `LivenessAnswer`, JSON:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `plane` | `manager` \\| `delivery` | MUST | the plane asked about; a caller MUST reject a reply whose `plane` differs from the plane it asked |\n| `responder` | `ResponderState` | MUST | `bound` \\| `unbound` \\| `stale` \\| `unknown` |\n| `instance` | string | MAY | an opaque token naming the responder that answered. Non-empty when present |\n\nA responder MUST put nothing else in the reply. In particular it carries no lease holder, pid,\nworkspace path, instance id, runtime or roster.\n\n`instance` is minted fresh each time a responder binds and is derived from nothing. It is not\nthe endpoint's principal, the lease row's `instanceId`, a pid, a host or a path. It lets a\ncaller that probes more than once tell two responders apart from one responder whose state\nchanged. The queue group hands one probe to one member, so a single answer samples one\nresponder and cannot report a split across instances.\n\n**Responder verdicts.** A responder grades only itself:\n\n- manager: `bound` while its v0.4 service endpoint (§13) is serving, otherwise `unbound`. A\n closed service connection is not serving, including while the manager re-dials it. A\n disconnected one is not serving either, including while the client reconnects it.\n- delivery: from its own shard lease row. Absent or not ready is `unbound`. A ready row held by\n a different instance than the responder is `stale`. A ready row it holds is `bound`.\n- A responder that cannot determine its state answers `unknown`.\n\n**Rebinding.** A responder MUST bind its serve filter again on every broker connection that\nreplaces the one it bound on. A filter left on a closed connection gets the broker's\nno-responders answer, which a caller grades `unbound` for a plane that is still served. Each\nnew bind mints a new `instance`.\n\n**Caller grading.** The caller grades the outcome of asking:\n\n| Outcome | `responder` | `instance` |\n| --- | --- | --- |\n| a reply that parses as above | the reply's `responder` | the reply's `instance`, if any |\n| the broker's no-responders status (503) | `unbound` | absent |\n| timeout, permission refusal, transport failure | `unknown` | absent |\n| a reply that does not parse | `unknown` | absent |\n\nOnly the broker's no-responders answer yields `unbound` without a reply. Every other failure\nto get a readable reply is `unknown`. A caller MUST NOT report `unknown` as either health\nstate. A caller using the NATS binding MUST request without the muxed inbox, so a\nno-responders status reaches it rather than surfacing as a timeout.\n\n**Grants.** An agent may publish the request subject for each plane under its own principal\nand subscribe `<request subject>.>` for its replies. It holds neither serve filter, so it\ncannot answer for a plane. The `delivery` profile holds the delivery plane's serve filter and\nreply grant. The `supervisor` profile holds the manager plane's pair, and the remote-manager\nprofile holds them only for its supervisor actor (`manager_<instanceId>`). No responder can\npublish a request subject, because its reply grant stops at the `.reply.` leaf. Appendix B\nlists the agent rows.\n\nReference implementation: `livenessSubject`, `livenessServeFilter` and `livenessReplyGrant`\nin `packages/core/src/subjects.ts`; `LivenessAnswer`, `parseLivenessAnswer` and\n`responderFromProbe` in `packages/core/src/liveness.ts`; `CotalEndpoint.serveLiveness`,\n`serveDeliveryLiveness` and `probeLiveness` in `packages/core/src/endpoint.ts`.\n\n---\n\n## 7. Channels\n\nA channel is addressable as soon as it is published to. Channel config is optional and lives\nin the per-space registry bucket `cotal_channels_<space>`, keyed by the concrete channel\ntoken.\n\n`ChannelConfig`:\n\n| Field | Type | Notes |\n| --- | --- | --- |\n| `replay` | boolean | history replay-on-join; overrides the space default |\n| `replayWindow` | string | backfill horizon matching `^\\d+(s\\|m\\|h\\|d)$`, e.g. `\"24h\"` |\n| `deliveryClass` | `live` \\| `durable` | per-channel delivery class (§4); overrides the space default |\n| `description` | string | one-line purpose; max 200 chars |\n| `instructions` | string | advisory usage text; max 2000 chars |\n\nSpace-wide defaults (`ChannelDefaults`: `replay?`, `replayWindow?`, `deliveryClass?`) live under\nthe reserved key `=defaults`. Effective replay is `channel.replay ?? defaults.replay ?? true`.\nEffective delivery class is `channel.deliveryClass ?? defaults.deliveryClass ?? \"durable\"`.\n`defaults.deliveryClass` MUST be written at space creation from the deployment profile\n(local/self-hosted ⇒ `durable`, persistence on by default; public/web-scale ⇒ `live`, durability\nopt-in per channel), so the effective default is always discoverable on the wire, never inferred\nfrom out-of-band context. The same effective config MUST be the single source of truth for live\njoin, durable fan-out, history read, and membership surfacing; an implementation MUST NOT resolve\nthe class differently in different paths.\n\nJoin subscribes the instance to the channel; leave unsubscribes it. A join target MUST be within\nthe instance's read ACL (`allowSubscribe`, §9); a join outside it MUST be refused by the broker on\nsubscribe. A client MUST NOT publish to wildcard channels, but a wildcard read ACL (`team.>`)\nauthorizes subscribing to any one concrete channel under it **without enumerating channels in\nadvance**. In the NATS binding, join is a native `sub.allow`-bounded core subscription to the\nchannel subject and leave is the corresponding unsubscribe; **no privileged mediation is\nrequired**: the broker enforces every subscribe against `sub.allow`, so an instance whose ACL\npermits a channel joins and leaves it on its own, with no manager present. Open mode behaves the\nsame (the client subscribes directly). Leaving the last channel is permitted: under the core-sub\nbinding an empty subscription set subscribes to nothing (the v0.2 \"empty filter subscribes to all\"\nhazard and its last-channel-leave refusal were artifacts of the multi-filter durable and no longer\napply). On a `durable` channel, join additionally establishes durable membership, a separate\n**privileged** step: the instance requests durable membership from the server-side delivery daemon (a\ndurable-join command on the `delivery` endpoint, §13, carrying the channel and its captured join\ncursor) and the daemon writes the membership record. This is decoupled from the live subscribe, so a self-serve live join never depends\non it: a `durable` channel still delivers live with no privileged writer present, and only its\ndurable backstop requires one. A locally created subscription that the\nbroker later refuses (the permission violation is asynchronous in the NATS binding) is NOT a\nsuccessful join: an instance MUST treat a join as effective only once the broker has accepted the\nsubscribe, and MUST drop the channel from its joined set on a late refusal (§12). Leave removes the\nmembership (see membership below).\n\nReplay / catch-up on join:\n\n1. Record the channel join watermark (the CHAT frontier) before the subscription is active, so\n live tail and backfill do not double-deliver.\n2. Subscribe to the channel subject (`sub.allow`-bounded; §8). The live copy now flows.\n3. If effective replay is on, read retained messages for that channel up to the watermark,\n through a single-channel history read bounded by the current read ACL (`allowSubscribe`, §8),\n optionally limited by `replayWindow`. History is ACL-bounded, not membership-gated: an ACL-holder\n may read a channel's retained content whether or not it is a current member (it could self-join\n and read regardless), so the confidentiality boundary here is the ACL, consistent with the live\n read.\n4. Surface backfilled messages with `MessageMeta.historical = true`.\n5. Deduplicate by `id` across the live tail, the backfill, and (on `durable` channels) the durable\n backstop, so a message surfaces once. Receiver deduplication MUST NOT coalesce copies solely\n because `id` is the empty string (§4).\n\n Informative: an implementation preserving an incarnation across a local restart may start step\n 3's read from the sequence that incarnation had reached, rather than from the retained window's\n start; a fresh joiner reads the window.\n\n`replay=false` is noise control, not confidentiality. CHAT history is readable only within an\ninstance's read ACL (`allowSubscribe`, §9); confidential content MUST use DM or anycast.\n\nChannel membership governs **durable-delivery inclusion** (who receives fan-out copies into their\nper-subscriber backstop) and is broker-known, not self-reported. It is NOT a confidentiality\nboundary tighter than the read ACL: `allowSubscribe` bounds what content an instance may read (live\nand history, §9), and an ACL-holder can self-join, so membership adds delivery semantics, not read\nconfinement. In the NATS binding, membership is a privileged-written record in the space registry\nplane under a key the agent's profile cannot write (NOT the agent's presence key), carrying per-member\njoin/leave cursors so a publish concurrent with a join or leave orders deterministically; it is NOT\nderived from consumer topology, and an agent MUST NOT self-assert its own membership. It is written by\nthe server-side delivery daemon in response to a durable-join command on the `delivery` endpoint\n(§8, §13, Appendix B), distinct from and not required by the self-serve live subscribe. The implementation MUST re-authorize every\n**durable-backstop** read of `(instance, channel, message)` against the instance's current read ACL\nand membership before surfacing content, so a channel dropped from the ACL or **left** is no longer\nsurfaced from the backstop: **leave is a hard read boundary for the durable backstop** (it does not\nrevoke the ACL: an instance may still re-subscribe live, or read ACL-bounded history, within\n`allowSubscribe`). Membership remains observability data for liveness/roster purposes and MUST NOT be\nused as a send authorization gate.\n\nOn a `durable` channel, membership carries the member's **join cursor** (the CHAT frontier captured\nat join, the same watermark used to deconflict the live tail and the backfill) and, on leave, a\n**leave cursor/tombstone**. The durable backstop is at-least-once (within retention)\nfor messages whose stream sequence is **> the member's join cursor and ≤ its leave cursor**, where each\ncursor is the CHAT frontier (the last sequence) captured at that transition; messages published before a\njoin or after a leave are not redelivered as durable and are reachable only via an ACL-bounded history\nread (within `allowSubscribe`). A rejoin takes a new join cursor, so messages published during the gap are not durably\nredelivered. A `durable` join is atomic across its two effects: the instance is durable-joined only\nonce BOTH the broker-confirmed live subscribe AND the membership write have succeeded, and on a late\nsubscribe refusal the membership record MUST be removed. If the live subscribe succeeds but durable\nmembership cannot be established (for example no privileged writer is present), the instance is\n**`joined live` with the durable backstop unestablished**: it MUST NOT be reported as `joined durable`,\nthe live subscription remains active, and the durable shortfall MUST be surfaced as an exceptional\ndelivery state (e.g. `durable backstop unavailable`), never silently.\n\n---\n\n## 8. NATS + JetStream binding\n\nBacking streams are created once at space setup. `STREAM.CREATE` is denied to agents in auth\nmode.\n\n| Stream | Captures | Retention | Required config |\n| --- | --- | --- | --- |\n| `CHAT_<space>` | `cotal.<space>.chat.>` | Limits | file storage, `max_msgs_per_subject=1000`, `discard=Old`, `allow_direct=true` |\n| `DM_<space>` | `cotal.<space>.inst.>` | Limits | file storage, no Direct Get |\n| `TASK_<space>` | `cotal.<space>.svc.>` | WorkQueue | file storage, no Direct Get |\n\n**Resume transfer bucket.** A manager instance that receives a carried resume transcript holds one\nJetStream Object Store bucket, `cotal_xfer_<space>_<instanceId>` (stream\n`OBJ_cotal_xfer_<space>_<instanceId>`): file storage, `discard=new`, `max_age=0`, rollup headers and\nDirect Get allowed, every other limit `-1`. An object is named `sha256:<hex>` for the transcript's\ndigest and is written in the stock Object Store layout with its `nuid` set to `<hex>`, so every\nattempt at the same bytes writes one chunk subject, `$O.<bucket>.C.<hex>`. Each chunk is a\nJetStream publish carrying `Cotal-Offset` (transcript bytes through this chunk), `Cotal-Chunk`\n(chunks through this chunk) and `Nats-Expected-Last-Subject-Sequence` (the previous chunk's stream\nsequence, `0` for the first); the acknowledged chain is the upload's only checkpoint, and a writer\ncontinues from its last chunk. The commit is the stock meta record, published with `Nats-Rollup:\nsub` and an expected last subject sequence. The target manager stages a committed object, verified\nagainst its digest, removes the object whole, and removes any transfer idle for ten minutes; no\nmessage expires by age.\n\nChannel **live** delivery is a native core-NATS subscription to `cotal.<space>.chat.*.*.<channel>`\n(wildcard sender owner+actor) bounded by `sub.allow` (§9), not a durable consumer; join/leave is the\nsubscribe/unsubscribe and needs no privileged mediation. The legacy v0.2 `chat_<owner>-<actor>`\nlive-tail durable is removed from this binding (it MAY coexist transiently during migration behind\n`id` dedup, but is not part of the contract).\n\nDurable consumers. Per-instance durables are keyed on the principal's **dash-form** `<owner>-<actor>`\n(a `.` is illegal in a durable name; see §2), so a durable name-scopes to exactly one principal:\n\n| Durable | Stream | Filter | Policy |\n| --- | --- | --- | --- |\n| `chathist_<owner>-<actor>-<uid>` | CHAT | one `cotal.<space>.chat.*.*.<channel>` per read | transient single-filter consumer for history reads (join-backfill / focus-recall); created per read scoped to one channel in `allowSubscribe`, then deleted; `AckNone`. History is ACL-bounded by the pinned filter, not membership-gated (§7, §9) |\n| `dm_<owner>-<actor>-<uid>` | DM | `cotal.<space>.inst.<owner>.<actor>.>` | provisioner-created in auth mode at lifecycle activation; bind only; `DeliverPolicy.ByStartSequence` with `OptStartSeq = activationFrontier + 1`, where the **activation frontier** is the DM-stream's last sequence captured at activation (`0` on an empty stream, so the start is `1`): `ByStartSequence` is inclusive and the lifecycle interval is half-open, so the consumer starts strictly AFTER the frontier, never `All`, which would replay a recycled alias's history and the inactive-gap backlog; `AckExplicit`; `ack_wait=60000ms` |\n| `svc_<role>` | TASK | `cotal.<space>.svc.<role>.>` | provisioner-created in auth mode; bind only; `AckExplicit`; `ack_wait=60000ms`. **Intentionally role-shared, not lifecycle-scoped**: anycast work belongs to the role, and successive holders draining one pool is the contract |\n\nFrom v0.4, each lifecycle's durable state lives in the **half-open interval**\n`(activationFrontier, retirementFrontier]` per stream: consumers start strictly after the\nactivation frontier (`OptStartSeq = frontier + 1`, table above; the frontier is captured\nAFTER any inactive alias gap), and terminal retirement records the\nretirement frontier before the alias is freed, so a successor lifecycle never receives the\npredecessor's pending backlog nor messages published while no lifecycle was active (§13.1).\n\nA client MAY read its DM inbox with nothing but its own `dm_<owner>-<actor>-<uid>` durable. Such a\nreader MUST bind only an existing durable and MUST NOT create one; a missing durable is a refusal,\nnot a fallback to any other credential or read path. It MUST apply the §5 sender check before any\nhandler sees a message. Its native requests are CONSUMER.INFO and MSG.NEXT on that durable plus\nacks under `$JS.ACK.<DM>.<durable>.>`; it needs no presence, registry, channel, delivery, history\nor account-level JetStream row. The credential profile for such a reader is not defined here.\n\nPer-instance durable names use the principal's dash-form `<owner>-<actor>` (both tokens\nfail-loud-validated, not lossily sanitized), so a durable name-scopes to exactly one principal (§2).\nThe authenticated wire identity is the principal, not the connection nkey. From v0.4, in auth mode,\nper-instance durable state is additionally **lifecycle-scoped** (§13.1): durable consumer names,\npending delivery cursors, membership rows, and ACL/ledger rows key on\n`(principal, lifecycleUid)` (dash-form `<owner>-<actor>-<lifecycleUid>`), terminal retirement\nrecords per-stream sequence cutoffs before an alias is reused, and a same-name successor\ninherits none of its predecessor's pending state: its consumers start after its OWN\nactivation frontier (which is ≥ the predecessor's retirement cutoff), the cutoffs bound the\npredecessor's interval, they are never the successor's start.\n\n**Durable backstop (§4).** The per-subscriber durable copy is a delivery contract, not a pinned\nlayout: each member has a private durable store, written on publish for a `durable` channel's current\nmembers and, for an `@mention` on a `live` channel, for each mentioned target authorized to read that\nchannel (its `allowSubscribe` covers it), so an authorized but offline target still receives it. The\nagent holds **no content-bearing read** on this mixed store. A **trusted reader** (the server-side\ndelivery daemon) pulls each pending entry, re-authorizes `(instance, channel, message)` against the\nmember's **current read ACL** and, for `durable`-channel fan-out entries, its **membership interval**\n(the message's CHAT sequence is `> joinCursor` and `≤ leaveCursor`; §7), not a current-member boolean,\nso a pre-leave entry stays deliverable and a post-`leaveCursor` one does not,\nand delivers each authorized copy to the member over an **at-least-once** handoff (its own\n`dlv_<owner>-<actor>-<uid>` DELIVER consumer, carrying the same ack semantics, not a fire-and-forget publish). The trusted reader MUST NOT ack or\ndelete the backstop entry until the member has confirmed the copy was surfaced or handled (or it has\nbeen transferred to an equivalent per-member at-least-once mechanism with the same ack semantics); on a\ndownstream nak, timeout, or crash before that confirmation, the entry remains pending and redelivers, so\na crash between the `dlv` handoff and the member surfacing the message cannot lose it, and `durable`\nstays at-least-once end-to-end, not maybe-once. Content\nfor a channel dropped from the ACL, or (for a durable channel) left, is never surfaced (at-least-once for\nthe member within retention; **leave is a hard read boundary for the backstop**); a `live`-channel\n`@mention` copy is delivered and `id`-deduped the same way. The read MUST run in this trusted component\nthe agent cannot bypass, because a self-bound consumer has no server-side per-message ACL/membership\nfilter. The store's stream/subject layout, the fan-out writer, the trusted reader, and the membership\nregistry are reference-implementation, not normative; a conformant deployment MAY realize the backstop\ndifferently as long as the §4 guarantee and the §9 checks hold.\n\nThe absence of a usable receiver dedup key does not relax acknowledgement ownership: a\nJetStream-consumed copy with `id: \"\"` that is surfaced or handled MUST be acknowledged\nindependently. The reference fan-out and transfer publishes carry no `Nats-Msg-Id` for an\n`id: \"\"` message, so id-less messages are not publish-deduplicated on the durable plane.\n\nPublishers MUST publish channel, unicast, and anycast delivery messages through JetStream and set\nthe JetStream message id to `CotalMessage.id` (`Nats-Msg-Id` on the wire). A JetStream publish is\nan ordinary subject publish that the stream also captures, so the same message reaches core\nsubscribers live (§4 `live`) and is retained for history and the durable backstop in one publish;\nthe publish path is unchanged from v0.2; only the live *read* moves to a core subscription.\nAck/nak/term semantics apply to JetStream-consumed copies (history, DM, anycast, and the durable\nbackstop): receivers MUST ack only after a message has actually been surfaced or handled, MAY nak\ntransient failures, and MUST term permanently invalid messages. The at-most-once `live` copy is not\nacked. A receiver still handling a copy MAY restart its ack wait with JetStream's in-progress ack\n(`+WPI`). An ack or in-progress ack addresses the stream sequence rather than one delivery of it,\nso a receiver SHOULD stop renewing a copy once its ack wait may have run out since the last\nrenewal, because the broker may by then have delivered that sequence to another consumer.\n\nHistory on join uses the pinned single-filter `chathist_<owner>-<actor>-<uid>` consumer create above, bounded to\n`allowSubscribe`; agents are not granted unfiltered Direct Get. DM and TASK MUST NOT enable Direct Get\nbecause it would bypass the consumer-create deny that is part of the confidentiality boundary.\n\nKV buckets are also streams and are pre-created:\n\n| Bucket | Holds | TTL |\n| --- | --- | --- |\n| `cotal_presence_<space>` | presence (§6) | 6000 ms |\n| `cotal_channels_<space>` | channel registry (§7) | none |\n| `cotal_membership_<space>` | derived channel-membership feed (below) | none |\n\n**Derived channel-membership feed (observability).** `cotal_membership_<space>` is a per-agent\n(key = `card.id`) derived view of who is subscribed to each channel: the **union** of an agent's\n`live` core-subscriptions (read by a privileged daemon from the broker's connection view) and its\n`durable` memberships (the members registry), each value `{ live: string[], durable: string[],\nobservedAt }` with `live` keeping subscription patterns (wildcards) the consumer expands at read time.\nIt exists so an observer can show silent readers and `live`-channel membership without a broker-admin\ncredential in the dashboard tier; it is written by a scoped privileged daemon and read only by the\nadmin/observer profile and by the `deployer` and `teardown` operator credentials, which check a\nmanifest's channels for other members. It is **DISPLAY-ONLY and broker-derived**: it MUST NOT be an\ninput to any delivery, ACL, or authorization decision (authority for those stays the broker's\n`sub.allow` and the members registry), and it is not part of the normative wire contract a client\nmust implement.\n\n---\n\n## 9. NATS + JetStream security and authorization\n\n**On by default.** A space is provisioned with decentralized JWT auth. Open unauthenticated\ndev mode is available but out of scope for the security claims here. *(Informative\noperator-facing views of this section: [docs/identity-and-auth.md](docs/identity-and-auth.md),\n[docs/channels-and-permissions.md](docs/channels-and-permissions.md); the threat model is\n[docs/security.md](docs/security.md).)*\n\n- **Account = space, user = agent.** A space is one NATS account. The **broker's** operator signs\n the account; an account signing key mints per-agent user JWTs. A broker (one nats-server trust\n root: one operator, one system account) MAY host several spaces — one account per space, every\n account signed by that one operator. Broker trust is therefore per-broker, never per-space: a\n space owns only its own account and references the broker's operator, and rotating or replacing\n broker trust is intrinsically broker-wide - it affects every tenant on the broker at once and\n cannot be scoped to a single space.\n- **Profiles are default-deny allow-lists.** Subject, stream, durable, and KV names are built\n from the same builders as §3 and §8. Exact profile shapes are in Appendix B.\n- **An agent's channel scope is three concepts**, each a list of channel names or wildcard\n subtrees (`team.>`): `subscribe`, the active read set, the channels it subscribes to at boot\n (now native core subscriptions; mutable at runtime by direct subscribe/unsubscribe with no\n mediation); it MUST be a subset of `allowSubscribe`. `allowSubscribe`, the read **ACL**, the\n channels it MAY read (default = `subscribe`), minted as native `sub.allow` subscribe grants over\n `cotal.<space>.chat.*.*.<channel>` (wildcards preserved, so an open ACL needs no enumeration) and\n as the matching per-channel history-consumer create grants. `allowPublish`, the post **ACL**,\n the channels it may publish to; **default-deny** (a chat publish grant is minted only for a\n declared channel).\n\nEvery grant below is keyed on the agent's **principal** `<owner>.<actor>` (§2), except the reply\ninbox, which is keyed on the **connection** `<connId>`: the connection nkey (static mode) or the\nclient-chosen nonce (user mode, §9). This is the one place the wire identity and the connection\ncredential diverge (§2): the principal keys subjects/durables/presence; the connId keys the inbox.\n\n| Profile | Application publish | Read surface | Notes |\n| --- | --- | --- | --- |\n| `agent` | own `chat.<owner>.<actor>.<ch>` for each `allowPublish` channel (post ACL, default-deny), `inst.*.*.<owner>.<actor>`, `svc.*.<owner>.<actor>`; endpoint request forms per minted capability (`ep.one`/`ep.all`/`ep.inst` with the capability's authz-mode/target pattern, caller triple `<owner>.<actor>.<uid>` pinned; `describe` by default; `epj` submissions for journaled capabilities; §13.9); own presence key | own `_INBOX_<connId>.>` + own endpoint reply rail (`ep.reply.*.*.*.<owner>.<actor>.<uid>.*`, exact arity); channel live tail via native `sub.allow` subscriptions to `chat.*.*.<channel>` per `allowSubscribe` (wildcards preserved); `STREAM.INFO` (stream-level state only, no body read) on `CHAT` and the world-readable KVs, plus `TASK` when the credential carries a `role`; presence and channel-registry KV watches, including create/info/delete of their client-managed ordered consumers on those two streams only; CHAT history via single-filter `chathist_<owner>-<actor>-<uid>` creates, one per `allowSubscribe` channel (ACL-bounded); own lifecycle-scoped `dm_…`/`svc_…` bind-only; durable backstop via own bind-only lifecycle-scoped `dlv_…` DELIVER consumer, **no** grant on the mixed pre-auth fan-out stream; granted record-key/event-topic read subtrees per capability | read bounded by `allowSubscribe`; ordered-consumer cleanup cannot delete KV records or streams; durable copies re-authorized (current ACL + membership + lifecycle) by the trusted reader before the `dlv` handoff; no Direct Get; DM/TASK/DLV create denied. The `manager-caller` view narrows this endpoint control set to `ep.inst.manager.<managerInstanceId>.<command>` only, plus the exact instance `describe`, contract reads, own reply/progress rows, and own inbox. It carries no agent messaging, delivery, class, or scatter rows. When the actor holds `spawn`, the view also carries `status`, `models` and `resolve-cwd` on that instance, the reads a launch there needs; a view without `spawn` gains none of them, and no view gains `ps` or `slots` from `spawn`. |\n| `observer` | none | chat, CHAT history, presence, channel registry | DMs invisible |\n| `admin` | none | whole space live tap plus DM history | plaintext god-view, opt-in |\n| `transfer-writer` | one carried transcript's chunk and meta subjects in one manager instance's transfer bucket (§8) | a last-message Direct Get on those two subjects | one-shot per CLI call, minted after the transcript is hashed; no consumer and no other object |\n| `dm-reader` | `CONSUMER.INFO` and `CONSUMER.MSG.NEXT` on its own lifecycle-scoped `dm_…`, and its `$JS.ACK` subtree | own `_INBOX_<connId>.>` | no message publish, presence, channel, CHAT, `dlv_`, `$JS.API.INFO` or stream INFO row; bound to the bearer's expiry |\n| `transfer-reader` | the stock delete marker on its own transfer bucket's meta subjects | its own `OBJ_cotal_xfer_<space>_<instanceId>` stream: info, message get, its push consumer, purge | one-shot per `transcript-receive` or sweep; no other instance's bucket |\n| scoped host profiles | least-privilege per function | least-privilege per function | The former allow-all `manager` is **deleted**; its host duties split into scoped, single-function creds (`supervisor`, `provisioner`, `delivery`, `membership-rw`, `operator`, `purger`, `teardown`, `channel-writer`, …). No allow-all credential exists. Appendix B summarizes them; the concrete grant lists are **generated from the §13.9 ownership matrix** into `provision.ts` (the matrix is the single oracle; `provision.ts` is its artifact, Appendix B its summary). |\n\nA Manager with explicit `execution: \"none\"` MUST construct no Runtime or connector workload.\nIt MAY use the existing genuine auth-local authority path, or the existing pooled signerless\nremote authority path. These authority paths MUST NOT be mixed. A local NONE instance MUST\nrequire its hosting user-auth marker, signing trust and user-mode mesh record before binding.\nIts persisted native instance, serve principal, owner checks and registration gates are unchanged.\nExecution capability MUST be immutable per instance; an existing unclassified local identity or\nretained seat/turn inventory MUST refuse NONE admission. Startup MUST NOT silently convert a\nruntime instance or adopt a sibling's workload.\n\nNONE status MUST report no runtime, custody, class spawn, workflow hosting or terminal sessions.\nLaunch and workflow requests MUST refuse before allocation or workload effects. Launch reads\nMUST refuse before resolving a Runtime, connector or host path. Targeted requests retain normal\nlifecycle-mapping validation; an instance with no managed mapping does not fabricate a target.\nNONE MUST refuse model inspection before connector or harness resolution. Caller-driven persona,\nhistory purge, transcript transfer, preservation, resume, turn-yield, cancellation and self-stop\nwrites MUST refuse before their effects. NONE MUST NOT start a transcript receiver or sweep.\nNative registration, lease, credential renewal, session-ledger and goal maintenance MAY still\nwrite their own control state autonomously; NONE is not a read-only broker or filesystem mode.\nNative ps remains this instance's managed map, not a presence or HTTP-session inventory.\n\nThe `resolve-cwd` launch read is limited by execution mode. A manager whose runtime delegates\nseats outside its host MUST refuse it with `failed-precondition` before any filesystem lookup.\nThe refusal MUST be independent of the requested path's existence, type and symlink target,\nand MUST NOT return a host name or canonical path. Such a runtime cannot use a manager-host cwd.\n\nOn such a runtime, a caller-supplied persona `config` override MUST be refused before resolving,\nchecking or reading its host path. Every path shape MUST receive `failed-precondition` and the\nsame message: `delegated execution cannot use a manager-host persona config path; select a named persona`.\nThis applies to `resolve-agent` and `spawn`, including starts submitted through library or workflow\nhosts. A named persona remains subject to the manager's catalog visibility rules. A validated\nresolved manifest may use its own host-materialized persona resource; public requests MUST NOT\nbe able to supply that internal resolved authority as a config override.\n\nDM and TASK confidentiality, and the CHAT read boundary, close the leak paths:\n\n1. Replies and pull responses ride a per-connection inbox prefix, `_INBOX_<connId>.>`, which\n `sub.allow` permits alongside the agent's channel read grants (next item) and nothing else. In user\n mode the client picks `<connId>` (a nonce) and the callout scopes the inbox to it, so a\n wildcard-inbox subscribe that would sniff peers' DM deliveries is refused. Re-authorized durable\n copies do NOT ride the inbox; they ride the agent's own lifecycle-scoped `dlv_<owner>-<actor>-<uid>` DELIVER consumer\n (item 5, §8).\n2. **Channel live reads are bounded by `sub.allow`.** `allowSubscribe` is minted as native subscribe\n grants over `cotal.<space>.chat.*.*.<channel>` (wildcards preserved); the broker refuses, per\n subscribe, any channel subject outside the ACL. There is no per-channel consumer name to confine,\n so an open ACL (`team.>`, `>`) grants selective single-channel join with no enumeration and no\n read-breakout. A `>` grant is read-all chat in the space by design (credential compromise reads\n all chat), so it suits trusted/local deployments, not least privilege.\n3. A consumer create on the bare/multi-filter subject is not ACL-constrainable, so the provisioner\n pre-creates `dm_<owner>-<actor>-<uid>`, `svc_<role>`, and the per-member `dlv_<owner>-<actor>-<uid>` handoff\n durables. Agents bind their own `dm_…-<uid>`/`svc_<role>`/`dlv_…-<uid>` only (never\n create); the mixed pre-auth fan-out store is read by a trusted reader, not the agent (§8, item 5).\n Those bare/multi-filter create forms are not granted to agents (default-deny), with explicit\n create-denies on `DM_<space>`, `TASK_<space>`, and the `DLV` stream; on `CHAT_<space>` the only\n consumer-create an agent holds is the pinned single-filter history create (next item), so a broad\n CHAT create-deny is intentionally absent: it would also deny that pinned create.\n4. CHAT history reads are bounded to `allowSubscribe`: a consumer create on the extended subject\n `$JS.API.CONSUMER.CREATE.<stream>.<name>.<filter>` carries a single filter the server pins to the\n request body, so an agent is granted exactly one such create-subject per `allowSubscribe` channel\n and can read history of no other channel. The unfiltered Direct Get grant is not given to agents.\n5. **The durable backstop is read by a trusted reader, not the agent.** The agent holds no\n content-bearing read on the mixed pre-auth fan-out store; a trusted reader (the server-side delivery\n daemon) MUST re-authorize `(instance, channel, message)` against the member's current read ACL and,\n for `durable`-channel fan-out entries, its current membership, before handing the authorized\n copy off to the member's own lifecycle-scoped `dlv_<owner>-<actor>-<uid>` DELIVER consumer:\n broker ownership of an inbox (\"this is agent A's\") is not authorization, since the store can hold\n messages for channels A has since dropped from its ACL or left, and a self-bound consumer cannot\n filter per-message on membership. Fan-out-on-write is routing, not an authorization check; for a\n durable channel a `leave` is a hard read boundary on the backstop. History/backfill reads are instead\n self-served and bounded by the current read ACL (the pinned single-filter create above), consistent\n with the live read. An `@mention` durable copy is written only to a target authorized to read the\n channel, so `mentions` cannot carry content outside a target's read ACL.\n6. **\"Current read ACL\" is the effective broker-accepted credential.** An ACL narrowing takes effect\n when the credential/permissions are updated and enforced by the broker (re-mint / reconnect /\n revocation), not as an instantaneous global value; until then an existing broad credential remains\n broad. Both the broker `sub.allow` checks and the trusted-reader re-checks are evaluated against that\n effective credential.\n\nThis binding provides containment and authenticity under a single trusted broker: an agent\ncan emit only as itself and only to its declared `allowPublish` channels, and read only its own\nDMs and chat *content* within `allowSubscribe` (and, for `durable` content, its current\nmembership), enforced by the server. It does not provide\nnon-repudiation, does not survive an untrusted relay, and DMs are plaintext to the broker and\nto `admin`. The read bound is on **content**, not metadata: agents hold `STREAM.INFO` on CHAT\n(for the join watermark, the recall drop-marker, and channel-list counts), so a `subjects_filter`\nquery leaks chat subject *metadata* (channel names, sender ids, and per-subject counts) for\nchannels outside `allowSubscribe` (channel names are already public via the registry). A\ncredential minted with a `role` also holds it on TASK, under the same gate as that role's\n`svc_<role>` bind grants, so a `subjects_filter` there leaks anycast subject metadata\n(`svc.<role>.<owner>.<actor>`, who anycast which role) to an operator-chosen role profile. DM,\nDLV, and EPC carry **no** agent `STREAM.INFO` grant: `subjects_filter` is a request-body field no\nACL can narrow to counts alone, so INFO there would enumerate who DMed whom, and no agent-side\nreader needs it (§13.1 reaches DM and DLV by durable name, EPC by subject-scoped `DIRECT.GET`).\nHiding the remaining metadata is deferred strict-containment work.\nSee [docs/security.md](docs/security.md).\n\n**Consumer-delivery confused deputy on the read grants.** A JetStream consumer delivers stored\nbytes to a **caller-chosen destination the broker does NOT confine to the requester's\n`pub.allow`**: a push consumer's `deliver_subject`, and a pull `MSG.NEXT`/`DIRECT.GET`\nrequest's reply subject, are set in the request body and the server's internal client publishes\nthere regardless of the requester's publish permissions. The v0.3 read grants above,\nCHAT-history `CONSUMER.CREATE`, the bind-only DM/DLV/TASK `MSG.NEXT`, and the KV watch creates\n(Appendix B); therefore let an agent redirect content it may legitimately READ onto a subject\nit may NOT publish to: e.g. replay a stored CHAT message whose `from.id` is another sender onto\n`inst.<victim>.<thatSender>`, where the recipient derives the DM sender from the subject and\nsurfaces it as a genuine DM from a principal who never sent it. The §13.9 \"Mediated reads\" rule\napplies here: **no untrusted agent holds a raw consumer `CREATE`/`MSG.NEXT` or `DIRECT.GET` on\n`CHAT`/`DM`/`TASK`/`DLV` or the KV buckets**; those reads are served by the trusted\nreader/mediator (§8) onto the agent's own confined rail. Which of these read paths require\nmediation and which are provably safe depends on whether a redelivered message retains its\noriginal captured subject and how the receiver's subject-derived kind check (§12) then\nclassifies it; the reference implementation determines this by test and pins the exact grants.\nOn the v0.3 rails without this mediation, read containment holds only against a *conforming*\nclient; the broker does not enforce it.\nSee [docs/security.md](docs/security.md).\n\n---\n\n## 10. Connection and onboarding\n\nJoin link grammar:\n\n```text\ncotal://[token@]host[:port]/space[?channel=a,b] plaintext\ncotals://[token@]host[:port]/space[?channel=a,b] TLS required\ncotal://user:pass@host/space user/password auth\n```\n\n- Default port is `4222`.\n- `channel` and `channels` query parameters are equivalent comma-separated channel lists.\n- Credentials in `userinfo` are parsed out and passed to the NATS client as connect options;\n they are not left inside the server URL.\n- Bare `userinfo` with no `:` is a token. `user:pass` is username/password.\n- `cotals://` means `nats://host:port` plus TLS-required connect options.\n- Credentials (`creds`) are mutually exclusive with token and username/password auth.\n- A client MUST set `inboxPrefix` to `_INBOX_<connId>` before any request, pull consumer, or KV\n watch operation, where `<connId>` is the connection identifier (the connection nkey in static\n mode; the client-chosen nonce in user mode, §2/§9), NOT the owner+actor principal, which the\n client may not know pre-connect.\n\nAuthenticated onboarding has two bindings. **Out-of-band credential minting** provisions a per-agent\ncredential ahead of connect (the static path). **Auth-callout onboarding** validates a user bearer at\nconnect time and mints the scoped data-account JWT then (user mode, §2/§10): the client presents a\ndeny-all sentinel credential plus its bearer, the callout derives the owner+actor principal and grants,\nand re-binds the connection into the data account. A space's callout requests are served inside that\nspace's dedicated auth account, so a responder holds one subscription per auth account it serves. One\nprocess MAY serve several spaces, holding one such subscription and one set of signing keys per\nspace; a response for a space MUST be signed only with that space's keys, and a bearer MUST be\nvalidated only against the issuer and audience of the space whose request it arrived on. A process\nMAY likewise serve several spaces' exchange and JWKS, as one full auth service per space: each\nspace's exchange MUST be served on listeners of that space's own and mint only from that space's\nkeys and ledger, and each space keeps its own authority plane (§13.13). The owner-token *derivation* (how a bearer maps to\nan owner token) is a pluggable identity adapter (any OIDC/IdP via a thin bridge), not fixed by this\ncontract; the callout *mechanism* and the resulting grants are. From v0.4 every minted connection also carries its **lifecycle UID** (§13.1): the manager\nmints it for managed agents at provision, and the callout/exchange attaches it as a claim at\nconnect for user-mode connections, so the caller-UID token in every endpoint-rail grant is\nauthority-assigned, never client-chosen. Every bearer additionally carries its incarnation's\n**root credential id** (`act.credentialId`, §13.1). The exchange ensures the ACTIVE\n`cred.<lifecycleUid>.<credentialId>` ledger row exists BEFORE the bearer bytes are released\n(the row durable first, the issuance-gate finalize CAS, the lifecycle head's current-root CAS\nlast), and the connect authority proves the presented id against the LIVE row, leader-served\nfrom the shape-proved primary auth store: the row MUST be `active`, unexpired, and bound to the\nconnecting principal and lifecycle, and a root-issued credential MUST additionally equal the\nlifecycle head's current root credential. A claimless bearer, a revoked, expired, or absent row,\nand an unreadable authority store all DENY the connect. The root credential is\n**incarnation-wide**: ONE `cred.<lifecycleUid>.<credentialId>` row per incarnation, re-stamped\n(the same id) on every exchange for the incarnation's lifetime, never a fresh id per exchange.\nRevoking that one row is the per-credential revocation lever and denies EVERY bearer of the\nincarnation at the next connect (deny-new; evicting an already-live connection is the lifecycle\nbarriers' job, §13.1). Because the id is incarnation-stable, a crash after the head's current-root\nCAS re-exports the SAME id on the next exchange (that id IS the incarnation's live root, so there\nis nothing unobserved to revoke); the only pre-release crash window is a durable active-but-\nunstamped row, which the head-equality check denies. Rotating an incarnation's root credential is\nexclusively a lifecycle barrier's job, never a bare re-mint. A bearer MAY carry a server-authored\n**view** claim, selected only by the exchange and re-authorized against the live grant ledger at\nevery connect. The callout then mints the connection as that closed profile instead of `agent`.\nElevated views such as `admin`, `purger`, `channel-writer`, and `deployer` remain human-only. The\nnarrowing `manager-caller` view MAY be minted by either the human or managed-agent exchange and is\nserved on both exchange faces. It adds no capability beyond the launch reads §9 lists for a `spawn`\nactor's view. Its required `act.managerInstanceId` binds\nevery manager request to one exact live registered instance and is valid with no other view. The\nexchange selects from read-only observations of manager issuance gates and service registrations.\nIt refuses zero or ambiguous candidates and refuses an unavailable owner-specific remote manager\nrather than falling through to a co-located manager. An explicit selector must name a live candidate.\nOn the public exchange face, once the caller's credential and ledger actor grant have verified\n(for a human exchange, the IdP JWT and the interactive actor grant; for an agent exchange, the\nmanaged actor secret and its ledger row), a `manager-caller` request that fails only manager\nselection MUST return its selection refusal reason on 401 without spending the per-peer probing\nbudget. The public face tracks those authenticated selection refusals in two rolling windows per\nprincipal (derived owner for human exchanges, `owner.actor` for agent exchanges) keyed by\nprincipal and request class (`pinned` when the request names `managerInstanceId`, `unpinned` when\nit does not, never by the requested instance id): each class counts only its own selection\nrefusals and, once its window is full, refuses requests of that class (including ones that would\nhave succeeded) with 429 and that class's remedy before running manager selection, while leaving\nthe other class open. On the loopback face, an authenticated unpinned refusal caused by no live\nmanager or ambiguous candidates returns its own reason without spending the shared probing budget.\nA trusted host composition MAY instead select its genuine local Manager up front for an unpinned\ninteractive human exchange. It MUST apply the same native local identity, open gate, serve principal,\nregistration revision and epoch checks, and MUST refuse an absent, unreadable or noncandidate local\nManager without reading or substituting remote candidates. This policy MUST NOT be request-selectable,\nchange explicit selectors, rebind managed or issued callers, or add command authority. Without the\nhost opt-in the default selection above is unchanged.\nThe auth service lists the same observations to a signed-in human at `POST /manager-instances` on\nboth faces: it verifies the same IdP proof, derives the owner the same way, and answers every manager\ngate of that owner using the same candidate checks as selection. A listed candidate is registration evidence, not proof that the instance answers, and a\nfailed read is unavailable, never an empty list.\nThe `session-caller` view carries a required `act.session` claim `{endpoint, sessionId, epoch, exp}`\n(exp in unix seconds) and is valid with no other view; `act.session` is valid only with it. It needs no\nledger scope: the redeemed §13.6 session grant is the authority. The human exchange accepts it only\ntogether with a `sessionGrant` body (each without the other is a 400), and the trusted auth path MUST\nleader-read the `session.<sessionId>` row from the dedicated sessions store before it signs. It MUST\nrefuse unless the row is `active`, `row.grantSig` equals the presented grant's signature, the row's\nholder principal and lifecycle are the bearer's owner, actor and `lifecycleUid`, the endpoint and\nserving epoch equal the presented ones, `row.exp` is in the future, and the serving manager's issuance\ngate is a candidate for this owner with a process epoch equal to the row's. The stamped `exp` is the\nrow's, and the bearer TTL is bounded by it. The callout MUST re-run the same check, without the\nsignature comparison, against a fresh read at connect. It mints the `session-caller` profile for that\none session and binds the minted connection's expiry to the grant's, which is the static arm's\nexpiry, rather than the bearer's. The auth service's host-issuer connection performs both reads and\nholds only `STREAM.INFO` and the leader-served `STREAM.MSG.GET` on `KV_cotal_sessions_<space>`: no\nDirect Get and no write on that store.\nThe `transfer-writer` view carries a required `act.transferWriter` claim `{instanceId, hex}` and is\nvalid with no other view; `act.transferWriter` is valid only with it. It needs ledger scope `admin`,\nthe scope of the `transcript-receive` row it serves. The human exchange accepts it only together with a\n`transferWriter` body (each without the other is a 400), and the callout mints the `transfer-writer`\nprofile for that one object of that one instance's transfer bucket (§8).\nOn a public exchange face, `channel-writer`, `channel-purger`, `manager-caller`, `session-caller`, and\n`transfer-writer` MAY be issued. `admin`, `purger`, `deployer`, and `manager-service` MUST remain loopback-only. A\nmanaged-agent secret exchange MUST refuse every view other than `manager-caller`.\nThe service-only `service-endpoint` view (§13.1) is not selectable on either ordinary exchange\nface. Its dedicated authority path checks native service custody rather than an enrolled actor row.\nThe `dm-reader` view needs no ledger scope and MUST remain loopback-only. It rides only a\npurpose-bound IdP proof. The proof carries the bridge's dedicated `dmReaderAudience`, which is\nexplicit configuration and MUST differ from the ordinary audience. It also carries\n`purpose: \"dm-reader\"` and the `actor`, `lifecycle` and `space` claims. The exchange MUST refuse\nunless the request names `view: \"dm-reader\"`, `actor` equals the requested actor, `lifecycle`\nequals the current ledger row's lifecycle UID, and `space` equals the bridge's space. Every other\ndoor that takes a human IdP proof MUST refuse any token carrying a `purpose` claim. At this release\nthose are the other `/exchange` forms, `/manager-instances`, `/manager-service-authority`, the three\nchat-session routes, `/tool-result-human-proof/verify` and `/tool-result-consent/issue`. The\nbearer's expiry, and with it the connection's, is bounded by the proof's.\n\n**Connect limits.** The auth service MAY limit connects per actor and per owner, charging a bearer\nwhose signature verifies to the principal it names even after it expires, and per client host for a\nbearer that does not verify. Buckets are per space: a process serving several spaces MUST keep a\nseparate set for each, so a connect to one space never spends another space's allowance. A callout that refuses a connect for a limit MUST answer with a signed\ndenial whose reason starts with `RATE_LIMITED retry-after <n>s`, and MUST do so before it reads the\nledger or records an issuance. While an actor or its owner is limited, an exchange for that actor\nMUST answer 429 with the body `{code: \"RATE_LIMITED\", retryAfterSeconds, limit, error}`, where\n`retryAfterSeconds` is a positive integer and `limit` is `\"actor\"` or `\"owner\"` for the bucket that\nran out, and a `Retry-After` header carrying the same number. It MUST NOT count that answer against\na refused-exchange budget. A client that receives it SHOULD NOT exchange or connect as that actor\nagain until those seconds have passed.\n\n**User-mode chat sessions.** The auth service is a minting authority for chat sessions only\n(§13.1). A signed-in human opens one with a fresh IdP proof and the SHA-256 of a holder secret the\nclient keeps in memory. The service derives the owner, draws the actor `chat_<26 base32>` and a\nfresh lifecycle UID, and pins the human's own `cli` grant: its lifecycle UID, head revision and the\nRFC 8785 digest of its row. The session's read and post lists MUST be contained in that grant, and\nits lifetime is at most 8 hours and never extended. A request that names an owner, actor, UID,\nscope, view or profile refuses. The holder index `chatholder.<owner>.<holderHash>` is created\nbefore any lifecycle write and only advanced by revision-pinned CAS (`reserved`, `provisioning`,\n`active`, `retired`), so a retry with the same holder hash converges on the same session and a\nretired hash never admits again. A `pending` session row authorizes nothing. Each bearer exchange\npresents the holder secret. Its TTL is at most the least of 900 s, the IdP proof's remaining life\nand the session's remaining life. The bearer is released only after the session row, the holder\nindex, the parent pin and the session's own lifecycle head and root credential are read current\nboth before and after signing. The callout mints a chat principal as the `agent` profile with the\nsession's lists and no role, capability, endpoint capability or view. It refuses a chat bearer\nthat carries a view or a scope, or whose row is not `active`, names another lifecycle, holds a\nmoved parent pin or has a holder index that is not `active`. Retirement settles the session's\nlifecycle through the §13.1 barrier before the per-owner quota row `chatowner.<owner>` releases its\nslot. The auth service's sweep retires expired sessions the same way. It acts on an unfinished\nadmission only after a 60 s quiet period, which is never the evidence: it fences the holder index\nfirst, drives the bound UID to a terminal gate, and releases the slot last. A pass makes at most 256\nof its own reads, runs at most 4 retirements at once and never waits for one. A retired row is\ncompacted 24 hours after its expiry, once the UID's footprint is removed again. The routes are\n`POST /chat-session/open`, `/chat-session/bearer` and `/chat-session/retire`, on both exchange\nfaces, with the same IdP proof check and the same capability rule as `/exchange`. Every refusal on\nthem carries its effect outcome: `not-executed`, `executed` or `unknown`.\n\n---\n\n## 11. Versioning and extensibility\n\n- Wire contract version is v0.2 as advertised today. `AgentCard.protocolVersion` (§6) carries\n this string. The two v0.3 binding revisions (channel live delivery and owner+actor identity,\n see the header) and the **v0.4 endpoint control surface** (§13) are the normative targets the\n reference implementation is converging to. The control surface is an intentional **hard\n cut on the pre-1.0 line** (§13.11): the v0.3 control grammar and envelope are removed from\n this contract, not dual-served, a breaking revision, permitted pre-1.0, shipping under an\n explicit new version marker per this section's rule; the marker is the disjoint endpoint\n subject grammar and versioned envelope. The advertised `protocolVersion` bumps to `0.4` when\n the control-surface migration completes (one campaign, one merge); a version string is not a\n per-surface cutover claim. **`1.0` is deliberately deferred**: it is a stability declaration\n to outside implementers, made separately once the contract has settled (further pre-1.0\n arcs (presence/addressing, multi-space, federation) may still break the wire). **The wire `protocolVersion`\n is the compatibility signal**; dated document snapshots (below) are navigation artifacts, not\n negotiation; an implementation MUST NOT treat a document date as an interop key.\n- **v0.5 (workflow runs, §14) is an additive revision.** It adds a per-space stream, four core\n record kinds, a per-run grant family and a normative language reference, and changes no existing\n kind, subject, grant row or shipped datum; a participant that ignores §14 conforms to v0.4\n unchanged. Two versions ride it and they are deliberately distinct: the wire `protocolVersion`,\n which targets `0.5` when the plane is served, and the language's own `languageVersion` (§14.2),\n which is bumped when a program's MEANING changes and is pinned per run, so a language revision\n never forces a wire revision and a wire revision never invalidates an open run.\n- v0 has no in-band capability negotiation. Deployments MUST agree on the binding and\n version out of band. A participant advertises the version it speaks via\n `AgentCard.protocolVersion` (§6) as a one-way change signal, optional before the v0.4\n marker, MUST from v0.4 (§6, §13.11); v0 defines no behavior on a mismatch beyond rejecting\n messages it cannot parse.\n- **A non-additive discovery change is an out-of-band deployment cutover, and it rolls out\n CALLER-FIRST.** A discovery change is non-additive when an unamended client that ignores it per\n the unknown-field rule below would then behave in a way the change exists to prevent — for such\n a change, ignoring is not a safe default and no default value repairs it. Every caller in a\n deployment MUST implement the new version's rules BEFORE any responder in that deployment\n registers or describes at that version. The two halves SHOULD therefore ship in **separate**\n releases — the caller side first and adopted across the deployment, the responder's emission only\n after — and shipping them in one release does not make a deployment safe, because **a release is\n not a deployment**: an already-running caller is unchanged by whatever a new artifact contains,\n so the order of two source edits says nothing about the processes on the wire. This rule exists\n because the preceding one leaves a responder no way to detect the hazard itself: with no in-band\n negotiation and no caller version on the wire, a responder cannot tell an amended caller from an\n unamended one, so the obligation rests on the deployment rather than on either participant. The\n observable marker is the discovery protocol's `protocol.v` on the registered service record\n (§13.7) — \"has any responder cut over\" is a checkable registry property, while \"has every caller\n adopted\" is exactly the out-of-band agreement this section already requires. **The residual is\n real**: a deployment that cuts a responder over early exposes its unamended callers to whatever\n the new version exists to prevent, and within v0 nothing in band detects it. Closing that needs\n negotiation v0 does not have, and the v1 marker below is where it belongs.\n- New message families, subjects, and routing kinds are added in the core contract,\n generalized for all deployments, not in one example.\n- Receivers MUST ignore unknown object fields and MUST NOT treat an unknown field as an\n error.\n- A future v1 MUST either keep v0 subjects backward-compatible or use an explicit new\n version marker in subjects, credentials, or deployment config.\n\n**Document snapshots.** Published revisions of this document are dated snapshots\n(`YYYY-MM-DD`, the **Last updated** date above): the current revision is canonical, and a\nsuperseded one stays retrievable from the repository history (the git history and tagged\nreleases of `SPEC.md`), so a client built against it can still be audited. The snapshot\ndate advances on any normative change; the wire `protocolVersion` moves only per the\nchange process below.\n\n**Change process.** This document is the change-control point: a change lands here first,\ngeneralized into `core`, and the reference implementation follows. Additive changes (a new\noptional field, a new namespaced `Part.kind`, a new subject) are backward-compatible and ship as\na minor bump, since receivers ignore what they do not recognize. Changing the meaning of an\nexisting field or subject, or removing or renaming one, is breaking. **Pre-1.0**, a breaking\nchange ships as a minor bump of the v0.x line under an explicit new version marker in\nsubjects, credentials, or deployment config (the v0.4 endpoint grammar is such a marker);\n**post-1.0**, it ships as a major bump. `1.0` itself is a stability declaration, made\ndeliberately and separately from any wire change.\n\n**Extension namespacing.** Core `Part.kind` values, `meta` keys, and `tags` are bare and reserved\nto this spec (`text`, `data`, `artifact`, and future core additions). A non-core extension MUST namespace its\ncustom `Part.kind` values and `meta` keys reverse-DNS, under a domain its author controls, e.g.\n`{ \"kind\": \"com.acme.snapshot\" }` or `meta[\"com.acme.region\"]`; Cotal's own non-core extensions\nuse `ai.cotal.*`. This keeps third-party names from colliding with each other or with future core\nnames, with no central registry.\n\nReserved future work: signed envelopes, `did:key` identity, auth-callout bootstrap tokens,\nmanager profile scoping, and federated/untrusted relay bindings. (Revocation/TTL for minted credentials is no longer future work on the control\nsurface: v0.4 defines it normatively via the credential ledger and the lifecycle barriers,\n§13.1.)\n\n---\n\n## 12. Conformance\n\n*(An informative build-order walkthrough of this checklist is\n[docs/build-a-client.md](docs/build-a-client.md).)*\n\nA conformant authenticated NATS client MUST:\n\n1. Use one stable principal `<owner>.<actor>` as its wire identity everywhere: subject sender\n tokens (§3), `from.id` (§5), presence key (§6), durable names (dash-form, §8); and treat the\n connection credential (nkey) as distinct, keying only its reply inbox (§2).\n2. Publish only on subjects whose sender tokens are its own principal `<owner>.<actor>` (§3).\n3. Publish delivery messages as UTF-8 JSON through JetStream with `msgID = id` (§8).\n4. Set exactly one routing field on each delivery message (§5).\n5. Reject any received delivery message whose `from.id` does not match the subject sender, and whose\n subject `<owner>` is not a well-formed principal owner token: a subject that split-parses but\n carries a non-owner in the owner slot (e.g. a raw nkey, an old-shape alias) MUST NOT be surfaced\n as a delivery (§3, §5).\n6. Derive delivery kind (channel/dm/anycast) from the subject, not payload routing fields (§4).\n7. Ack only surfaced/handled messages and terminate permanent anomalies (§4, §8).\n8. Write only its own presence key on the heartbeat interval (§6).\n9. Set the per-instance inbox prefix before transport operations (§10).\n10. Treat unknown fields as ignorable (§11).\n11. Resolve a channel's effective delivery class (`live`/`durable`) from channel config, not from a\n deployment assumption, and use one resolution across live join, durable fan-out, history read,\n and membership surfacing (§4, §7).\n12. On a `durable` channel, tolerate the at-most-once `live` gap and catch up via the durable\n backstop; deduplicate by `id` across the live, backfill, and durable copies (§4, §8). Receiver\n deduplication MUST NOT coalesce copies solely because `id` is the empty string (§4).\n13. Join and leave a channel's **live** subscription by subscribing/unsubscribing under `sub.allow`\n with no privileged mediation; treat a live join as effective only once the broker accepts the\n subscribe, and drop it on a late permission refusal. On a `durable` channel, additionally establish\n durable membership via the privileged provisioner; if it cannot be established, report `joined live`\n with the durable backstop unestablished, never `joined durable` (§7, §9).\n14. Bound history/backfill reads by the current read ACL, and re-authorize every durable-backstop read\n against the current read ACL (and, for `durable`-channel entries, membership) before surfacing\n content, treating a leave as a hard read boundary on the backstop (§7, §9).\n\nTest vectors use these sample principals (`<owner>.<actor>`); `<ownerA>` = `u_aaaaaaaaaaaaaaaaaaaaaaaaaa`,\n`<ownerB>` = `u_bbbbbbbbbbbbbbbbbbbbbbbbbb` (owner tokens are `u_` + 26 base32-lower, §2):\n\n- Alice: `<ownerA>.alice`\n- Bob: `<ownerB>.bob`\n- Reviewer role: `reviewer`\n\nSubject parsing. `parseSubject` **splits only** (§3): it recovers tokens by prefix and per-kind arity\nbut does NOT validate the owner token: a well-formed *split* is necessary, not sufficient, for a\nsubject to be surfaced as a delivery. The last row shows an old-shape alias that split-parses yet MUST\nbe dropped at the surfacing boundary (§9):\n\n| Subject | Result |\n| --- | --- |\n| `cotal.main.chat.<ownerA>.alice.team.backend` | `kind=chat`, `sender=<ownerA>.alice`, `rest=team.backend` |\n| `cotal.main.inst.<ownerB>.bob.<ownerA>.alice` | `kind=inst`, `sender=<ownerA>.alice`, `rest=<ownerB>.bob` (recipient) |\n| `cotal.main.svc.reviewer.<ownerA>.alice` | `kind=svc`, `sender=<ownerA>.alice`, `rest=reviewer` |\n| `cotal.main.ctl.manager.<ownerA>.alice` | no sender; v0 control subject, retired (§13.11): nothing serves it and it MUST NOT be handled |\n| `cotal.main.chat.<ownerA>.alice` | no sender; malformed (owner+actor but no channel token) |\n| `cotal.main.chat.UAQGWOEVJKMIO4WXSYOTLARXYOZTCXFK67JASEH6AFFFYK6FOPSKQCAD.team.backend` | split-parses (`kind=chat`, `owner=UAQ...QCAD`, `actor=team`, `rest=backend`) but MUST be dropped: `UAQ...QCAD` is not a principal owner token (§3, §9) |\n\nSample multicast message:\n\n```json\n{\n \"id\": \"018f1d0a-0000-7000-9000-000000000001\",\n \"ts\": 1710000000000,\n \"space\": \"main\",\n \"from\": {\n \"id\": \"u_aaaaaaaaaaaaaaaaaaaaaaaaaa.alice\",\n \"name\": \"alice\",\n \"role\": \"planner\"\n },\n \"channel\": \"team.backend\",\n \"mentions\": [\"bob\"],\n \"parts\": [{ \"kind\": \"text\", \"text\": \"Can you review this?\" }],\n \"contextId\": \"ctx-1\"\n}\n```\n\nSample unicast message changes only the routing field:\n\n```json\n{\n \"id\": \"018f1d0a-0000-7000-9000-000000000002\",\n \"ts\": 1710000001000,\n \"space\": \"main\",\n \"from\": {\n \"id\": \"u_aaaaaaaaaaaaaaaaaaaaaaaaaa.alice\",\n \"name\": \"alice\"\n },\n \"to\": \"u_bbbbbbbbbbbbbbbbbbbbbbbbbb.bob\",\n \"parts\": [{ \"kind\": \"text\", \"text\": \"Direct note.\" }]\n}\n```\n\nInterop scenario:\n\n1. Provision a space and credentials for Alice and Bob.\n2. Alice and Bob connect with inbox prefixes `_INBOX_<connId>` (per-connection, §2).\n3. Both write presence and join `team.backend`.\n4. Alice multicasts on `team.backend`; Bob receives with `kind=channel`.\n5. Alice unicasts to Bob; Bob receives with `kind=dm`.\n6. Alice anycasts to `reviewer`; exactly one reviewer receives with `kind=anycast`.\n7. A late joiner joins `team.backend`; replayed messages arrive with `historical=true` and\n live-tail duplicates at or below the join watermark are ack-dropped.\n\n---\n\n## 13. Endpoint control surface (v0.4)\n\nEverything on the mesh that serves structured commands (the manager daemon, the delivery\ndaemon, a wrapped MCP server, a third-party service) is an **endpoint**: a daemon that\nregisters a service identity, publishes its contracts, and answers `describe`. There is no\nspecial-cased service in this contract: `manager` and `delivery` are endpoint names like any\nother, and no subject or envelope in this section knows them. This section supersedes and\n**deletes** the v0 control rail (`ctl.<service>.<owner>.<actor>`, `ControlRequest`/\n`ControlReply`, the `self`/`manager`/`admin`/`delivery`/`delivery-admin` service tiers, and the\nreserved `control.<instance>` subject). The cut is hard (§13.11): no v0 control subject,\nenvelope, handler, or grant survives, and a pre-cut control credential cannot reach a post-cut handler.\n\nLayering: identity and transport are §2/§3, extended by the lifecycle identity below; §13.1\nidentity; §13.2 grammar; §13.3 envelope; §13.4 delivery contracts; §13.5 verbs; §13.6\ncomposites; §13.7 contracts and discovery; §13.8 distributed guarantees; §13.9 authority\nboundary; §13.10 receipts and signing anchors; §13.11 the hard cut; §13.12 the NATS binding;\n§13.13 plane ownership; §13.14 conformance.\n\n### 13.1 Lifecycle identity\n\nThe principal `owner.actor` (§2) is a **recyclable routing alias**: despawning an agent frees\nits actor name, and a later spawn may legitimately reuse it. An alias is therefore never\nsufficient *authority* identity on this surface. Two further identity components exist:\n\n- **Lifecycle UID** (`lifecycleUid`, one token `[a-z0-9]{26,32}`, ≥128 bits of CSPRNG\n entropy in a fixed canonical encoding): an unguessable, never-reused\n identifier of one managed lifecycle under a principal. The UID is entropy, never order:\n no allocator counter exists, and what is durable and monotonic is only the never-used\n set. Before anything else, the minting authority (the manager for managed agents; the\n provisioner for endpoint daemons and operator credentials; the auth service for user-mode chat\n sessions only, §10) **reserves the candidate UID\n space-globally**: a create-only write of the reservation key `uid.<lifecycleUid>`\n (§13.7), never deleted for the life of the space. A create conflict burns the candidate\n and draws a fresh one (the alias head alone cannot reject the same UID under a different\n alias, and the `gate.`/`cred.` families key by UID alone, so uniqueness must be\n space-wide); a DEL/PURGE marker on a reservation is corruption, never reusable absence.\n A reservation carrying `kind: \"native-service-uid\"` is reserved for service custody. Its\n closed shape is `{ v:1, kind, native:{accountPublicKey,space,lifecycleUid},\n assignment:{owner,actor,endpoint,instanceId,duty:\"serve\"},\n creation:{operationId,requestDigest} }`. Its embedded UID must equal its key. The actor is\n `svc_` followed by the lowercase base36 encoding of the unsigned SHA-256 of RFC-8785\n canonical JSON `[1,accountPublicKey,space,owner,endpoint,instanceId,\"serve\"]`, padded to\n 50 characters. Ordinary executors MUST refuse this reservation before mutation or\n idempotent root reuse and MUST NOT project it into an ordinary audit. Ordinary connect\n and currency paths also refuse it. No reservation creation, service credential release\n or terminal service transition is enabled by this reserved shape. Legacy ordinary audit\n bytes and their existing validation remain unchanged. Mixed-version writer exclusion\n and restore reconciliation remain prerequisites for any future service admission.\n A separate package-internal read-only service prerequisite accepts only the canonical active\n marked head, open native `gate.<uid>` generation1 and active exact root row, with all three\n `serviceCustody:{v:1,uidDigest}` mirrors matching the complete closed immutable reservation.\n Head `managerInstance` MUST equal reservation assignment `instanceId`, and native\n `processEpoch` is exactly1, independently of endpoint serving gate/witness epochs. Full\n configured account/space/UID/assignment, derived actor, root key/current stamp/holder,\n `sourceChain:[\"root\"]` and unexpired millisecond root expiry are checked with sealed\n primary leader-served readers. Account identity is trusted host configuration: sealed readers\n do not attest the broker account or detect a cross-account pair of legitimately constructed\n handles. Missing or mismatched native gate evidence refuses even if an endpoint gate exists.\n Creating/cancelling states and their RootPlan recovery cannot\n authorize through this active-only reader. It confers no writer, bootstrap, abort, rotation\n or terminal authority and makes no atomic multi-key snapshot claim. Ordinary readers stay\n closed to every marked service row.\n A package-internal custody writer, reached in the product only through the service endpoint\n host's decide and revoke (whose proposals nothing in the product creates), may advance one sealed\n reservation. Bootstrap order is reservation, pending-root endpoint gate, `service-creating`\n head, native gate created frozen at generation0 under the creation operation and opened at\n generation1, RootPlan `{credentialId,expMs}` fixed once by head CAS at\n `now + ROOT_CREDENTIAL_TTL_MS`, planned active root by zero-history create, identical-bytes\n native gate touch, then the active head stamp. The endpoint gate is re-read at open, before the\n plan, root and stamp steps and before every write attempt of those steps; a revoked endpoint\n stops bootstrap. Cancellation is\n endpoint-first: endpoint deny-new (on a registration freeze it revokes approval and keeps the\n registration op), `service-cancelling` head (an active head's stamp and its\n root row's expiry become the preserved plan), native gate frozen under the cancel operation,\n then root disposition. An unstamped planned root MUST be fenced only by a zero-history create\n of revoked bytes or a CAS of the exact active row; a stamped root is retained. Every result is\n nonterminal. An absent reservation leaves endpoint deny residue and reports unconfirmed; a\n foreign or tombstoned reservation refuses before any write. Each write is a per-key create or\n revision CAS under a genuine plane-claim hold re-read before and after it plus a fatal latch.\n This is local readiness control, not broker writer exclusion. Each broker request is bounded\n by `min(5s, remaining live authority)`, where live authority is the invocation's original\n deadline. In bootstrap, once the plan step has fixed or read the RootPlan, live authority is\n also bounded by the plan expiry. Cancellation keeps only its own deadline, so an accepted\n cancellation can still proceed after the root expires. A request still in flight at the\n live-authority bound ends held; the writer stops waiting for it but does not cancel it at the\n broker. CAS re-decisions, native gate re-pins and\n unknown-outcome rounds are capped at 4, 8 and 3, and an unknown outcome is classified by a\n leader read before any reissue. Endpoint-gate reads and writes are the writer's own leader\n reads and conditional writes built from pure package-internal rows, so no endpoint-gate\n request starts after an invocation returns. Bootstrap's final active-root proof is bounded the\n same way, but it is a sequence of read-only leader reads behind one wait: when that wait ends\n at its bound, the abandoned proof can still issue its remaining reads after the invocation\n returns. Those reads write nothing. An already-active head reaches that proof before any plan\n clip, so bootstrap MUST hold `plan-expired` rather than report an active root whose expiry a\n final synchronous check, made after its last read with no await before the return, observes.\n This does not make the result fresh when the caller receives it. The held check is the closure captured when the hold was\n acquired, not the hold's mutable guard field. A frozen activation native gate is valid only at\n generation0; any other frozen activation form holds. The deadline and reservation are\n caller-supplied original material, not durable host authentication.\n Only then does the ordinary minting authority mint **before the entity is reachable**,\n persisting a CAS-fenced\n mapping\n `{ owner, actor, lifecycleUid, managerInstance, processEpoch,\n state: active | retiring | retired, currentCredentialId?, lastTakeoverOpId?, op? }` (closed\n schema; the\n embedded `owner`/`actor` MUST equal the key's alias tokens, so a key-mismatched row\n never authorizes; `currentCredentialId` is absent until the credential ledger releases\n a root under the reopened gate; `lastTakeoverOpId` is the opId of the takeover operation\n that LAST advanced `processEpoch` (the epoch advance and this stamp are ONE head CAS, so a\n completion is bound to exactly one operation: a resuming barrier confirms the completed head\n carries ITS opId, and a LOSING concurrent takeover that captured the same pre-takeover\n coordinates finds a foreign opId and refuses, never claiming the winner's completion; absent\n until the first takeover); `op` is required at `retiring` and forbidden elsewhere)\n under the alias's **CAS head key** (§13.7:\n the **unsplit** `lifecycle.<owner>.<actor>` head key HOLDS this mapping as one atomic\n record, the single authoritative current mapping and the only source of `mappingRevision`,\n §13.9; the UID-suffixed `lifecycle.<owner>.<actor>.<lifecycleUid>` key is optional\n append-only audit, never the authority). `mappingRevision` IS the head key's store\n revision, learned from the publish ack or from the leader-served read that returned the\n mapping (one read returns `{ mapping, revision }`); the value carries NO revision field,\n and a body-supplied revision is never a CAS coordinate. Head states: `active` is the\n ONLY current state. `retiring` is the containment phase of the terminal barrier (below),\n bound to the retirement operation's `op.opId`; it is non-current and NOT replaceable.\n `retired` is terminal and asserts the barrier COMPLETED (the cleanup proof), which is\n what makes replacing a retired predecessor safe. **Every currency seam fails closed on\n both non-`active` states**: target resolution, the process-epoch reads gating\n record/status writes, admission/start, and supervision derive current authority only\n from `state: \"active\"`; `retiring` and `retired` alike yield no current mapping and no\n current epoch. Activation is the head CAS (create-only for a virgin alias;\n revision-pinned from a `retired` predecessor), so two concurrent mints for one alias\n serialize there and exactly one activates; the loser terminalizes its own orphan gate\n and burns its reserved UID, never deleting either (`currentCredentialId` is a public key\n identifier/fingerprint plus authority epoch, never secret material). A supervised restart\n of the same entity **preserves**\n the UID (revoking/rotating the connection credential and advancing the process epoch); a\n terminal despawn, explicit stop, or supervision escalation retires the UID through the\n terminal barrier *before* the alias is freed. A retired UID is never reactivated\n (`retired → active` for the SAME UID is forbidden; only the ALIAS is replaceable, by a\n freshly reserved UID); recycling cannot move to the reservation, which is never freed.\n- **Process epoch** (`incarnation`, an unsigned integer): the fenced ownership epoch of the\n process currently animating an identity, advanced by CAS on every takeover or restart. At\n most one live epoch owns an identity; a superseded process MUST stop serving and its commits\n are rejected (§13.8). **The epoch fences egress only**: reply, event, timer, session, and\n record-write-ingress publish grants pin it (§13.9), but request subjects deliberately omit it; a caller cannot\n know the serving epoch, so **no subject-level fence for ingress exists or can exist**. An\n un-revoked superseded serve credential remains a member of the class queue group and can\n consume (and externally effect, and never validly answer) one call in N. Takeover therefore\n carries a **normative barrier, in order**: freeze issuance for\n the lifecycle in the credential ledger (below) → revoke EVERY active credential-ledger\n row under the lifecycle prefix, every root (the superseded `currentCredentialId` and any\n earlier unexpired root: each root mint, initial or rotation, writes its own ledger row)\n and every ledgered descendant (handle-redemption-minted and per-session credentials,\n §13.6), via the deployment's auth\n authority, verifying the updated revocation state is enforced on EVERY server of the\n cluster before proceeding (fail-closed on partial acknowledgment: an unrevoked-anywhere\n credential can reconnect there) → evict the live connections of every revoked\n credential's `holderPrincipal` (from its ledger row, above)\n cluster-wide and verify the re-scan found none, the barrier executor (the trusted auth\n path) holds the delivery endpoint's `evictPrincipal` capability for exactly this step\n (Appendix B: granted to the barrier executor, not only `supervisor`); `evictPrincipal`:\n system-account CONNZ scan → per-server KICK → re-scan verify, fail-closed on partial\n scans; Appendix B) → **only THEN advance the process epoch by CAS (N→N+1), reopen the gate\n at the new generation, and activate the successor's serve subscription**. The epoch CAS is\n LAST, not first: a superseded process is revoked and evicted before the successor's epoch\n exists, so it cannot publish a reply or event in a window between the CAS and the eviction;\n the egress epoch is honest attribution precisely because no live predecessor egress survives\n the barrier. (A reply the predecessor emitted for an in-flight call before eviction reaches\n a caller only within that caller's own deadline and from a not-yet-evicted process; the\n barrier's job is that no such process remains once the successor answers.) Where\n revocation or verified eviction is unavailable (e.g. static credential material\n pre-rotation, Appendix B), takeover MUST fail loud rather than proceed.\n\n**Retirement-only composition.** A manager instance MAY run as a retirement-only composition of\nits own commit path. Its first durable act MUST be to acquire the per-instance liveness lease of\nits own persisted logical `instanceId`; it MUST NOT read a lifecycle, slot or gate row before\nthat lease is held, and it MUST exit without effect if the lease is held by another process. It\nMUST NOT register or serve the endpoint, hold the renewal lease, accept spawn or launch, adopt or\nrestart a seat, or run the resume path. It drives only the terminal retirement of non-retired\nlifecycles whose slot names its own logical `instanceId` as owner, through the same operation\nidentity an ordinary instance would use, then releases the lease and exits. For every slot it\nreads it records one outcome: `retired`, `already-retired`, `skipped-not-owned` (the slot names\nanother owner or none), or `held` (the slot or its head could not be read or parsed, or the\nterminal did not complete). A `skipped-not-owned` or `held` slot is never counted as retired.\nIt is the minting manager's commit path for the purposes of the §13.9 lifecycle-mapping writer\nrow; no other principal, credential profile or grant is introduced.\n\n**Credential ledger (normative).** Ingress has no epoch fence, so revocation is only as\ncomplete as the set of credentials it covers, and the lifecycle's `currentCredentialId` is\nnot that set. Every credential the trusted auth path mints **derived from** a lifecycle (the\nshort-lived credential of a handle redemption, the two per-session credentials of a session\nredemption, §13.6) is recorded at mint time in a durable, auth-owned **credential ledger**\nrow `{ credentialId, holderPrincipal (the `<owner>.<actor>` whose connections the barrier evicts; the credential id is NOT the principal, and eviction is by principal), lifecycleUid (the holder's), sourceChain: [root |\nhandle.<issuerKeyId>.<id>… | session.<sessionId>], the FULL verified lineage: for a\nhandle redemption, EVERY handle in the presented `parentDigest` chain (§13.6), never only\nthe leaf, state: active | revoked (monotonic), exp }`, keyed\n`cred.<lifecycleUid>.<credentialId>` so both barriers enumerate a lifecycle's full descendant\nfamily by key prefix. Each mint additionally writes one reverse-index key\n`bysrc.<issuerKeyId>.<id>.<lifecycleUid>.<credentialId>` per chain member, so **revoking a\nsturdy handle revokes every credential minted under it or under any of its descendant\nhandles**; a credential redeemed through a child handle carries the parent in its\n`sourceChain`/`bysrc` keys, so parent revocation reaches it without walking handle records.\n**Source gates.** The same fence applies per issuing handle, because a handle's revocation\nstate lives in the records bucket while credential indexes live here, and two buckets share\nno order: each sturdy handle has an auth-bucket gate `srcgate.<issuerKeyId>.<id>`\n(`{ state: open | frozen }`, CAS). Handle revocation CASes the source gate to `frozen`\n**before** it enumerates `bysrc.`, and a redemption, after writing its `cred.`/`bysrc.`\nrows, revision-pinned-CASes the source gate of EVERY handle in the presented chain (plus the\nlifecycle gate below), releasing only if all are still `open` at their observed revisions. An\nin-flight redemption under a handle being revoked therefore either finishes before the freeze\n(its rows are in the enumeration) or loses a CAS and never releases. **Handle revocation\ncarries the SAME cluster-wide eviction as a lifecycle barrier** (§13.9 `evictPrincipal`):\nafter freezing the source gate and enumerating `bysrc.`, revocation revokes every descendant\ncredential AND verifies revocation enforced on every server, then evicts and re-scans the live\nconnections of every revoked credential's principal, fail-closed, an already-connected\ndescendant credential is never silently left with live grants. The handle status write is\nacked only after that eviction is verified complete.\n\nAn unledgered mint MUST NOT occur (the ledger write precedes credential\nrelease, fail-closed), and the rule carries a mechanical audit invariant in the style of the\n§13.9 matrix grep test: every credential the auth authority has ever released MUST resolve\nto a `cred.<lifecycleUid>.<credentialId>` row; an issuance path that cannot show its ledger\nrow is non-conformant, auditable by diffing issued-credential ids against the ledger.\n\n**Issuance gate (normative).** \"Freeze issuance\" is a durable transition, not an assertion:\neach managed-agent lifecycle has a gate key `gate.<lifecycleUid>` in the same auth KV,\n`{ state: open | frozen | retired, generation, op? }` (CAS). A `frozen` gate MUST carry a\ndurable **operation intent** `op = { opId, kind: activation | takeover | registration |\nretirement, successor? }`: after a crash the intent alone\ndecides WHICH operation a frozen gate belongs to and what may advance it, a retry or\nreconciler resumes the SAME `opId`, and a writer that is not that operation's executor\nMUST NOT advance, reopen, or terminalize the gate.\n**A crash can leave the gate frozen under an operation whose executor no longer exists**, and\nfail-closed then blocks every restart while protecting nothing. An operator-facing reconciler\nMAY complete that dead operation's obligation — resuming its SAME `opId` and reopening at the\nUNCHANGED coordinate with `generation` advanced by one — but ONLY after it has AFFIRMATIVELY\nverified that the gate's freeze-holder principal is gone, via the same liveness machinery the\nbarrier's eviction trusts (`principalLiveness`, §13.9). A holder that is alive, or whose\nliveness cannot be proven, MUST refuse; a timeout or an incomplete sweep is unknowability and\nMUST NOT be read as death. The affirmative check is a PRECONDITION ON TOP OF the barrier's own\nverified eviction, never a replacement for it. A `retired` gate RETAINS the\nterminalizing operation's intent as audit, and an idempotent terminal retry succeeds only\nfor that SAME operation. **Successor coordinates are per-kind and derivable, never loose\nprose**: an `activation` or `retirement` intent carries NO `successor` (an activation's\nsuccessor IS the head mapping the same operation writes; a retirement has none); a\n`takeover` or `registration` operation's successor artifacts are durably keyed by its own\n`opId` (the `stage.<opId>.` staging family and the operation's audit rows), so\n`{ opId, kind }` alone resumes deterministically. The gate MAY carry a `successor` summary\ntoken for those two kinds, but the staged rows are authoritative and a resumer MUST NOT\nact on a summary that the staged rows do not corroborate. **Allowed transitions are also\nper-kind**: a gate is BORN `frozen` only under an `activation` intent (and only for a UID\nwhose `uid.` reservation already exists); `open → frozen` belongs to `takeover`,\n`registration`, and `retirement`; `frozen → open` (reopen) belongs to `activation`,\n`takeover`, and a `registration` abort, NEVER `retirement` (a retirement freeze never\nreopens); `frozen → retired` belongs to `activation` (a head-CAS loser terminalizing its\nown orphan gate) and `retirement`, NEVER `takeover` or `registration` (those abort by\nreopening). An implementation MUST refuse a transition whose gate op kind is outside these\nsets, before any CAS is attempted. The `opId` is an identifier, never a\nbearer capability: a resumer re-authenticates as the operation's executor, and possession\nof the id alone grants nothing. `retired` is terminal, a retired\nlifecycle never mints again. `frozen` is **not** terminal, because a supervised restart\npreserves the UID (§13.1) and must mint the successor process's root credential: the\ntakeover barrier freezes at generation `G`, completes revoke + verified eviction of the\nfamily, and only then CASes the gate to `open` at generation `G+1`; the reopen is the\nbarrier's own final step, so no credential of generation `G` is ever live when generation\n`G+1` mints. A gate reopen by anyone but the completing barrier is non-conformant.\n**Endpoint instances use a disjoint gate family, distinguished by explicit prefix and\nnever by token arity**: the endpoint issuance gate is `epgate.<endpoint>.<instanceId>`,\n`{ state: open | frozen | retired, generation, processEpoch, registrationRevision,\nnameAuthorityRevision, principal, op? }` (the endpoint fence coordinates of §13.5/§13.7, plus\n`principal`: the serving instance's own CONNZ-attributable connection principal, recorded at\nregistration), and\nendpoint-derived credentials ledger under `epcred.<endpoint>.<instanceId>.<credentialId>`\nwith the same row schema, mint protocol, gate discipline, and never-delete rules as\n`cred.`/`gate.`. An interrupted endpoint registration repair MAY journal verified evictions\nunder the disjoint cursor key `eprepair.<endpoint>.<instanceId>`. A cursor MUST bind the exact\nregistration `opId`, the observed frozen-gate KV revision, and the sorted distinct holder set.\nA holder is appended durably only after its eviction verifies, and the holders one eviction sweep\nverified are appended before the next sweep is attempted. A retry MUST repeat the freeze-holder\nliveness precondition, MAY skip only holders in a cursor whose complete binding still matches, MUST\nrestart from empty progress on any mismatch, and MUST reopen only after every current holder\nverifies. Cleanup occurs after reopen; a cursor that\ncannot be deleted cannot authorize a later freeze because that freeze has a different gate revision.\n\nA standalone user-authorized service gate adds `authorityFamily: \"service\"` and a required\n`serviceAuthority` value. Its closed fields are `v: 1`, `assignmentDigest`, native\n`lifecycleUid`, `state: pending-root | approved | revoked`, `rootCredentialId`, `rootExpiresAt`,\n`approvalDigest`, `approvalExpiresAt`, `callerCeiling`, `activationIssued`, and optional\n`registration: {operationId, requestId, requestDigest, processEpoch, registrationRevision,\nnameAuthorityRevision, registrationProof}` and\n`pendingRegistration: {operationId, requestId, requestDigest}`. Expiries use Unix seconds.\nThe completion stamp's coordinates must equal the gate's. A positive registration revision\nrequires a completion stamp. A pending identity is present only under its matching registration\nfreeze, and activation cannot be recorded while that identity is pending.\nA pending-root value has null root and approval fields, an empty ceiling, no registration and\n`activationIssued: false`. An approved value binds the native root and immutable approval;\nonly approval expiry may be null. Revocation retains any existing binding. An activated value\nrequires the registration stamp. A service value without its family, or the family without\nits value, is invalid. Existing nonservice gates do not acquire this authority. A §13.6 session\nnever serves on a service gate: the session's serving-gate read refuses the service family before\nit returns a pin or stages a ledger row.\n\nService registration freeze requires live approval and `activationIssued: false` at the gate CAS.\nUnder that freeze, a complete leader read must prove the issuance family empty. Active, revoked,\nmalformed or deleted credential evidence is inconsistent with pre-activation state and blocks\nregistration and recovery. Failed or partial reads never prove emptiness.\nGate transitions retain approval, root and activation fields. A new registration freeze retains\nthe prior completion stamp and records the new operation's request identity and digest. Successful\nreopen writes the new completion stamp and resulting coordinates in the same CAS. A definite\nabort-reopen preserves the prior stamp. Both paths remove the pending identity. Recovery binds\nthe recorded operation; an open surface alone cannot establish which request completed.\nA separate post-reopen writer cannot attach a completion stamp.\nServing release requires live approval,\nrecorded activation and a finite credential expiry bounded by the service access lifetime,\nnative root expiry and approval expiry. Release rechecks the fixed expiry after asynchronous\nstaging and commit; expired material is refused and never given a new expiry. A registration recovery that reopens an already revoked\napproval does not authorize serving release. Standalone service authority does not support\nsibling credential duties. Native root validation, owner consent, activation and coordinated\nretirement remain requirements of the trusted host; parsing this value does not establish them.\n\nNative application-service name bindings use `servicename.<endpointToken>` in the primary auth store.\nThe closed record has `v:1`, `kind:\"service-name\"`, accountPublicKey, space, endpoint, owner,\nclaimReference, requestId and requestDigest. The trusted host authenticates operator authority and\nverifies the namespace claim before creation. A stored assertion alone proves neither of those checks.\nCreation requires zero retained key history. Only an identical request can recover the binding;\nchanging its owner, claim or request identity does not update it. Owner and binding revision are read\nfrom one leader snapshot. Transfer and release are unsupported. Native auth, delivery and manager\nnames remain with their existing control authorities and cannot be application-service bindings.\n\nNative service caller policy is stored at `servicepolicy.<granteeUid>` in the primary auth store.\nIts closed value is `{v:1,accountPublicKey,space,grantee,grants}`; grantee is the exact owner, actor\nand lifecycle UID. A grant contains its immutable id, endpoint and source instance, approval digest,\nnormalized capabilities, source and parent references, and status. Source and parent references\nname immutable grant ids at their original grantee UIDs. Source instance is provenance; native\ncapability route and instance fields still determine request reach.\n\nInitial policy and create-only service authority writes require zero prior key history at the\nwrite CAS. A deletion or purge marker, including one arriving after an absence read, MUST refuse\nrecreation. An additional pre-read is not this fence.\n\nA new grant is appended at the observed policy revision. An existing id cannot change its capability\nor provenance and cannot become active again after revocation starts. Revocation first records\n`{state:\"revoking\",operationId,phase:\"cutoff-required\"}` at that revision. Unrelated writes preserve\nthis intent. Repeated same-operation reads do not advance it or establish terminal retirement.\nDeleted, malformed or unreadable policies are not empty policies. Stored syntax and successful CAS\ndo not establish current grantee, service, granter or ancestor authority; the native host must verify\nthose before committing or using a grant. Neither a policy row nor a deny-new intent proves live\nconnection absence.\n\nNew caller-policy appends MUST reserve serialized status-growth headroom for every grant\nsimultaneously under the unchanged 2 MiB policy limit. Compute canonical policy bytes plus each\ngrant's nonnegative remaining growth to the largest supported closed status, including a\n512-character marker and maximum safe-integer revision/time fields. Refuse before the append CAS\nif that worst-case total exceeds the limit. This is not a retroactive repair of older near-cap\npolicies: their bytes and grant history remain unchanged, append refuses insufficient headroom,\nand revocation can still fail the byte bound. Such residue blocks service writer/admission\nenablement pending a separately authorized compatibility protocol. No cap raise, pruning,\nreactivation or terminal absence claim follows from the headroom check.\n\nNative service host operations keep five closed record families in the primary auth store:\n`svcop.<operationId>` (one request's binding), `svcprop.<proposalId>` (a proposal),\n`svccap.space` (the space's pending-proposal capacity), `svcasg.<endpointToken>.<instanceId>`\n(one selector's assignment) and `svchost.admission`. The operationId is the first 32 lowercase hex\ncharacters of SHA-256 over `cotal-service-host-op`, NUL, space, NUL and requestId, so one id\nnamespace covers every host request in a space. A binding stores the canonical request digest; a\nreused requestId with any other body is a conflict and is never rebound. Every create requires zero\nretained key history, and a deletion or purge marker at any of these keys refuses and is never\nrecreated. No record carries a TTL, and none is deleted or purged. A live operation or proposal\nbecomes terminal only by a CAS on the same key, after every write it depends on is durable.\n\nEach write is one create or one exact-revision CAS on one key; there are no multi-key batches.\nAn invocation writes only its scope: the exact keys its discovery read located before the\ninvocation's effect connection opened, which are its own records and, for a located reservation, the\nnative custody keys of that one reservation. Only an approval's scope holds the reservation's UID\nkey; a revoke's never does. A step that needs a key outside the scope holds as `scope-mismatch`\nbefore anything is issued, including before native custody of a reservation the scope does not name.\nA replay of the same request discovers the stored binding and assignment and scopes them.\nEach invocation's effect connection is a fresh self-minted data-account identity named\n`cotal:service-host-effect:<space>`. Its credential publishes exactly the scope's keys as `$KV`\nsubjects, and one more token under each auth family, beside the leader reads both stores need;\ndiscovery's credential publishes no `$KV` subject at all. That grant confines publish subjects only;\nit does not restrict what a publish on a granted subject does, and the engine's own writes are only\ncreates and exact-revision CASes on those keys. Reads are not confined: the leader reads\nare stream-wide on both stores. The effect credential never renews or reconnects. Its one expiry is\nthe invocation's original deadline, at most 60 s ahead, rounded up to the whole second. The broker\nchecks expiry in whole seconds against its own clock: it admits no connect once its current second\nis past that expiry, and it closes a live connection with one whole-second timer armed at connect.\nWith a broker clock that agrees with the host's and timely broker and client scheduling, that close\ncomes within the second after the expiry, up to about 1999 ms after the deadline. This is timer\ngranularity, not a guaranteed close time: a skewed clock or a paused or late broker or client moves\nthe close either way. Neither the expiry nor the close is proof that an earlier write cannot still\nsettle. Losing the effect connection fences the invocation: a later write holds, and a write\nin flight across the loss reports held. An effect connection that does not open holds as\n`unavailable` at `effect-open` with nothing written.\nRegister reads admission, capacity, the selector's assignment and the name binding first. An initial\nrefusal writes nothing and binds nothing. Otherwise the binding is created before the capacity CAS\nand the zero-history proposal create, whose times are fixed once in the binding. A refusal found\nafter the binding exists is recorded on it. Capacity counts entries whose `expiresAtMs` is still in\nthe future: at most 256 per space, 32 per owner and one per selector. Clock skew between writers\ncan under-count that bound; it never extends authority. Past a register's own bound an absent\nproposal key is fenced with a terminal `expired` tombstone, so a delayed create loses. Every close\nwrites the proposal's terminal record before it releases capacity. An unobserved release stays as\nrecorded debt until a later read observes it.\n\nAn approval binds before its first effect, then moves the proposal to `approving` at the admitted\nrevision, creates the assignment, runs native custody bootstrap and writes the endpoint-gate approval\nCAS. No authority-increasing step starts at or after the operation's original deadline, which is at\nmost ten minutes after admission and never past the proposal's expiry. An endpoint gate carrying\nthe approval's digest, approved or later revoked, proves that approval landed; a landing observed\nafter the deadline is recorded as a historical result, not current readiness. An expired approval\nthat holds an assignment binds its own cancel identity in that assignment, or adopts the one\nalready bound, and cancels natively.\nThe assignment record carries the complete native cancel identity `{operationId, requestDigest,\ncause}`. Any authorized revoker can cancel from that record alone, and the first binding wins.\nDeny-new has landed exactly when the endpoint gate reads `revoked` for this assignment. After that, an\n`approving` proposal of the assignment closes as `approved` when the gate carries an approval digest\nand as refused otherwise. A gate row at the key that belongs to another assignment is no evidence\neither way: every revoke path that reads the gate reports deny-new `unknown` for it, as for a failed\nread; an already fenced assignment is its own evidence and reports `landed`. Revocation stays\nnonterminal. Owner-scoped reads authorize against the subject owner fixed at binding, and terminal views carry no commands or cluster digests. None of these\nrecords proves a human decision, broker writer exclusion, restore readiness or terminal retirement.\n\nAn authority plane opened with `serviceEndpoints` hosts these operations; without it, the default,\nthe plane opens no service host, no discovery connection and no `svchost.admission` write. The host\nuses the plane's own claim hold, data account and actor ledger directory. Its startup MUST be named\n`normal`: a restore or a missing startup refuses the whole plane open, which unwinds what it opened\nand releases the claim. If that unwind cannot close an effect connection, for instance the startup\nadmission write's, it stops there. The open still refuses, but with the close failure; the claim stays\nheld; the cleanup timer, discovery, both scanners and every client opened so far stay live; and no\nhandle exists to retry. Until the process exits, a successor cannot reclaim the claim while those\nscanners live; after exit, the existing crash reclaim applies. Discovery is one standing connection named\n`cotal:service-host-discovery:<space>` on the ordinary renewing profile with the read-only grant. A\nbroker loss makes its reads fail until the stock client reconnects; a read that fails answers as\n`unavailable` within its invocation's own limit, with nothing written. A renewal failure closes it\nfor good, and every later read through it fails until the plane is opened again; nothing reopens it.\nBoth plane fatal paths, a scanner death and a failed native-issuance cleanup, trip the host's fatal\nlatch, and a fence that lands while the host is opening latches it once it exists. A scanner death\nor a failed cleanup while the plane closes still trips the host, so a call close is draining stops at its next step, but\nit does not make the plane fatal. From the moment\nplane close is called it refuses every host call, before it waits for anything. It then waits until\nevery call that entered before it has returned, including one still reading discovery or opening its\neffect connection. An effect connection whose close failed stays owned by the plane after its call\nhas settled, and that call rejects with the failure. Close closes every such connection again and,\nwhile one remains open, rejects with the claim still held, so a later close retries it; a request\nthat was only rejected does not hold close. A close rejected that way has already stopped the\ncleanup and sweep timers, but discovery, the administrative rail, both scanners and the remaining\nclients stay live, so no successor can reclaim the claim until a later close succeeds or the process\nexits. Only then does close close discovery, and only after that does it release the claim. Close\nitself trips no call it waits for: each ends under its own discovery-read bound and invocation\ndeadline, each at most 60 s. Its own scanner teardown, after that wait, does trip the host, which by\nthen has no call in flight, and does not make the plane fatal.\n\nThe plane and a hosted context expose `decide`, `revoke`, `name-bind`, `operation-read` and\n`proposal-read` as one in-process function; a hosted context refuses it as `unavailable` while it is\nnot ready. The host checks an owner granter's current interactive row but authenticates no caller:\nthe embedder MUST authenticate the granter it passes, operator or owner. The stock auth service\nserves that function on `POST /service-endpoint-host` when started with `--service-endpoints`, or\nas a lane of `auth-service --spaces` whose manifest entry sets `serviceEndpoints`: the\nbody is `{ idpToken, request }` with no granter, the route verifies the IdP token and derives the\ngranter itself. `decide`, a revoke whose cause is `owner-request`, the four caller-policy operations\n(`caller-grant`, `caller-revoke`, `caller-policy-read`, `caller-policy-list`) and the reads\n(`proposal-read`, `operation-read` and `name-read`, each scoped to the owner's own records; a\nproposal read names its endpoint's binding only when that binding is the owner's) run as the proved\nowner on either face; `name-bind`, any other revoke and the admission operations are the operator's\nand are served on the loopback face under the exchange capability only, with the proved subject as\nthe audit id. The admission operations have no engine handler in this cut and answer `unsupported`.\nThe engine's answer, replay included, is returned as is. Host requestIds share one space-wide\nnamespace, so a client MUST mint them unpredictably (16 random bytes); a guessable id can be bound\nfirst by another owner.\n\n`name-bind` is create-only and needs an operator granter. Its `expectedRevision` MUST be 0; any other\nvalue answers `unsupported`, and a native control endpoint name is refused. It issues one\nzero-history create of `servicename.<endpointToken>` through its invocation's custody host, whose\nscope and effect credential hold only that key. The row binds account, space, endpoint, owner, the\noperator's `claimReference`, requestId and the canonical request digest. Only the identical request\nrecovers an existing row; the same requestId with another body is a `conflict`, and any other request\nfor a bound name is `name-bound`. Nothing updates, transfers or releases a binding. The host verifies\nno domain control: the claim reference is the operator's assertion, and an unused name is no proof.\nA `held` name binding names its requestId's deterministic operation coordinate, which no operation\nrecord carries; it recovers only by replaying the same request.\n\nThe public route `/service-endpoint-authority` exists only with `serviceEndpoints`, on both faces;\nwithout it the route answers 404. `GET` returns `{v:1, kind:\"service-endpoint-authority-info\", space,\naccountPublicKey, issuer, keys}` for the receiver's own account with `cache-control: no-store`:\n`issuer` is the exact `iss` its service access bearers carry and `keys` the Ed25519 verification\nkeys it publishes at `GET /jwks`, public coordinates only (`kty`, `crv`, `kid`, `x`, at most 16),\neach a canonical encoding of a full-order point; a key of small order is refused on both sides. A\nguest verifies its access bearer under them before it brands its serve grant (§13.6). A door that\npredates the identity answers the four account fields alone, and a guest that needs it refuses to\nserve rather than brand unverified. `POST` takes one\nenvelope of at most 2 MiB. The proof is the credential on either face; the loopback capability is\nnever read. A request naming another account or space is refused before its proof is used. The proof\nkinds each operation admits are fixed: register needs IdP; activate needs IdP or a renewal proof;\nrenew needs a renewal proof; ready needs an access proof; status admits all three. Any other pairing\nis bad shape (400). An IdP proof verifies under the pinned issuer and exact audience, and its subject\nderives the owner, who also needs a current interactive cli or web row. A renewal or access proof\nverifies against this context's own issuer keys and yields its signed witness, never an owner's\nauthority: its owner is the witness's, and a request that carries a witness must carry the proof's.\nStatus carries none, so a renewal proof's own witness is the expected one. A refused proof counts\nagainst the face's refusal budget and answers 401, or 429 once that budget is spent; a valid proof\nnever consumes it. Protocol answers are 200 for `registered`, `credential`, `ready` and `status`, 202\nfor `approval-required` and `pending`, and for `denied` 409 on a conflict, a closed proposal or a\nmoved registration, 422 on refused input, 429 on a bound and 403 otherwise. An answer that cannot be\ncompleted after the proof, an unread, unknown or inconsistent record, or a `held` engine answer is a\n503 with no protocol echo, because the request may already be bound.\n\nRegister compiles the submitted closures in memory. Each cluster digest names a submitted manifest\nwhose root names a submitted cluster document, each verified against its content digest. The schema\nclosures the commands reference (each `inputDigest` and `outputDigest`) MAY be submitted with them;\na submitted one is admitted only whole: its manifest at that digest, its root and every member\npresent, and the bundle recompiling to that closure digest. Every artifact must belong to a declared\ncluster closure or to a referenced schema closure. A schema closure that is not submitted is not\nrefused: the host publishes the canonical void closure itself when it opens service endpoints, and\nany other schema closure is the registrant's to publish. The proposal's commands are exactly those\ndocuments' declarations; a journal-class command, or one declaring a governed trait (`ai.cotal.guarded`,\n`ai.cotal.priced`), is refused as `unsupported-runtime`, in the proposal phase and the registration\nphase alike. A native control endpoint name (`auth`, `delivery`, `manager`) is refused as\n`permission-denied` before any effect and binds nothing. The engine requestId is the first 32 lowercase hex\ncharacters of SHA-256 over the canonical JSON `[\"cotal-service-endpoint-authority\", 1, account,\nspace, owner, endpoint, instanceId, operation, requestId]`, with the derived owner, so the full public\nidempotency key selects the binding. That binding's request digest covers the public request's\ncanonical digest, which excludes the proof: a changed public body under the same key is a\n`conflict`.\n\nRegister has two phases, chosen by the derived owner's assignment at the selector. Until that\nassignment's endpoint gate carries an approval (no assignment, or one whose approval is still\nsettling), register is in its proposal phase, which takes only `expected:{state:\"unregistered\"}` and\nanswers `conflict` for any other. A first admission answers `approval-required` with the proposal id\nand digest. A replay answers from the proposal as it is now: `approval-required` while it is live and\nunexpired, also while its approval is in progress; `pending` at phase `approved-unregistered` if its\napproval landed after the phase was read; and `denied` once the proposal is refused or expired or its\napproval revoked. An undecided proposal reads as expired once the whole second of its expiry has\npassed, before any tombstone closes it. The door never answers expired before the host would refuse\nits approval, but its other answers can trail the expiry: an undecided proposal can still read\n`approval-required` or `proposed` for up to one second after it; a proposal whose approval is in\nprogress answers `approval-required` to a replay and `proposed` to status, with no expiry mapping on\neither, until that decision settles; and a first admission's `approval-required` is computed when the\nproposal is created, so an admission that was held and settles on a later replay can produce it after\nthe expiry, not only deliver it late.\n\nOnce the gate carries an approval, register is in its registration phase, and so are activate, renew\nand ready. Each of these requests, in order: proves its caller as above; resolves the caller's own\nassignment at the selector before any read by request key, so another owner or a selector with no\nassignment answers `permission-denied` (a revoked one `approval-revoked`) and any witness the request\ncarries must name that assignment's selector, owner, serving actor and lifecycle UID; reads its\nintent `svcint.<id>`, where `id` is the engine's operation id of the request's engine requestId; and,\nonly when no intent exists, checks the state the request needs. A register key keeps the binding its\nproposal phase gave it: the operation record of the same id, when one exists, must be a register\nadmitted with this body, else `conflict`, and must name the approved proposal; a key whose proposal\nwas refused or has expired answers `proposal-refused` or `proposal-expired`, as its proposal-phase\nreplay does, and any other proposal is `conflict`. Both are decided before the state check and before\nanything is written. A registration needs a bound\nassignment with no cancel identity, an approved gate without `activationIssued`, a recompiled surface\nwhose proposal digest equals the approved proposal's, and an `expected` that matches the current\nregistration stamp exactly (no stamp for `unregistered`); refusals are `approval-revoked`,\n`registration-active`, `approval-mismatch` and `conflict`. Activate, renew and ready need their\nwitness to be the current stamp's, else `stale-witness`. A new admission then lists its id in the\ninstance's index `svcintx.<endpointToken>.<instanceId>`, which is created with the assignment's owner\nand checked against it on every read; an id already listed takes no slot, and a 65th id is\n`resource-exhausted` (429) before any effect. It then creates its intent with zero history. The\nintent records the operation, account, owner, selector, the public requestId and digest, the\nregistration the request names (register's expected one, or the request witness's) with that\nwitness's digest, and its admission time. No proof, token or reply is ever stored. An existing intent\nwith another digest is a `conflict` before any state check, and a create that loses to an equal\nintent is a replay. Intents and the index are never updated, pruned or deleted in this cut: they\nstay for the assignment's lifetime, and an id listed without an intent (a stop between the two\nwrites) stays listed.\n\nEvery effect is then evaluated against current native state. A registration answers\n`approval-revoked` first if the assignment is revoked. Otherwise, when the current stamp names this\nrequest (requestId and digest), it answers the top-level `registered` with that witness and snapshot,\nbefore or after activation and readiness: no barrier, no epoch advance and no artifact publish.\nOtherwise it answers `registration-active` once activation has been issued. A gate frozen by this\nsame request's operation resumes with no further check here; any other request requires the gate\nopen (else `registration-pending`), `expected` to match the stamp (else `conflict`), and a live\napproval (else `expired`). It then publishes each submitted artifact\ncreate-only to the contract store and runs the native registration barrier and spec registration\nunder the request's operation id, with no repair cursor (a service's credential family is empty\nbefore activation). The barrier freezes the gate revision it observes after those publishes\nwhenever the gate is not frozen by this request's operation, which includes a request that read it\nfrozen and finds it reopened, and the request checks again on exactly that revision before anything\nis frozen or written: a stamp that already names this request answers as a replay does, and a gate\nthat moved answers `conflict`, or `approval-revoked` once revoked; those answers are definite. A\ngate the recheck finds frozen by this request's own operation with no stamp yet is another\ninvocation of the request still running, so this one is held and answers 503, and its replay resumes\nor recovers it. A request whose barrier observes the gate already frozen by its own operation\nresumes with no recheck. A refusal the native barrier makes itself, such as a gate it observes\nfrozen by another operation or a freeze it loses after the recheck held, is a held step that answers\n503. It answers `registered` only once the stamp names this request. A first\nregistration keeps process epoch 0; a pre-activation re-registration advances it. Activate requires\nthe gate open with a live approval and native root, the request witness to be the current stamp's,\nand then lands the monotonic `activationIssued` CAS unless it already holds. Renew requires the same\nand an activated gate, and writes nothing. Both answer `credential` with a fresh access bearer and\nrenewal proof whose expiries are fixed when the door admits the request: at most 60 s and 24 h, and\nnever past the native root's or the approval's expiry. Material that cannot be minted is `expired`\nonly once its fixed access expiry has passed; any other failure answers 503, and the replay mints.\nA replay of either mints replacement material for the same current registration; earlier material\nkeeps its own expiry. Ready requires the same as\nrenew, plus the native name binding at the witness's revision, and writes the service-reported status\n`ready` at the witness's process epoch and spec revision, with `reportedAt` in Unix seconds, fenced on\nthe gate's epoch. It answers `ready`. Every write of a serving request goes through its own\ninvocation, whose effect credential publishes exactly its intent and index keys and that operation's\neffect keys (the endpoint gate for register and activate, the spec and governance head for register,\nthe status for ready), and publishes and reads back exactly the submitted artifacts. The\ncredential also grants an exact Direct Get on each records key the operation reads, but the\nregistry's KV handles are bound without Direct Get: every auth and records read of a serving\neffect is a leader message get (`STREAM.MSG.GET` last by subject) under the base read grant. The\nnative registration and the ready status write through their own\nclient on that connection, and a fatal latch closes the connection, so none of their requests is\nissued after the fence; a request already issued stays unknown.\n\nA serving client keeps one requestId per (operation, witness), persisted with the witness and its\nrenewal material in its single-owner store before dispatch, and reuses it, with an unchanged body,\nafter a restart. Only a pre-activation re-registration produces a new witness and so new keys. An\nactivated instance therefore needs a handful of keys for its life, and the 64-intent bound is\nreached only by a client that draws fresh keys.\n\nStatus takes `target:{kind:\"instance\"}` or `target:{kind:\"operation\", operation, requestId}`, where\n`operation` is one of `register`, `activate`, `renew`, `ready` and `revoke`; this selector replaced\n`{kind:\"operation\", requestId}`, which no longer parses. An owner's IdP proof reads that owner's own\nrequests and assignment, and only while the owner holds an interactive row, as for every owner\nrequest: without one it is `denied` `permission-denied` (403) before any read. A renewal or access\nproof reads only intents whose witness digest is its own, and the instance only as its own\nincarnation; a register with no intent is not readable by it. A witness naming another selector\nreads `not-found` before any read, and on a bound assignment a witness that does not name the\nbinding reads `not-found` before the precedence below, so another instance's revocation is never\nvisible to it.\nAnother owner's request reads `not-found`. `revoke` answers `denied` `unsupported`. Every required\nrecord that is unreadable, missing where it must exist, or inconsistent with another answers 503,\nnever `not-found` and never a `superseded` whose ids were not read from records. An operation status\nfollows this precedence:\n- an id listed in the index without its intent answers 503; it stays 503 if a later replay is\n refused, because no effect ran or can run and status never guesses absence;\n- with neither record, a register is in its proposal phase (below) and anything else is `not-found`;\n- a bound cancel identity or a fenced assignment answers `revoking` first, with phase\n `deny-new-landed` once the gate reads revoked and `deny-new-pending` before;\n- a register intent answers, first match wins: `registered` or `ready` when the stamp is this\n request; `superseded` with this request's id and the stamp's when the stamp names neither this\n request nor its expected registration, or names the expected one after activation; `registering`\n at phase `barrier` when the gate's pending registration is this request; `registering` at phase\n `admitted` when there is no stamp and nothing was expected, or the stamp is the expected one before\n activation, with the gate open or frozen by another request; otherwise 503;\n- an activate, renew or ready intent answers `superseded` with its registration's id and the stamp's\n when the stamp moved on, `registering` at phase `barrier` with the other operation's id while the\n gate is frozen, and `registered` or `ready` when the current witness is the intent's; otherwise 503.\n\nA register with no intent answers from its proposal-phase operation record: `registering` while that\nregister is in flight, `refused` for a refused register or a closed proposal, which stays refused and\nnever reads another proposal's assignment, `proposed` while its proposal is live and unexpired or its\napproval is in progress, `revoking` once the assignment it approved has a cancel identity, and, once\napproved, `approved-unregistered` with the gate's approval digest while no registration exists, or\n`superseded` with the current stamp's request id once another request registered: this request can\nnever register, because its replay would expect no registration. Instance status answers the\ncaller's assignment as it is: `revoking`, `registering` at phase `approving` while its approval\nsettles, `approved-unregistered`, `registering` at phase `barrier` while the gate is frozen,\n`registered` or `ready`, and for a service proof whose registration was replaced, `superseded`.\n`registered` and `ready` say only that the request's registration is current; neither says whether a\nreply was delivered or whether an activation landed, and the recovery is always to replay the same\nrequest.\n\nAn authority plane opened with `serviceEndpoints` also composes the native service callout. A\nconnection presenting a service access bearer is minted only for the current bound assignment its\nwitness names, which the service host reads, on its own writer connection\n`cotal:service-callout:<space>`. That writer adds the endpoint gate and endpoint credential families\nto the base writer grant; a broker grant cannot confine those families to service assignments, and\nthe native mint writes only the bearer's own rows. A fenced plane or a latched host refuses the\nmint. Registered closures are read back from the contract store on the issuer connection's\nexact-subject Direct Get. Revocation, the Describe view, caller policy, terminal retirement and\nrestore remain unsupported: a revoked assignment's bearer is refused at its next connect, but a\nconnection already open keeps its original expiry of at most 60 s.\n\nA local scoped Describe callback may receive immutable request context alongside the caller.\nIts subject comes from actual dispatch, and its fingerprint is the canonical digest of\n`{subject,envelope}`, using the complete original decoded JSON envelope after native Describe\nvalidation. A picked parser projection cannot substitute for that envelope. Local receive time\nis monotonic and captured before validation; deadlineMs remains the original relative budget.\nThis is receiver-relative context, not a publisher-start timestamp. The context exposes no raw\nproof bytes. Neither a context value nor its digest establishes actual receipt or authority to\nanother process; a trusted observer must establish that independently.\n\nThe service authority's read-only `describe-view` request adds the complete current `witness` and\n`observation:{subject,fingerprint}` to its common coordinates. Only service-access proof is admitted.\nThe subject must be an untargeted native Describe for this space and endpoint; an instance route\nmust name this instance. Parsing does not prove that the request was observed. The host must verify\ncurrent native service authority and an independent live observation before evaluating caller policy.\n\nIts successful result has `state:\"view\"`, the matching witness and observation,\n`basis:\"principal-policy-v1\"`, unique declared command names and positive integer `validForMs` no\ngreater than 2000. That basis denotes current principal-policy visibility, not the connected\ncredential's exact permission ceiling. The serving client verifies commands against its registered\nsurface. It requires request and response no-store, original receive-relative budget and the host's\nremaining duration after subtracting the full local query roundtrip. Proof, preparation, HTTP body\nand validation work cannot restart the deadline. Missing access proof never triggers IdP login.\nTransport failure on this read is not an unknown mutation outcome. The host's current-root,\nobservation, source/provenance and freshness checks remain mandatory beyond this wire shape.\n\nA service access bearer uses the user-token shape with `act.view: \"service-endpoint\"`.\nIts closed payload has `iss`, scalar `aud`, `sub`, `iat`, `nbf`, `exp`, `ver`, `scope` and `act`.\nIts protected header has only `alg: \"EdDSA\"` and `kid`. The closed actor has `owner`, `actor`,\n`scope`, `lifecycleUid`, `credentialId`, `view` and `service`. Both scopes are empty lists.\nThe closed service claim is `{duty: \"serve\", witness}`. The complete witness binds the same\nspace, owner, actor, native lifecycle UID and root credential as the outer bearer. Parent, manager,\nsession and transfer claims are forbidden. Times are integer Unix seconds, `nbf` equals `iat`,\nand the fixed expiry is at most 60 seconds after issuance. Validation refuses at the original\nexpiry, without extending it through clock tolerance. Ordinary exchange and profile construction\nMUST refuse this view. Only a dedicated service authority path may issue and authorize it after\ncurrent native root, approval and registration checks. Signature validation alone does not\nestablish that authority.\n\nThe dedicated callout authenticates the sealed broker request before using its user key, server\nkey or client id. It captures admission time before authority reads and fixes native expiry no\nlater than the access expiry or admission plus 60 seconds. It derives serving permissions from\nthe current native registration, preserves principal-name attribution and uses the separate\nclient inbox nonce. Native issuance and receipt checks and final root authorization precede the\nencrypted response. An expiry reached while encoding or sealing that response refuses release.\nAn unconfigured or non-native service authority cannot fall through to ordinary actor hooks.\n\nA service renewal proof is a separate EdDSA JWT class with protected `typ:\n\"cotal-service-renewal+jwt\"`, `alg` and `kid` headers. Its closed claims are `ver: 1`,\n`kind: \"service-renewal\"`, the complete registration `witness`, its canonical `witnessDigest`,\nand `iss`, `aud`, `sub`, `iat`, `nbf`, `exp`. Issuer and key resolution are pinned by the host;\naudience is the one space and subject is the witness owner. `nbf` equals `iat`; expiry is a fixed\nUnix-second deadline no more than 24 hours after issuance. Validation rejects the proof at its\noriginal expiry and binds every witness coordinate, not just the service name. User/connect token\nvalidation rejects this JWT class even if it carries actor-like claims. A normal user bearer is\nnot a service renewal proof.\n\nThe signature primitive does not establish current authority. Before issuing or accepting service\nauthority, the host checks the current native root, approval, registration and operation eligibility.\nIt bounds expiry by root and approval expiry. Signing cannot extend a supplied fixed deadline;\nmaterial that expires while signing is not released. Renewal proofs contain no ordinary capability\nscope and are never native DATA-account credentials.\n\n**`holderPrincipal` is ALWAYS a CONNZ-attributable `<owner>.<actor>` in\nBOTH families** (the barrier KICKs it; an endpoint NAME is not attributable and never sits\nthere): in `cred.` it is the caller principal; in `epcred.` it is the serving instance's own\nconnection principal, copied from the endpoint gate's `principal`, while the endpoint NAME that\nforms the `epcred.` KEY is a SEPARATE row field, so the key identity and the eviction target\nstay disjoint (an `epcred` row that put the endpoint name in `holderPrincipal` could never be\nKICKed). The `cred.`/`epcred.` families hold ONLY conformant ledger rows:\nimplementation staging, half-minted state, and tombstone fences live in a distinct\n`stage.` family, never under a ledger prefix a barrier enumerates.\n\nService-callout `epcred` rows also carry the closed `serviceConnection` object\n`{userNkey, serverId, clientId}`. The user and server keys are checksum-valid NKeys of their\nrespective kinds; clientId is a positive safe integer from the authenticated broker request.\nThese fields are forbidden in the `cred` root family. Service issuance requires this binding,\npreserves it during staging and leader-reads the row and unchanged gate authority after its CAS.\nAn ordinary serving issuance cannot carry service connection evidence. These rows prove issuance,\nnot broker acceptance or response delivery. Native root authorization remains separate.\n\nService-callout natkey evidence additionally carries\n`service:{witness,credentialId,connection}`. The outer credentialId is the native root; the nested\ncredentialId identifies the issued service JWT in epcred. The connection is the same authenticated\nbroker triple, and its user key must match the natkey key. Recording checks the active epcred\nbinding before and after the create-only write, verifies its receipt, reauthorizes and checks the\noriginal expiry before release. Existing receipt history cannot be reused. Expired service evidence\nis retained until topology-qualified retirement authorizes removal; the ordinary expiry pruner\nreports it separately and cannot remove it. That terminal pruning path is not implemented yet.\n\n**Native-key issuance evidence.** Every callout success first writes one create-only\n`natkey.<userNkey>` row in the same auth bucket, where `userNkey` is the broker-generated\nper-connection user public key the minted JWT is issued to (never the client's inbox nonce or a\ndisplay name). The row is the closed v1 record `{v, space, owner, actor, lifecycleUid,\ncredentialId, view, connId, iat, exp}`, taken from the validated bearer's own signed claims\n(already equality-checked against the current row) and from the minted JWT's own `iat`/`exp` (a\nsession-caller's is its grant's). An existing row for the key, under any lifecycle, refuses. After\nthe write the responder re-reads the lifecycle and credential authority in the same stream; only\nthen may the JWT leave. Any failure is a signed deny. A row is evidence of an issuance, not proof\nthat a client received the JWT or that the broker accepted the connection: a write that landed\nbefore a refusal stays. `natkey.` is not a ledger family and authorizes nothing. The issuing\nservice removes a row only after its `exp` plus the clock tolerance, at boot and then on its own\ntimer, walking the family with the leader-served `STREAM.MSG.GET` `next_by_subj` read (never a\nconsumer) and purging each row pinned to the sequence it read, with the bucket's marker TTL on the\npurge marker so it expires too. A row\nthat does not parse fails the boot open or fences the running service. Connections admitted\nbefore this row existed, responders that do not write it, and static (non-callout) JWTs have no\nrow. This evidence names keys; it does not by itself stop a still-authorized bearer from\nconnecting again under a fresh key.\n\n**Remote manager-service authority (user-auth only).** `manager-service` is one CLOSED,\nserver-authored authority view, not a profile name, arbitrary bearer profile, or client-supplied\npermission set. The human exchange serves only a signed-in human whose current actor-ledger row\ncontains the dedicated `supervise` scope. A trusted host composition may separately issue the\nowner-bound platform supervisor registration material defined in §13.15, without a human exchange.\n`spawn` and `admin` never imply `supervise`, and `supervise` never\nimplies either. Only the loopback/operator exchange MAY issue this view; the public exchange and\nevery managed-agent secret exchange MUST refuse it. The callout re-reads the ledger row at exchange\nand connect, so a missing, narrowed, or revoked `supervise` scope denies the next view exchange and\nnew connection with the full re-grant requirement. A plain user bearer remains `agent`-scoped.\n\nThe view names exactly one ordinary derived owner, a fixed server-selected manager actor, that\nactor's lifecycle UID, and one opaque locally selected `instanceId`. The actor and instance id are\nnot client-selectable, and the view grants no second manager instance, other endpoint, or other owner.\nIt may reach only the manager instance's own `svc.manager.<instanceId>` registration/status,\npre-authorized immutable contract publication, endpoint rails, and the disjoint\n`epgate.manager.<instanceId>` / `epcred.manager.<instanceId>.<credentialId>` family. It does not\nconfer the space signer, callout signer, owner secret, static provisioner credential, generic\nstream/KV authority, or authority over another instance's gate, records, contracts, or\ncredentials. A manager-service credential is ledgered and gated exactly as this section requires;\nits `holderPrincipal` is the derived-owner/fixed-actor principal, never the endpoint name.\n\nThe typed protocol includes two host-owned registration-maintenance operations. An\n`evict-family-principal` request names `principals`, 1 to 256 distinct holders, so a restart's\nfamily eviction costs one request and one family scan per 256 holders. The host MUST enumerate the\nauthenticated caller instance's `epcred.manager.<instanceId>.*` family once per request and refuse\nunless every named principal is one of its holders. The host, using its signer, then mints the\nbounded delivery-admin caller, requests `evictPrincipals` for the set, and returns `evictions`, one\nclosed `EvictionResult` per principal in request order; a garbled, foreign, misordered, or\ncontradictory result MUST NOT authorize. The participant never receives that credential. A\n`reconcile-registration` request MAY name another manager instance in the same space only to clear\nan abandoned governance-slot holder. The host MUST observe that target's frozen registration gate,\nprove the freeze-holder `gone` under a complete liveness sweep, run the normal registration repair\nwith verified eviction, and refuse live, unknown, incomplete, unestablishable, or non-registration\nstates. There is no force path. A participant credential still gains no direct authority over the\ntarget gate, records, family, or delivery-admin rail.\n\nThe bounded executor returned by `prepare` is renewable through `renew` for the same public nkey and\ncurrent open registration. A remote manager MUST obtain a fresh executor before maintenance or clean\nderegistration when its retained credential is not healthy. A restart MUST drive family eviction\nthrough the host operation before advancing its epoch. A registration blocked by a foreign frozen\nmanager governance slot MAY request guarded host reconciliation and retry exactly once.\n\nThe typed protocol also carries two host-owned MANAGED-AGENT operations,\n`manager-managed-agent-enrollment` and `manager-managed-agent-prepare-retirement`. Both name the\nauthenticated owner's own managed agent and both require the caller's current `supervise` scope;\n`spawn` and `admin` never imply it. Both MUST be authorized against the caller instance's CURRENT\nopen manager gate: the gate's principal MUST equal the server-derived serve principal, its process\nepoch MUST equal the request's `serveEpoch`, and the request's registration proof MUST match the\nproof the host issued for that registration revision and epoch. An enrollment request MUST carry the\nSHA-256 digest of the agent's standing actor token and never the token itself, and MUST NOT carry a\nlifecycle UID: the HOST selects it, because only the host can observe the retirement tombstones that\nmake a UID permanently unusable. A prepare-retirement request MUST name a target owner equal to the\nauthenticated owner, and its `opId` MUST equal `managedRetirementOpId(target.lifecycleUid)`,\nrecomputed by the host rather than trusted, so one lifecycle never carries two terminal operations.\n\nThese two operations mutate host-owned storage, so an implementation that owns no such storage MUST\nrefuse them with `unimplemented` rather than answering a manager-lifecycle phase for them. An auth\nservice that owns the actor ledger and the space's provisioning authority answers both itself, after\nthe same decision. Its enrollment writes the managed grant at a fresh host-minted lifecycle UID with\nthe request's supervising actor as the grant's parent, so the ledger's delegation envelope bounds it,\nand then provisions that UID's durables; a provisioning failure revokes the grant and releases the\nfootprint before the refusal. An enrollment whose token digest matches the agent's standing grant is\na retry of that enrollment: it walks the held grant through the supervising actor's current\ndelegation envelope and refuses as a fresh enrollment would when the grant falls outside it;\notherwise it answers the held UID and provisions it again, and its failure leaves that grant in\nplace. While the agent holds a grant with another digest, enrollment MUST be refused\nwith `conflict` until that lifecycle's retirement is prepared, so a successor never takes a running\nagent's grant. Its prepare-retirement releases the target UID's broker footprint and then revokes the\ngrant, only while the grant still names that UID, so a repeated request is harmless. The service runs\nenrollment and prepare-retirement of one agent one at a time, and every revoke it performs names the\nUID it releases. The enrolled agent's bearer exchanges at the public exchange face, so an auth\nservice without that face MUST refuse enrollment with `failed-precondition`. A host\nplatform that owns the writers MAY intercept them on its own authenticated route and obtain the\ndecision alone from the auth service's loopback door\n`POST /manager-service-authority/verify-enrollment`, which carries the same loopback guards as the\nmanaged-retire door (POST only, no `Origin`, JSON, the per-start capability, a closed\n`{ owner, request }` body). That door MUST derive the caller's capability scope from its own ledger\nand MUST NOT accept a scope from the caller. It decides only: it mints nothing, writes nothing, and\nreturns no secret.\n\nTwo further host-owned kinds address the hosted runtime of an already-enrolled managed agent:\n`manager-managed-agent-runtime-create` and `manager-managed-agent-runtime-status`. Each carries the\nmanaged-agent envelope plus exactly `target: { owner, actor, lifecycleUid }`. Both schemas are closed:\nan unknown top-level or target field, including `providerRef`, `handle`, or `name`, MUST be refused as\n`bad-request` with no effect. There are no participant stop, adopt, or probe kinds. Both MUST be\nauthorized with the same gate, epoch, and proof checks as enrollment, with a target owner equal to the\nauthenticated owner, and with `supervise` read from the host's own ledger row for the manager actor.\nThe decision yields only the verified owner, instance id, manager actor, and target. A status decision\nauthorizes no effect. An implementation without host intent storage MUST refuse both with\n`unimplemented`. The answer carries `state` (`reserved`, `creating`, `bound`, `create-unknown`,\n`closing`, or `closed`), `readiness` (`ready`, `bound-not-ready`, or `none`), and an optional\n`retirementPhase`. An enrollment result MAY carry `runtimeIntent: { state: \"reserved\" }`, which is\ndisplay-only and MUST NOT be treated as authority.\n\nThe host, not the participant, issues every data-account credential requiring the account signing\nkey. The only remote path is the lifecycle- and instance-bound typed protocol of §13.6; a broader\nbearer or a generic credential-mint endpoint is non-conformant. Its gate is frozen before staged\nmaterial becomes usable; every release is preceded by the ledger write and gate CAS; and all\nreplay/idempotency coordinates bind the owner, fixed actor, lifecycle UID, instanceId, operation,\nand public nkey. A remote manager may provision a managed descendant only after the host validates\nthat its current owner equals the manager-service owner and the current manager grant; that is a\nsame-owner validation seam, not delegated signer authority. Revocation freezes the one family,\nrejects fresh material and new connections, and proceeds through the bounded renewal/verified\nrevocation policy below. It MUST NOT silently substitute static or local authority.\n\n**Platform control authority (service view).** `platform-control` is a second CLOSED,\nserver-authored manager authority view, beside and separate from `manager-service`. It lets a host\nplatform run one control manager per assigned data account without any human's session. It is not a\nprofile name, not an exchange view, and not a generic host profile: the public exchange, the\nloopback exchange, and every managed-agent secret exchange MUST refuse it as a view. Its holder is a\nplatform principal. The holder's owner is a platform owner token, `p_` followed by 26 base32-lower\ncharacters, which the host derives from the space's owner secret, the space, and the assigned\ndata-account public key. This extends the §2 owner-token format for this view's principals and\ntheir same-owner descendants only; everywhere else §2 stands. A platform owner token is disjoint\nfrom every `u_` derived owner, from `local`, from nkeys, and from the §13.2 mode words. The host\nMUST NOT derive it from, or bind it to, an IdP subject, and MUST NOT name a `u_` owner on this path.\nNo human is authenticated, and no ledger `supervise` scope is read or synthesized.\n\nThe view exists only while the host's current platform-control assignment names it. An assignment\nis one row `{ space, accountPublicKey, instanceId, lifecycleUid, predecessorInstanceId?,\nassignmentRevision, state }` that the platform backend alone writes. An account has at most one\ncurrent row, so it has at most one platform control instance. The host MUST read it fresh for every\nrequest under this view\nand MUST refuse, writing nothing, when it is absent or `revoked`, or when it disagrees with the\nrequest's account, instance id, lifecycle UID, or assignment revision. A failed read MUST refuse\nrather than reuse an earlier answer. The instance id and lifecycle UID are the assignment's, not\nthe caller's choice. They stay the same across the instance's restarts: a restart re-registers\nthrough the same-principal registration barrier at an advanced process epoch and is never a second\ninstance. The actors are the same fixed functions of the instance id. When the assignment names a\n`predecessorInstanceId`, the host MUST refuse `prepare` and `activate` with `failed-precondition`,\nwriting nothing, while that instance has a current `svc.manager` registration or a `frozen`\nissuance gate. The host only reads that instance's rows. It MUST NOT probe, freeze, evict, revoke,\nreopen, or deregister them. Apart from the\nholder's owner and this authorization source, the view is the `manager-service` family: the same\n`svc.manager.<instanceId>`, `epgate.manager.<instanceId>`, and\n`epcred.manager.<instanceId>.<credentialId>` rows, ledgered and gated as this section requires, with\n`holderPrincipal` the platform owner plus the fixed actor.\n\nThe view MUST NOT reach an instance whose issuance gate names another principal, including an\ninstance a signed-in human registered under `manager-service` and a manager registered under the\n`local` owner. There is no force or takeover path between the two views. Such an instance retires\nthrough its own owner's path before a platform instance may register. A re-registration never\nchanges an instance's owner, so the view never binds to an existing instance registered under\nanother owner. It registers its own assigned instance once that instance's predecessor has left\nthrough the predecessor's own path. Both registration proofs bind the owner, so a `manager-service` proof never\nvalidates under this view and a `platform-control` proof never validates under `manager-service`.\n\nA manager holding this view MUST run with no local signing trust and no local or custodial runtime\n(pooled control). The view confers no space signer, callout signer, owner secret, provisioner\ncredential, or launch authority. It provisions, enrolls, retires, validates, and authorizes only\nsame-owner descendants, whose owner is its own platform owner token, and grants nothing over a\nhuman owner's agents.\n\n**Environment manager authority.** `environment-manager` is a third CLOSED, host-authored\nmanager authority family. It admits one signerless manager and at most one managed child\nlifecycle in one provider environment. It is not an exchange view or caller-selectable\nprofile. Every human, public and managed-agent exchange MUST refuse it. Its owner is the\nordinary derived owner recorded by the hosting authority, not a synthetic human ledger\nrow or the `platform-control` owner. Neither this family nor its bootstrap authenticates\nan owner's IdP session.\n\nBefore issuance, the external authority MUST durably bind the environment record ID,\nowner, space, data-account public key, manager instance ID, manager lifecycle UID,\nbootstrap caller triple, admission revision and finite expiry. These coordinates come\nfrom host admission, never guest claims. The bootstrap caller uses that manager lifecycle\nUID and the sixth fixed actor `manager_bootstrap_<instanceId>`. This temporary actor is\nseparate from the five standing identities. Admission reserves the UID, creates\n`epgate.manager.<instanceId>` open, then freezes it `open → frozen` under one host-selected\nregistration operation intent in the same admitted operation, all before bootstrap mint.\nA gate is never born frozen under registration. The closed endpoint gate row gains the\noptional immutable discriminator `authorityFamily: \"environment-manager\"`, written only\nby this admission and retained by every subsequent CAS at open, frozen and retired states.\nIt cannot be cleared or reassigned. This extends §13.1's endpoint gate row grammar by\nthat single optional field and one literal value; any other value or new field remains\nrefused. This gate-level marker, not an op on an open gate, keeps symmetric family checks\neffective after activation; existing open/op rules remain unchanged. Only the trusted host\nmay write this family's gate, repair cursor or credential ledger. The environment supervisor\nand executor MUST NOT reuse the shipped `remote-manager` profile, whose direct writes\ncould remove this marker. Fixed mediated profiles below keep those writes host-only;\nfield-level immutability is not claimed for a credential that can publish the whole row. Staged environment, revision and operation coordinates use `stage.<opId>.…`\nand the operation's normal retention. No new permanent `stage.` key is introduced.\nThe retained retired gate remains the permanent terminal family marker. The bootstrap mint writes `cred.<managerUid>.<credentialId>` with the native\n`sourceChain: [root]` lineage (§13.1) and admission expiry, then CAS-pins that staged gate before returning\nmaterial. Only the fixed bootstrap profile is usable in this pre-preparation phase.\n`prepare` continues that same registration operation, never a second intent.\n\nEvery issuance pins the admission revision through its native issuance-gate CAS.\nTermination MUST fence that gate and revoke the bootstrap credential before marking the\nprivate admission ended. Before activation it aborts registration `frozen → open`, then\nruns retirement `open → frozen → retired` under its own intent. After activation it runs\nretirement alone. No bootstrap mint or preparation is admitted without the admission's\nsame live registration intent, regardless of revision, so the abort's reopened interval\nmints nothing. Gate advancement and verified revocation precede private admission ended. Issuance records the revision it observed in its gate intent and CAS; a termination\nadvance makes the stale CAS fail without returning material. A crash between those steps\nleaves closing/retirement-pending state and resumes the same intent. Auth unavailability\ncannot prevent bounded provider termination, but MUST NOT be reported as completed authority\nretirement. The auth gate is the issuance fence; the private admission store records its\noutcome. A fresh admission read alone MUST NOT permit material to escape a concurrent\ntermination. The admission also records the only permitted\nchild actor and its delegation ceiling. Its first enrollment binds one host-selected\nchild UID permanently; retirement does not permit a second child lifecycle. This is a\nsingle-shot environment: a crashed child cannot be relaunched under its handed-off UID\n(§13.17) or replaced by another UID. Lang reports that failure; a replacement requires a\nnew admitted environment. Missing\nmanager registration, child enrollment, run admission or terminal retirement policy MUST\nrefuse admission before bootstrap issuance.\n\nThe authority MUST re-read that binding for every request, bootstrap and renewal included.\nAn absent, expired, ended, destroyed or mismatched binding authorizes nothing. A failed\nread refuses rather than reusing a previous decision. The registration, five manager\nidentities, process epochs, credential ledger and issuance-gate barriers remain those of\nthis section and §13.6. This family MUST NOT construct a human `supervise` holder or use a\nplatform-control holder to reach issuance. Credentials MUST expire no later than admission\nexpiry. A registration proof alone is not bearer authority: later requests require the\nbroker-authenticated, instance-bound caller issued for the corresponding manager identity,\nthe current registration proof and the current process fence. The host-issued proof MUST\nalso bind this authority family, environment ID and admission revision. A human or platform\nregistration proof MUST NOT validate here, nor an environment proof under either other\nfamily. This requires a distinct, family-discriminated environment registration-proof\nderivation binding the existing coordinates and artifacts plus environment ID and admission\nrevision; the current human/platform derivation cannot be reused unchanged. Admission MUST\nrefuse an instance already bound to another family, including the same owner's human\nmanager; it provides no takeover or force path.\n\nSymmetrically, human `manager-service` and `platform-control` prepare, activate, renew,\nmaintenance and retirement MUST refuse `permission-denied` before effect for an instance or\nlifecycle whose gate or stage names `environment-manager`, under any owner. They gain no\ntakeover or repair path through this insertion. The family check precedes any freeze, epoch\nadvance, liveness probe, eviction, deregistration or credential issue. An unreadable family\nbinding refuses. Environment-bound cleanup remains the external host's admitted path.\n\nThe manager and child MUST have separate effective OS users and private material stores.\nChild launch material crosses into the child's store by value, never as paths into the\nmanager's store. The child MUST NOT receive the provider credential, hosting or model\nsponsor key, account signing seed, owner IdP token, manager credentials or manager proof.\nA runtime unable to enforce this boundary MUST refuse launch. Provider RUNNING alone\nestablishes neither manager nor child readiness. Their presence binds the opaque\nenvironment record ID through the existing `environment` field.\n\n**A read is never a fence; only a CAS write is.** JetStream `DIRECT.GET` may be served by a\nfollower or mirror and gives NO read-your-writes guarantee (a mint that *reads* the gate can\nobserve a stale `open` after a barrier froze it on the leader), so the auth bucket sets\n`allow_direct=false` (§13.12) and every fence here is a leader-served, revision-pinned CAS\nwrite. The mint protocol is **observe gate → write rows → CAS the gate → release**: the auth\npath reads the gate (recording `state`, `generation`, and KV `revision`), writes the\n`cred.`/`bysrc.` rows, then performs a **revision-pinned CAS update of `gate.<lifecycleUid>`\nitself at the observed revision**; a leader write that fails if the gate changed at all,\nand releases the credential only on CAS success with the gate still `open` at the same\ngeneration. On CAS failure, `frozen`/`retired`, or any generation advance it aborts and marks\nits own row revoked, never releasing. A barrier CASes the gate to `frozen` FIRST and only then\nenumerates the family. The race is closed by **serialization on one key**, not by timing or\nread freshness: freeze and mint-finalize are both CAS writes to the SAME gate key, so one\nloses; a mint that wins wrote its rows before its winning CAS, so the barrier's later\nenumeration sees them; a mint that loses never released. The ledger is written only by the\ntrusted auth path (§13.9 matrix; NATS binding: the auth KV, §13.12).\n\n**Every lifecycle operation is a cross-bucket saga, never an implied transaction.** The\nrecords head and the auth gate/ledger live in different buckets with no shared order, so\neach operation persists its durable intent (the gate `op`, above) before touching the\nsecond bucket, every crash boundary resumes the SAME operation from that intent, and the\nsafe orders are normative. **Initial activation, in order**: reserve the UID (create-only\n`uid.<lifecycleUid>`, above) → create the issuance gate `frozen` carrying the activation\n`op` (unmintable from birth; no credential is ever released under a frozen gate, per the\nunledgered-mint rule) → CAS the alias head to the new mapping (`active`) → reopen the gate\nat its first mintable generation as the operation's LAST step. A head-CAS loser\nterminalizes its own orphan gate and burns its reserved UID (never deleting either); a\ncrash after the head CAS leaves the lifecycle active-but-unreachable, and recovery resumes\nthe same activation `opId`, never minting a second UID for one activation. **Takeover**\nkeeps the barrier order above (freeze → revoke + verified-evict → epoch head CAS LAST →\nreopen). **Terminal retirement** keeps the barrier order below. No other head transition\nexists: the head advances only inside these operations, and no epoch-advance or retire\nseam is exposed outside the operation that completes its barrier.\n\nBinding rule (normative): **durable** authority and state; sturdy handles, accepted goals,\ncheckpoint tokens and resumes, durable consumers and delivery state, ledger rows, bind\n`(principal, lifecycleUid)` and survive supervised restart. **Live** authority, session\ngrants, reply attribution, serve/commit ownership, additionally binds the process epoch and\ndies on restart. The alias alone authorizes nothing: a delayed or redelivered request, handle,\nor teardown that names a recycled alias fails against the replacement because the lifecycle\nUID differs. Endpoint daemons carry the same triple, with the **stable logical instance id**\n(`instanceId`, `[a-z0-9]{26,32}`, ≥128 bits of CSPRNG entropy, persisted for the endpoint\nlifetime) as their routable identity component. `instanceId` is **minted by the provisioner,\nnever reused, and unique within `(space, endpoint)`**, the allocator records it in the\ninstance's service record by create-only CAS and rejects collisions durably. Reply\nattribution, scatter deduplication, queue ownership, and the event/timer planes all key on\nit, so its uniqueness and entropy are load-bearing, not cosmetic. `instanceId` is to an\nendpoint what `lifecycleUid` is to a managed agent, and both follow the same\nrestart-preserve / terminal-retire / epoch-fence rules.\n\n**Cross-plane scoping.** Chat/DM/presence *subjects* keep the §3 grammar (the alias), but\ntheir backing state is lifecycle-scoped: presence carries the current `lifecycleUid` (§6);\nper-instance durable consumers, pending delivery cursors, durable memberships, history\ncutoffs, and ACL/ledger rows key on `(principal, lifecycleUid)` (§8, §9). The DM subjects\n(`inst.>`) DELIBERATELY stay alias-keyed; a second implementer MUST NOT uid-scope them; the\nsuccessor cut for DMs is the ACTIVATION FRONTIER (the DM stream sequence captured at the\nlifecycle's provisioning, delivery starting at frontier+1, §8), and that frontier capture is\na leader-served read (the §13.9 read-service class), never a follower get. Explicit same-name\nrecreation inherits **no** predecessor authority or content: terminal retirement records\nper-stream sequence cutoffs before the alias is freed, messages published while no lifecycle\nis active do not flow to a later replacement, and retirement across streams is ordered and\nreconciled (never assumed atomic). **Destructive cleanup is broker-enforced where the resource is broker-addressable**: durable\nconsumer names, ACL rows, KV record keys, and membership rows are lifecycle-keyed, the UID\nis part of the resource NAME, and the teardown credential (the deprovisioner) is minted\ntarget-pinned to `(principal, lifecycleUid)` by exact name, so a credential minted for\nlifecycle A cannot even NAME lifecycle B's resources; the broker denies the stale delete\noutright. Only resources the broker cannot see (the manager's local credential/token/health\nfiles) fall back to a handler-side **delete-if-current** check carrying the retiring UID +\nexpected ownership revision. In both regimes the alias stays reserved until retirement and\ncleanup have durably completed, so a stale detached teardown can never destroy a same-name\nsuccessor. **Terminal retirement is additionally a credential barrier, in order**: CAS the issuance\ngate `open → frozen` carrying the durable retirement `op` FIRST (the bar: a staged mint\nloses the gate CAS, exactly the mint-protocol race above; the gate revision moves, so a\nmint that observed `open` cannot finalize) → CAS the head `active → retiring` bound to the\nsame `op.opId` (from this point every currency seam yields no current mapping and no\ncurrent epoch, and the alias is NOT replaceable) → revoke every\nactive credential-ledger row under the lifecycle prefix (all roots and all descendants,\ncredential ledger above), verifying revocation enforcement on every server as in the\ntakeover barrier → cluster-verified eviction of every revoked credential's live connections\n(`evictPrincipal`, as in the takeover barrier above) → **drain the target's acceptance\nobligations to quiescence** (§13.8: enumerate `oblig.<targetUid>.>`, settle every\nunresolved row through its decision coordinate, and re-enumerate until an enumeration\nfinds none unsettled; every writer that observed the pre-`retiring` mapping is settled\nHERE, before the cleaner below runs and before any frontier closes) → **fence the drain's\nper-op repair principals** (the commit applier, pool-route reconciler, and effects canceller\nminted inside the drain, `local.{epapl|eprec|epcan}_<opId-hash>`): cluster-verify eviction of\nany live connection under each BEFORE the cleaner and BEFORE any frontier — the applier\nespecially, whose records-KV last-value write is returned to a normal reader regardless of the\nper-stream frontier cutoff. These are self-minted data-account bearers with NO credential-ledger\nrow, so there is no connect-time deny-new: the guarantee here is **kill-live** (verified eviction\nof currently-connected principals), NOT reconnect prevention; a fresh connect within the\nbearer's TTL is the accepted residual NAMED per drain-repair profile in the §13.9 matrix (each\n\"RETIREMENT-FENCE residual\" row), of the same kill-live-not-deny-new class §13.13 fences for the\nplane connections (repair connections MUST be minted non-reconnecting so a verified eviction is\ndurable) → the trusted terminal **pool\ncleaner** settles the lifecycle's expired and orphaned pool work under a DISTINCT,\nseparately minted, exact-pool scoped profile whose pool set is this operation's **effective\ninventory**: the target's accepted `oblig.<lifecycleUid>.>` pool routes enumerated from the\nSAME drained, now-`retiring` obligation set (so no new row can appear and the enumeration is\ndeterministic across resumes). The inventory is DISCOVERY-ONLY: the barrier takes no\ncaller-supplied pool hint, so every inventory entry is an obligation-discovered pool this target\nholds accepted work on, and no pool ever enters the cleaner/executor grant without a backing\nobligation. Confinement is the EXACT per-pool effective-inventory grant plus the\nexecutor's per-item decision/horizon/retire-target checks (which bind HONEST execution, not a\ncompromised bearer): (§13.9\nmatrix row: bind-only on the pool's\npre-created durable, terminal-only ACK after the item's durable terminal fact, no consumer\ncreate/update/delete, no raw stream DELETE; it never holds, reuses, or impersonates the\nrevoked owner's authority, which this barrier just killed) → **retire the cleaner\ncredential itself, verified, BEFORE any frontier closes**: once the cleaner has settled the\npool and proven it quiescent (every pre-existing owner ACK drained through `AckWait`, and a\nfresh consumer read shows zero `num_pending` and zero `ack_pending`; a fire-and-forget ACK\nis confirmed with `AckSync` or re-proven, never assumed), the barrier REVOKES the cleaner's\nown bounded-lived credential and cluster-verifies eviction of its principal (`evictPrincipal`,\nexactly as for the owner above), so no in-flight cleaner can ACK a redelivery or write a\nterminal after the alias is reused; the cleaner's authority MUST be dead before the frontier\nrecords → record the\nper-stream retirement frontiers (the create-only, never-deleted `frontier.<lifecycleUid>`\nrecord, §13.7: one key per retired lifecycle, recorded once under this operation's `opId`) →\nCAS the gate `frozen → retired` (terminal; unlike\ntakeover, retirement never reopens it) → CAS the head `retiring → retired` → only then\nfree the alias, and a successor activates only with a freshly reserved UID. `retired` on\nthe head therefore ASSERTS completed cleanup: replacing a retired predecessor needs no\nfurther proof, because nothing reaches `retired` without the barrier. Every boundary of\nthis sequence is crash-resumable through the durable `op` intent, and only the same\noperation resumes it. A **managed** lifecycle's terminal retirement has exactly one operation\nidentity, `managedRetirementOpId(uid)`, whichever entry point requests it: the participant\nmanager's `retire-lifecycle` rail request (§13.2) or the host's loopback managed-retire door, which\nfinishes the retirement when that manager is gone and requires the managed grant to be revoked at\nthat UID first. Both entry points create or resume the same durable operation, and one process\nnever executes it twice concurrently. Chat/DM/presence subjects stay\nalias-keyed, so without the revoke-and-verified-evict step a still-connected stale process\ncould keep speaking as the recycled alias. Where the deployment cannot revoke the credential\nor cannot verify eviction, alias reuse is **forbidden**: a same-name respawn fails loud.\nSupervised restart of the same UID retains all of it.\nIntentional role-mailbox continuity across lifecycles is only available as an explicit,\nseparately authorized transfer operation, never an accidental consequence of string reuse.\n\n### 13.2 Grammar\n\n**Endpoint names.** An endpoint name is one or more DNS-shaped labels, each matching\n`[a-z0-9]([a-z0-9-]*[a-z0-9])?` (no leading/trailing dash, no bare dashes; `_` MUST NOT\nappear in a label). Single-label names (`manager`, `delivery`) are reserved for\nendpoints shipped by this contract's reference implementation and require the space operator's\nprovisioning authority to serve; a third-party endpoint name MUST be reverse-DNS (two or more\nlabels under a domain its author controls, e.g. `com.acme.deploy`) and is mintable only under\nthe owner that registered that domain claim. In a wire subject the name is one token with `.`\nreplaced by `_` (`com_acme_deploy`); because `_` cannot appear in a label the mapping is\nbijective. Name authority is the credential, never the registry (§13.9). Endpoint-name\ntokens may contain `-` inside labels; they are never used to derive principal dash-form\nnames; control-surface consumer names are the §13.9 pinned grammars, each carrying a\nstated collision-freedom argument, and none is ever parsed back into its components, so\nthe §2 dash-form separator stays unambiguous.\n\n**Command tokens.** A command name is one token `[a-z0-9-]{1,32}`. The command is a validated\nsubject token so the broker enforces per-command authority (§13.9). `describe` and `cancel`\nare reserved command names (§13.7, §13.6).\n\n**Request subjects.** Three **addressing modes** under one kind `ep`, the mode token says\nwhere a request routes, never which verb it is (the verb rides the envelope, §13.3/§13.5):\n`one` (queue-group anycast: exactly one class member), `all` (scatter: every instance),\n`inst` (one instance by its stable triple). The `one` rail's queue group is canonically\nnamed by the endpoint-name token, and serve subscriptions to it are **queue-qualified\nonly** (§13.9): no credential can plain-subscribe the class rail, which is what keeps\nper-request nonces visible only to the queue-selected instance. Every request carries the caller as **three**\nforge-locked tokens `<owner>.<actor>.<uid>` (principal + lifecycle UID, §13.1) followed by a\ncaller-chosen unguessable **nonce** token (`[A-Za-z0-9_-]{22,64}`, ≥128 bits of CSPRNG\nentropy; one outstanding call per nonce; reuse before the prior call resolves is a caller\nerror and the reply rail MUST treat the earlier subscription as dead); always, on calls and\ncasts alike, so one grant row covers both verbs and no shape is distinguished by counting. A\ncommand whose contract declares it **targeted** carries an **authorization-mode token** and,\nper mode, zero to three pinned target tokens between the command and the caller:\n\n| Form | Subject | Tokens |\n| --- | --- | --- |\n| Class, untargeted | `cotal.<space>.ep.one.<endpoint>.<command>.<owner>.<actor>.<uid>.<nonce>` | 10 |\n| Class, `self` | `cotal.<space>.ep.one.<endpoint>.<command>.self.<owner>.<actor>.<uid>.<nonce>` | 11 |\n| Class, `owner`/`any` | `cotal.<space>.ep.one.<endpoint>.<command>.<authz>.<tOwner>.<owner>.<actor>.<uid>.<nonce>` | 12 |\n| Class, `child`/`ledger` | `cotal.<space>.ep.one.<endpoint>.<command>.<authz>.<tOwner>.<owner>.<actor>.<uid>.<nonce>` | 12 |\n| Class, `handle` | `cotal.<space>.ep.one.<endpoint>.<command>.handle.<tOwner>.<tActor>.<tUid>.<owner>.<actor>.<uid>.<nonce>` | 14 |\n| Class, `exact` | `cotal.<space>.ep.one.<endpoint>.<command>.exact.<tOwner>.<tActor>.<tUid>.<owner>.<actor>.<uid>.<nonce>` | 14 |\n| Scatter | as class forms with mode token `all` | 10-14 |\n| Instance | `cotal.<space>.ep.inst.<endpoint>.<instanceId>.<command>[.<authz>[.<target tokens per mode>]].<owner>.<actor>.<uid>.<nonce>` | 11-15 |\n| Reply | `cotal.<space>.ep.reply.<endpoint>.<instanceId>.<epoch>.<owner>.<actor>.<uid>.<nonce>` | 11 |\n| Versioned rail (§13.15) | every form above with `ep.v1` in place of `ep` and `<generation>` inserted between `<uid>` and `<nonce>` | 12-17 |\n\n**The versioned rail.** An **issued** caller (§13.15) rides `cotal.<space>.ep.v1.…`: the same\nforms, one more token, the caller's issued `<generation>` (32 lowercase hex characters), placed\nbetween `<uid>` and `<nonce>` on every request and reply form. The legacy `ep.` rail and the\n`ep.v1.` rail are disjoint subject spaces at the broker: an issued credential holds rows on the\nversioned rail only, a legacy credential holds rows on the legacy rail only, and an endpoint\nserves both. A responder derives the reply subject from the authenticated request subject on\nwhichever rail it arrived, generation included. `v1` versions the rail encoding, not the\nprotocol.\n\n**Single-owner endpoint names (normative).** An endpoint name binds to exactly ONE owner\n(§13.9: operator-provisioned core names, domain-owner-bound reverse-DNS names), so the name\ntoken alone determines the serving owner and instance-addressed subjects carry **no owner\ntokens**: `(endpoint, instanceId)` is the complete routable instance address. Two parties\nwanting the \"same\" name use their own reverse-DNS names; an owner-qualified shared-name form,\nif ever wanted, would be a later additive subject form, not a change to these. This trades an\nalready-forbidden expressiveness for structurally smaller subjects and credentials.\n\n**Remote manager service.** The core `manager` name remains operator-governed: a\n`manager-service` bearer (§13.1) does not transfer its name authority or create a generic\nuser-owned endpoint. It is the one closed user-auth exception to the single-owner endpoint rule:\nthe host may authorize one `manager` service instance whose service-record owner and serving\nprincipal are the bearer's derived owner plus fixed server-selected manager actor. The exception is\nscoped by the server-authorized lifecycle UID and opaque globally unique instance id, so the\n`(manager, instanceId)` route stays unambiguous and no registration can be mistaken for another\nowner's. The standard `ep` grammar is unchanged: the bearer reaches only that exact manager\ninstance, while the manager's own agent-control requests use the existing owner and same-owner\ndescendant checks. No endpoint name, target form, or wildcard is added for this view.\n\nThe target's **lifecycle UID is body-carried, not a subject token** (`target.lifecycleUid`,\n§13.3): a grant could only ever wildcard it (targets are dynamic; the UID is unknowable at\nmint time), so a token there would add zero broker enforcement while costing every targeted\ngrant row a token, the trusted validator, not the broker, compares the expected UID against\nthe current mapping (§13.1). The one exception is `handle` mode: at handle redemption the\ntarget's UID IS known and current, so the redemption-minted form pins the full target triple\nas subject tokens (below); pin what is knowable at mint time; body-carry only what is not.\nEvery form stays within the NATS 16-token recommendation.\n\n**Explicit discrimination (never arity counting).** The forms are distinguished by the token\nafter `<command>`: it is either one of the six reserved authorization-mode tokens (`self`,\n`owner`, `any`, `child`, `ledger`, `handle`) or the caller's owner token, and the two sets\nare disjoint by construction, because an owner token is `local` or `u_`+base32 (§2), never a\nbare mode word. The target-block arity then follows the mode (`self`: none;\n`owner`/`any`/`child`/`ledger`: one `<tOwner>` token; `handle`: three,\n`<tOwner>.<tActor>.<tUid>`); a closed set at a fixed position, exactly the property that\nmakes per-mode arity safe. A parser dispatches on that set; a subject matching no defined shape\nhas no sender and MUST NOT be handled.\n\n**Token bounds (normative).** On the endpoint rails every identity token is bounded:\n`owner` ≤ 64, `actor` ≤ 64, `command` ≤ 32, `endpoint` ≤ 64, nonce and ids ≤ 64 characters;\n`lifecycleUid` and `instanceId` are bounded by their single defining grammar\n`[a-z0-9]{26,32}` (§13.1); deliberately not restated here, so the bound cannot drift from\nthe definition. A total request or reply subject MUST NOT\nexceed 1024 bytes; implementations validate fail-loud at build time. (Transport headroom:\nthe reference deployment raises `max_control_line` to 64 KiB; the PUB line is never the\nbinding constraint; minted-credential size is, §13.9.)\n\n**The authorization-mode token** (`<authz>`) makes the authority gradient explicit and\nbroker-enforced where it is statically expressible, and honestly validator-primary where it is\nnot. Seven modes:\n\n- `self`, the target IS the caller: the form carries **no target tokens and no body\n `target`** (a supplied one is `target-mismatch`, never ignored); the endpoint derives the\n target from the broker-authenticated caller triple in the same subject. Fully\n broker-confined, including the lifecycle UID, because the caller's own `<uid>` token is\n the target's UID, forge-locked by the mint: a stale lifecycle's credential cannot even\n publish the successor's subject.\n- `owner`, owner-domain: the target block is `<authz>.<tOwner>` (ONE target token); grants\n pin `<tOwner>` to the caller's own owner (standing mints; a handle redemption instead pins\n the issuer-signed target owner, §13.6). The target actor and expected lifecycle UID are\n body-carried (`target`) and validator-checked against the current mapping, the broker\n cannot express \"any actor under my owner, currently mapped to this UID\". An `owner`-mode\n grant is NEVER minted with a wildcard target owner. Broker-confined on the owner; validator\n on the rest.\n- `any`, unrestricted target owner (`<authz>.<tOwner>` with `*`): a distinct mode mintable\n only for operator/admin capabilities, so no widening of an `owner` grant can ever reach\n it. Validator-checked target as for `owner`.\n- `handle`, **redemption-minted only** (§13.6): the target block is\n `handle.<tOwner>.<tActor>.<tUid>` (THREE target tokens), each a literal pinned at\n redemption from the issuer-signed grant against the then-current mapping. Never a standing\n capability, never wildcarded. Broker-confined on the full target triple; the validator\n re-checks only currency; a subject `<tUid>` that no longer matches the current mapping is\n `expired`.\n- `exact`, **privileged exact incarnation, minted only through its owning profile** (Cotal\n #399): the target block is `exact.<tOwner>.<tActor>.<tUid>` (THREE target tokens), the same\n literal-triple shape `handle` carries, minus the redemption promise. There is no issuer-signed\n artifact, no redemption step, and no `sourceChain`; the row is built directly by the profile\n that owns this command under root authority for one target it names, never a standing\n capability, never wildcarded. Broker-confined on the full target triple, exactly as `handle`;\n the validator re-checks only currency, and a subject `<tUid>` that no longer matches the\n current mapping is `expired`. A generic reader of this mode infers precisely a privileged,\n grant-pinned exact triple with a current-mapping check, and nothing more.\n- `child`, static-mesh own-child (`spawner == caller`): a **distinct trusted-validator form**.\n The grant means \"may ask this validator\", not \"already authorized\"; the handler MUST\n fresh-check the immutable spawner relation against durable state and fail closed. Its\n `<tOwner>` ceiling is the caller's own owner, as for `owner` mode (a static-mesh child\n shares its spawner's owner).\n- `ledger`, fresh-ledger escalation: a distinct trusted-validator form; the handler MUST\n fresh-read the authorization ledger and fail closed on lookup failure, timeout, or absence.\n Its grants pin literal `<tOwner>` values named at mint; a wildcard target owner in `ledger`\n mode is mintable only for operator/admin profiles.\n\n`any`, `child`, `ledger`, `handle`, and `exact` are never wildcard-reachable from a `self`/`owner`\ngrant (distinct token ⇒ distinct subject ⇒ distinct grant row). A handler MUST resolve the target (the\nrevision-pinned `(alias, lifecycleUid)` mapping, §13.1) immediately before effect and reject\nany request whose body target disagrees with the subject target tokens (`target-mismatch`) or\nwhose expected target lifecycle UID does not match the current mapping (`expired`). The\nsubject, never the body, is the authorization boundary; handler policy only narrows.\n\nA responder that finds no current mapping for the target refuses `expired` with `outcome:\nnot-executed` and `details[].kind = ai.cotal.ep.target-unmapped`, which says the instance that\nanswered holds no mapping for it. A responder whose mappings are instance-local, as a manager's\nare for the agents it hosts, cannot tell a target another instance hosts from one retired\neverywhere. A caller that reached it on the class rail MAY therefore re-resolve and re-issue, as\nafter a bind refusal; on the `inst` rail the refusal is that instance's answer.\n\n**Replies.** Every reply rides the dedicated reply rail above, **deterministically derived\nfrom the authenticated request subject**: the responder copies the caller triple and nonce\nfrom the request subject and prefixes its own endpoint/instance/epoch tokens (the owner is\ndetermined by the endpoint name; no owner tokens appear). A responder\nMUST ignore any transport- or payload-supplied reply target (the confused-deputy boundary).\nThe grants are exact-arity, no `>` tail admits subjects outside the grammar: the caller's\nread grant is its own rail (`ep.reply.*.*.*.<owner>.<actor>.<uid>.*`), so it reads only\nreplies addressed to it; the responder's publish grant pins its own instance triple and\nepoch (`ep.reply.<endpoint>.<iId>.<epoch>.*.*.*.*`), so the answering instance and\nepoch are read off the broker-authenticated reply subject, never trusted from the payload.\nTwo properties, enforced differently, stated precisely: **attribution** (who answered) is\nbroker-enforced by the responder's pinned prefix; **addressing** (whom a responder may\nanswer) is capability-by-secret, the responder's grant spans all caller suffixes, and what\nconfines it to the requester is possession of the unguessable per-request nonce, which only\nthe request's recipients hold. A stale process (superseded epoch) publishes attributably\nstale replies that callers reject; scatter gathers additionally reject replies from\ninstances outside the frozen expected set (§13.5).\n\n**Incarnation admission (the bound-incarnation fence).** Rejecting a reply is a REPORT, not a\nguard: it happens after the responder has already handled the request. On the class rail the\nqueue picks the responder, so a caller that resolved incarnation B can have its command executed\nby A and then be told the call failed — with no way to say whether any effect landed. A caller\nthat will accept an effect only from the incarnation it resolved therefore declares it in the\nrequest (`bind`, §13.3), and a responder that is not that incarnation **MUST refuse it at the\npre-effect seam** — before args validation, before target resolution, and before the §13.6/§13.10\ngoverned gate, which may consume a one-use payment proof. The refusal carries\n`ai.cotal.ep.bind-refused` and means the command did not run, so re-resolving and re-issuing\ncannot duplicate an effect; that is the distinction `ai.cotal.ep.unbound-responder` (raised by the\ncaller, on the reply) cannot make. `bind` is a caller declaration and never authority: it can only\nnarrow a request the subject already routed, and attribution still comes from the reply subject —\na refusal attributed to the very incarnation the caller bound is incoherent and MUST be rejected\n(`internal`) rather than honored. A responder that does not implement the fence ignores the field\n(§5) and executes; the caller-side check remains the only protection in that skewed pair.\n\nThe **caller's** process epoch is\ndeliberately NOT encoded in the rails: reply consumption binds to the requesting process\nbecause a caller MUST subscribe the exact concrete nonce subject before publishing a call\nand MUST NOT persist nonces; a restarted successor never holds the predecessor's nonce\nsubscriptions, so in-flight calls die with the process (they are ephemeral by definition)\nand a late reply is unreadable rather than misdelivered.\n\n**Event and journal subjects.** Endpoint-published planes, captured by per-space streams\n(§13.12); the publishing instance's identity is forge-locked into the subject:\n\n| Plane | Subject |\n| --- | --- |\n| Events | `cotal.<space>.epe.<endpoint>.<instanceId>.<epoch>.<topic...>` |\n| Canonical facts | `cotal.<space>.epf.<endpoint>.<topic...>` |\n| Submissions | `cotal.<space>.epj.<endpoint>.<command>[.<authz>[.<target tokens per mode>]].<owner>.<actor>.<uid>` |\n| Timers | `cotal.<space>.ept.<endpoint>.<instanceId>.<epoch>.<timerId>.<schedule\\|armed\\|fire>` |\n| Record writes | `cotal.<space>.epr.<endpoint>.<instanceId>.<epoch>.<kind>.<qualifier...>` (mediated record-writer ingress; the instance's epoch-pinned rail for `svc`/`goal`/`cp` status writes; consumed ONLY by the record writer, which reads the writing epoch from the broker-authenticated subject, never from payload, §13.9) |\n| Contract artifacts | `cotal.<space>.epc.<digest-hex>` (one immutable artifact per subject; `<digest-hex>` is the artifact's SHA-256 hex, 64 chars; the `sha256:` prefix is not a subject token; §13.7) |\n| Work pools | `cotal.<space>.epw.<endpoint>.<pool>.<cOwner>.<cActor>.<cUid>.<id>` (one item per subject; the trailing four tokens are the item's **acceptance identity**; the accepted submission's caller triple + request id, §13.6) |\n| Sessions | `cotal.<space>.eps.<endpoint>.<sessionId>.<epoch>.<in\\|out>` |\n\nEvents carry the publishing instance's **epoch as a subject token**, pinned by the serve\ngrant, so a superseded process cannot emit progress indistinguishable from the current\nincarnation's; readers match the current (or goal-accepted) epoch and treat stale-epoch\nevents as attributably stale. A **targeted** journal command carries the same authz/target\nblock in its submission subject as its request forms, so the broker confines targeted\njournal work exactly as it confines calls; the canonicalizer additionally requires exact\nbody/subject agreement before acceptance. Timers use three forms: `.schedule` is the\ninstance-published **schedule request**, captured by a stream with message schedules\nDISABLED, so any client-set scheduling header is inert bytes, and the mediated timer writer\nrejects a request carrying one; `.armed` holds the **authoritative schedule message**,\npublished only by the mediated timer writer (§13.9), which derives the ADR-51\n`Nats-Schedule-Target`, the sibling `.fire` subject, from the broker-authenticated\nREQUEST subject's own tokens, never from any payload or header (a schedule's target MUST\ndiffer from its publish subject per ADR-51; replacement is the writer's same-subject\npublish on `.armed`); `.fire` is where fires appear. An instance's serve grant covers\n**only `.schedule`** (epoch-pinned); no client credential holds `.armed` or `.fire`\npublish; fired messages are written by the broker's scheduler alone, and the handler\nvalidates the carried `(timerId, generation)` against current status AND\n`now ≥ the authoritative deadline` AND that the broker-authored scheduler-origin header\nnames its own exact sibling `.armed` subject (§13.12) before acting.\n\nReserved event topics: `ev.<cluster>.<event>` (cluster events), `goal.<cOwner>.<cActor>.\n<cUid>.<goalId>.<t>` (per-goal action progress; the caller identity in the subject gives\nmint-time read containment), `cp.<token>.<t>` (checkpoint transitions). Reserved fact topics:\n`dec.<cOwner>.<cActor>.<cUid>.<id>` (canonical decisions (accepted/rejected) caller-scoped, §13.4), `quar.<sourceSeq>` (poison quarantine, §13.4; its own family,\ndisjoint from the caller-id `dec` namespace by construction), `goal.<cOwner>.<cActor>.<cUid>.<goalId>.result` (terminal\nresults), `wrk.<pool>.<cOwner>.<cActor>.<cUid>.<id>` (per-work-item terminal results,\nkeyed by the item's acceptance identity, §13.5/§13.6), `eff.<cOwner>.<cActor>.<cUid>.<id>`\n(per-request effect-complete facts for non-action effects commands, §13.9), `cp.<token>` (one-use checkpoint\nresume, journaled by create-only CAS, §13.6),\n`receipt.<cOwner>.<cActor>.<cUid>.<id>.<sourceSeq>`\n(caller-scoped; request ids are caller-chosen, so an endpoint-wide `receipt.<id>` would\nlet two callers collide and read each other's receipts, and **execution-scoped**: the\naccepted submission's `sourceSeq` is unique per execution, so a request id lawfully reused\nafter its decision retention expires (§13.4) mints a NEW receipt subject instead of\nappending to the old one, where a last-by-subject read would have hidden the earlier\nreceipt for the rest of its 90-day retention). Submissions are publishable directly by capability holders\nand are **explicitly untrusted** (§13.4); canonical fact subjects are publishable only by\ntheir mediated writer (§13.9). `<id>`, `<goalId>`, `<timerId>`, `<token>`, `<sessionId>` are\nsingle tokens `[A-Za-z0-9_-]{1,64}`.\n\nThe v0 subjects `cotal.<space>.ctl.>` and `cotal.<space>.control.>` are retired: nothing\nserves them and no post-cut credential carries a grant on them. `trace.<instance>` remains reserved,\nunchanged. `<pool>` is a single token `[a-z0-9-]{1,32}` (command-token grammar).\n\n### 13.3 Envelope\n\nRequests, replies, submissions, events, facts, and progress payloads are UTF-8 JSON. The\nenvelope is versioned and typed; `ControlRequest`/`ControlReply` are deleted.\n\n`EndpointRequest`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `v` | `1` | MUST | envelope schema version (independent of the wire `protocolVersion`; the envelope starts at its own v1 inside the v0.4 revision); other values rejected (`unsupported-version`) |\n| `id` | string | MUST | caller-chosen request id, `[A-Za-z0-9_-]{1,64}`; the idempotency key at the declared scope (§13.8), realized on journaled planes by the caller-scoped decision CAS (§13.4), never by a transport header |\n| `op` | object | MUST | `{ endpoint, command, inputDigest, outputDigest }`; MUST agree with the subject (`op-mismatch`). The digests bind the invocation to the described contract and are **both REQUIRED on every command except `describe`** (the discovery bootstrap), unconditional, because every command declares both schemas: a side with no payload declares the canonical void schema (§13.7), whose digest exists like any other. A serving member rejects a missing digest (`contract-mismatch`) before any effect, and one that cannot honor a pinned digest replies `contract-mismatch`, never coerces |\n| `class` | `ephemeral` \\| `journal` | MUST | the submission's declared delivery contract; MUST equal the command's contract class (`class-mismatch`); immutable per submission. (`record` is a state contract, never a request class; the action composite is a command marker, not a class; an action command's submissions are `journal`) |\n| `replyExpected` | boolean | MUST | the verb: `true` = call (a reply is expected on the reply rail; `deadlineMs` required; the caller subscribes its exact nonce before publishing), `false` = cast (fire-and-forget; a responder MUST NOT reply). The subject shape is identical for both; the verb never changes the grammar |\n| `goalId` | string | action commands | MUST for a command whose contract declares the action composite: the client-generated goal id (§13.6); absent otherwise. `id` remains the per-request idempotency key |\n| `target` | object | per mode | `{ owner, actor, lifecycleUid, mappingRevision? }`. **Absent for `self`** (and for untargeted ops): a supplied one is `target-mismatch`, never ignored. **Required for `owner`/`any`/`child`/`ledger`/`handle`**: `owner` MUST equal the subject `<tOwner>` token (`target-mismatch`); `actor` and `lifecycleUid` are validator-compared against the current mapping (`expired` on mismatch), and in `handle` mode MUST additionally equal the subject `<tActor>`/`<tUid>` tokens (`target-mismatch`); `mappingRevision`, when present, additionally pins the exact mapping revision the caller observed |\n| `bind` | object | MAY | `{ instanceId, epoch }` — the incarnation the caller's `describe` resolved against. A responder whose own `(instanceId, epoch)` differs **MUST refuse before any effect**, at the pre-effect seam and ahead of the governed gate: `failed-precondition` when a different instance received it, `expired` when the same instance is at another epoch, both carrying `details[].kind = ai.cotal.ep.bind-refused`, which asserts the command **did not run**. **Absent on `describe`** (the bootstrap that produces the bind; a supplied one is `bad-request`) and **absent on the scatter rail** (which addresses every incarnation; `bad-request`). On the `inst` rail it MUST name the subject's instance (`bad-request` otherwise) and adds the epoch the subject grammar has no token for. It confers nothing and can only make a responder the subject already reached refuse, so it satisfies monotonic attenuation |\n| `args` | object | MAY | validated against the input schema before any effect (`bad-request`) |\n| `from` | `EndpointRef` | MUST | as §5; `from.id` MUST equal the subject sender principal, and the sender UID token MUST match the caller's minted lifecycle UID (broker-enforced by the grant) |\n| `deadlineMs` | number | MUST for call/scatter and journal submissions | caller deadline budget; bounded, never unbounded. On a journal-class submission it is the **decision deadline**: the bound within which the caller expects its durable decision fact (§13.4) |\n| `correlation` | object | MAY | `{ traceparent?, tracestate?, baggage? }` per W3C Trace Context; propagated to downstream calls, events, facts, receipts |\n| `auth` | string | MAY | opaque signed authorization-context slot (capability handle, obligations, payment proof). Opaque to the transport, never to identity: its **`authDigest`** (§13.4 fingerprint) is `sha256:<hex>` over the UTF-8 bytes of this string **exactly as carried**; the slot is already a canonical signed artifact, so it is digested as bytes, never re-canonicalized, and is absent from the fingerprint iff `auth` is absent |\n\n`EndpointReply`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `v` | `1` | MUST | |\n| `id` | string | MUST | echoes the request `id` |\n| `ok` | boolean | MUST | |\n| `data` | any JSON | MAY | present iff `ok`; validated against the output schema |\n| `error` | object | iff `!ok` | `{ code, message, details?[], outcome? }`; codes below; `details[]` entries carry reverse-DNS `kind`; `outcome` per **Effect outcome** below |\n| `receipt` | string | MAY | opaque signed receipt slot (§13.10) |\n\n**Effect outcome.** An error reply MAY carry `error.outcome`, one of `executed`, `not-executed`,\nor `unknown`, stating whether the command's effect occurred. It is emitted by the **responder**,\nwhich is the only party that knows: a responder that refuses BEFORE dispatching to the handler\nMUST carry `not-executed`, and one that refuses AFTER the handler has run MUST carry `executed`.\nA responder that cannot distinguish the two MUST carry `unknown` rather than guess. An error\nreply that omits `outcome` MUST be read as `unknown`. A handler that refuses before its command's\nfirst effect has started SHOULD carry `not-executed`, because nothing occurred. A handler that\nrefuses after an effect may have started MUST NOT carry `not-executed`.\n\n`outcome` describes a reply, and only a reply. A refusal a CALLER raises locally is not an\n`EndpointReply` and carries no `outcome` field. It does not follow that the caller knows nothing:\nit MUST classify the refusal from what it observed, and only one of the four cases below is\ngenuinely `unknown`.\n\n- **Refused before publication** — the request was never put on the wire. The caller knows the\n effect did not occur and MUST classify it `not-executed`. Treating this as `unknown` suppresses\n a retry that is provably safe, including for a `write`.\n- **Refused while holding a reply** — the caller parsed a reply and then rejected it for a reason\n of its own, the §13.2 post-reply currency check being the case in this document. What the caller\n knows comes from the reply it holds: an `ok:true` reply means the handler ran to completion, so\n the refusal is `executed`; an `ok:false` reply carries the responder's own `outcome`, which the\n caller MUST adopt rather than overwrite. Discarding a held reply's outcome because the caller\n went on to reject the reply loses the one fact the responder was in a position to state.\n- **Answered by the broker with no responders** — the request subject had zero subscribers, and\n the broker says so on the reserved no-responders sentinel. That is a positive, broker-attested\n fact that nothing received the request, so it is `not-executed`, not merely unanswered. A caller\n MUST trust it ONLY on that reserved sentinel, which carries no responder publish grant: the same\n status on an ordinary reply subject is a responder's own claim and proves nothing about\n delivery.\n- **No reply observed** — a deadline that expires with no answer at all, a transport failure after\n publication, any path where the caller cannot tell whether the request was handled. This is\n `unknown`, and it is the only local case that is.\n\nA caller **MUST NOT infer execution from the mere arrival of a reply**: a reply proves the request\nwas HANDLED, never that it executed. The two differ on every path where a responder refuses before\nthe handler — the version, class, target, sender, authz, contract, and guard checks all publish\n`ok:false` having executed nothing, and each of those replies says so in its own `outcome`.\n\n`outcome` exists because a refusal code alone cannot carry this fact: the same code and the same\nmessage are correct for a request that ran and for one that never left, and a caller that cannot\ntell them apart and retries duplicates the effect. `effect` (§13.7) tells a client whether a\nrepeat is safe; `outcome` tells the caller what already happened. Neither substitutes for the\nother, and a `write` command refused with `unknown` is precisely the case where no automatic\nrecovery is available and the decision belongs to the caller.\n\n`outcome` is NOT a goal's terminal state. An action accepted under §13.6 reports its result as a\ngoal fact; an accepted action whose caller then loses its follow has an `outcome` of `executed`\nfor the SUBMISSION and no terminal state at all, which are different facts about different\nthings. `outcome` MUST NOT be used to report, replace, or summarize a goal outcome.\n\nThe answering instance, its epoch, and the addressee are read from the **reply subject**\n(§13.2), not from payload fields; a payload claim of either is advisory display data only.\n\nEvery other plane is typed too: a journaled **submission** is an `EndpointRequest` (same\nenvelope, published to `epj`); an **event** (incl. per-goal progress) is\n`{ v: 1, topic, ts, data, correlation? }`; an **acceptance fact** is the `AcceptanceFact` of\n§13.4; a **terminal result fact** carries the goal's terminal state (one of the five\nterminal values of §13.6), outcome digest, and\nresult payload (or its digest-pinned reference). All are runtime-validated at their\nconsuming boundary.\n\n**Monotonic attenuation (invariant).** Envelope content, the `auth` slot, a handle,\nobligations; may only narrow what the presenting credential already permits, never widen it.\nA handler that honors envelope content as authority beyond the broker grant is non-conformant.\nAuthority *conferral* exists only as trusted redemption (§13.6 capability handle).\n\n**Error catalog.** `code` is one token: `bad-request`, `unsupported-version`, `op-mismatch`,\n`class-mismatch`, `target-mismatch`, `sender-mismatch`, `unauthenticated`,\n`permission-denied`, `not-found`, `already-exists`, `conflict` (CAS/fencing loss,\nfingerprint conflict, duplicate resume), `contract-mismatch`, `contract-invalid` (schema\noutside the profile / over budget at registration), `failed-precondition`,\n`deadline-exceeded`, `cancelled`, `expired` (lease, handle, lifecycle UID, epoch, token),\n`unavailable` (no responder), `unimplemented`, `resource-exhausted`, `internal`. Extensions\nadd codes only under reverse-DNS. A `code` (catalog or extension) is one token of at\nmost **64 bytes**, so every fact shape that embeds one (`RejectionFact`, `QuarantineFact`)\nstays bounded by construction and the §13.12 fact fixture is a true worst case.\n\n### 13.4 Delivery contracts\n\nThree delivery contracts, chosen per command class, declared in the contract, immutable per\nsubmission. Decision rule: crash means \"just re-ask\" → **ephemeral**; long-lived state\nsomething converges on → **record**; must survive restart, be audited, metered, or\ncompensated → **journal**. Wrong-class submission fails loud.\n\n**Ephemeral**, request/reply on the `ep` rails; no broker persistence; at-most-once effect\nunless the command is idempotent by `id`. No-responder is a loud `unavailable`.\n\n**Record**, a `{kind, schema, spec, status, meta}` resource in the per-space records bucket,\nstored as **two keys with independent revisions**: `<key>.spec` and `<key>.status`. The split\nis the broker-enforced writer boundary: the spec-writer and status-writer roles hold publish\ngrants on their own key only (per-kind writer table, §13.9). Writes use per-key CAS; a lost\nrace is a loud `conflict`. The merged logical read returns both\nrevisions and carries `status.observedSpecRevision`; a reader treats\n`observedSpecRevision < spec.revision` as a stale-but-valid level-triggered projection, not\nan error, and `observedSpecRevision > spec.revision` (a lagging spec read, possible across\nreplica freshness points) as its own signal to re-read the spec key, bounded retries until\ncaught up or the caller's deadline, never trusting the mismatched pair. Watch delivers\ncurrent values then deltas per key; a watcher that falls behind MUST re-read both keys and\nresume, never patch forward across a gap. Records are\nbounded (§13.8).\n\n**Journal**, an explicitly **untrusted at-least-once submission log** feeding **canonical\naccepted-fact subjects** with a mediated writer; effects consume only canonical facts, never\nraw submissions.\n\n1. A journaled submission is published to the submission plane (`epj`) as a **plain append**:\n submitters MUST NOT set `Nats-Msg-Id`, and native dedupe is **not relied upon**, the\n server does not accept a zero duplicate window (§13.12), so the reference config sets the\n server minimum and the guarantee rests on the header rule, not the window: a conformant\n submission carries no dedupe header and cannot be suppressed by one. Native broker dedupe\n keys on a caller-set header value compared\n **stream-wide**, so on a shared submissions stream any writer could pre-seed a predicted\n header value from its own allowed subject and silently suppress another caller's first\n submission for a full dedupe window, a cross-caller denial that no \"advisory\" framing\n makes safe; with the MUST NOT in force, a hostile header-bearing publish can suppress only\n another non-conformant header-bearing write. Transport retries therefore simply append\n again; the caller-scoped decision\n CAS below resolves every copy to one decision. Submission subjects and fact subjects are\n disjoint by construction (§13.2), so a submission credential cannot write a fact.\n2. The **semantic fingerprint** covers every effect-defining dimension, the fingerprint\n object is `{endpoint, command,\n class, authz?, target?: {owner, actor, lifecycleUid, mappingRevision?}, inputDigest,\n outputDigest, args, authDigest?, caller: {id, lifecycleUid}, goalId?, id}`, and the\n fingerprint VALUE is that object's `sha256:<hex>` content digest per §13.7 (strict\n RFC 8785 over I-JSON, the SAME canonicalization every contract artifact uses; one\n canonicalizer, never a second): absent optional fields are OMITTED from the object, never\n written `null`, so two implementations digest identical bytes, which also makes the\n fingerprint **computable for EVERY parseable submission**, however incomplete: a\n parseable envelope missing `class` or digests fingerprints the subset it carries and is\n rejected with that fingerprint. **\"Parseable\" here means canonicalizable I-JSON**, not\n merely syntactically valid JSON: bytes that parse but cannot be canonicalized, duplicate\n object names, a lone surrogate, a non-finite or out-of-I-JSON-range number; have no\n interoperable RFC 8785 form and therefore no fingerprint, so they take the quarantine\n path exactly as unparseable bytes and an invalid `id` do (§13.4 item 3: raw-byte digest,\n no fingerprint). Every submission thus has exactly one terminal path. Same id +\n same fingerprint is the same request (idempotent, first-wins); same id + different\n fingerprint (including the same args retargeted at a different lifecycle) is a loud\n `conflict`, never accepted or effected.\n3. The **canonicalizer**, the narrowly scoped mediated writer for this endpoint's facts\n (§13.9); consumes the submission plane through a **normative durable `AckExplicit`\n consumer** and acks a submission ONLY after a durable decision fact exists, and, for a\n pool-admitted acceptance, ONLY after the §13.6 EPW enqueue create has additionally\n succeeded (or lost its CAS to an already-present entry): a crash anywhere between\n acceptance and enqueue therefore redelivers the submission, and the reconciliation\n predicate resolves the redelivered copy; recovery never has to DISCOVER orphaned\n acceptances, because an acceptance without its enqueue is by construction an unacked\n submission that comes back. A crash before\n the fact redelivers the submission; a crash after it observes the CAS winner on\n redelivery. It validates each submission (schema, body/subject agreement incl. the target\n block, authorization per §13.6, and (for work-pool commands) pool admission/capacity\n BEFORE acceptance) and then decides each request exactly once by publishing a\n **decision fact** to the caller-scoped subject\n `epf.<endpoint>.dec.<cOwner>.<cActor>.<cUid>.<id>` with create-only CAS (expected last\n sequence on the subject = 0), so distinct callers can never squat each other's ids. **For\n an action command the canonicalizer additionally binds the goal before accepting**: it\n create-only-CASes a **goal-bind fact** `epf.<endpoint>.goal.<cOwner>.<cActor>.<cUid>.<goalId>.bind`\n carrying the accepted fingerprint, and rejects (`conflict`) any later submission whose\n `goalId` matches but whose fingerprint differs, so two distinct `id`s naming one `goalId`\n cannot both be accepted-and-effected (the decision CAS keys on `id`, which alone would let\n both through; the goal-bind CAS keys on `goalId`, which stops the second BEFORE acceptance\n and effect, not at the terminal-result stage where the effect has already happened).\n The decision is `accepted` or `rejected` (with the catalog error); **rejection is as\n durable, caller-readable, and idempotent as acceptance**, so a permanently invalid\n submission is distinguishable from a lost one. First decision wins atomically; a later\n attempt fails its CAS and reads the existing fact. There is no append-then-memo pair to\n crash between. The canonicalizer is a **singleton per endpoint** (one active principal,\n epoch-fenced like any serve identity, recovered through the §13.1 takeover barrier):\n admission checks (pool capacity for work-pool commands) are thereby serialized with the\n decisions they gate, so two canonicalizers cannot both admit the last slot; capacity is\n consumed by the acceptance itself, never checked apart from it. A submission that cannot\n yield a decision key; bytes that are not canonicalizable I-JSON (unparseable, duplicate\n object names, lone surrogate, out-of-range number), or no `id` within the token\n grammar; **or bytes that breach the command's declared `admissionCeiling`** (§13.7): raw\n size over `maxBytes`, nesting over `maxDepth`, or member count over `maxItems`; is\n **quarantined, never redelivered forever**: the canonicalizer publishes a\n **`QuarantineFact`** to the disjoint quarantine family\n `epf.<endpoint>.quar.<sourceSeq>` (§13.2); keyed by the source sequence, which exists\n for every stored copy by construction, in a family that shares no namespace with\n caller-chosen `dec` ids, so no legal request id can collide with a quarantine key, with\n create-only CAS, and terminally acks\n (`AckTerm`) the submission ONLY after that fact durably exists (or its CAS loss shows it\n already does), so a poison message cannot pin `MaxAckPending` and the\n fact-before-terminal-ack rule holds on the poison path exactly as on the decision path.\n `QuarantineFact` = `{ v: 1, decision: \"quarantined\", sourceSeq, submissionDigest (the\n `sha256:<hex>` digest of the raw stored bytes, §13.7), error: { code (catalog token),\n detail? (≤ 256 bytes) }, caller?: { id, lifecycleUid } (from the broker-authenticated\n submission subject, when it parses), ts }`, every field bounded or fixed-size, so the\n fact fits by construction; it never carries the poison bytes themselves.\n4. Journal submissions set `replyExpected: false`; the caller **observes its decision** by\n watching/reading its own decision subtree (`epf.<endpoint>.dec.<its triple>.>`, a\n caller-scoped read grant minted with every journal capability). An action command's\n accept/reject is exactly its decision fact, expected within the submission deadline.\n5. The **acceptance fact is self-sufficient for effect and replay** (`AcceptanceFact`, the\n `accepted` decision): `{ v: 1, id, decision: \"accepted\", fingerprint, request: <the\n canonical EndpointRequest, args INLINE, bounded by the broker's max_payload; a submission\n too large is refused loudly with resource-exhausted, never spilled into storage>, caller:\n {id, lifecycleUid}, target?: {owner, actor, lifecycleUid, mappingRevision},\n contractDigests: {input, output}, authzDecision: {revision, epoch},\n route: \"effects\" | `pool.<pool>` (the acceptance's SINGLE execution route, decided by\n the canonicalizer at admission: a pool-routed acceptance is executed by the pool's\n worker path (§13.5) and the effects consumers MUST ack it without effect; an\n effects-routed acceptance is executed by exactly one instance off the shared effects\n durable (§13.9). No acceptance is ever executed twice, because the fact names its route),\n readinessDeadlineMs?: <the acceptance-relative readiness bound, present iff the command\n declares bounded readiness, §13.6; persisted HERE because it is goal state, not the\n request's decision deadline>,\n workExpiry?: <absolute expiry of a pool-routed item, present iff `route` is a pool, §13.8;\n survives reconciliation re-enqueue unchanged>, sourceSeq, ts }`. A `target`-bearing\n acceptance (work bound to a lifecycle) publishes ONLY after its target-indexed\n obligation row exists AND only under an unexpired admission proof the mediator issued\n for that row (§13.8: proof issuance is the post-create currency recheck, so a row whose\n target or policy moved between create and recheck never admits; the fact's durable\n address is caller-scoped, so the obligation row, keyed target-first, is the ONLY\n target-enumerable record a retirement barrier can drain;\n `target.mappingRevision` is provenance, never a fence). The\n canonicalizer preflights the **serialized decision fact**, not merely the inline args,\n against `max_payload`: a submission whose acceptance fact would not fit is rejected\n `resource-exhausted`, and the rejection fact always fits by construction: every field\n is bounded or fixed-size (the operator floor assertion covers the maximum serialized\n rejection/quarantine fact, §13.12):\n `RejectionFact` = `{ v: 1, id, decision: \"rejected\", fingerprint, error: { code (catalog\n token), detail? (≤ 256 bytes) }, caller: {id, lifecycleUid}, authzDecision?: {revision,\n epoch}, sourceSeq,\n ts }`; the fingerprint and the catalog error, never the args (a parseable submission\n always yields the fingerprint; the unparseable/no-id case is the QuarantineFact above,\n which requires neither `id` nor `fingerprint`). Digest-pinned\n references inside a fact may name **only already-published public contract artifacts**,\n never per-request payloads: the contract store is public, immutable, and permanent,\n the opposite lifecycle of private, horizon-bounded request content (a large-payload\n facility, if ever needed, is its own future primitive with its own store, retention, and\n §13.9 rows). Effects and replay read the fact, never the raw submission (a TOCTOU re-read\n of the untrusted log is non-conformant).\n6. Decision facts/tombstones are retained at least the declared **idempotency horizon**\n (default 24h, space-configurable) AND longer than the maximum submission-log retention\n plus recovery/redelivery lag; otherwise a rebuilt canonicalizer could re-accept an old\n submission still sitting in the log as new work. The horizon is **realized by decision\n retention, not by a clock**: the create-only CAS returns the recorded decision for exactly\n as long as the fact exists, and a reused id becomes new work only once retention has\n evicted the old fact and freed its subject; there is no separate time rule for the CAS\n to disagree with. The §13.12 retention floor states the horizon by OUTCOME: no removal\n cause may drop a decision fact or tombstone before it. The canonical subjects are the authority (D12) for anything\n auditable, metered, compensated, effected, or replayed. Ordering is per-subject;\n consumers never assume cross-subject order.\n\n**Events are not facts.** Cluster events and per-goal progress (`epe`) are direct,\nepoch-fenced, instance-published notifications on a durable, ordered, replayable stream;\nthat is the sense in which they ride the journal contract. They do NOT pass through the\ncanonicalizer, carry no acceptance semantics, and MUST NOT drive effects that require\ncanonical acceptance; anything auditable/metered/compensated goes through submissions and\nfacts.\n\n### 13.5 Verbs\n\n- **call**, bounded request/reply (`replyExpected: true`, `deadlineMs` mandatory). On the\n `one` rail it is queue-group anycast; on `inst` it addresses one stable instance. No\n responder → `unavailable`.\n- **cast**, the same subjects and grants (`replyExpected: false`): fire-and-forget,\n at-most-once, the responder MUST NOT reply and the caller never reads the rail (the nonce\n is present but unused). A cast to a journaled command is `class-mismatch`; journaled work\n goes through submissions. In the NATS binding a publish violation is asynchronous — the\n publish call returns normally while the broker refuses — so a caller-side cast\n implementation MUST watch the connection status for a violation on the cast's own subject\n and raise `permission-denied` naming that subject, exactly as a call does; a cast\n implementation MUST NOT resolve as though a refused publish had been cast.\n- **watch**; observe a record (KV watch; fell-behind ⇒ re-read, §13.4) or an event topic\n (live subscription within the read grant plus filtered replay from the event stream).\n Per-key and per-goal subjects carry read containment; a watch grant names the exact subtree.\n- **claim**, competitive at-most-one-winner acquisition from a durable work pool (`epw`),\n **owner-mediated**: the pool's owning endpoint holds the pool's single `AckExplicit` pull\n consumer (§13.12); workers hold **no** JetStream grant on the pool and acquire, renew, and\n settle work exclusively through the owning endpoint's reserved **`lease`** and **`commit`**\n commands on the ordinary `ep` rails. This is the only shape that satisfies both claim\n invariants at once: the delivery's ack token never leaves the party allowed to use it, and\n the attempt binding is **owner-recorded at assignment** rather than asserted by the worker\n (a worker-carried \"sequence + attempt\" proves nothing about delivery; an owner assignment\n does). The stored pool message is **work identity and input only, never the authoritative\n lease**: broker redelivery re-delivers the same stored bytes, so a token in the payload\n cannot fence, and the consumer's `ack_wait` is the broker's redelivery-to-owner timer only,\n never the lease. `lease` (call): the owner fetches the next stored item and records the\n lease `{item, sourceSeq, attempt: the delivery count, worker: the broker-authenticated\n caller (principal + lifecycle UID, plus epoch for endpoint workers), fencingToken,\n leaseDeadline}` in its `lease` record (key grammar §13.7, writer table §13.9) by\n **first-wins idempotent CAS per (item, attempt)**, a duplicate or\n delayed `lease` call for a still-current attempt returns the SAME lease; an attempt is\n superseded once redelivery advances the delivery count; `fencingToken` is CAS-incremented\n per attempt and `leaseDeadline` comes from the owner's own clock. Expiry revokes the claim\n at that deadline even before reassignment. Every Cotal-owned commit from claimed work is\n submitted through the reserved **`commit` command** carrying the exact lease tuple; the\n handler validates token currency AND unexpired lease against its own clock AND that the\n caller is the lease's bound worker, then performs an **atomic, idempotent per-item CAS to\n a cached terminal result**, the per-item terminal fact\n `epf.<endpoint>.wrk.<pool>.<acceptance identity>` (§13.2), create-only CAS per item,\n under its mediated writer credential (§13.9): a committed item\n can never be leased again, a duplicate commit returns the cached terminal outcome, and a\n raced commit loses loudly. Only after observing the committed terminal state does the\n owner ack the WorkQueue message; it holds the delivery natively, so the deletion\n capability is never transferred, and no worker-side ack can destroy an item whose commit\n was rejected. A lost owner ack merely redelivers the item to the owner, which observes the\n committed terminal state and acks again: **settled work is never re-enqueued as new** (the\n durable bridge is the acceptance fact plus the per-item terminal CAS; an accepted item\n with no terminal result and no live pool entry is the only re-enqueueable state, §13.6). A\n stale token, expired lease, or superseded worker is `expired`/`conflict`; workers hold no\n bypass write.\n- **scatter**, a request on the `all` rail. The caller freezes a **request-scoped expected\n set**, the live instances of the class from the service registry, each as\n `(instanceId, registrationRevision, epoch)`, where `registrationRevision` is the store\n revision of the instance's `svc….spec` record key (§13.7: it advances only on mediated\n registration writes, and the record read/watch grant that freezes it is a §13.9 matrix\n row), at send time. Gather accepts at most one\n terminal reply per expected `instanceId`, attributed from the reply subject **including its\n epoch** (§13.2): a second reply from the same `(instanceId, epoch)` is classified\n `duplicate` and **reported, never silently dropped** (first reply wins); a reply from a\n frozen `instanceId` at a different epoch, or an observed registration-revision advance;\n is classified `churn` (the instance restarted mid-scatter and may never have seen the\n request) and does not count toward completion; replies from outside the frozen set are\n classified `unexpected` and never count toward completion. Completion is\n all-expected-replied or deadline, in which case the result is explicitly partial with\n `missing` / `churn` / `unexpected` / `duplicate` / `late` classifications (a churned slot\n reports as `churn`, not `missing`). An empty or unreadable registry is\n `failed-precondition`, not an empty success. Deadline mandatory. A per-instance liveness\n probe that asks the broker about an instance's own rail is such a cast, and a refused\n probe publish MUST surface as that same `permission-denied` refusal naming the refused\n subject, never as a liveness verdict: only the broker's no-responders answer is a\n liveness fact, and a refusal licenses nothing (a caller that swallowed it into `unknown`\n would read a permission problem as \"no verdict\" and pay the full budget for it).\n\n### 13.6 Composites\n\nPatterns over the verbs and contracts; zero new transport.\n\n**Action**, a long-running command. `action` is a command **marker**, never a class: an\naction command's submissions are `class: journal` (§13.3).\n\n1. The caller submits with a client-generated `goalId` and the request fingerprint (§13.4).\n Accept/reject is the durable decision fact (§13.4), expected within the submission's\n decision deadline; there is no reply-rail answer to recover.\n **Authorization linearizes at acceptance**: the acceptance fact persists the caller and\n target lifecycle tuples, command + contract digests, and the authorization decision\n revision/epoch it was made under. A scope narrowing before acceptance rejects the goal;\n after acceptance it blocks *new* goals but an accepted goal continues, unless the\n command's contract declares **continuous reauthorization**, in which case each declared\n checkpoint re-validates and deterministically transitions to `cancelling`/`failed`\n (`permission-denied`) on narrowing. Handle expiry/revocation mid-goal follows the same\n declared policy.\n2. States: `accepted → running ⇄ waiting → succeeded | failed | cancelled | expired |\n uncertain`, with\n `cancelling` between a cancel and its terminal state. This is the **single status\n vocabulary** for every long-running surface. All five of `succeeded`, `failed`,\n `cancelled`, `expired`, and `uncertain` (item 6) are **terminal**, and first-terminal-fact-wins\n applies uniformly: `uncertain` is not an absence of an outcome, it is the outcome\n \"this action's success signal did not arrive within its readiness deadline\".\n3. Progress rides per-goal events (`epe…goal.<caller triple>.<goalId>.progress`), read-scoped\n to the caller at mint time. The goal's current state is a status-only record projection;\n the journal owns the facts.\n4. Cancel is the reserved `cancel` command: `graceful` (compensations, default) or\n `terminate`. Cancel of an unknown/terminal goal is `failed-precondition` with the cached\n outcome attached. Cancel races completion at the mediated commit point: first terminal\n fact wins; the loser observes it.\n5. The terminal result is a journal fact and is cached. The full payload is retained at least\n the declared result retention (default 24h); a **terminal tombstone**\n `{goalId, fingerprint, state, outcomeDigest}` at least the idempotency horizon (≥ result\n retention; outcome-stated by the §13.12 retention floor). Same goalId + fingerprint returns the cached outcome (after payload eviction:\n the tombstone summary, `data.evicted: true`); same goalId + different fingerprint is\n `conflict`; beyond the horizon a reused goalId is explicitly new work.\n6. **Bounded readiness (`uncertain`).** An action whose success signal may lawfully not\n arrive within its readiness bound declares a **readiness deadline**, a distinct,\n acceptance-relative bound persisted in the acceptance fact/goal state, NOT the\n submission's `deadlineMs` (which bounds only the decision, §13.3). Spawn readiness is\n the reference case: its readiness deadline is **30 s**, the migrated presence-or-exit\n backstop, D29; every legacy spawn-timeout consumer converges on this single bound. A\n spawn whose agent application waits for the operator before its session joins, as its\n connector declares for the launch's options (a session picker, for one), has its running\n process as the success signal: the owner records `succeeded` once that process has run\n briefly without exiting, and the result's `waitingFor` names the screen. When\n the deadline passes without the signal, the owner records the goal's terminal **result\n fact** (`goal….result`, §13.2) with the outcome\n `uncertain`, and the goal IS terminal: `uncertain` is a terminal outcome like\n `succeeded`/`failed`, immutable, first-terminal-fact-wins as for any goal (there is no\n call and no reply rail here: an action is a journal submission, and the result fact IS\n the caller-visible outcome, item 5). The underlying ENTITY's later convergence\n (ready/exited) is observable on that entity's own status record (`svc….status`, the\n lifecycle mapping); a caller that needs the eventual answer watches the entity, never\n the goal; the goal is not rewritten and its status does not linger non-terminal. An owner\n that observed the entity still running when the deadline passed MAY add a detail of kind\n `ai.cotal.goal.entity-running` to the `uncertain` result's `details`, and a caller then\n reports the action as still starting.\n7. Goals bind the target's `(principal, lifecycleUid)` (§13.1): a goal accepted against a\n lifecycle is not redeemable, cancellable, or effectful against a same-name successor. A\n restarted instance (same `instanceId`/UID, advanced epoch) recovers its goals from journal\n + records; a superseded epoch cannot commit transitions.\n\n**Awaitable checkpoint**; one durable pause primitive (approvals, guard holds, payment\nauthorization). A waiting action mints a checkpoint: a durable token persisted with the goal,\na `waiting` status carrying the checkpoint id and its **deadline generation**, and a durable\ntimer (§13.12). Deadlines are mandatory. Heartbeat/extension CAS-advances the generation in\nstatus, then replaces the timer (a new `.schedule` request; the mediated timer writer's\nsame-subject `.armed` publish is the server rollup, §13.2/§13.12, the 2.14 atomic\nstop-plus-publish is NOT assumed at the 2.12 floor). A firing timer carries\n`(timerId, generation)`; the endpoint validates the generation against current status before\nacting, stale fires **no-op**. Because status and timer are two resources with no atomic\nbridge, a **durable reconciler** on the owning endpoint repairs the pair after crash or\nleadership change WITHOUT any status↔schedule read the no-read timer plane cannot serve: the\nreconciler **re-emits a `.schedule` request at the current generation for every `waiting`\nstatus it owns**, and a same-`(timerId, generation)` arm is **idempotent at the timer writer**\n(it re-derives the same `.armed` message; a duplicate is a no-op replacement), so\nover-emission is harmless and a missing schedule is repaired without the reconciler ever\nhaving to observe whether one exists. Stale-generation fires still no-op at the handler. Cancellation of a timer is cleanup, never the correctness boundary.\nTimer retention MUST exceed the maximum deadline plus a recovery margin. Resume: a `resume`\ncommand presenting the checkpoint token; resume authorization is **one-use** (journaled by\ncreate-only CAS on the checkpoint token; duplicate resume is `conflict`) and holder-bound\n(§13.10). Expiry fails the checkpoint closed.\n\nA settlement MAY name the answer it accepted. The one-use settle fact carries an OPTIONAL\n`answerId`, and the status carries the matching OPTIONAL `settledAnswerId`; both are id tokens,\nboth are permitted ONLY on a `resumed` settlement, and an implementation MUST reject either on an\nexpiry. Their key sets are closed: an endpoint that does not know these keys MUST hard-error on a\nfact that carries one. The answer's payload MUST NOT ride either field.\n\n**Guard checkpoint**, the pre-effect authorization hook. A command carrying the governed\n`ai.cotal.guarded` trait MUST NOT effect until the guard endpoint named by the trait value\nanswered **allow** (class call). Answers: `allow | deny | hold` plus optional signed\nobligations (attenuations the endpoint MUST apply; monotonic). `hold` converts the action to\n`waiting` on a checkpoint owned by the guard decision. Timeout or unreachable guard is\n**deny** (fail closed). Ordering is guard-then-effect. Side-effecting guards own their own\nreconciliation.\n\n**Capability handle**, the one passable reference type: a signed JSON grant, RFC 8785\ncanonical, Ed25519-signed by a key in the trust-anchor registry (§13.10):\n\n`{ v: 1, id, space, issuer: { keyId }, holder: { id, lifecycleUid }, grants: [{ endpoint,\ninstanceId?, commands: [{ name, authz?, targetOwner?, targetActor?, targetLifecycleUid? }],\nreads?: [<record-key or event-topic subtree>] }], iat, nbf?, exp, parentDigest?, sturdy,\nepoch?, sig }`\n\nA grant entry carries **every subject-level dimension** a capability has (§13.9): a targeted\ncommand names its authorization mode and target components; read scopes name exact\nrecord-key / event-topic subtrees. The per-command target tuple is a **closed set of three\nlegal shapes**, no target components; `targetOwner` alone; or the full triple\n`{targetOwner, targetActor, targetLifecycleUid}`, and **every other combination is\nschema-invalid** (`contract-invalid`): in particular `targetActor` without\n`targetLifecycleUid` (a handle that pins a recyclable alias component MUST pin the lifecycle\nit means) and `targetLifecycleUid` without `targetActor` (a lifecycle restriction with no\ncompile target would otherwise be silently DROPPED into an owner-wide grant, a partial\ntuple never weakens into a broader one). The normative compiler maps a grant entry to\nexactly the subjects the equivalent minted capability would receive (never wider) it MUST\nconsume every present signed component (a component the compile target cannot express is\nschema-invalid, never ignored), and every legal entry HAS a compile target:\n\n- a **no-target** entry compiles to the untargeted or `self` form per the command's\n contract; an `authz` field on it is schema-invalid.\n- an **owner-domain** entry (`targetOwner` alone) compiles to the mode its `authz` field\n names, `owner` (the default), `child`, or `ledger`, and NOTHING else: each pins the\n signed `targetOwner` in that mode's own subject form (§13.2), **never collapsing `child`\n or `ledger` to `owner`** (the modes are distinct validator-primary rails and rewriting\n one into another widens authority), and **`authz: \"any\"` is schema-invalid in a handle\n grant entry** (`contract-invalid`): the `any` rail is operator-ceiling authority, minted\n only as a standing capability under an operator-scoped anchor (§13.10), never conferred\n or attenuated through a handle; a compiler therefore has no `any` case, and no\n implementation choice exists between rejecting, literalizing, or widening it.\n- an **actor-pinned** entry (the full triple) compiles to the `handle`-mode form pinning the\n full signed triple `<targetOwner>.<targetActor>.<targetLifecycleUid>` (§13.2); an `authz`\n field on it is schema-invalid (the triple IS the mode).\n- an **instance** entry compiles to\n the exact `ep.inst` rails; complete, because `(endpoint, instanceId)` is the whole instance\n address and instance ids are never reused (§13.1).\n\nA capability that cannot be represented in this shape MUST\nNOT be carried by a handle.\n\n- **Two uses, both fail-closed.** *Attenuation:* presented in the `auth` slot, a handle only\n narrows; the handler enforces `effective = presenter-cred ∩ handle.grants ∩\n issuer-authority`, and additionally requires any signed target triple to match the\n request's target and the current mapping (`expired` on mismatch); it never confers broker\n reach. *Conferral:* a handle grants reach only by **redemption through the trusted auth\n path** (the exchange/callout of §9/§10), which verifies the signed target triple against\n the current mapping **at redemption time** (`expired` on mismatch) and mints a short-lived\n credential whose grants are the intersection of issuer authority, handle grants, and the\n redeeming holder's current lifecycle + credential; actor-pinned grants compile to\n `handle`-mode subjects carrying the verified triple (§13.2), so a target lifecycle that\n rotates after mint is caught by the endpoint's currency check; no handler-side widening\n exists. The minted credential is **ledgered before release** in the credential ledger\n (§13.1), keyed under the redeeming holder's lifecycle with the FULL presented handle\n chain as its `sourceChain` (plus the per-ancestor `bysrc.` index keys), so\n takeover/retirement barriers revoke it with the family and revoking ANY handle in its\n lineage (parent or leaf) cascades to it. Chain verification itself checks the\n revocation status of EVERY sturdy link in the chain, not only the presented leaf,\n failing closed on any revoked ancestor.\n- **Holder-bound:** `holder` names the one `(principal, lifecycleUid)` that may present or\n redeem it; bearer transfer exists only as an explicit issuer-signed re-issue. `space` binds\n it to one space. A recycled alias cannot present its predecessor's handles (UID mismatch).\n- **Attenuation chain:** `parentDigest` references the parent handle; a child MUST be ⊆ its\n parent under the **normative containment order**, per grant entry: endpoint within the\n parent's endpoint/domain pattern; `instanceId` equal or newly pinned (never widened to\n absent); commands a name-subset with per-command mode never higher in `self < owner < any`\n (`child`/`ledger`/`handle` are grantable only where the parent names the same mode); target\n components equal or newly pinned; read subtrees subject-prefix-contained, and per\n envelope: same `space`, validity window within the parent's, `sturdy` only if the parent is\n sturdy. The issuer of a child is the parent's holder, anchor-registered with a `handles`\n role whose scope covers the child (§13.10); the same containment order defines issuer-scope\n coverage. Presentation carries the full chain inline (`parentDigest`-linked artifacts\n presented together, no ambient fetch); verification walks every link to a registered\n anchor, failing closed on widening, unknown/revoked keys, or expiry.\n- **Sturdy vs live:** live handles (`sturdy: false`) bind the current process `epoch`, are\n never persisted, `exp ≤ 24h`, and die on restart. Sturdy handles bind the lifecycle UID\n (surviving supervised restart), persist as issuer-namespaced `handle.<issuerKeyId>.<id>`\n records (spec create-only; status = revocation state, monotonic; §13.9 writer table), and\n verifiers MUST check revocation (fail closed if unreadable). Max sturdy TTL is\n space-configured (default 30d).\n- Handles are reusable within TTL unless a composite declares one-use (checkpoint resume);\n the replay matrix of §13.10 governs every signed artifact.\n\n**Session (bidirectional stream)**, the generic composite for interactive byte/frame\nstreams (terminal attach is its first consumer; nothing terminal-specific is normative). It\nis exactly D26's cast-ingress + watch-egress composed over dedicated per-session subjects,\nno new verb and no new transport: the `in` subject is a cast-only rail (caller publishes,\nendpoint subscribes) and the `out` subject is a watch rail (endpoint publishes, caller\nsubscribes). A session is established by an ordinary command whose answer is a **session\ngrant**: a one-use,\nholder-bound handle (live: bound to the caller's lifecycle AND current process epoch,\nlive authority dies on restart, §13.1, so redemption fresh-checks the holder epoch and an\nunredeemed grant does not survive the caller's restart, plus the serving instance epoch) naming a fresh\nunguessable `sessionId` and the epoch-pinned session subjects\n`eps.<endpoint>.<sessionId>.<epoch>.in` (caller → endpoint) and `….out` (endpoint → caller).\nSession subjects are **core-only**, never stream-captured; the bounded flow window lives in\nmemory and a dropped frame is the composite's problem, not retention's. Redemption mints\nexact asymmetric per-session credentials: the caller publishes `in` and subscribes `out`;\nthe serving instance the reverse; no third party holds either, and no standing wildcard EPS\ngrant exists. Frames are opaque; flow control is bounded (window declared in the grant;\noverflow is `resource-exhausted`, never unbounded buffering). Close is explicit, and\nrevocation has a **durable** named authority that survives the\nserving endpoint: the trusted auth path (the exchange/callout of §9/§10) persists a **session\nledger row** at redemption, key `session.<sessionId>` in the auth store (§13.12), value\n`{sessionId, endpoint, serving instance + epoch, holder (principal + lifecycleUid), both\nminted credential ids, per-credential revocation marks, state, exp}` (the endpoint is in the\nrow because an `instanceId` is unique only within its endpoint, so every serving-party\noperation authenticates against the full serving identity the row pins), create-only CAS per\n`sessionId` (this CAS IS the one-use\nredemption), state monotonic\n(`active → closed | expired | superseded | retired`, all terminal), and each per-session\ncredential is simultaneously a credential-ledger row under its holder's lifecycle (§13.1),\nwhich is the index the §13.1 barriers enumerate, and a barrier that revokes a\nsession-sourced credential MUST resolve its `session.<sessionId>` row, transition it\nterminal, and revoke BOTH per-session credentials, so either side's takeover or retirement\ntears down the whole pair, not its own half. Redemption's writes are ordered by a **finalize CAS**, so no half-issued session is ever\nusable: the create-CAS writes the session row in state `issuing` (this create IS the\none-use), then both per-session credential rows are written gate-checked (§13.1), then the\nredemption **CAS-finalizes the session row `issuing → active`**, fresh-checking BOTH the\nholder and serving process epochs and both lifecycle gates at that CAS, and releases the two\ncredentials only on finalize success. A credential is authority ONLY once its session row is\n`active`; an `issuing` row confers nothing. Close/expiry/either barrier CAS the row to a\nterminal state (`closed`/`expired`/`superseded`/`retired`) and revoke both credential ids by\nname (the ids are known from the row, whether or not both credentials were released) so a\ncrash mid-issue leaves an `issuing` row that the expiry sweep collects (revoking both ids and\ntombstoning), never a live half-pair, and a redemption racing a close loses its finalize CAS\nand releases nothing. A revocation mark is set only by a revoke that SUCCEEDED; a terminal\nrow with an unmarked credential is retried by every later sweep pass, exactly the unconfirmed\nids, until both marks confirm, so a transient revocation failure can never quietly leave half\na pair alive. The auth path revokes BOTH per-session\ncredentials with eviction (bounded\npropagation) on any of: an **authenticated close input** on the trusted auth path itself,\na defined operation of the SAME exchange/callout surface that redemption already uses\n(§9/§10, off-broker, so no broker grant row applies): the caller authenticates as one of\nthe session's two parties (its lifecycle or per-session credential) or as the operator and\nnames the `sessionId`; the auth path verifies party membership against the ledger row\nbefore transitioning it. The in-band close frame\nis an advisory peer signal, never the revocation authority, because EPS subjects are\ncore-only and captured by nothing; expiry per the handle rules (`exp` is enforced by the\nauth path's own timer, not by the endpoint), or the serving\nepoch's supersession / lifecycle retirement via the §13.1 barriers (either side's lifecycle:\nholder and serving rows both index the family). Neither side can keep a\nhalf-closed session alive, and a crashed serving endpoint cannot orphan one, the ledger, not\nthe endpoint, remembers what to revoke. Ledger rows are retained at least the maximum\nsession `exp` plus a recovery margin. The session dies with the serving instance's epoch\n(the epoch is in the subject, so a restarted instance cannot resume it; a durable session is\na new establishment). Routing is authenticated broker routing end to end; there is no loopback URL\nor out-of-band transport in the contract, and cross-machine reachability is exactly broker\nreachability.\n\n**Remote manager service registration.** A remote registered user becomes a manager only through\none host-operated, typed `prepare → activate → renew` exchange. It is not a generic credential\nmint surface and is available only on the loopback/operator face to a signed-in human holding the\nclosed `manager-service` view (§13.1); the public exchange and managed-agent secret exchange\nrefuse every stage. All inputs and stored stage records are closed schemas. An operation is keyed\nby `{ owner, managerActor, lifecycleUid, instanceId, operationId }`, where `managerActor` and the\nlifecycle UID come from the server-authorized view, `instanceId` is opaque and collision-resistant,\nand `operationId` is caller-generated for replay convergence. A repeated operation with the same\nfingerprint returns its recorded result; a different fingerprint at the same coordinate is\n`conflict`; a retired lifecycle or instance is never revived.\n\n`prepare` fresh-checks the ledger scope and lifecycle, freezes only\n`epgate.manager.<instanceId>`, and durably stages the exact service registration, contract closure,\nstatus coordinate, requested public nkey, and credential lifetime. It releases no usable material.\n`activate` re-checks that same live ledger row and gate, creates the exact `svc.manager.<instanceId>`\nregistration, publishes only the staged immutable contract artifacts, and asks the host to sign\nNATS JWT material for that public nkey. The host writes the matching\n`epcred.manager.<instanceId>.<credentialId>` row before the gate-finalize CAS and returns the JWT\nonly after that CAS; it never returns a signing seed. `renew` is the only way to obtain successor\npublic-nkey JWT material. It re-checks the live `supervise` grant, owner, actor, lifecycle,\ninstance, current gate, and bounded renewal window, then records and releases a replacement under\nthe same family. It cannot create another instance or broaden a staged contract, record, endpoint,\nor credential grant. A crashed operation resumes only from its durable stage and operation id.\n\nRenewal is bounded and denial is fail-closed. When a manager cannot renew because its login,\nledger scope, or host service is unavailable, it reports degraded state, retains already-live\nagents only while their independently valid authority remains usable, and refuses new starts,\nrestarts, replacement credentials, and unsafe recovery. It MUST NOT turn a transient failure into\nstatic authority or kill a live agent merely to make the state look healthy. When the current\nfamily expires or is revoked, the host's verified revocation path closes it; a later restart still\nrequires a new successful prepare/activate operation. Same-owner descendant provisioning is\nhost-validated at every request, and loss of that validation also refuses a new start or restart.\n\n**Platform control registration.** A platform-run control manager registers, activates, renews,\nand retires through the same typed `prepare → activate → renew` protocol and operations as the\nremote manager service above: `session`, `retire`, `transferReader`, `renewStandingBundle`, `renewRunDriver`, the\nhost-owned maintenance operations, retained-agent validation, the goal-index scan, admin\nauthorization, and run admission and attempt. Each request rides inside one closed\n`platform-control-authority` envelope that adds only the space, the assigned account, and the\nassignment revision. The envelope and every inner request are closed schemas. The envelope carries\nno profile name, permission set, subject, lifetime, claim, or identity assertion. An inner request\nkeeps its existing operation-specific coordinates, such as the `session` operation's requested\n`exp`, which the host caps at its own bound, and the run admission's served `run.subject`, which\nthe host re-parses and checks against the caller's issued ceiling. The host validates each one as it\ndoes under `manager-service`. No field of either selects a signing subject, permission set,\nprofile, claim, or a credential lifetime past the host's bound, and an unknown kind or field MUST\nbe refused as `bad-request` with no effect. The managed-agent enrollment, retirement-preparation, and\nruntime kinds are not carried; a host without its own storage for them MUST refuse them as\n`unimplemented`. The door is a typed in-process operation of the host's authority context. It\nexists only where the host supplies its assignment source, and no listener serves it. It needs no\nexchange capability: the host MUST NOT hand its loopback capability or account signer to a control\nmanager, and a host that runs the control manager in another process carries the closed envelope\nover its own caller-bound channel. A request carrying a human IdP token MUST be refused. It is not a\ngeneric credential-mint surface and adds no daemon, listener, or protocol.\n\nHost-owned maintenance is narrower under this view than under `manager-service`. Under\n`platform-control`, a maintenance request's `targetInstanceId` MUST equal the assigned instance id\nfor both `evict-family-principal` and `reconcile-registration`, and the host MUST observe that the\ntarget gate's principal is the platform owner plus that instance's fixed serve actor. Both checks\nrun after the assignment check and before any liveness probe, revocation, eviction, or reopen. A\nfailure is `permission-denied` with no effect. A foreign slot holder therefore blocks platform\nregistration with the existing registration refusal, and it is repaired only through its own\nowner's `manager-service` maintenance or the host operator's guarded gate repair, neither of which\nthis view reaches. `manager-service` maintenance, including its reconciliation of a foreign slot\nholder, is unchanged.\n\nRenewal and fencing are the remote manager service's, unchanged. `renewStandingBundle` returns the\nclosed five-credential family for the same caller-held nkeys and the assigned account only when the\ncurrent gate is open, its principal is the platform owner plus the fixed serve actor, its process\nepoch equals the request's, and the host-keyed current registration proof matches. A stale epoch\nis `conflict`. A revoked or advanced assignment refuses the next request, renewal included, so\nrevocation never waits on a person and renewal never authenticates one. The remote manager\nservice's degraded-state and fail-closed renewal rules apply with the assignment in place of the\nlogin and ledger scope. A start after revocation or expiry requires a fresh `prepare` and\n`activate` under a current assignment.\n\n**Environment manager bootstrap and registration.** A hosting authority MAY serve this\nfamily as an ordinary registered, instance-addressed endpoint. `bootstrap` declares the\nephemeral class only. Its responder realizes §13.4's at-most-once effect through the\nauthenticated reservation and canonical fingerprint; this adds no idempotency-basis field\nto §13.7's contract. It is not a journal action. Wrong-class invocation MUST refuse before\neffect. Its bootstrap principal has the fixed `environment-bootstrap` grant of §13.9,\nnot manager supervisor or executor authority. The host admits first, waits for observed\nprovider RUNNING, then mints and delivers the file through a native post-boot secret/file\nchannel. It caps lifetime at the lesser of five minutes and remaining admission lifetime;\nno channel or insufficient remaining lifetime refuses delivery rather than using an\nexpired create-time file. No provider create or guest boot acknowledgement is registration.\n\nThe bootstrap file carries version one, the environment record ID, preselected manager\ninstance and lifecycle, credential and private connection nkey, finite expiry, pinned WSS\nbroker hostname, authority endpoint and instance, and the two bootstrap commands' contract\ndigests. It carries no owner session, account signing seed, profile selector or grants.\nThe verified immutable image's system trust store anchors TLS; deployments using a private\nCA MUST separately supply explicit digest-bound mesh trust. Certificate and hostname\nverification MUST remain enabled. Bootstrap admits no trust-on-first-use path. The host\nMUST NOT retain the private bootstrap seed after writing the private file; its durable\nrecord holds only digest, recipient lifecycle, expiry and consumed state. The guest MUST\nrefuse any file version other than one before connecting.\n\nThe post-boot channel first delivers the private file, then starts or signals the stock\nentry point. An entry started without the file refuses and exits; it never polls for one\nor opens a plane without it. The manager takes and unlinks the manager-only file before\nordinary command handling or connecting a plane. It generates the five manager nkeys locally and atomically persists\nthem with the bootstrap recovery material in its private store before sending a request.\nA crash after taking the file but before that first persistence is terminal: the external\nhost closes the environment and retires its reserved UID. It MUST NOT mint another\nbootstrap for that admission.\n\n`bootstrap` takes only `{ environmentId, identities }`, where `identities` has the five\npublic-nkey coordinates of the existing registration request. It returns the existing\n`RemoteManagerAuthorityMaterial` for preparation. The broker-authenticated subject selects\nthe admitted bootstrap caller; payload fields cannot choose its owner, account, manager\ninstance, lifecycle, permission ceiling or private signing material. Before preparation,\na first-wins CAS MUST pin the canonical request fingerprint and the preselected manager\ncoordinates. A different fingerprint at that reservation refuses `conflict`. An unknown\nissuance outcome stays held and MUST NOT start another preparation.\n\n`bootstrap-status` takes only `{ environmentId }` and reads that caller's reservation.\nDuring the bootstrap lifetime it returns the same recorded, public-nkey-bound preparation\nresult, or an explicit pending state. It issues nothing and selects no new keys or\nlifecycle. Same-input lost-reply recovery uses this command, not a second prepare. A\ncompleted registration or terminal admission refuses both commands; expiry does not delete\nthe reservation or permit reuse. Stored preparation material may contain signed JWTs under\nthe host-private credential-custody contract, never a guest private seed.\n\nThe subsequent `authority` command takes one closed `{ v: 1,\nkind: \"environment-manager-authority\", environmentId, admissionRevision, request }`\nenvelope. `request` is one of the existing closed manager registration, standing renewal,\nmaintenance, managed-child enrollment, child retirement, retained-child validation,\ntransfer, goal-index read, serve-time admin-authorization decision, run-admission or\nrun-attempt requests, plus the closed `environment-manager-deregister` request below.\nPer-session attach and shared MCP sessions are unsupported in this first family: their\nentry points MUST refuse `unimplemented` before issuing, staging or redeeming any session\nmaterial. The authority MUST refuse `session` and `session-revoke` requests rather than\nminting a JWT whose guest-side stage would need the forbidden auth-store write. The stock\nmanager does not construct the session plane for this family. Its attach/shared-MCP entry\nrefuses before `mintSessionServing`; the host's session refusal is a second fence.\nThere is no generic signing, mint, profile, permission, administrative control or\ncross-environment operation. An unknown field or\nkind refuses `bad-request` before any effect. Missing host policy refuses `unimplemented`;\nan adapter MUST NOT substitute a human or platform holder.\n\nPreparation, activation and restart use the existing registration barrier, performed by\nthe trusted host through this closed authority command. The guest MUST NOT execute\n`registerRemoteManagerAuthority` over the shipped executor's direct store profile. This\nrequires an additive stock host-mediated registration path; a private adapter cannot replace\nit by widening guest grants. The authority binds the authenticated caller to the recorded\nmanager identity for that phase and checks\nthe current host-issued proof, admission revision and process epoch. Activation rechecks\nthe same preparation's frozen gate; later operations require the current open registration.\nThe host uses its embedded canonical manager contract closure for the admitted stock\nrelease, pinned by the immutable workload profile digest. A host with no closure for that\nrelease MUST refuse admission `unimplemented` before bootstrap issuance. A guest whose\nembedded closure differs from the returned serving snapshot MUST refuse to serve.\nThe guest cannot select another closure or submit an unbounded artifact set. The existing two-document activation envelope\nand 64-artifact cap are unchanged; the full schema closure is available to the host without\na guest contract-store grant.\n\nRegistration returns the host-authorized serving snapshot: epoch, registration and\nname-authority revisions, complete command surface, closure digest and descriptor. Before\nserving, the guest verifies that snapshot against its embedded manager closure and the\nhost-signed serve credential's account, owner, instance and epoch. An additive stock\nreconstitution seam explicitly validates this authenticated host-to-guest direction and\nproduces the process-local branded serve grant. A JSON copy, self-asserted snapshot or\ncalling the trusted-host-only reconstruction seam as a guest shortcut MUST refuse.\nAll issued material stays inside the admission's five-key family and expiry. The guest\natomically persists prepared and activated material in its manager-only store. A restart\nuses that identity and proof at a newly admitted process epoch, never bootstrap redemption.\nRenewal rides a still-valid executor credential and MUST be scheduled before its JWT\nexpiry. Per-operation reconnects and the existing all-duty preflight dials remain allowed\nunder the fixed profiles; they open no store and require no new authority. A manager stopped beyond executor validity cannot renew or redeem bootstrap again;\nthat admission becomes terminal and external cleanup must close it. There is no owner\nlogin, static credential or fresh-key fallback.\nMaintenance targets only the admitted instance; a foreign governance-slot holder blocks\nregistration and requires its own authorized repair path.\n\nGraceful stop uses `environment-manager-deregister`, a closed inner request carrying only\n`{ v: 1, kind: \"environment-manager-deregister\", registrationRevision,\nregistrationProof, processEpoch }` inside the admission-bound authority envelope. The host\nderives the instance, owner and expected proof/epoch from the bound executor and current\nadmission; it compares the supplied proof and epoch and checks the revision against the\nregistration receipt it committed. It performs native revision-pinned `deregisterServiceInstance` and its own gate\ngeneration read. Absent or already superseded registration is an idempotent observation;\nno caller-selected endpoint, key or foreign instance is accepted. The stock stop path uses\nthis mediated result instead of opening stores or printing a signer-only repair command.\nDeregistration alone issues no replacement lifecycle and does not retire the admission;\na still-current manager restart uses the existing fenced registration ceremony.\n\nChild enrollment preserves the existing host-selected UID and delegation checks. The\nhost commits its sole-child binding before releasing child material; changed input,\na second actor or a second lifecycle refuses before launch. Child retirement addresses\nonly that recorded UID and retains the existing terminal-operation and custody fences.\nRun admission and attempts preserve the starting caller's issued ceiling, owner and process\nfences. Provisioning adds no scheduler or Lang syntax. Delegated launch still refuses\nsupervise restart policy, caller cwd, resume, exact continuity and shared MCP servers.\nRepository/ref checkout is admitted workload configuration; Lang worktree identity is a\nlogical exclusion key rather than a workstation path.\n\nA bootstrap never presented before expiry, or a preparation not activated before expiry,\nbecomes terminal durably. Activation MUST revoke the bootstrap credential and evict\n`manager_bootstrap_<instanceId>` connections through the ordinary ledger eviction before\nreleasing activated material. `activate` is requested and answered on the executor\nconnection from prepare material, not the bootstrap connection, so eviction cannot cut\nthat reply. The external\nhost revokes prepared credentials and burns or retires the reserved UID; an unavailable\nrevocation service leaves a persisted cleanup obligation, never reusable admission.\nEnvironment expiry or forced close proceeds independently of the guest manager. Observed\nprovider termination, result retention and retirement of the bound manager/child UIDs are\nseparate facts; host-side retirement failure remains pending and does not erase termination.\n\n| Refused input or state | Required refusal and boundary |\n|---|---|\n| Unknown field, kind, profile or permission selector | `bad-request`, before policy or issuance (§13.6) |\n| Wrong authenticated bootstrap/manager caller or foreign environment, owner, account, instance or UID | `permission-denied`, no issuance or lifecycle effect (§13.1, §13.9) |\n| Changed request at an existing bootstrap reservation | `conflict`, original reservation retained (§13.1, §13.6) |\n| Expired bootstrap, ended admission or completed registration used as bootstrap | `permission-denied`, no new preparation (§13.1, §13.6) |\n| Bootstrap mint without an admission-pinned frozen registration gate and the same live operation intent | Refuse with no material (§13.1, §13.6) |\n| Human or platform operation naming an environment-family gate or stage | `permission-denied`, no takeover, repair, issuance or retirement (§13.1, §13.6) |\n| Guest direct gate/repair/credential write or auth-store read/scan | Broker-denied by every credential in this family; no field-parser substitute (§13.1, §13.9) |\n| Attach or shared MCP session, including session mint/stage/revoke | `unimplemented` before session material or ledger effects (§13.6) |\n| Deregistration revision not from the host's receipt or a foreign instance/key selector | `conflict` or `bad-request` before any delete; no stale delete of a successor (§13.6) |\n| Missing or unreadable current admission, ledger or gate | Refuse before effect; no cached authorization (§13.1) |\n| Stale admission revision, proof or process epoch | `conflict`, no replacement material (§13.1, §13.6) |\n| Missing child/run/retirement policy or unsupported UID/material delivery | `unimplemented`, admission or launch remains refused (§13.1, §14) |\n| Second child actor or lifecycle, including after terminal retirement | `permission-denied`, first binding retained (§13.1, §13.6) |\n| Child scope, channels or capabilities exceeding the admission ceiling | `permission-denied`, first binding retained (§13.1, §13.6) |\n| Run not admitted by the recorded owner, or placement naming another instance | `permission-denied`, no admission, attempt or launch (§13.6, §14) |\n| Foreign maintenance target or foreign slot-holder repair | `permission-denied`, no probe, eviction or repair (§13.1, §13.6) |\n| Ambiguous preparation, result retention or retirement | Preserve the held operation or cleanup obligation; never infer success (§13.1, §13.6) |\n\n**Virtual endpoints.** An endpoint MAY be virtual: registered (`spec.activation = on-demand`)\nwith no live instance. A virtual endpoint's commands MUST be journal-class: the buffered\ningress path is the ordinary submission plane (`epj` is durable and needs no live\nsubscriber), and the canonicalizer, which for a virtual endpoint runs wherever its\nactivator/owning authority runs, checks pool admission BEFORE deciding (an over-capacity\nsubmission is rejected `resource-exhausted` as its durable decision fact, never accepted and\nstranded), then accepts and enqueues the work into the endpoint's `epw` pool. Admission\noccupancy is the pool consumer's `num_pending + num_ack_pending`, read fresh from the exact\nper-pool consumer INFO after reconciling the canonicalizer's own outstanding acceptances\nagainst the predicate below (a repaired item is inside the count new work competes under);\nthe read fails closed (an unreadable consumer is `unavailable`, never an empty pool), and the\nsum is honest only while the pool consumer's delivery ceiling is unlimited\n(`max_deliver = -1`) AND its filter is exactly the pool's own subtree; BOTH are editable after\ncreation, so both are pinned at creation AND re-proved at every read (a message that exhausts\na finite ceiling stays stored but leaves both counters; a narrowed or foreign filter reads\nempty while stored work remains). The admission capacity comes from the endpoint's REGISTERED\nactivation policy (declared as the registration's `spec.activation` block, a closed schema\nwhose `capacity` is required; the registration path publishes each version as an immutable\n`policy` record, §13.7, and the govern head's selector below names the enforced one), READ\nleader-served at each decision (the read is FENCING by use, so a\nfollower Direct Get is never used; a scoped canonicalizer executes it only through the\nconfined policy reader of §13.8, whose request subject binds the authenticated endpoint)\nand its enforced revision RE-PROVEN after the decision's\nlater reads and carried into the acceptance commit, never a free-standing argument; the\ncarried revision is provenance, and the FENCE against the policy or lifecycle moving while\nthe acceptance is in flight is the §13.8 obligation row, not the carried value. The\n**endpoint-wide policy coordinate** is not a new head: it is the governance head\n`govern.<endpoint>` (§13.7, the endpoint's registration linearization point). To make the\nenforced policy MACHINE-SELECTABLE by any second implementer (not inferable from prose), the\ngovern head value carries a normative **policy selector**: `{ enforcedPolicyKey (the exact\nrecords key of the immutable `policy` record currently governing, §13.7), enforcedPolicyRevision\n(that record's STORE revision), pendingPolicyKey?, pendingPolicyRevision? }`. A canonicalizer reads\ngovern leader-served, follows `enforcedPolicyKey`, and re-proves it is still at\n`enforcedPolicyRevision`, with no per-instance guesswork; `policyRevision` throughout this\nsection IS `enforcedPolicyRevision`. **`enforcedPolicyKey` MUST name an IMMUTABLE,\nREVISION-ADDRESSED policy record, not a mutable per-instance slot** (a bare\n`svc.<endpoint>.<instanceId>.spec` overwritten on every re-registration is disqualified: the\nrecords bucket keeps history 1, so once a mutation overwrites it the OLD `enforcedPolicyRevision`\ncan no longer be read, and the drain window's claim that \"the old policy keeps governing\" would\nbe unbacked). The normative immutable form is the **`policy` record kind** (§13.7):\n`policy.<endpoint>.<digest-hex>`, one unsplit, create-only, NEVER-DELETED key per policy\nversion, where `<digest-hex>` is the SHA-256 hex of the record's canonical value bytes: the\nkey is self-certifying (a reader re-digests the value and refuses a mismatch), so a\ndifferent-byte overwrite is caught on read, and BOTH the enforced and the pending revisions\nstay readable throughout the drain. Immutability is upheld by the sole writer's create-only\nCAS plus that read-time self-certification, not a broker-level subtraction (§13.9). A\ndeployment that cannot provide an immutable policy key MUST pause admission during the\nmutation rather than claim the old value remains readable.\nA policy mutation is a re-registration under the frozen registration gate that lands in TWO\nfenced govern-head CAS steps (§13.9): (1) **stage** records the new registration as\n`pendingPolicy{Key,Revision}` (a NEW immutable policy key) while `enforcedPolicy...` still\npoints at the OLD immutable record, so\nthe old policy keeps governing and stays readable; (2) **promote**, only after the mutation has **drained the\nendpoint's unresolved obligations to quiescence** (§13.8: enumerate `oblig.*.<endpoint>.>`,\nsettle every unresolved row pinning an older `enforcedPolicyRevision` through its decision\ncoordinate, re-enumerate until none remain), moves `pendingPolicy...` into `enforcedPolicy...`\nand clears the pending slot. Admission always pins the CURRENT `enforcedPolicyRevision`,\nand **while a `pendingPolicy…` is staged, proof issuance for policy-admitted decisions\nREFUSES** (`failed-precondition`: the endpoint is inside its drain window; target-bound-only\nadmissions are unaffected). The pause is what makes the drain CONVERGE under load and makes\n§13.8's rule (a row created after the drain's final enumeration can never admit) hold for\npolicy movement exactly as it holds for retirement; rows admitted BEFORE the stage keep their\npinned old revision readable through the immutable key, so no admission is ever judged\nagainst a policy it did not pin. The stage/drain/promote order is a durable, resumable\ngovern-head sequence, never an implied transaction. The **restart-status commit is the same two-coordinate\nclass**: before its status CAS the supervisor obtains a `self`-class obligation (§13.8)\nthrough the same mediator, pinning the `enforcedPolicyRevision` its thresholds were read\nunder AND the complete commit intent `{ commitKey, commitBaseRevision, commitValue, commitDigest }`\nof the\nstatus record it will write; the status CAS is authorized only while that obligation is\n`accepted`, so a policy or lifecycle movement settles the obligation and the delayed commit\nloses a CAS, and a crash after `accepted` is finished deterministically from the pinned\nintent (§13.8 recovery), never a\ncarried-revision comparison. The\nrestart-intensity thresholds are read leader-served from the SAME registered policy, so neither\na caller nor a follower-stale read can loosen the window to suppress an escalation. A command\nname is declared ONCE across the whole closure; a cross-cluster duplicate is an ambiguous\nsurface and registration refuses it, and a command declared non-journal-class in ANY cluster is\nnon-journal for the on-demand registration check. The supervisor-owned status fields (the\nrestart history and the retirement mark) and the `escalated` state can be ORIGINATED only\nunder the supervisor's DISTINCT WRITE AUTHORITY (a package-private branded capability held by\nthe restart-note and the escalation reconciler, never an ambiently-mintable factory or the mere\npresence of a revision pin): an instance-side status write, whether it creates the first status\nor updates a later one, has them stripped and cannot originate `escalated`. The restart history\nand retirement mark are validated at every read boundary (a unique-epoch history, an integer\nmark present only on an escalated row), and a DEL/PURGE status marker fails closed on the\nretirement path (a deletion is never clean absence). Every status write operates on a validated DETACHED snapshot\ntaken before its first read, so a caller mutating a shared status object mid-write cannot split\nthe authenticated coordinate from the stored bytes. The activator's reply authority is its\nown CONNECTION-SCOPED inbox (`_INBOX_<connId>.>`), never the account-wide default, and its\noccupancy read re-proves the pool consumer's ack policy and pull mode alongside its editable\ndelivery ceiling and filter (a delete/recreate must not substitute a semantically different\nconsumer). A supervision clock behind the newest recorded restart is refused before the\nduplicate-note short-circuit, so a rolled-back clock never returns a stale count. The virtual endpoint's canonicalizer durable serializes admission\n(`max_ack_pending = 1`): one submission is in the count-decide-enqueue path at a time, so two\nsubmissions cannot both observe the same free slot; because MaxAckPending is also editable\nafter creation, every admission re-proves the live pin and refuses on drift rather than\ndeciding under a serialization it no longer has; pool-worker execution concurrency is an\nindependent knob, already inside the count via `num_ack_pending`. A virtual endpoint's\nregistration REFUSES if any declared command is not journal-class (an ephemeral surface\ncannot exist with no live instance). Acceptance and\nenqueue span two streams with no atomic bridge, so the enqueue is **idempotent, keyed by the\nacceptance identity, and reconciled against a decidable predicate**: the pool subject carries\nthe acceptance identity and the enqueue is a create (expected-last-sequence-for-subject 0),\nso a duplicate enqueue loses its CAS harmlessly; because the pool owner acks only after the\ncommitted terminal state (§13.5), an acceptance fact **with** a terminal result is settled\nand never re-enqueued, and an acceptance fact with **no** terminal result and **no** live\npool entry (a FENCING absence: the probe is the leader-served `STREAM.MSG.GET` last-by-subject\nread of the §13.9 work-pool reconciliation row, never a follower-servable Direct Get, because a stale\nfollower miss would re-arm settled work) is unambiguously never-enqueued-or-lost, the\nonly re-enqueueable state. A crash after the acceptance CAS but before the enqueue is\nrepaired by exactly that predicate; an enqueue without an acceptance fact cannot occur\nbecause only the canonicalizer holds the pool-write grant and it enqueues only from its own\naccepted decisions. The stored item bytes are the CANONICAL derivation of the acceptance —\nthe RFC-8785 canonical JSON of exactly `{ v: 1, id, fingerprint, sourceSeq, workExpiry,\ncaller, request }` (work identity + input only; never a lease, token, or decision metadata) —\nso any two conforming writers (a first enqueue and a crash repair) produce BYTE-IDENTICAL\nitems, and the create's same-subject-same-bytes idempotency holds across them; a differing\nbody under the same acceptance identity is a mixup and refuses loud. An ephemeral\ncall to a virtual endpoint with no live instance is an honest `unavailable`; nothing\nsilently buffers it. An **activator** (holder of its activation capability) watches the pool\nand starts an instance; single-writer per identity is fenced by instance-record CAS +\nepoch. The exact consumer INFO the activator watches is a request/reply snapshot with no\nbroker wakeup, so watching is bounded polling with backoff to a finite maximum interval, and\nan INFO failure is loud, never a silent skipped poll; the activator's broker authority is\nexactly that INFO read plus its mediated, target-bound start seam (no pool consume/ack, no\nstream read, no consumer create/update/delete). Passivation drains, updates status, exits;\ndurable reminders ride the timer plane.\nSupervision is restart-intensity escalation: more than `maxRestarts` (default 3) within\n`restartWindow` (default 60s) escalates; the instance stops restarting, status records\n`escalated`, the lifecycle retires terminally (§13.1), and the failure is loud. The restart\nhistory is DURABLE on the instance's own status record, SUPERVISOR-OWNED (the status writer\ncarries it forward through every ordinary instance-side write, so a successor's `ready`\nconvergence can neither reset nor forge it), and each note is a revision-pinned CAS: a\nsupervisor restart cannot amnesty the count and two concurrent notes cannot merge-lose a\nrestart. Each history entry is bound to the DYING PROCESS EPOCH (a real restart advances the\nepoch), so a replayed or duplicated notification of one restart is an idempotent no-op, never\na double count; and a supervision clock behind the newest recorded restart REFUSES rather\nthan silently truncating history. `escalated` is IRREVERSIBLE at the status writer (no later\nwrite, any epoch, replaces it), refuses further notes, and is excluded from every liveness\nderivation (a frozen scatter expected set never contains an escalated instance). The\nescalation commits before the lifecycle retirement runs; the retire seam MUST be idempotent,\na retirement failure leaves the escalation standing, and a reconciler retries retirement on\nalready-escalated rows until it completes, recording completion durably (nothing\nun-escalates).\n\n**Interactive session**, a one-use, holder-bound, bidirectional byte stream to a managed target\n(the `attach` reference case). Establishment is a two-step, collapsible exchange: the serving endpoint\nmints a signed **session grant** bound to `(holder triple, target (owner, actor, lifecycleUid),\nserving instanceId + epoch, expiry)` and returns it as the establishment answer, **never a transport\nURL and never logged**; the holder **redeems** it by opening the session, which consumes it (create-only\nCAS on the durable `session.<sessionId>` ledger row, §13.12; a second redeem is `conflict`). The grant\nis non-bearer: redemption is **presenter-equality** bound to `holder` (§13.10), so a leaked grant confers\nnothing. Authorization is the target command's own (`owner`/`any` + name authority, §13.9); a session is\nnever a path around the despawn/attach authorization.\n\nThe byte stream rides two CORE-ONLY rails, `eps.<endpoint>.<sessionId>.<epoch>.<in|out>` (§13.9), never\nstream-captured: the holder publishes `in` and subscribes `out`, the serving endpoint the reverse; the\nholder's grant covers exactly its own session's two subjects. **Framing** (the terminal-session profile):\napplication bytes are `{ k: \"data\", b: <standard base64> }`; control is structured JSON, `{ k: \"ready\" }`,\n`{ k: \"resize\", cols, rows }` (both positive integers), `{ k: \"end\", reason }`, `{ k: \"drop\", bytes }`.\nOrdering is per direction by publisher sequence. Flow is a bounded in-flight window per direction; output\nthe window cannot take is **dropped, counted, and surfaced** as a `drop` frame before the resumed stream,\nnever silently lost. On the holder's `ready` the serving side replays a byte-exact reconstruction of the\ntarget's current screen, then streams live output in order. A degenerate or unparseable caller frame is\ndropped, never a session teardown.\n\n**Termination is honest and distinct**: every teardown surfaces an `end` frame naming a bounded reason,\n`process-exit` (the target exited), `closed` (a party closed), `expired` (the session TTL elapsed),\n`target-despawn` (the target lifecycle retired), `manager-restart` (the serving incarnation advanced its\nepoch). The session binds the target's `(principal, lifecycleUid)` and the serving epoch (§13.1): a\nsuccessor incarnation (advanced epoch) refuses old-epoch grants, and a same-name successor is a distinct\nsession.\n\n### 13.7 Contracts and discovery\n\n**Clusters.** An endpoint's surface is a set of composable **capability clusters**, each\n`{ urn, revision, attributes[], commands[], events[] }`:\n\n- `urn`, reverse-DNS cluster type URN (`ai.cotal.lifecycle`, `com.acme.deploy`).\n- `attributes`, readable/watchable state; each declares a name, value schema, and record\n derivation (which record key carries it). Attribute reads/subscribes ride the record\n contract, never ephemeral replies.\n- `commands`, each declares name, input/output schemas, `class`, `targeted` (and if so which\n authz modes it admits), its **capability requirement** (the named capability minting maps to\n subjects, §13.9), its `effect` (below), and optional traits.\n Each `journal`-class command **MUST** declare **`admissionCeiling`** =\n `{ maxBytes, maxDepth, maxItems }`, the bounds its canonicalizer refuses beyond (§13.4\n item 3). The ceiling is **declared, never compiled in**, because it decides what a\n submission durably *becomes*: two implementations that agree on the wire and disagree on a\n constant would write different permanent decisions for identical bytes.\n- `events`, name + payload schema; events ride the journal contract on the event plane\n (`epe….ev.<cluster>.<event>`), read-contained by event-topic grants.\n\n**Manager presence reads.** The reference manager's `ps` and `inspect` rows may carry\n`presenceIdentityVerified` and `presenceObservedAt`. A true identity flag means the\nname-matched roster card also matched the managed seat's principal and lifecycle UID.\nThe timestamp is the manager's snapshot time and appears only when its presence view\nis current and identity is verified; it is not a heartbeat from the seat. A client\nrequires both a current `meshView` and a true identity flag before presenting the\nrow's roster status or `activeAt` as this lifecycle's observation. A false or absent\nflag is not proof that the seat is absent, and older managers may omit both fields.\n\n**Effect.** A command declaration carries `effect`, one of `read` or `write`.\n\n**Reachability.** `effect` is reachable only under `protocol.v: 2` (*Version*, below). A responder\nwhose descriptor is pinned to `v: 1` cannot declare the field on the command surface a caller\nresolves against, and nothing in such a deployment consumes it, so the `v: 1` rule below is the\nwhole of what governs.\n\nNote what the pin does NOT do. A descriptor MAY inline the registered cluster artifact verbatim\n(*Descriptor and describe*, §13.7), and an artifact is not filtered against the parsed command\nsurface, so a key named `effect` inside one can appear on the wire under a `v: 1` descriptor. Its\npresence there is not a declaration and MUST NOT be read as one. Repeat-safety information exists\nonly at `protocol.v: 2`, and a caller that recovers it from raw artifact bytes under a `v: 1`\ndescriptor has reinstated exactly the retry this section exists to stop, while believing it read a\ndeclaration. A reference implementation that has not moved to\n`2` therefore carries its repeat-safety knowledge somewhere off the wire, as a static allowlist of\nthe commands it knows to be safe to repeat. Such an allowlist stands in for this field for exactly\nas long as no `v: 2` descriptor can exist, and it is superseded by the declaration the moment one\ncan: allowlist-says-safe and author-declares-`write` are answers to the same question, and two\nanswers to one question is one answer too many.\n\n`read` asserts that executing the command again **changes nothing the command is trying to\nchange**: the state after two executions is the state after one, and any difference between their\nresults is only the freshness a caller would see by asking twice. The state in question is not\nonly the endpoint's own — a command whose intended effect lands somewhere else is still a `write`.\n`evictPrincipal` on the delivery endpoint is the case that fixes the boundary: it drops live\nbroker connections and leaves the endpoint's own records untouched, and it is a `write`, because\ndropping those connections is the point of calling it.\n\nExactly one class of difference is excluded, and it is narrow: the incidental trace of having been\ncalled. Request ids, spans, access logs, metrics, counters, and timing are observable and are not\nwhat the command was for, so a command is not `write` merely because it can be seen to have been\ncalled. The test is not \"did anything change\" — something always does — but **would a caller who\nrepeated this command be surprised by what the repeat did**. If the answer is no, it is `read`.\n\n`write` asserts nothing and MUST be assumed unsafe to repeat.\n\nA client MUST NOT automatically re-issue a command declared `write` after any outcome that does\nnot prove non-execution (§13.3), **whatever `id` the re-issue carries**. The exemption is not the\ntoken but the CONVERGENCE: a re-issue is a resubmission, governed by §13.8 rather than by this\nrule, only while the responder will converge it onto the recorded prior decision. A re-issue the\nresponder accepts as NEW WORK is a repeat, and this prohibition binds it however the `id` was\nchosen.\n\nThat distinction is load-bearing because the two are not distinguishable by inspection. Same-`id`\nconvergence lasts only while the prior decision is retained (§13.8), and a caller cannot observe\nretention from outside — so a client that reuses an `id` after the horizon has issued a repeat\nwhile believing it issued a resubmission. Reusing the token is therefore not a substitute for the\nproof this rule demands: absent an outcome that proves non-execution, a client that cannot\nestablish convergence MUST treat its re-issue as a repeat and MUST NOT make it automatically.\n\n`effect` is a property of the command, not of its delivery class: `class` says how a request is\ncarried, `effect` says whether carrying it twice is safe, and the two are independent — an\n`ephemeral` command may be either.\n\n`effect` is declarative, and a declaration is a claim the endpoint author makes. It binds\nclients, not the responder: nothing in this section relieves a handler of its own correctness,\nand a `read` declaration over a mutating handler is a defect in the endpoint, not a licence.\n\n**Version.** `effect` cannot be introduced additively. A client that does not implement it\nignores it and retries exactly as it did before, and no default value repairs that direction,\nbecause the field's entire purpose is to STOP a retry an older client already performs. So it\nrides the discovery protocol's version marker rather than the unknown-field rule (§7).\n\nThat marker is the one that already exists: `protocol.v` on the **service record spec and the\ndescribe descriptor** (*Descriptor and describe*, below). It is deliberately not a new field on\nthe cluster document, which has no `protocol` of its own — adding one there would be subject to §7\nand dropped unread by exactly the clients this cut has to stop, which is the failure it is meant\nto prevent. An instance whose registered clusters declare `effect` MUST register and describe with\n`protocol.v` of `2`, and every command in every cluster it serves MUST then carry `effect`. `v:1`\ndescriptors remain valid, carry no `effect`, and give a resolving caller no repeat-safety\ninformation — it MUST treat every command served under one as `write`. There is therefore no\n\"omitted `effect`\" case under a `v:2` descriptor, and no surface in which the field is present but\noptional.\n\nA client that does not implement this section MUST refuse to resolve a descriptor whose\n`protocol.v` it does not implement, rather than ignore what it cannot honor. **That refusal is a\nrequirement this section CREATES, not one already met.** What protects an unamended client today\nis a fence on the other side of the wire: `describe`'s pinned output schema fixes\n`descriptor.protocol.v` to the constant `1`, so an unamended responder cannot publish a `v:2`\ndescriptor at all — its own reply fails output validation and surfaces as a responder bug. The\nregistry read path fails closed the same way, refusing a service record whose `protocol.v` is not\n`1`. The resolving caller does neither: it reads the describe answer without validating it, and\nthe shape it reads does not carry `protocol`. So the version marker is enforced today by the\nRESPONDER's contract and by the REGISTRY reader, and by nothing in the caller — which is safe only\nfor as long as no `v:2` descriptor can exist.\n\n**Emission.** Moving to `protocol.v: 2` **is** a non-additive discovery change, so §11's\nchange-process rule for one governs it and is the authority on how it is rolled out; this section\nadds only what is specific to `2` and states no cutover rule of its own.\n\nSpecific to `2`: a caller that resolves a descriptor whose `protocol.v` it does not implement MUST\nfail the resolve (`unsupported-version`) and MUST NOT invoke against it — a descriptor it cannot\nread is not a weaker descriptor, it is no descriptor, and treating it as `v:1` reinstates exactly\nthe repeat this section exists to stop. Implementing that refusal is what makes a caller count as\nhaving adopted this section for the purposes of §11's rule, which is the condition a responder's\ndeployment must satisfy before any responder in it registers or describes at `2`.\n\nWhy the rule lives there and not here: the condition is a property of the whole deployment, and a\nresponder cannot evaluate it from where it stands — per §11 there is no in-band capability\nnegotiation and no request carries a caller version, so a responder cannot tell an amended caller\nfrom an unamended one. A rule stated here would bind the one party unable to check it. §11 assigns\nit instead to the deployment, which can.\n\nAn **endpoint type** is a conformance set of cluster URNs. `manager` and `delivery` are\nordinary conformance sets defined by the reference implementation; core knows only\n\"endpoint\".\n\n**Schemas.** Contract schemas are JSON Schema **2020-12**, validated by a real 2020-12\nvalidator (the reference implementation pins `ajv`), under this normative resource profile: a\nschema is a **closed resource bundle**, either fully self-contained (local `$defs`/`#/…`\nrefs) or referencing other contract-store artifacts **by digest** only. `$id`/`$anchor`/\n`$dynamicRef` resolve deterministically within the bundle; ambient HTTP/file/URI resolution\nMUST NOT occur. Contract identity is the **closure digest** (above): the digest of the\nmanifest naming the complete resolved closure, not of the root document alone. Registration-time bounds (loud `contract-invalid`, distinct from\ninvocation-time `bad-request`): document ≤ 256 KiB, closure ≤ 1 MiB, nesting ≤ 32, ref chain\n≤ 32, bounded pattern complexity, compile/validation time budgets, and a bounded compiled-schema cache (reference: 256-entry LRU) (§13.8). Runtime\nvalidation at the serving boundary is mandatory: args before any effect, replies against the\noutput schema. Authoring tooling is free (the reference implementation authors in Zod); the\nwire artifact and validation semantics are the JSON Schema documents themselves.\n**Every command declares BOTH an input and an output schema**: a side with no payload\ndeclares the **canonical void schema**, the artifact `{\"type\":\"null\"}`, whose RFC 8785\ndigest is therefore one fixed value, so both `op` digests exist for every command (§13.3)\nand no shape in this section is conditional on a missing side. Validation against the void\nschema means the side's payload is absent or `null`.\n\n**Content addressing.** A contract artifact (cluster document, schema bundle member, trait\ndefinition or attachment) is identified by the SHA-256 digest of its RFC 8785 canonical JSON\n(strict RFC 8785 over I-JSON; the reference implementation pins `json-canonicalize`'s strict\npath and gates on the RFC's published test vectors, including number-serialization and\nsurrogate edges). **Two digests, never conflated.** An **artifact digest** identifies ONE\ndocument's bytes and is the value that keys its subject and every by-digest reference. A\n**closure digest** identifies a whole resolved bundle, a cluster document or a schema\nclosure, and is the artifact digest of that bundle's **manifest**: the artifact\n`{ v: 1, root: <artifact digest>, members: [<artifact digest>, …] }`, `members` being every\nartifact transitively reachable through by-digest references from `root`, sorted\nlexicographically and deduplicated. The manifest is itself an ordinary artifact on its own\ndigest subject, so a closure digest is an artifact digest, nothing dispatches on which kind\na digest is. Contract identity (§13.7 `contractDigest`, `clusterDigests[]`, and the\n`op.inputDigest`/`outputDigest` a caller pins) is always a CLOSURE digest; a `$ref`-by-digest\ninside a schema is always an ARTIFACT digest.\n\n**Every `*Digest` field in this section is one scalar shape**, `sha256:<hex>`, lowercase\nhex, and each names exactly one input, so no field's digest is implementation-defined:\n`inputDigest`/`outputDigest`, `contractDigest`, `clusterDigests[]` = the CLOSURE digest of\nthe named bundle (above); a schema's by-digest `$ref` = an ARTIFACT digest;\n`argsDigest`/`outcomeDigest`/`resultDigest` = over the strict RFC 8785 canonical JSON of\nthat value (absent iff the value is absent); `authDigest` = over the raw UTF-8 bytes of the\n`auth` slot as carried (§13.3); `submissionDigest` = over the raw stored submission bytes\n(§13.4). Integer fields on the wire (`sourceSeq`, `revision`, `epoch`, `ts`,\n`deadlineMs`, `readinessDeadlineMs`) are non-negative integers ≤ 2^53 − 1, the I-JSON\ninteroperable range, so at most 16 decimal digits, which is what makes the §13.12\nmaximum-fact fixture a computable worst case rather than an estimate.\n\nArtifacts live in the per-space **contract stream**: one artifact per\ndigest-keyed subject `cotal.<space>.epc.<digest-hex>` (§13.2), published as a single\nmessage; possible because a document is bounded at 256 KiB (below) and the operator floor\nasserts `max_payload` covers it (§13.12); a closure is fetched artifact-by-artifact through\nits digest references, never as one blob. Reads are the subject-scoped last-by-subject\nDirect Get on the exact digest subject, no consumer, no replay machinery, and nothing\nbody-selected (§13.9). Readers MUST verify fetched bytes against the digest and fail loud\non mismatch. Publication is mediated and create-only (§13.9): artifacts are immutable once\npublished. A single-message digest subject is readable subject-confined; a chunked object\nstore is not, because chunk replay needs a consumer whose delivery target is body-selected\n(§13.9).\n\n**Record kinds and key grammar.** Every record kind is registered: core kinds are defined\nby this section (writer table, §13.9), and each kind's registry entry pins its **key\ngrammar** (the qualifier tokens between the kind token and the `.spec`/`.status` suffix),\nits writer roles, and its mediation class; grants and merged watches are derived from that\ngrammar, so two implementations always agree on which key carries what. The core kinds'\nkey grammars, pinned here (each key then splits `.spec`/`.status` per §13.4, EXCEPT the\nunsplit atomic keys the table marks: the `lifecycle` head, `govern`, `uid`, `oblig`,\n`goalidx`, `goaleff`, `epname`, `epmig`, and `answer`):\n\n| Kind | Key grammar |\n| --- | --- |\n| `svc` | `svc.<endpoint>.<instanceId>` |\n| `signer` | `signer.<keyId>` |\n| `handle` | `handle.<issuerKeyId>.<id>` |\n| `contracts` | `contracts.<endpoint>` |\n| `goal` | `goal.<endpoint>.<cOwner>.<cActor>.<cUid>.<goalId>` |\n| `goalidx` | `goalidx.<endpoint>.<cOwner>.<cActor>.<cUid>.<goalId>` (atomic; an in-flight action's reconcile index, written create-only before the goal binds and deleted at its terminal, enumerated by a bounded boot-sweep authority so a superseded executor's orphaned goals settle; never caller-addressed). A deleted entry is not recorded again: a later record of the same goal is refused `failed-precondition`, since that goal settled or its acceptance was withdrawn. The reference local signer composition uses its ephemeral provisioner. The signerless remote-manager composition uses an authenticated host operation backed by a sealed, owner-filtered `goalidx.manager.<cOwner>.>` scan; no participant credential carries records consumer create or delete. Writer: the **goal-writer** principal (§13.9), which composes the commit principal with three additions, this index subtree among them, and NOT the bare commit principal, whose enumeration does not reach this kind. The two are separated because the index is created BEFORE the bind, so the principal that writes it is the one that also binds; a deployment that grants the index on the bare commit row has widened every commit principal to reach a key only the goal writer needs |\n| `goaleff` | `goaleff.<endpoint>.<cOwner>.<cActor>.<cUid>.<goalId>.<gen>` (atomic; the at-most-one-launch election for one accepted action, written create-only by the effects executor that wins it and advanced by revision-CAS through its phases). `<gen>` is the accepted submission's **EPJ `sourceSeq`**, the sequence it was delivered at, carried verbatim into the acceptance fact; the only discriminator that exists at the EARLIEST coordinate, since `goalidx` is created before the bind and therefore before any decision fact exists, so a decision sequence cannot key it. The generation token is what keeps this kind out of the one-use-forever trap: a lawful later acceptance under the same `goalId` gets a different `<gen>` and a fresh key, never a permanent tombstone. Writer: the owning endpoint's **commit path** ONLY (§13.9), inherited by the goal-writer principal that composes it; the generic per-kind spec/status writer row does not reach it, because this kind is unsplit and has no `.spec`/`.status` to write. The value machine, including which actor may settle a row, is *The two coordination machines* below |\n| `epname` | `epname.<endpoint>.<nameToken>` (atomic; the durable claim on one name, keyed by the NAME rather than by a caller triple, because the thing being made exclusive is the name and two callers must contend on one key). Writer: the owning endpoint's **commit path** ONLY (§13.9); unsplit, so create-only for the claim and revision-CAS for every state change. The state machine, its actor roles, and the claimant union are *The two coordination machines* below |\n| `epmig` | `epmig.<endpoint>` (atomic; the endpoint's cutover manifest: the inventory a migration is performed against, and the durable record of the cutover runs performed against it, so a run generation is never reused by a later run). That run generation is **scoped to cutover and is key material nowhere else**: the `<gen>` token in the `goaleff` grammar is the accepted submission's EPJ `sourceSeq` and only that, the `goal`, `goalidx`, and `goal….result` grammars carry no generation token at all, and an implementation that keys any of them from this manifest has built an election two conforming peers can never meet inside. Writer: the owning endpoint's **commit path** ONLY (§13.9); unsplit, and its qualifier profile is `[qEndpoint]` alone, one manifest per endpoint, never one per caller or per run |\n| `cp` | `cp.<endpoint>.<token>` |\n| `lease` | `lease.<endpoint>.<pool>.<cOwner>.<cActor>.<cUid>.<id>` (the item's acceptance identity, §13.2) |\n| `lifecycle` | `lifecycle.<owner>.<actor>.<lifecycleUid>` (the §13.1 mapping detail) |\n| `lifecycle` head | `lifecycle.<owner>.<actor>`; the alias's **authoritative current mapping**, and the ONLY key `mappingRevision` (§13.3) counts: a **single unsplit key** (NOT `.spec`/`.status`-split; the mapping is one atomic record, and a handler's \"fresh current mapping\" read is one leader-consistent read of this key returning `{ mapping, revision }`, the revision being the STORE revision, never a value field), CAS-updated, NEVER-DELETED (the head discipline: no grant permits DEL/PURGE, true absence alone is virgin, a deletion marker refuses loudly as corruption). States `active \\| retiring \\| retired` (§13.1): the mapping is current ONLY at `active`; `retiring` is the op-bound containment phase, non-current and not replaceable; `retired` asserts the completed §13.1 barrier. Activation CASes it from none (create-only) or from a `retired` predecessor to a freshly reserved UID's mapping; two concurrent mints for one alias cannot both win the CAS; the terminal barrier CASes `active → retiring` at its bar and `retiring → retired` as its final head step. The per-UID `lifecycle.<owner>.<actor>.<lifecycleUid>` detail below is optional append-only audit, never the authority |\n| `uid` | `uid.<lifecycleUid>`; the §13.1 **space-global UID reservation**: a **single unsplit key**, create-only, NEVER-DELETED, value = `{ owner, actor, mintedBy }` (the reserving authority and intended alias, audit only; the KEY is the reservation). A key exists for every UID ever reserved, including burned candidates; a DEL/PURGE marker is corruption |\n| `policy` | `policy.<endpoint>.<digest-hex>`; the §13.6 **immutable admission-policy version**: a **single unsplit key** per policy version, create-only, NEVER-DELETED. `<digest-hex>` is the SHA-256 hex (64 chars) of the record's canonical value bytes, so the key is SELF-CERTIFYING: a reader re-digests the value it read and refuses a mismatch. Immutability is a TRUSTED-WRITER invariant (create-only CAS by the sole writer) BACKED by that read-time self-certification, not a broker subtraction (KV create/update/delete share the one subject, §13.9): a different-byte overwrite is refused on read, and the residual (a DEL or same-byte overwrite by a buggy/compromised writer destroying availability under history 1) fails admission closed rather than admitting a lost policy. `enforcedPolicyKey`/`pendingPolicyKey` on the govern head (§13.6) name keys of exactly this kind, which is what keeps BOTH the enforced and the pending policy readable through a mutation's whole drain window. Writer: the provisioner registration path ONLY (§13.9); a DEL/PURGE marker is corruption |\n| `oblig` | `oblig.<targetUid>.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>`; the §13.8 **target-indexed acceptance obligation**: a **single unsplit key** whose grammar IS the deterministic acceptance identity (target lifecycle UID first, so a retirement barrier enumerates `oblig.<targetUid>.>`), create-only winner, monotonic value states, NEVER-DELETED. An admission under policy with NO target lifecycle keys the row with the fixed sentinel target token `ep` (which the §13.1 UID token grammar can never produce, so no collision exists): `oblig.ep.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>`: excluded from retirement drains (it binds no lifecycle) and included, like every targeted row, in the endpoint's policy drain via the endpoint-position filter `oblig.*.<endpoint>.>` (§13.6/§13.8) |\n| `frontier` | `frontier.<lifecycleUid>`; the §13.1 **per-stream retirement frontiers**: a **single unsplit key** per retired lifecycle, create-only, NEVER-DELETED, value = `{ lifecycleUid, opId, streams }` where `streams` maps each lifecycle-bounded stream to its last sequence at retirement. Written by the terminal barrier AFTER the obligation drain, the drain's repair-principal fence, the pool cleaner, and the cleaner-credential revoke+evict, and BEFORE the gate/head terminals (§13.1 order), so a `retired` head implies its frontier exists. The cutoffs bound the predecessor's half-open interval `(activationFrontier, retirementFrontier]` (§8); they are never a successor's start (a successor captures its OWN activation frontier). Writer: the minting authority's retirement barrier ONLY; it records once, under its own operation (a foreign-op record refuses the barrier closed); a DEL/PURGE marker is corruption |\n| `govern` | `govern.<endpoint>`; the endpoint's **governance head**: a **single unsplit key** (NOT `.spec`/`.status`-split), value = the endpoint's MONOTONIC binding map, command to governed URN set, the NORMATIVE **admission-policy selector** `{ enforcedPolicyKey, enforcedPolicyRevision, pendingPolicyKey?, pendingPolicyRevision? }` (§13.6: `enforcedPolicyKey` is the exact records key of the immutable `policy` record currently governing admission and `enforcedPolicyRevision` its store revision, so any implementer selects the endpoint-wide enforced policy WITHOUT per-instance guesswork; a mutation stages `pendingPolicy…` and promotes it into `enforcedPolicy…` only after the endpoint's obligation drain, so the selector alone decides which revision governs during the drain window), plus whatever internal serialization state the provisioner's registration CAS needs (that state is non-normative: a second implementer may linearize registration with a different slot shape and conform, provided every registration contends on this head under its frozen gate through spec publication, the policy selector fields carry the meaning above, and the external guarantees hold). One of those external guarantees is LIVENESS of the linearization itself, and it is normative however the slot is shaped: an in-flight registration that stops before its spec publication MUST NOT block the endpoint's registrations permanently. Whatever state a registration holds on this head, an implementation MUST be able to decide that state ABANDONED from durable facts rather than from a liveness probe, and a later registration MUST then be able to take it. The reference implementation decides it by comparing the held state's recorded gate generation against the holder's live issuance gate: a gate that has reopened past it proves the hold can never complete, since completion requires that same generation still frozen. An implementation that cannot make that determination MUST refuse rather than take the hold, because an in-flight registration and an abandoned one are otherwise indistinguishable, and taking a live one would put two registrations through the linearization point at once. Enforcing the governed-attachment no-strip/no-downgrade mandate (Traits, below) is a HISTORY-bearing, ENDPOINT-WIDE property: a fresh instance, a remove-then-re-add, or a concurrent registration must not launder a governed binding away, so this head is also the endpoint's **registration linearization point**. Writer: the provisioner registration path ONLY (§13.9); NEVER-DELETED, per the `lifecycle`-head discipline |\n\n| `run` | `run.<endpoint>.<runId>`; a **workflow run's** last-value-wins state beside its append-only step journal (§14). `.spec`/`.status`-split, and the split is load-bearing: the spec is what the run IS, decided once at start and never rewritten (`{ v: 1, run, pins, createdAt }`, the resolved PIN SET of §14.3), the status is what it is DOING (`{ v: 1, observedSpecRevision, state, holder, epoch, fencingToken, journalHigh, at, failure? }`), so a lease renewal can never rewrite the pins. A `failed` status MAY carry `failure: { code?, message }`, the error the program failed with: its `L` code when it has one, and its message, at most 4000 characters. No other state carries it, and a reader MUST NOT require it, because a status written before it existed has none. `<runId>` is an id token minted by the DRIVER, never caller-supplied and **never reused**: a run is never re-run under its own id (that is a fork, and a fork takes a new id), so a deleted `run` key staying closed is correct and no generation token is owed. A fork's child is a new run under a new id and this revision records no lineage on it (§14.3); a later revision that adds a parent field puts it on the SPEC half and never the status half, because parentage is decided at creation and a status-half lineage could name a different parent after a takeover. Writer: the run driver's commit path ONLY (§13.9) |\n| `answer` | `answer.<endpoint>.<token>.<answerId>`; a checkpoint's ANSWER payload beside its one-use settle fact (§13.6, `answerId`/`settledAnswerId`): a **single unsplit key**, create-only, never updated and never deleted, value `{ v: 1, token, answerId, value?, artifact?, by, at, supersedes? }` (`supersedes` only on an amendment, §14.5). **Keyed per answer rather than per presenter because a workflow checkpoint's holder is the run driver and every resolver reaches the checkpoint through it, so every presenter is the same principal**: a presenter-keyed slot collapses to one, two racing resolvers overwrite it, and the settlement then selects whichever answer was written last rather than the one that won. `<answerId>` is derived from the answer's own content (§14.5), so a retry after a crash lands on its own record with its own bytes; an amendment's is minted fresh per filing (§14.5). Writer: the run driver's commit path ONLY (§13.9) |\n| `notice` | `notice.<endpoint>.<runId>.<addresseeId>.<noticeId>`; one bounded decision a workflow told one agent (`notify`, [`spec/cotal-lang.md`](spec/cotal-lang.md) §6.8), filed onto the run and rendered ahead of that agent's next turn, never a channel message. `.spec`/`.status`-split: the spec is the notice (`{ v: 1, run, step, addressee, fact, at }`) and is create-only, the status is its consumption (`{ v: 1, consumedAt, by, observedSpecRevision }`). **`<addresseeId>` is a digest of the agent's name and never the name, because an agent name is dotted and a dot is the key separator**: a raw name re-tokenizes the key into a key of another shape, and mangling it destroys the identity being keyed on; a reader holding the handle re-derives the same token (§14.5), so per-addressee enumeration stays one prefix scan. `<noticeId>` is derived from the step's request id and the addressee, so a `notify` re-run after a crash lands on the same records. Writer: the run driver's commit path ONLY (§13.9) |\n| `migration` | `migration.<endpoint>.<runId>.<migrationId>`; one run's move onto edited source ([`spec/cotal-lang.md`](spec/cotal-lang.md) §11.2): what the divergence-and-orphan check found, which refusals a person overrode, and who they were. `.spec`/`.status`-split: the spec is the REPORT (`{ v: 1, run, fromHash?, toHash, at, consumedThrough, orphans[], overrides[], actor }`) and is create-only, the status is the APPLICATION (`{ v: 1, appliedAt, by, observedSpecRevision }`) and names the driver that advanced the run. Its own kind because it is neither half of the run record: a migration is append-only history with an actor on it, and a run can migrate more than once, so the status half would let the second erase the first and the spec half cannot be written twice. **`<migrationId>` is a digest of the report's own content and never a counter**, because a migration is decided by a dry walk a crash can force to be re-run, so the same decision must land on the same record rather than filing a second one, and a counter would need a second arbiter for a fact the content already determines (§14.5). **The application is create-only for the same reason the notice's consumption is**: two drivers racing to advance one run both find no status and both write, and the store decides which one moved it. Writer: the run driver's commit path ONLY (§13.9) |\n\nThird-party kinds\nregister under reverse-DNS kind names.\n\n**The two coordination machines.** `goaleff` and `epname` carry closed value machines. A row's\nlegal field set is fixed per phase or per state, and a writer that presents a field the phase does\nnot define, or omits one it does, is refused rather than accommodated: a single broad object with\neverything optional cannot express that a field is present exactly when a launch is in flight, and\npresent-exactly-when is the only form in which those fields decide anything.\n\n`goaleff` has four phases: `claimed`, `launching`, `launched`, `settled`. Every row carries `v: 1`,\nthe electing `executor` as an incarnation `{ instanceId, processEpoch }`, the `attemptId` nonce of\nthe attempt that won the election, and `ts`. `launching` and `launched` additionally carry `addr`,\nthe allocated address `{ nameToken, lifecycleUid }`; `settled` MAY carry it; `claimed` MUST NOT.\nThe legal edges are `claimed → launching`, `claimed → settled`, `launching → launched`,\n`launching → settled`, and `launched → settled`. `settled` is terminal because no edge leaves it,\nwhich is the terminality rule itself rather than a separate check that could come to disagree with\nthe table. The `executor` and `attemptId` do not move across an edge, and an allocated `addr` is\nnever rewritten to a different one.\n\nTwo actor roles take those edges. An **executor** may take any of them and MUST be the row's own\nexecutor at the row's own `attemptId`: a re-read that finds a foreign incarnation or a foreign\nnonce is a loss, never a licence to proceed. A **sweeper** acts for an executor it believes is gone\nand MAY take only the edges into `settled`, because advancing a launch phase on a dead executor's\nbehalf is the split brain the election exists to prevent, and the resulting row is\nindistinguishable from the executor having advanced it. An actor presenting neither role is\nrefused; an unrecognized role that falls through both checks is the most permissive possible answer\nto the question of who is acting.\n\nEvery settle is gated on the goal's terminal fact **already existing**. Settling without one\npublishes a row asserting that a goal finished when nothing durable records that it did, so the\nterminal-first order is normative and the reverse order is never legal. A crash between the two is\na row left un-settled with its terminal present, which is recoverable; the reverse would not be.\n\n`epname` has seven states: `claimed`, `launching`, `live`, `preserved`, `relaunching`, `draining`,\n`released`. Every row carries `v: 1`, `ts`, `state`, and `claimant`, which is either `null` or one\nof three kinds: an **action** claim `{ goalId, gen }`, a **direct** claim\n`{ instanceId, processEpoch, opId }`, or an **incumbent** claim `{ backfillId }` recorded by a\ncutover backfill. A launch in flight (`launching`, `relaunching`) additionally carries\n`lifecycleUid`, `launchAttemptId`, and the `executor` incarnation; a name that is up (`live`,\n`preserved`) carries `lifecycleUid` and `runtimeOwner`; `draining` carries `lifecycleUid`,\n`runtimeOwner`, and `enteredAt`; `claimed` and `released` carry the base fields alone.\n\n`runtimeOwner` is the incarnation that owns the handle table for the name, and it is **moved, never\nderived**. It MOVES on the four launch-resolving edges, `launching → live`, `relaunching → live`,\n`launching → draining`, and `relaunching → draining`: the row's full `executor` incarnation becomes\nits `runtimeOwner` and `launchAttemptId` is cleared, recorded at the moment it becomes true. Both\nfields of the incarnation move together, because an `instanceId` without its `processEpoch` names a\nprocess rather than the run of it that holds the handle table. On the three edges that neither\ncreate the row nor resolve a launch, `live → preserved`, `live → draining`, and\n`preserved → draining`, it is CARRIED unchanged. The one creation edge that produces a `live` row,\nthe cutover backfill, INSTALLS it instead, read from the incumbent's own live gate row: a cutover\nthat cannot read one MUST record a casualty rather than backfill, because a `live` row whose owner\nis unknown puts an unevaluable value into the durable record that every later release reads. Except\non that edge it is never reconstructed from any other row, because a supported deployment mode has no such row to read and a\npredicate that cannot be evaluated on a supported path either refuses forever or falls back to\nabsence. An `instanceId` alone will not stand in: an identity is not an incarnation, and a\nrestarted process under the same identity holds an empty handle table, which is the absence of\nknowledge rather than knowledge of absence.\n\nSix actor roles take the `epname` edges. An **allocator** creates a claim (`→ claimed`, and\n`released → claimed`, so a released name is claimable again and the row is never deleted). A\n**claimant** drives its own launch (`claimed → launching → live`) and may abandon an unlaunched\nclaim (`claimed → released`). A **holder**, identified by the row's `lifecycleUid`, drives the\npreserve cycle (`live → preserved → relaunching → live`). A **sweeper** may release an unlaunched\nclaim and may move `launching`, `live`, `preserved`, or `relaunching` into `draining`. A\n**cutover** may establish a `live` incumbent directly, which is the backfill path. An **operator**\nhas exactly one edge, `draining → released`.\n\nThat last edge is operator-only by design rather than by omission. An ordinary release would\nrequire an actor attesting that a runtime is gone, and no such actor can exist: an owner still\nalive has no per-attempt handle to attest about, and a restarted one is a different incarnation.\nThe edge is therefore removed rather than weakened, and `draining` is a state an operator clears by\nhand until a durable runtime-attempt token exists. Two consequences follow and are normative. A\ngoal reaching a `succeeded` terminal does **not** release the name it holds; and release is a\ntransition to `released`, never a delete, so the row survives to answer who held the name last.\n\n**The actor roles above are entitlements inside the value machines, not wire principals, and which\nprincipal may present each of them is unspecified: RAISED, NOT SETTLED.** The write grants on both\nkinds are the commit path and the goal-writer principal that composes it (§13.9). No sweeper,\noperator, allocator, or cutover principal is granted anywhere in this document, so this section\ndoes not say whether a conforming sweep runs under the commit principal or under a principal a\ndeployment would have to add. An implementation MUST NOT read a role in these machines as\nconferring a grant, and a deployment that needs a distinct sweep identity is outside what this\nversion specifies.\n\n**Descriptor and describe.** Each instance registers a **service record** (kind `svc`, key\n`svc.<endpoint>.<instanceId>`; the owner is determined by the name and recorded in the\nvalue): spec = `{ endpoint, owner, endpointType?,\nclusterDigests[], protocol: { v: 1 | 2 }, activation? }`, status = `{ epoch, state,\nobservedSpecRevision, … }` (writer table §13.9). The spec key's **store revision is the\ninstance's `registrationRevision`**, the value scatter freezes (§13.5): it advances only\nwhen the mediated registration path writes the spec key, so an advance during a scatter is\nexactly a re-registration. The `processEpoch` of the instance's issuance gate (§13.1) is 0 after\nthe first registration of its `instanceId`, and each later registration of it commits the previous\nepoch plus one. A registration is the first when the gate's `registrationRevision` is still 0; a\nderegistration leaves the gate unchanged, so the registration after it is a later one. Epoch 0 is\nopen and serving like any later epoch, and a consumer or sweeper MUST NOT treat it as absent or not\nready. `describe` is a reserved untargeted\nephemeral command every endpoint MUST serve, returning the descriptor with clusters inline or\nby digest. **Authorization-scoped answers use a trusted authorization source only**: the\nanswer is intersected against a fresh view of the caller's authority obtained from the\ndeployment's authorization ledger/callout (§9/§10), keyed by the broker-authenticated caller\nidentity, never against payload- or slot-asserted scope, which is ignored. If the trusted\nview is unavailable or stale beyond its declared freshness bound, describe fails closed\n(`unavailable`) rather than answering from a weaker source; deployments MAY declare an\nendpoint's descriptor public, in which case no view is consulted and the answer says so.\nDescriptor visibility is never inferred from reachability of `describe` alone. A KV browse\nindex (record kind `contracts`) is an advisory convenience copy; `describe` is authoritative.\n\n**Manager-service records.** A remote manager registration is one closed, opaque-instance family:\nits `svc.manager.<instanceId>` spec/status pair, its instance-bound contract closure, and its\n`epgate.manager.<instanceId>` / `epcred.manager.<instanceId>.<credentialId>` rows all name the\nsame server-authorized `{ owner, managerActor, lifecycleUid, instanceId }` tuple. The registration\nmediator MUST reject any tuple mismatch, instance collision, contract substitution, or status/gate\noperation from another principal or lifecycle. It may publish only the contract artifacts staged by\n`prepare`; it may not use manager-service authority to publish a contract for any other endpoint.\nRetiring the family retires the instance record and gate together; no stale stage, registration,\ncontract, status, or credential can activate a new lifecycle or another instance. `describe` and\nstatus report the manager instance's serving/degraded state without treating discovery as\nauthorization (§13.9).\n\n**Invocation binding.** The digests are not caller courtesy but a two-sided requirement\n(§13.3): a caller MUST pin `op.inputDigest`/`op.outputDigest` on every command except\n`describe` (the discovery bootstrap), and a serving member MUST reject their absence\n(`contract-mismatch`) before any effect; an unpinned invocation cannot silently bypass the\ndescribe→invoke binding, and MUST honor pinned digests or reject `contract-mismatch`. Rolling updates keep classes contract-homogeneous: an incompatible\ngeneration registers a distinct routable identity (new endpoint name or explicit version\nlabel) until homogeneous.\n\n**Traits.** A trait attaches governed metadata to a cluster, command, attribute, or event.\nA **trait definition** `{ urn, valueSchema (digest), selector, breakingChanges, authority }`\nis content-addressed and signed: `ai.cotal.*` definitions by the space-operator authority;\nthird-party definitions by their defining owner's registered key. **Attachment authority is\ndistinct from definition authority**: every *required/governed* attachment (this revision governs\nexactly `ai.cotal.guarded` and `ai.cotal.priced`) is separately signed by the definition's\nnamed authority over `{ endpoint, command, contractDigest (the cluster document's complete\nclosure digest), traitUrn, value }`, so a self-published descriptor cannot strip, forge, or downgrade a governed\nannotation; removal or downgrade is an authorized contract revision. Enforcement is\nfail-closed at the pre-effect seam: missing, unverifiable, or stale governed attachments\nrefuse before effect. Non-governed traits are unsigned vocabulary.\n\n**Compatibility.** Cluster evolution is BACKWARD by default: within a revision line, changes\nMUST be additive and added fields MUST carry defaults; removal, rename, or semantic change\nmints a new cluster URN version. A push-time JSON-native compatibility differ + review gate\nenforce this in the reference workflow (repository tooling under `scripts/`, not shipped\nclient code). The discovery protocol itself is versioned under `protocol.v`, additively by\ndefault: a bump is reserved for a change a client cannot safely ignore, and `effect` (§13.7) is\nthe one such change so far — a client that ignored it would keep performing exactly the retry the\nfield exists to stop, so it refuses the document instead.\n\n### 13.8 Distributed guarantees\n\n- **Idempotency scope.** Ephemeral idempotent commands by `id` (handler-local, within result\n retention); journaled submissions and actions by `id`/`goalId` + fingerprint within the\n declared horizon. Exactly-once is bounded honestly: delivery is at-least-once; Cotal\n guarantees idempotent submission/fact recording and fenced commits of Cotal-owned state; an\n external side effect is exactly-once only when the external API honors the propagated\n idempotency key or fencing token, else the contract documents at-least-once effects. A\n workflow step inside a `once` scope (`spec/cotal-lang.md` §7.8) is dispatched at most once per\n step key whatever the far side honors, a dispatch being one call of its handler under its request\n id that the handler does not refuse (the handler may retry inside that call): a resume that finds\n it begun and unsettled opens a hold under a token derived from its recorded request id instead of\n dispatching it again, trading the run's liveness for the bound.\n- **Repeat versus resubmission.** **A command that is idempotent by `id` is NOT thereby `read`:\n safe to resubmit is not safe to repeat.** That is the rule neither mechanism states alone, and\n declaring such a command `read` licenses a fresh-`id` retry that duplicates the effect. The two\n properties are independent; a command may hold either, both, or neither.\n\n A **resubmission** is a re-send the responder CONVERGES onto the decision it already recorded; a\n **repeat** is a re-send it accepts as new work. Reusing the `id` is how a caller ASKS for\n convergence, and within the horizon below it is how convergence is keyed — but the `id` is the\n request, not the answer, and a re-send under a reused token that the responder accepts as new\n work is a repeat by this definition. `effect` (§13.7) governs repeats, whatever token they\n carry. `id` governs resubmissions — and what `id` alone is worth differs by rail:\n - **Ephemeral** — `id` is the whole key. A same-`id` resubmission within result retention is\n the same call; an idempotent command may dedup on it and consult nothing else.\n - **Journal** — `id` is necessary but NOT sufficient. It is one of the fields the fingerprint\n binds, so a same-`id` resubmission converges to the first outcome only if the rest of the\n fingerprint matches too. Same `id` with different args is neither a resubmission nor a fresh\n call: it is a loud `conflict` (§13.4), because the decision subject is already occupied by a\n fact with a different fingerprint. A caller that mutates arguments and reuses an `id`\n therefore gets an error rather than either behaviour it might have expected from the\n ephemeral rail.\n\n **Both rails are bounded by a horizon, and outside it neither rule applies.** A resubmission is\n a resubmission only while the prior decision is still retained — the idempotency horizon is\n realized by decision-fact retention on the journal rail and by result retention on the ephemeral\n rail, never by a clock (§13.4). Once the retained decision is gone, the `id` carries no history:\n a re-send under it is a fresh call that WILL execute, and the same `id` with different args is\n no longer a `conflict` but simply a new submission. The finite horizon is what makes the decision\n store finite, so this is a fact callers MUST hold rather than a hole to be closed — but the hole\n it WOULD open if `repeat` were defined by the token is closed at the definition above: a re-send\n the responder accepts as new work is a **repeat**, so a post-horizon same-`id` re-send of a\n `write` is exactly what §13.7 prohibits a client from making automatically. Reusing the token\n buys nothing outside the horizon, and a caller that cannot establish it is still inside one has\n not established that its re-send is safe.\n\n Neither word is \"retry\": callers retry under a reused `id` and under a fresh one and mean the\n same English word both times, which is the confusion this paragraph exists to remove. And the\n dangerous reading is a REASONABLE one, not a careless one — an operator who has correctly\n learned that a command is idempotent by `id` will retry it after a timeout, mint a fresh `id`\n because the old request is gone, and get a second effect. Nothing in this document told them\n those were different acts until now.\n- **Fencing and mediated commits.** Every Cotal-owned authoritative transition flows through\n its mediated writer (§13.9) carrying `(fencingToken | lifecycleUid | epoch)` as applicable;\n the writer validates token currency, unexpired lease against its own clock, lifecycle\n currency, and epoch currency. Value-carried tokens + CAS stop conforming-but-stale writers;\n scoped credentials + mediation stop everything else. The threat boundary of any\n direct-owner write is explicitly downgraded (§13.9).\n- **CAS conflict.** Any lost CAS is a loud `conflict`; the loser re-reads and re-decides.\n- **Authority-head reservation/drain.** An authority head (the §13.1 lifecycle head; the\n §13.6 registered admission policy) and a durable acceptance/start fact live in different\n streams; no cross-stream CAS exists, and a revision carried inside a fact is provenance,\n never a fence. Any durable acceptance or start that creates work bound to a lifecycle,\n or admits work under a policy read, therefore contends with the head's movement on ONE\n durable serialization coordinate: the **target-indexed obligation row** (kind `oblig`,\n §13.7). In order: (1) BEFORE the EPF decision publish, the writer obtains the obligation\n through the **admission mediator**. The mediator owns the `oblig.` prefix (the\n canonicalizer holds no raw write on it), derives the coordinate from the\n broker-authenticated request subject (never from a body field), and IMMEDIATELY before\n the create performs the FENCING currency reads it will pin: for a target-bound\n admission a leader-served read of the target's lifecycle head, REFUSING unless the state\n is `active` (a `retiring` or `retired` target admits nothing); for a policy-admitted\n decision a leader-served read of the governance head (§13.6) that FIRST refuses if a\n `pendingPolicyKey` is present (the endpoint is inside its drain window; the drain-window\n admission pause is a normative step of THIS algorithm, not only a §13.6 property, so any\n conforming mediator refuses without needing to infer it) and only then follows\n `enforcedPolicyKey`, self-certifies it (§13.7), and pins its `enforcedPolicyRevision` as\n `policyRevision`. Refusing at the create-fence (not only at the post-create recheck) is\n also what bounds the row set: a request that could not create its row leaves no\n never-deleted `oblig` debt behind, so a long or crashed drain cannot accumulate an\n unbounded set of rejected rows. An admission with no target lifecycle keys the\n row under the fixed sentinel target token `ep` (§13.7). It then creates the row\n create-only at the deterministic acceptance-identity\n key `oblig.<targetUid>.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>`. The KEY never contains\n `sourceSeq`, delivery attempt, mapping revision, or writer op id (a redelivery of the\n same logical acceptance MUST land on the SAME key); where a digest stands in for the\n tuple it is a versioned, collision-resistant digest of exactly that tuple, never\n delimiter-ambiguous concatenation. The VALUE pins the first winner under a CLOSED\n per-class schema: every row carries `{ state: provisional | accepted | rejected |\n terminal, decision: epf | self, opId }` plus the currency pins taken above\n (`mappingRevision` iff target-bound, `policyRevision` iff policy-admitted; at least one\n present); an `epf`-class row (a canonical acceptance) adds `{ fingerprint, sourceSeq,\n route }`; a `self`-class row (a guarded record commit, e.g. the restart-status CAS,\n §13.6) adds the COMPLETE commit intent `{ commitKey, commitBaseRevision, commitValue,\n commitDigest }`: the exact record key its accepted state authorizes, the store revision of\n that record the commit CASes FROM, the value it commits, and that value's digest.\n `commitValue` is a CLOSED discriminated union, so two implementations resolve and replay the\n SAME value: `{ enc: \"b64u\", bytes }` carries a JSON encoding of the committed value,\n base64url-encoded (RFC 4648 §5, no padding), or `{ enc: \"ref\", key }` names an\n IMMUTABLE, create-only records key (the §13.7 `policy` kind or another never-overwritten\n key) whose stored value IS the commit value; a mutable or absent `ref` target\n refuses at recovery, fail-closed. Never only a digest (a digest cannot reconstruct the\n value a crash recovery must re-write). `commitDigest` is the RFC-8785 CANONICAL content\n digest of the committed value, `sha256:<hex>` (the same `*Digest` scalar shape §13.7 uses\n everywhere; over the CANONICAL value, never a non-canonical storage stringify, so the\n landed/not-landed comparison is insensitive to how the store serializes the record). A\n crashed writer's commit is thus deterministically finishable from the row alone (below). The\n `decision` class is fixed by the TRUSTED operation kind, never caller-selectable. A\n create loser leader-reads the winner: the FULL pinned identity must match to join (an\n `epf`-class row on coordinate + fingerprint + route; a `self`-class row on the ENTIRE commit\n intent `commitKey` + `commitBaseRevision` + `commitDigest`, so two different desired values\n or base revisions never join under one `commitKey`); any\n mismatch is `conflict`, never a second obligation. (2) **Proof issuance is a post-create\n currency recheck, and admission is proof-gated**: after winning or joining the create,\n the mediator leader-reads the SAME coordinates AGAIN, and only if the target head is\n still `active` at the pinned `mappingRevision` AND (for a policy-admitted decision) the\n governance head STILL stages no `pendingPolicyKey` and the enforced policy is still at\n the pinned `policyRevision` does it return the opaque admission proof; otherwise it\n IMMEDIATELY settles its own provisional through the row's decision coordinate (below) and\n refuses. The recheck reads the SAME govern head the create-fence read, so a\n `pendingPolicy` staged in the window between the create and the recheck also fails\n proof issuance, not merely a moved `enforcedPolicyRevision`.\n No target-bound or policy-admitted EPF acceptance may publish, and no `self`-class\n guarded commit may run, without an unexpired proof issued under this rule. This is the\n structural half of the head fence: an obligation created in the window between a fresh\n `active` read and a head or policy movement exists durably, but its proof can never\n issue, so it can never admit; it is inert cleanup debt any later drain settles. (3) The\n EPF decision CAS runs as\n specified (§13.4), publishing with the WINNER's pinned acceptance identity and\n `sourceSeq`, whichever delivery is processing; a `self`-class writer instead advances\n its own row `provisional → accepted` (revision-pinned) and performs its guarded commit\n only while the row is `accepted`. (4) On acceptance the SAME key advances\n `provisional → accepted` and is retained until the accepted route is\n terminal and cleaned: the only enumerable record of accepted work is never\n erased at the moment it wins. States are monotonic (`provisional → accepted →\n terminal`, or `provisional → rejected`), the row is NEVER-DELETED, and a DEL/PURGE\n marker is corruption. The stored `opId` is not a bearer capability: a resuming writer\n re-authenticates as the same endpoint-scoped principal through the mediator and joins\n by acceptance identity + fingerprint; any opaque reservation token the mediator issues\n is target/endpoint/connection-bound, bounded-lived, and checked against the CURRENT\n obligation state; the durable obligation is the authority, never possession of its\n identifier. **The decision coordinate is per-class** and is where every unresolved row\n settles: an `epf`-class row settles through the EPF decision subject's create-only CAS\n (read the winner; if absent, create-only publish the terminal rejection so a delayed\n acceptance CAS loses; the mediator holds that rejection-publish authority and executes\n it for its own recheck refusals and on behalf of the drains, §13.9); a `self`-class row\n settles on ITSELF: while still `provisional`, the drain CASes `provisional → rejected`\n (the writer's `provisional → accepted` CAS and the drain's rejection contend on the ONE\n row, exactly one wins, and a delayed guarded commit finds its authority gone). An\n `accepted` `self`-class row is NOT stuck and does NOT block quiescence: because the row\n pins the complete commit intent `{ commitKey, commitBaseRevision, commitValue, commitDigest }`,\n either\n the writer's own resume OR a drain reconciler drives it `accepted → terminal`\n deterministically. Read the record at `commitKey`: if its value canonically digests to\n `commitDigest` the commit landed, CAS the row `accepted → terminal`; if it is still at\n `commitBaseRevision` the commit did not run, re-apply it by CASing the resolved\n `commitValue` (decode `b64u`, or leader-read the immutable `ref` key's value, verifying its\n canonical digest against `commitDigest` BEFORE writing) at\n `commitBaseRevision` then CAS the row terminal; if the\n record has moved PAST\n `commitBaseRevision` to a foreign value the intended commit can never land (the guarded\n CAS would lose), so CAS the row straight to `terminal` as superseded. Quiescence therefore\n means NO `provisional` and NO un-driven `accepted` `self`-class rows remain: an accepted\n commit is always completable from the row alone, never an unrecoverable orphan. **Reclamation is never\n clock-only**, and because the EPF writer need not be the retiring lifecycle (a\n cross-endpoint canonicalizer publishes decisions bound to a foreign target, and revoking\n the TARGET's credential family disarms nothing that writer holds), target-side\n revocation alone is NEVER the reclamation condition. An unresolved `provisional` is\n reclaimed only by: settling it through its decision coordinate; or revoking +\n verified-evicting the WRITER's own commit authority; or the target head being\n non-current AND the drain below having completed to quiescence under the create fence +\n proof gate. A timeout alone never frees a slot\n while the writer retains publish authority. **Drain to quiescence**: after the head\n CASes to `retiring` (§13.1), and equally when a policy mutation must enforce a new\n revision (§13.6, enumerating `oblig.*.<endpoint>.>`), the drain enumerates the prefix\n (`oblig.<targetUid>.>` for retirement), settles every\n unresolved row through its decision coordinate, completes accept-side reconciliation\n (enqueue/goal/terminal, §13.6) for accepted rows, then RE-ENUMERATES, and records its\n cleaner and frontier completion (or treats the new policy as enforced) only when an\n enumeration finds no unsettled row. A provisional whose pinned `mappingRevision` or\n `policyRevision` is no longer the live coordinate is settled as REJECTION, never treated\n as still open for acceptance. A row created after the final enumeration cannot admit\n (its proof can never issue, step 2) and is settled by any later enumeration;\n an acceptance published after the recorded cleanup frontier from a\n stale `active` read is non-conformant even if later effect resolution would reject it.\n Whether the obligation is released once the route is settled under ordinary policy\n movement (`release-after-accept`) or survives as cleanup debt the terminal barrier must\n observe (`promote-to-lifecycle-obligation`) is fixed by the TRUSTED operation kind,\n never caller-selectable. The admission-policy specialization additionally binds\n identity at the read: the confined policy reader's request subject pins the\n authenticated canonicalizer endpoint AND the requested policy endpoint, requires their\n equality, derives the reply rail from that authenticated subject, and returns\n `{ policy, revision }` with an opaque proof binding `{ space, endpoint, policy\n revision, obligation/op id }`; endpoint A can never obtain, or replay, endpoint B's\n admission proof.\n- **Retry/backoff.** Only idempotent-at-scope operations are retried: exponential backoff,\n base 250 ms, factor 2, cap 15 s, full jitter, bounded by the caller deadline.\n- **Deadlines.** Mandatory on call, scatter, claims, checkpoints, timers, sessions. Reference\n default call deadline 15 s; defaults are overridable, never removable.\n- **Cancellation ordering.** First terminal fact at the mediated commit point wins.\n- **Watch recovery.** Fell-behind ⇒ snapshot re-read then resume; bounded relist; no silent\n gap-skipping.\n- **Ordering/partitioning.** Per-subject only; the subject is the partition key.\n- **Retention floors.** Submissions ≥ recovery/redelivery lag (§13.12; native dedupe is not\n relied upon, §13.4); facts/tombstones ≥ idempotency horizon;\n results ≥ result retention; receipts ≥ receipt retention; timers ≥ max deadline + recovery\n margin. **Pool coupling:** every accepted pool item carries an **absolute work expiry**\n (`workExpiry`, set at acceptance in the AcceptanceFact, NOT a per-message age a\n reconciliation re-publish would reset; a re-enqueue re-publishes with the SAME `workExpiry`,\n and the item is dead once it passes, leased or not). The EPW stream's max age is ≥ the\n maximum `workExpiry` + recovery margin, and a pool item's decision and `wrk` terminal facts\n are retained ≥ that same bound, so a live (or crash-recovering) item can never outlive the\n facts that identify it as accepted or settled: a decision that expired under a still-live\n item would let a reused id collide with the old enqueue, and an expired `wrk` under a\n lost owner ack would make settled work unrecognizable on redelivery. A reused `id` becomes\n new work only after the old item's `workExpiry` AND its facts' retention have both passed.\n An endpoint MUST refuse to start against a store below its declared floors.\n- **Backpressure and budgets.** Bounded consumer pending (default 1024), bounded\n virtual-endpoint pools and session windows, flow control on watches; overload is\n `resource-exhausted`. Schema compile/validate budgets (reference: 100 ms / 10 ms) and\n bounded regex; over budget is `contract-invalid`/`bad-request`.\n- **Timers.** Broker message schedules at the 2.12 floor; same-subject replacement only (at\n the mediated `.armed` subject, §13.12); generation- and scheduler-origin-validated firing\n (stale or foreign-origin ⇒ no-op); durable reconciliation repairs\n status↔schedule divergence; replication and offline-assets downgrade fail loud at the\n broker floor gate.\n\n### 13.9 Authority boundary\n\nThe credential is the coarse boundary; every subject in §13.2 is default-deny. Every\n**statically expressible** authorization dimension is broker-enforced through the subject\ngrammar: caller identity + lifecycle, endpoint,\ncommand, the target components each mode pins statically (§13.2: the full triple for `self`,\nthe caller's own, and for `handle`, redemption-pinned; the owner for\n`owner`/`any`/`child`/`ledger`), serve identity, reply\n**attribution**, and plane writer ownership.\nReply **addressing** is the one deliberate exception: it is capability-by-secret (the\nper-request nonce, §13.2), not a broker grant, and it is sound precisely because serve\ncredentials cannot plain-subscribe the class rail (queue-qualified grants, §13.2), so nonces\nare visible only to the instance the queue selected (plus every instance on a scatter, which\nis scatter's definition). Target enforcement is stated per mode, never as a blanket claim:\n`self` is broker-confined end to end including the lifecycle UID; `handle` is broker-confined\non the full redemption-pinned target triple, with the validator re-checking only mapping\ncurrency; `owner`/`any` are broker-confined on the target owner and validator-primary on the\nactor and UID currency; `child`/`ledger` are validator-primary within their distinct broker\nrails. The **named dynamic relations** (static-mesh\nown-child, fresh-ledger escalation, target-mapping currency, authorization epochs after\nacceptance) are trusted-validator-primary by design, fail-closed, and operate only within\nthe broker ceiling. Handlers only narrow. **The process epoch fences only the five planes\nwhose subjects carry it** (reply, `epe`, `ept`, `eps`, `epr`). Request-ingress subjects and durable record\nkeys cannot carry it; the caller cannot know it, and a restart-stable key must not change,\nso those two classes are fenced by the mechanism each admits: records by mediation (writer\ntable below), ingress by credential revocation with verified eviction (§13.1), never by\nsubject.\n\n**Caller grants.** Minting maps each named capability to exact endpoint+command subjects:\npublish on the request forms (class + instance) with the authz-mode/target pattern the\ncapability specifies, subscribe on the caller's own reply rail, publish on matching `epj`\nsubmission subjects for journaled commands, and the exact record-key / event-topic subtrees\nfor attribute/event read capabilities (per-goal containment rides the caller triple in the\ntopic). The caller's lifecycle UID token is pinned in every granted subject, so a credential\nis dead against its principal's next lifecycle by construction. Wildcards are bounded: `*` in\nthe command position only when the capability covers every command of the endpoint; `*` in\nthe endpoint position never, outside operator/admin profiles; `child`/`ledger` mode subjects\nare never covered by an `owner`-mode wildcard. `describe` is granted by default for all\nendpoints; a space MAY narrow it. Because the subject shape is verb-invariant (§13.2), one\npublish row covers call and cast of a command. Minted credentials MUST stay within the\ndeployment's JWT size envelope, and the envelope is validated against a **normative\nmaximum-capability fixture**, not an adjective: the reference fixture is an agent holding\nevery baseline grant plus capabilities on 3 endpoints x 12 commands each, each targeted\ncommand in both `self` and `owner` modes, plus journaled submissions and per-goal read\nscopes for all of them. Minting MUST fail loud before emitting a credential that exceeds the\npolicy gate (reference: 16 KiB); the transport bound is the CONNECT control line\n(`max_control_line`, §13.12) and the policy gate MUST be the tighter of the two. The mint\nMUST also refuse, before any issuance record is written, a user JWT whose byte size exceeds the\ncontrol line minus the CONNECT envelope (`MAX_MINTED_JWT_BYTES`), so a composition of individually\nvalid grants can never produce a credential the broker drops silently. The fixture\nset additionally includes a **maximum-command serve credential** (a 12-command endpoint's\nper-command rows, below); the §13.12 operator assertion uses the largest encoded CONNECT\nline in the set.\n\nThe agent baseline includes the self-targeted manager command `run-answer`. Its grant is only the\n`self` request form. The manager MUST authorize a baseline managed seat only when an open `ask` or\nescalated checkpoint is named by a pending relay addressed to that exact caller incarnation, and\nMUST refuse every other run or pause. A caller holding the explicit `run` capability may use the\nsame self-targeted form for ordinary run answers. The request never carries the answerer's name.\nThe amend form of `run-answer` (§14.5) addresses a settled pause instead, and the manager MUST\nauthorize it for a baseline managed seat only when the accepted answer it supersedes was recorded\nunder that seat's own name.\n\n**Serve grants.** Serving is granted authority, dual to calling. On the **subscribe side**\nan instance's credential binds its registered service name, stable instance id, and\n**registered command set**, one queue-qualified subscribe row per registered command\n(matrix below), never a bare `>` tail spanning commands the instance did not register. The\nper-command enumeration is affordable precisely where the caller-side equivalent is not:\nserve credentials are one per instance, a handful per space, with no capability-count\nscaling pressure. The subscribe side deliberately does NOT bind the epoch; a caller cannot\nname the serving epoch, so no request subject carries it and **ingress cannot be\nepoch-fenced by subject**; the fence for a superseded subscriber is the §13.1 takeover\nbarrier (revoke + cluster-verified eviction), not a grant shape. On the **publish side** the\ncredential binds the epoch everywhere it is real: the epoch-pinned reply prefix, the\nepoch-pinned `epe` event plane, its `ept` timer schedule requests, and its `epr`\nrecord-write ingress. Session subjects are\ndeliberately absent from the standing serve grant: both sides of a session hold only\nredemption-minted per-session credentials (§13.6); no standing EPS grant exists on either\nside. The credential also carries the record keys the writer table assigns it and, where\nthe endpoint owns a work pool, the pool's consumer + ack grants (§13.5; matrix below).\nNothing else. Every \"binds X\" in this paragraph has a matrix row below that actually binds\nX. Serve\ncredentials are re-minted on takeover (new epoch, §13.1 barrier); a superseded credential's\nreplies and commits are rejectable by epoch. Core names require operator provisioning\nauthority; reverse-DNS names bind to their registered owner. The registry is discovery; the\nserve grant is the authority: a foreign credential cannot subscribe a class rail, answer as\nan instance, or enter a frozen scatter set.\n\n**Remote manager-service grant.** The server-authored `manager-service` view is an\ninstance-scoped authority family, not a reusable host profile. Its generated grant is the exact\nunion of the one manager instance's serve rows, its one service registration/status mediator,\nits staged contract-publication row, `epgate.manager.<instanceId>`, and\n`epcred.manager.<instanceId>.<credentialId>`; no wildcard may span an instance, manager actor,\nowner, endpoint, record kind, contract digest, or credential id. The trusted auth path alone owns\ngate/ledger writes and all host signing. The manager service's descendant-provision request is\nmediated by that host path and MUST re-derive the requested agent's owner from the authenticated\ncaller, require it to equal the manager-service owner, and fresh-validate the active grant before\nminting any child material. It is never a raw provisioner, stream, KV, consumer, signer, or\ncross-owner control grant. The registration and renewal operations are typed/idempotent as §13.6\nrequires, and their stage records remain inaccessible to every ordinary agent, observer, admin,\nor managed-agent exchange.\n\n**Platform control grant.** The `platform-control` view's generated grant is the remote\nmanager-service grant above with the platform owner token as owner: the union of the one assigned\ninstance's serve rows, its one service registration/status mediator, its staged\ncontract-publication row, `epgate.manager.<instanceId>`, and\n`epcred.manager.<instanceId>.<credentialId>`, with no wildcard spanning an instance, manager actor,\nowner, account, endpoint, record kind, contract digest, or credential id. Descendant provisioning\nMUST re-derive the requested agent's owner from the authenticated caller and require it to equal\nthe platform owner token. Serve-time admin authorization answers `authorized: true` only for a\ncaller whose owner equals that token; a human `admin` scope never authorizes against it. It is\nnever a raw provisioner, stream, KV, consumer, signer, launch, or cross-owner control grant.\n\n**Environment manager grants.** `environment-bootstrap` is a fixed, ephemeral caller\nprofile for the host-admitted bootstrap triple. It publishes only the literal instance\ncommand rows `ep.inst.<authorityEndpoint>.<authorityInstanceId>.<command>.<cO>.<cA>.<cUid>.*`\nfor the closed set `describe`, `bootstrap` and `bootstrap-status`. `describe` is read-only\nand supplies the current authority epoch; it issues no workload material. It subscribes\nonly to its native caller rail `ep.reply.*.*.*.<cO>.<cA>.<cUid>.*` and its own\nconnection-scoped inbox. The native reply filter includes the broker's reserved\nno-responders sentinel and matches the standard client's subscription. It exposes no\nother caller's replies; every accepted response still binds the request nonce, endpoint,\ninstance and current epoch. Endpoint and instance tokens use §13.2's native encoding. The\ncommands are ephemeral and untargeted; the nonce is the only wildcard request token.\nThe released stock bootstrap client embeds both complete command contract artifacts and\nverifies their digests against the admitted file before sending. The stock path uses\nnative instance-pinned `describeEndpoint` to observe the authority epoch, verifies its\ncommand declarations against the embedded contracts, then invokes native `epCall` with\nthat instance/epoch and the pre-effect bind. It neither fabricates `ResolvedService` nor\nrequests arbitrary contract artifacts. An authority restart permits a fresh read-only\ndescribe followed by the same held bootstrap-status or bounded operation, never a new\ncreation or lifecycle. A changed contract pin refuses. No artifact-store, class or scatter\ngrant is needed. This profile grants no messaging, presence, JetStream API,\nconsumer, KV, manager, signer or other authority-endpoint access.\n\nThe admitted manager keeps five locally generated identities but uses fixed\n`environment-manager-supervisor` and `environment-manager-executor` profiles in place of\n`remote-manager` for those two duties. Neither holds publish, read, scan, consumer-create,\nupdate, delete or purge authority on `cotal_auth_<space>`, nor direct service registration,\ncontract publication, governance or repair writes. The trusted host performs those bounded\neffects through native barriers under the authenticated authority command. The existing serve and session-ledger profiles keep their own duties and MUST NOT gain\nan authority-family write or auth-store scan through this addition. The goal-writer\nidentity uses fixed `environment-manager-goal-writer`: native goal/coordination rows for\nthis manager, but no auth-store `STREAM.MSG.GET` or consumer access. Its optional own-gate\nfast-fail read is omitted; the native barrier revoke and verified connection eviction\nremain the durable supersession fence. The stock manager skips installing the optional\ngoal-writer gate belt for this family; it MUST NOT open the auth bucket and tolerate a\ndenial. The accepted residual is a deposed incarnation's ability to initiate terminal\npublishes from barrier start until its eviction is verified, the existing §13.1 class for\nother endpoints on an auth mesh. Removing the belt MUST NOT add a fallback or permit\nwrites after verified barrier revocation/eviction.\n\nThe environment supervisor holds its exact\n`$KV.cotal_manager_<space>.lease.<instanceId>` create/CAS row, manager-bucket\n`STREAM.INFO` and leader `STREAM.MSG.GET` rows for lease binding/read, `$JS.API.INFO`,\nits own presence write, existing presence-roster watch and flow control, manager-plane\nliveness serve/reply rows and its own inbox. Those manager/presence bucket reads confer\nno auth-store access. It holds no broad manager/profile grant. The environment executor holds only the fixed instance caller rows for `describe` and\n`authority`, under `<cO>.<executorActor>.<managerUid>`, its native own-caller reply filter\nand its own connection inbox. No command, endpoint, instance or caller wildcard is added. Any required\nregistration, gate, goal-index or credential-currency read is host-mediated, not a broad\nstream read granted to the guest. This row is authority-request access, not an issuance or\nledger-write grant. The host binds it to the admitted account, environment, manager instance,\nexecutor nkey, UID and expiry; it accepts no user-selected profile or command wildcard.\nLike bootstrap, the stock executor binds the current epoch with instance-pinned native\ndescribe and uses the embedded `authority` contract through `epCall`, never a fabricated\n`ResolvedService` or a contract-store read. Standard reply attribution and pre-effect bind\nchecks remain mandatory.\nThe family still holds no account signer, provider API key or foreign instance authority.\n\nThe trusted host alone writes admission/reservation and credential-custody records and\nperforms issuance and external retirement through their existing native barriers. No guest\ncredential receives that private store's reads, writes, deletes, scans or consumer access.\nGrant generation MUST use the ownership rows below. This amendment adds two fixed mediated\nregistration profiles and the narrowed goal-writer profile, rather than adding caller\nrows to the shipped direct `remote-manager` grant.\nNeither these profiles nor their authority caller rows may be issued through ordinary\nhuman or platform-control registration. Tests MUST attempt raw broker writes and auth-store\nscans with every guest credential, not merely pass them through trusted-path parsers.\n\n**Manager status metadata.** The Manager `status` contract permits optional string fields\n`host` and `version`. The stock Manager emits its answering process's host name and its own\nrunning `@cotal-ai/manager` package version, captured at module load. These fields are advisory\nonly and MUST NOT grant authority, select a route or determine placement. Callers MUST use\nverified responder attribution for instance identity and accept payloads that omit either field\nwithout inferring a value from the broker, browser, presence or service registry.\n\n**Platform readiness read.** A platform composition learns whether its assigned control manager\ninstance is serving through the auth context's readiness read. The trusted auth process answers over\nits own self-minted reader connection and hands out neither that connection nor its credential. The\nreader's grant is the `describe` and `status` request rows on `ep.inst.manager.<instanceId>` for the\none assigned instance under the reader's own caller triple, the subject-scoped contract-store Direct\nGet, its own reply rail, and its own `_INBOX_<connId>.>`. It holds no other command, instance, class\nor scatter route, no other store read, no KV write, and no signer. The read observes the current\nassignment on every call, refuses any other instance, and refuses an instance whose gate names\nanother principal. The reader renews as the other self-minted authority connections do: a\nshort-lived user JWT re-minted in process at a random point between 50% and 80% of its lifetime,\nafter which the connection reconnects onto it.\n\n**The ownership matrix (normative).** Every profile × resource × transition is classified\n**mediated** or **direct**, in an independently reviewed matrix from which grants are\ngenerated (never the reverse). Each row names the writer PROFILE, the exact subject/API\nnamespace (including the queue qualifier where one applies; the grant grammar has a queue\ndimension, §13.2), the operation, and the enforcement class; **read, consume, ack, and\ndelete authority are rows in the same table**, never prose that \"follows\" it. Every\ncredential and every audit probe is generated from these rows.\n\n**Consumer-name grammar (normative).** Every consumer a row names has a pinned name grammar\n(dash-form, §2; `<e>` is the endpoint-name token, `<uid>` the holder's lifecycleUid or\ninstanceId): `canonD = canon_<e>` (the canonicalizer durable), `poolD = pool_<e>_<pool>`\n(the pool durable, **pre-created by the provisioner** with exact filter\n`cotal.<space>.epw.<e>.<pool>.>`, the §8 item-3 pattern: the bare create form is\nbody-filter-selectable and is granted to NO ONE on control-surface streams), `timerD =\ntimerw_<space>` (the timer writer durable), `recwD-k = recw_<space>-<kind>` (one record\nwriter durable PER RECORD KIND, §13.9), `effD = eff_<e>` (the endpoint's ONE shared\neffects durable; below), `goalD = goal_<uid>-<e>` (the caller's own goal-result durable).\nEvery composite name is **collision-free by construction**, and\neach derivation states why: `pool_<e>_<pool>` parses uniquely from its LAST `_` because a\npool token contains no `_` (`[a-z0-9-]`) while `<e>` may (a dash separator would be\nambiguous, both tokens admit `-`); `dec_<uid>-<e>` parses from its FIRST `-` because\n`<uid>` is `[a-z0-9]` and contains none, and `goal_<uid>-<e>` likewise; `eve_<uid>-<e>-<gid>-<n>`\ncarries TWO `-`-adjacent soft components (`<e>` and `<gid>`), so `<gid>` is constrained\nSEPARATOR-FREE (`[a-z0-9]`, no `-` or `_`): then `<uid>` (leading, `-`-free), `<n>` (trailing\ndigits) and `<gid>` (separator-free) are each a single token off their edges, leaving `<e>` as\nthe only `-`-bearing component with an unambiguous extent (`eve_<uid>-a-b-c-0` can ONLY be\nendpoint `a-b`/gid `c`, never endpoint `a`/gid `b-c`). `rec_<uid>-<gid>-<n>` has one soft\ncomponent `<gid>` bounded by `-`-free `<uid>` and digit `<n>`. Without the separator-free `<gid>`\nthe two grants above would collide on one durable name. A derivation that cannot state its\ncollision-freedom argument is non-conformant. Reader consumers use **mint-time-enumerated LITERAL names**, and every one\nis **pre-created by the provisioner at capability mint as a PULL durable with its exact\nfilter; the holder receives BIND-ONLY grants** (INFO/MSG.NEXT/ACK, never CREATE or\nDELETE): `decD = dec_<uid>-<e>` (one per journal capability), `goalD = goal_<uid>-<e>`\n(one per action capability),\n`eveD = eve_<uid>-<e>-<gid>-<n>` and `recD = rec_<uid>-<gid>-<n>` (one per granted subtree;\n`<gid>` is the **grant id**, a short stable SEPARATOR-FREE (`[a-z0-9]`) id the provisioner\nassigns per minted capability grant, so two independent capability mints for one lifecycle UID\nnever collide AND the `<e>`/`<gid>` boundary stays unambiguous, and `<n>` is\nthe subtree's zero-based index within THAT grant, sorted lexicographically at mint; the\ndeprovision key is `<uid>-<gid>`, so revoking one capability deletes exactly its own reader\ndurables and cannot reach a sibling capability's). Two reasons, both\nload-bearing. A NATS wildcard replaces a\nWHOLE dot-separated token and never matches inside one, so an embedded `*` in a name token\n(e.g. `dec_<uid>-*`) is a literal character, not a glob; every name token in a grant is\nfully literal.\n\n**Mediated reads (normative).** No untrusted capability holder is granted **any** raw\nJetStream read of a control-surface stream, not a consumer create, not a bind-only pull,\nnot a `DIRECT.GET`. Every JetStream read is request/reply where the server delivers stored\nbytes to a **caller-chosen destination the broker does not confine to the caller's\n`pub.allow`**: a push consumer's `deliver_subject`, a pull `MSG.NEXT` request's reply\nsubject, and a `DIRECT.GET` request's reply subject are all set in the request body, and the\nserver's internal client publishes there regardless of the requester's publish permissions.\nA holder with only `MSG.NEXT` or\n`DIRECT.GET` on its own filtered reader can therefore route stored bytes onto a victim's DM,\nreply, or record subject, a confused deputy no filter tail, literal name, or pull-vs-push\nchoice prevents, because the destination is the vulnerable field, not the filter. Untrusted\ncallers instead read exactly as the §8 durable backstop already does, through a **trusted\nread path**, never a self-bound consumer: a caller receives its decisions, goal results,\nevent catch-up, and record reads over its OWN confined rails, a live core subscription to a\nsubject inside its `sub.allow` (bytes land only on the caller's own subscription), or a\nmediator that owns the reader consumer, re-authorizes each read against the caller's current\ngrants, and returns bytes over the caller's own attribution-pinned reply rail\n(`ep.reply.…<caller triple>.<nonce>`: the mediator holds the publish grant, the caller the\nread grant, and the nonce confines addressing, §13.2). The mediator IS a trusted\nsingle-purpose principal (the delivery/read daemon, §8/Appendix B) that delivers only to the\nre-authorized caller and never proxies to an arbitrary subject; raw\nconsumer/`DIRECT.GET`/`STREAM.MSG.GET`\nauthority stays with trusted single-purpose infra principals (canonicalizer, commit\nprincipal, record writer, timer writer, the read mediator, the auth path) that deliver to\nthemselves. A registered endpoint MAY also mediate its own callers' goal-result reads through\nits separate trusted commit/read connection. Each request MUST be authorized by the requesting\nconnection's broker-enforced command grant on its authenticated caller triple. User-auth revocation\nhas the same bearer-lifetime bound as other live endpoint commands; renewal requires a fresh\nexchange and connect that re-authorize the caller. This read does not claim a per-request ledger\ncheck. The endpoint and full caller triple MUST come from the broker-authenticated request\nsubject; caller input supplies only the goal id. The response MUST\nuse the derived attribution-pinned caller reply rail, never a caller-supplied destination. This\nhosting choice grants no raw read to the endpoint's serve credential or to its callers. The\nexisting trusted reader's body-selected, space-wide leader-read residual MUST remain documented.\nThis contract fixes the boundary; untrusted callers never hold raw reads; reads are mediated onto\nconfined caller rails, and leaves the read-command wire shape (batching, cursors, flow control) to\nthe reference implementation.\n**Subject convention:**\napplication subjects in rows are written relative and are prefixed `cotal.<space>.` on the\nwire; **JetStream API tails (extended-create filter tails and `DIRECT.GET` subject\ntails) are always spelled in FULL** (`cotal.<space>.…`/`$KV.…`/`$O.…`), because the API\nsubject embeds the stored subject verbatim and a relative tail matches nothing (the\nstreams capture `cotal.<space>.ep*.>`, §13.12).\nThe grep tests the matrix MUST pass: the only `CONSUMER.CREATE` grants below belong to\ntrusted provisioning/infra profiles and each carries a full literal filter tail; every\nconsumer-name token in a grant is a LITERAL (no embedded `*`); every filter or Direct-Get\ntail is fully qualified; **no UNTRUSTED profile (agent/observer/admin) holds any\n`CONSUMER.CREATE`/`MSG.NEXT`/`DIRECT.GET`/`STREAM.MSG.GET` on a control-surface resource** (an\naudit MUST run this over Appendix B too, not only this matrix; the profile tables are\ngenerated from these rows, so a generated grant that contradicts the matrix fails the build);\nand the ONLY `STREAM.MSG.GET` (body-selected) grants that exist at all are the leader-served\nreads of named TRUSTED single-purpose profiles, each granted to no other profile - every one\na FENCING read (read service, below) except where its row names it a CAS-PINNING read, a\nleader-served currency read whose FENCE is the pinned CAS write it feeds (§13.1: a read is\nnever a fence): the auth path and the host-private tool-result snapshot reader on\n`KV_cotal_auth_<space>`, the lifecycle mapping-reader and\nthe provisioner-registration principal on the `cotal_records_<space>` heads, the endpoint's\ncanonicalizer on `EPF_<space>`/`EPW_<space>`, the endpoint's commit principal on its own\n`EPF_<space>` fact families AND on `KV_cotal_records_<space>` (its goal/checkpoint FENCING\nspec-and-currency reads: the terminal-commit's spec read and the epoch/deadline reads the\nread-service clause names), each record kind's spec/status writer principal on\n`KV_cotal_records_<space>` (its fresh lifecycle-mapping `processEpoch` currency read, the\nwriter-table stale-writer fence; per §13.1 a mapping yields a current epoch ONLY at\n`state: \"active\"`, and `retiring`/`retired` alike refuse the write), and the space's timer writer on\n`KV_cotal_records_<space>` (its fresh generation/deadline check before arming, a FENCING\nread) and on `EPT_<space>` (`$JS.API.STREAM.MSG.GET.EPT_<space>`, the armed-subject's own\nlast-by-subject sequence read: CAS-PINNING, the leader-served input to the arm's\n`Nats-Expected-Last-Subject-Sequence` publish, whose broker CAS - not the read - is the\nfence, the same §13.1 complementarity class as the FIRE handler's status CAS). The timer\nFIRE handler holds no records `STREAM.MSG.GET`: its settlement is a revision-pinned status\nCAS, so a stale read loses the CAS loudly (§13.1 complementarity), never mis-fires (the\nmatrix rows below). The body-selected form is not\nsubject-confinable by the broker, so each of these grants trades broker confinement for\nprofile trust; the trade is acceptable exactly because every holder IS a trusted\nsingle-purpose principal for whom read-your-writes is a correctness requirement, not a\nhazard (on the `allow_direct=false` buckets a leader-consistent get is precisely a\n`STREAM.MSG.GET`). Every OTHER subject-scoped read is NON-fencing and uses the\nlast-by-subject `DIRECT.GET.<stream>.<subject>` form, which the broker confines by subject\ntokens. (The pre-v0.4 messaging-surface CHKV/DLVKV reads in Appendix B are the v0.3 binding,\noutside this matrix; their confused-deputy exposure is the §9 in-scope-for-v0.4 remediation.)\n\n**Read service (fencing reads are leader-served).** A read is FENCING when its result, a\nvalue, a revision, OR an authoritative ABSENCE, gates a subsequent CAS or authorizes an\neffect; fencing is defined by USE, never by subject family. A CAS loser reading the winner,\na terminal-commit's spec read, and the work-pool re-enqueue predicate (accepted, with the\nauthoritative absence of BOTH a committed terminal and a live `EPW` entry, §13.6) are all\nfencing: a stale follower read that misses a committed terminal while the `EPW` entry is\nlegitimately absent re-arms settled work. A fencing read MUST be leader-served, meaning one\nof `STREAM.MSG.GET`, a get against a bucket with `allow_direct=false`, or delivery\nserialized by the authoritative primary stream/consumer (an authoritative `MSG.NEXT`, e.g.\nthe accepted-fact effects row and the auth path's snapshot enumeration below), and it MUST\nbe served against the AUTHORITATIVE stream or bucket for its key, never a mirror, a sourced\nstream, or a cross-space replica (\"leader-served\" means that authoritative primary; a\nmirror's own leader can lag its source). `allow_direct=true` and Direct Get exist for\nNON-fencing, subject-confined reads only; a client MUST NOT let a fencing read silently\nride Direct Get because the bucket allows it. This does not weaken §13.1's rule that a read\nis never a fence: the fence itself stays a CAS or create-only write; leader service is what\nkeeps the read's result from silently falsifying the CAS or effect it feeds.\n\n| Transition | Writer profile | Exact namespace (per space/endpoint) | Class |\n| --- | --- | --- | --- |\n| Native current-connection identity | one-shot `provisioner` | publish only `$SYS.REQ.USER.INFO`, subscribe its existing connection-scoped inbox. The configured NATS system account imports/maps this service to the requesting connection's own account and user; no arbitrary-account/user variant or system credential is granted. Clients compare the response's user/account and serving server with their pinned connection. Response permissions, expiry and metadata are not an issued ceiling, lifecycle or apply authority | native NATS read; own connection only |\n| Request publish | capability holder (agent, per capability) | per §13.2 form: `ep.{one,all}.<endpoint>.<command>[.<mode>[.<target tokens per mode>]].<cO>.<cA>.<cUid>.*` and `ep.inst.<endpoint>.<instanceId>.<command>[.<mode>[.<target tokens per mode>]].<cO>.<cA>.<cUid>.*`, mode/target tokens literal per the minted capability (`handle`: the full redemption-pinned triple) | direct, untrusted input, broker-confined |\n| Reply subscribe (caller) | capability holder | `ep.reply.*.*.*.<cO>.<cA>.<cUid>.*` (exact arity) | direct read; own rail only |\n| Serve subscribe | the endpoint's serve credential | per registered command: `\"ep.one.<endpoint>.<command>.> <endpoint>\"` (queue-qualified ONLY), `ep.all.<endpoint>.<command>.>` plain, `ep.inst.<endpoint>.<instanceId>.<command>.>` exact (never a cross-command `>` | direct) name/instance/command-pinned; epoch deliberately absent (§13.1 barrier is the fence) |\n| Reply publish | the endpoint's serve credential | `ep.reply.<endpoint>.<instanceId>.<epoch>.*.*.*.*` | direct; attribution-pinned; addressing by nonce |\n| Versioned-rail request, reply, serve (§13.15) | as the four rows above | the same rows with `ep.v1` for `ep` and one more pinned token: the caller's `<generation>` literal in its request-publish and reply-subscribe rows (`ep.v1.reply.*.*.*.<cO>.<cA>.<cUid>.<generation>.*`), a spanned token in the serve credential's reply-publish row (`ep.v1.reply.<endpoint>.<instanceId>.<epoch>.*.*.*.*.*`) and its three serve-subscribe shapes per command | direct; broker-confined on the generation exactly as on the caller triple |\n| Issuance (§13.15) | the `issuer` principal, minted by the party holding the space signer: one auth-service session per account, space and authority plane for its callout's user-auth issuance, renewed before expiry; one-shot per issuance window or lifecycle terminal otherwise | `$KV.cotal_issued_<space>.>` and `$KV.cotal_accepted_<space>.>` publish, `STREAM.INFO`/`STREAM.MSG.GET` on `KV_cotal_issued_<space>`, `STREAM.INFO` on `KV_cotal_accepted_<space>` (the bind-time shape check of both stores), its own ordered consumers on that store, and ONE leader-served `STREAM.MSG.GET` on `KV_cotal_auth_<space>` for source liveness; NO auth-store write, no rail row | mediated; create-only CAS on evidence, revision-CAS on the attempt row |\n| Run admission (§14.8) | the `run-admitter` principal (one-shot, 60 s, minted per run by the hosting endpoint or the local operator) | exactly `$KV.cotal_admission_<space>.admission.v1.<endpoint>.<runId>` and `….revoked.v1.<endpoint>.<runId>` publish plus `STREAM.MSG.GET` on that store; nothing else | mediated; create-only |\n| Resume transfer write (§8) | the `transfer-writer` principal (one-shot, 5 min, per `cotal spawn --resume --detach --on` call after the CLI hashes the transcript: minted by the operator holding the space signer, or on a user-auth space exchanged as the `transfer-writer` view, §10) | publish exactly `$O.cotal_xfer_<space>_<instanceId>.C.<hex>` and `$O.cotal_xfer_<space>_<instanceId>.M.<name>` (one object of one instance's bucket), plus `$JS.API.DIRECT.GET.OBJ_cotal_xfer_<space>_<instanceId>.` followed by each of those two subjects; no consumer, no stream API, no other object | direct; object-pinned |\n| Resume transfer read (§8) | the `transfer-reader` principal (one-shot, 5 min, minted per `transcript-receive` or sweep by the receiving manager from the space signer, or issued to a remote manager by the host's `transferReader` authority operation for that manager's own instance) | `STREAM.CREATE`, `STREAM.INFO`, `STREAM.MSG.GET`, `STREAM.PURGE` and `CONSUMER.CREATE` on its own `OBJ_cotal_xfer_<space>_<instanceId>` only, publish `$O.cotal_xfer_<space>_<instanceId>.M.>` (the stock delete marker), `$JS.API.INFO`, and that stream's `$JS.FC.OBJ_cotal_xfer_<space>_<instanceId>.>` flow control; every other credential, seats, the spawn capability, the supervisor, the provisioner and other instances' readers included, holds nothing that names `OBJ_cotal_xfer_` or `$O.cotal_xfer_` | mediated; instance-pinned |\n| Run admission read (§14.8) | the `run-mediator` and `run-operator` principals | `STREAM.MSG.GET` on `KV_cotal_admission_<space>` (leader-served; body-selected, stream-wide, the same residual as every records reader); the `run-driver` holds NO row on this store | mediated read; fail-closed |\n| Journal submission append | capability holder | `epj.<endpoint>.<command>[.<mode>[.<target tokens per mode>]].<cO>.<cA>.<cUid>` | direct, explicitly untrusted input |\n| Canonicalizer consume | the endpoint's canonicalizer principal (singleton, §13.4) | its durable on `EPJ_<space>`: `$JS.API.CONSUMER.CREATE.EPJ_<space>.<canonD>.cotal.<space>.epj.<endpoint>.>` (full-tail single filter), `$JS.API.CONSUMER.INFO.EPJ_<space>.<canonD>`, `$JS.API.CONSUMER.MSG.NEXT.EPJ_<space>.<canonD>`, plus `$JS.ACK.EPJ_<space>.<canonD>.>` (ack/term after durable decision only, and, for pool-admitted acceptances, after the enqueue, §13.4) | mediated |\n| Canonical decisions + quarantine + goal-bind | the endpoint's canonicalizer principal | publish `epf.<endpoint>.dec.>`, `epf.<endpoint>.quar.>`, and `epf.<endpoint>.goal.*.*.*.*.bind` (the per-goal first-wins bind, §13.4, create-only CAS per subject; the `.bind` leaf is disjoint from the commit principal's `goal….result`/status writes, so no writer overlap) | mediated |\n| Canonicalizer CAS-winner + terminal read | the endpoint's canonicalizer principal | leader-served `$JS.API.STREAM.MSG.GET.EPF_<space>` (body-selected `last_by_subj`; these reads are FENCING, read service above, so the follower-served `$JS.API.DIRECT.GET.EPF_<space>.…` form is NOT granted; the body-selected form is the broker-confinement-for-profile-trust trade above) over exactly its families: `epf.<endpoint>.dec.>` + `epf.<endpoint>.quar.>` (observes the winning fact on redelivery, §13.4) + `epf.<endpoint>.wrk.>` (READ-ONLY: the reconciliation predicate's terminal probe, §13.6; `wrk` writes stay with the commit principal, row below) + `epf.<endpoint>.goal.*.*.*.*.bind` (the goal-bind CAS winner: on a lost `.bind` create the canonicalizer reads the existing bind to decide same-fingerprint retry vs. `conflict`, §13.4) | mediated |\n| Caller durable reads (decisions, goal results, receipts, event catch-up, record reads/watches) | the **read mediator** owns the reader consumers; a registered endpoint MAY mediate its own callers' goal results through its separate trusted commit/read connection; the **caller** holds only its own reply rail | **Mediated (normative above).** The caller holds NO consumer/`DIRECT.GET` grant on EPF/EPE/EPC/records. It issues a read command and receives its own caller-scoped facts (`dec`/`goal…result`/`receipt` under its triple, §13.2), event catch-up, and record snapshots over its attribution-pinned reply rail `ep.reply.…<cO>.<cA>.<cUid>.<nonce>`; the read mediator re-authorizes each read against the caller's current grants before delivering; registered-endpoint goal reads use the connection-grant authorization and bearer-lifetime bounds specified above. Live progress is the caller's own core subscription to granted `epe` subtrees within `sub.allow` (bytes land only on its own sub). Reader consumers (`decD`/`goalD`/`eveD`/`recD`) are owned and bound by the mediator, never the caller | mediated read; confined to the caller's own rails |\n| Accepted-fact consume (effects) | every instance's serve credential, on the endpoint's ONE shared durable | **bind-only** on the provisioner-pre-created pull durable `effD = eff_<e>` (exact filter `cotal.<space>.epf.<endpoint>.dec.>`, `AckExplicit`): `$JS.API.CONSUMER.INFO.EPF_<space>.<effD>`, `$JS.API.CONSUMER.MSG.NEXT.EPF_<space>.<effD>`, `$JS.ACK.EPF_<space>.<effD>.>`; instances **pull-compete on the shared durable** so each accepted decision is delivered to exactly one live instance (at-least-once): a per-instance consumer over the class-wide decision subtree would be broadcast, and every instance would duplicate the external effect. Effects consume canonical facts, never raw submissions (§13.4); a rejected/quarantined decision is ack-skipped, and so is any acceptance whose `route` is a pool (§13.4, the pool's worker path executes it; effects MUST NOT). **Ack barrier:** an effecting instance MUST ack a `dec` message ONLY after its effect is durably recorded, for an action command the terminal `goal….result` fact; for a **non-action `route:\"effects\"` journal command** a generic per-request **effect fact** `epf.<endpoint>.eff.<cO>.<cA>.<cUid>.<id>` (create-only CAS, written by the effecting instance's commit path before ack; every `route:\"effects\"` acceptance has exactly this durable effect-complete marker), never before; an ack-before-effect would let a crash drop journal work the at-least-once contract promised. A crash before the ack redelivers the decision to another competing instance, which observes the existing terminal fact (idempotent) or effects it | direct read, endpoint-scoped, work-shared |\n| Result/receipt/terminal/resume facts | the endpoint's commit principal | enumerated fact families, no subtraction and **never `dec.>`/`quar.>`** (canonicalizer-only): publish `epf.<endpoint>.goal.*.*.*.*.result` (the goal terminal result; the `.bind` leaf under `goal.>` is the canonicalizer's, row above), `epf.<endpoint>.eff.>` (per-request effect-complete fact for non-action `route:\"effects\"` commands, create-only CAS, §13.9 ack barrier), `epf.<endpoint>.receipt.>` (caller-scoped subjects, §13.2), `epf.<endpoint>.wrk.>` (per-item terminal, create-only CAS), `epf.<endpoint>.cp.>` (one-use resume CAS); read-back is FENCING (read service above: it gates create-only CAS emission and idempotent re-commit decisions), leader-served `$JS.API.STREAM.MSG.GET.EPF_<space>` (body-selected `last_by_subj` over exactly these five families; the follower-served per-family `DIRECT.GET` form is NOT granted) | mediated |\n| Live event progress (caller) | capability holder (per read capability) | a caller-owned **core subscription** to the granted `epe` subtrees (fully-qualified `cotal.<space>.epe.…` in `sub.allow`, Appendix B), incl. per-goal `epe.<endpoint>.*.*.goal.<cO>.<cA>.<cUid>.>`; safe because a core sub delivers only to the caller's own subscription, never a caller-chosen subject; durable catch-up/replay is the mediated read above, not a self-bound consumer. A follower settles a goal from live progress only on a terminal whose subject names the instance and epoch that accepted it and the same goal as its body; any other terminal is at most a prompt to read the goal's recorded result | direct read; own subscription only |\n| Claim / action / checkpoint commits | the owning endpoint's commit path | its own record keys (`goal`/`cp`/`lease`/`goaleff`/`epname`/`epmig` grammars, §13.7, per the writer table; the three coordination kinds are enumerated HERE because a shared registry profile does not confer a grant; a kind absent from this enumeration is default-denied however it is registered, and that default-deny binds every principal in this table, including the composed profile in the row below) + the enumerated commit fact families of the Result row above, never `dec.>`/`quar.>`; its goal/checkpoint FENCING reads (the terminal-commit's spec read, epoch/deadline currency) are leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` (read service above; the records bucket's Direct Get is NON-fencing only) | mediated (validates fencing, lease clock, lifecycle, epoch) |\n| Goal-writer commits (journal-class actions) | the **goal-writer** principal: the commit principal of the row above, composed with three additions and nothing else | the composed profile is exactly (i) everything the commit row grants, inherited rather than restated, (ii) the per-goal first-wins bind leaf `epf.<endpoint>.goal.*.*.*.*.bind`, (iii) the reconcile index subtree `goalidx.<endpoint>.>` in the records bucket, key-pinned to this endpoint, and (iv) a currency read of its OWN issuance gate `epgate.<endpoint>.<instanceId>` before the first terminal-fact CAS, so a superseded writer declines to commit. That read carries the NAMED RESIDUAL this section requires of every bucket-blind read: the auth store is not Direct-Get enabled, so the read is a leader-served body-selected `STREAM.MSG.GET` that cannot be key-pinned to the single gate key, and the profile can therefore read any row of that bucket's gate and ledger METADATA, never bearer bytes. It is the same residual class the one-shot serve-executor profile carries, here on a standing connection, and it is a fast-fail belt rather than the fence; the durable fence is barrier revocation. `goalidx` is enumerated HERE and NOT on the commit row, because the index is written create-only BEFORE the goal binds, so the principal that writes it is the one that also binds; granting it on the bare commit row would widen every commit principal to a key only this profile needs. This profile holds NO records consumer create: the sweep that enumerates the index runs over the provisioner (row below), never over this standing connection, which is why an index write grant is not an index enumeration grant | mediated (as the commit row, plus the bind's create-only CAS per subject) |\n| Contract-artifact publication | the contract publisher principal | publish `epc.<digest-hex>` (`epc.*`), create-only per subject (`Nats-Expected-Last-Subject-Sequence: 0`; a digest subject is written at most once); read-back via the reader row below | mediated, immutable once published |\n| Contract-artifact read | trusted infra directly (`DIRECT.GET.EPC_<space>.cotal.<space>.epc.>`); untrusted callers via the read mediator | contract artifacts are content-addressed and public (verify-on-read is the tamper boundary, §13.7), so exposure is not the risk; the confused-deputy INJECTION is, so an untrusted caller's artifact fetch is mediated onto its own reply rail exactly like any other read; trusted infra fetches directly | mediated for callers / direct for infra |\n| Record write ingress (`epr`) | the owning instance | publish `epr.<endpoint>.<instanceId>.<epoch>.<kind>.<qualifier...>`; the instance's ONLY path to `svc`/`goal`/`cp` status writes; the epoch token is pinned by the serve credential, so the record writer reads the writing epoch from the broker-authenticated subject, never from payload | direct; epoch-pinned ingress to the mediated writer |\n| Record writer consume + `spec`/`status` writes | the kind's separately scoped spec/status writer principal (writer table); **one principal and one consumer PER KIND**, never a single writer draining every kind | consume: `$JS.API.CONSUMER.CREATE.EPR_<space>.<recwD-k>.cotal.<space>.epr.*.*.*.<kind>.>` (full-tail single filter on the `<kind>` token of §13.2's `epr` grammar; `recwD-k = recw_<space>-<kind>`) + `$JS.API.CONSUMER.INFO.EPR_<space>.<recwD-k>` + `$JS.API.CONSUMER.MSG.NEXT.EPR_<space>.<recwD-k>` + `$JS.ACK.EPR_<space>.<recwD-k>.>`; write: `$KV.cotal_records_<space>.<that kind's §13.7 key grammar>.{spec,status}`; its writer-table stale-writer fence (the FRESH lifecycle-mapping `processEpoch` currency read; current ONLY at `state: \"active\"`, §13.1, so a `retiring` or `retired` mapping refuses the write) is leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` (a FENCING read, read service above); the kind token in the ingress subject is what keeps the writer separation the writer table declares | mediated per kind below, no row left open |\n| Reader/pool/effects consumer provisioning (one-shot, at capability mint / endpoint setup) | the provisioner | exact full-tail extended creates for every pre-created durable this matrix names: `$JS.API.CONSUMER.CREATE.EPW_<space>.<poolD>.cotal.<space>.epw.<e>.<pool>.>`, `$JS.API.CONSUMER.CREATE.EPF_<space>.<effD>.cotal.<space>.epf.<e>.dec.>`, `$JS.API.CONSUMER.CREATE.EPF_<space>.<decD>.cotal.<space>.epf.<e>.dec.<cO>.<cA>.<cUid>.>`, `$JS.API.CONSUMER.CREATE.EPF_<space>.<goalD>.cotal.<space>.epf.<e>.goal.<cO>.<cA>.<cUid>.>` (per action capability), `$JS.API.CONSUMER.CREATE.EPE_<space>.<eveD-n>.<granted full-tail subtree>`, `$JS.API.CONSUMER.CREATE.KV_cotal_records_<space>.<recD-n>.$KV.cotal_records_<space>.<granted subtree>` (the reader-config seam is an ALLOWLIST: the `<granted subtree>` kind token MUST be a registered caller-readable record kind, so it REFUSES every authority-control kind (`oblig` above all, plus `govern`/`policy`/`uid`/`frontier`) and every unregistered kind, and for a dual-token kind whose atomic head is authority (`lifecycle`, head `lifecycle.<owner>.<actor>`) it admits only a filter strictly deeper than the head, never one that can match the head key itself; so no reader durable is ever pre-created over the `oblig.` subtree the sealed records scanner owns nor over an authority head, nats-server#8274), every create PULL, every filter a full literal tail; plus matching `CONSUMER.DELETE` for deprovisioning (lifecycle-keyed names, §13.1) | mediated, trusted provisioning only |\n| Events | the owning instance | `epe.<endpoint>.<instanceId>.<epoch>.>` | direct; subject-confined, epoch-pinned |\n| Timer schedule request | the owning instance | publish `ept.<endpoint>.<instanceId>.<epoch>.*.schedule` (never `.armed`/`.fire`); a request carrying any scheduling header is rejected by the timer writer (§13.2) | direct; epoch-pinned; captured by the schedules-DISABLED request stream |\n| Timer request consume + arm | the space's timer writer principal (singleton infra, like the delivery daemon) | consume: `$JS.API.CONSUMER.CREATE.EPT_REQ_<space>.<timerD>.cotal.<space>.ept.*.*.*.*.schedule` (full-tail single filter) + `$JS.API.CONSUMER.INFO.EPT_REQ_<space>.<timerD>` + `$JS.API.CONSUMER.MSG.NEXT.EPT_REQ_<space>.<timerD>` + `$JS.ACK.EPT_REQ_<space>.<timerD>.>`; arm: publish `ept.*.*.*.*.armed`, deriving `Nats-Schedule-Target` = the sibling `.fire` from the authenticated request subject tokens ONLY, stripping/rejecting every client scheduling header, and **fresh-checking the authoritative timer generation/deadline before arming** (a FENCING read: leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` on the checkpoint record, read service above); the arm also reads the armed-subject's own last sequence via `$JS.API.STREAM.MSG.GET.EPT_<space>` and publishes with `Nats-Expected-Last-Subject-Sequence` pinned to it - that read is CAS-PINNING, not fencing: the broker CAS is the fence and a delayed writer's stale read loses it loudly (§13.1 complementarity, the FIRE handler's class); a redelivered or delayed stale-generation request is discarded, never armed, so it cannot overwrite the current schedule and silently lose the live deadline (§13.2, §13.6, §13.12) | mediated |\n| Timer fire consume | the owning instance | its own `ept.<endpoint>.<instanceId>.<epoch>.*.fire` (fired messages validated against its authoritative schedule state AND the broker-authored scheduler-origin header = its exact sibling `.armed`, §13.12); no client credential holds `.armed` or `.fire` publish | direct read |\n| Session `.in` publish | the session's caller (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.in` exact | direct |\n| Session `.in` subscribe | the serving instance (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.in` exact | direct read |\n| Session `.out` publish | the serving instance (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.out` exact | direct |\n| Session `.out` subscribe | the session's caller (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.out` exact | direct read |\n| Chat-session admission index, owner quota and sweep cursor (§10) | the trusted auth path (§9/§10), admission and its sweep only | `$KV.cotal_auth_<space>.chatholder.<owner>.<holderHash>` (create-only, then revision-pinned CAS, never deleted), `….chatowner.<owner>` (create-only when absent, then revision-pinned CAS), `….chatsweep.cursor` (revision-pinned CAS); exact arity on each, never a `chat…>` wildcard. The chat principal's own leaf holds none of them | mediated |\n| Session ledger (one-use redemption, credential ids, revocation state, authenticated close) | the trusted auth path (§9/§10) | `$KV.cotal_auth_<space>.session.<sessionId>`, create-only CAS per `sessionId`, monotonic state (§13.6) | mediated |\n| Credential ledger (issuance gate, descendant enumeration, lineage index, revocation) | the trusted auth path (§9/§10) | writes: `$KV.cotal_auth_<space>.cred.<lifecycleUid>.<credentialId>` + `….gate.<lifecycleUid>` (the issuance gate, revision-pinned CAS is the mint fence, §13.1) + `….epgate.<endpoint>.<instanceId>` + `….epcred.<endpoint>.<instanceId>.<credentialId>` + the exact `….eprepair.<endpoint>.<instanceId>` interrupted-repair cursor (the disjoint endpoint families, §13.1: same protocol, explicit prefixes, never arity; the repair executor is pinned to one exact cursor key) + `….stage.>` (implementation staging/tombstone fences; NEVER under `cred.`/`epcred.`, §13.1) + `….natkey.<userNkey>` (create-only native-key issuance evidence, §13.1) + `….srcgate.<issuerKeyId>.<id>` (per-handle source gate, §13.1) + `….bysrc.<issuerKeyId>.<id>.<lifecycleUid>.<credentialId>` (the per-ancestor lineage index) + `….session.<sessionId>` (create-CAS `issuing`, finalize-CAS `active`, §13.6) + `….plane` (the ONE plane-ownership claim row, §13.13: create/revision-CAS by the barrier profile only, exact arity, never `plane.>`); reads: **leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_auth_<space>`** (with `allow_direct=false` a KV get is exactly this body-selected `last_by_subj` call against the stream LEADER; read-your-writes, not a follower-served `DIRECT.GET`; the body-selection trades broker confinement for trusted profile custody; the separate tool-result snapshot reader below holds the same leader-read verb without ledger write authority) for gate/session/row state, which is why the mint and session fences are revision-pinned CAS *writes* rather than reads (a read is never a fence, §13.1); and **fence-free prefix enumeration through the SEALED auth-ledger scanner, never a runtime consumer create**: no standing or runtime-reachable auth credential (the takeover/retirement/handle-revocation barrier, the session sweep, any replayable executor) holds `$JS.API.CONSUMER.CREATE` on `cotal_auth_<space>`, because a consumer-create request BODY is not subject-ACL confinable: an extended `CONSUMER.CREATE.<stream>.<name>.<filter>` grant still admits a body with `durable_name` (equal to the subject name token) and a push `deliver_subject`, a DURABLE exporter of every current and future row that SURVIVES the credential's connection close and revocation; a subject ACL cannot constrain that body, so the only safe runtime grant is none. The dynamic-enumeration `CONSUMER.CREATE` lives in exactly ONE profile, a SEALED scanner the trusted auth process opens for itself and NEVER hands out: its credential, connection, and identity seed reach no caller, child, log, or persistence (a process-memory compromise reaches it, the SAME residual class as the account signing seed the process already holds; never broker confinement, never a network-reachable JWT). The scanner is pinned to ONE literal consumer name under a FORCED config: pull (no `deliver_subject`), ephemeral (no `durable_name`), `AckPolicy.None`, `DeliverPolicy.LastPerSubject`, memory storage, bounded inactivity; re-read and bind-verified before use and unconditionally deleted after, with every scan over the stream serialized on that one name, and the injected scanner bonded to its exact space so a hand-assembled or foreign-space scanner never enumerates. The scan is FENCE-FREE by construction: under the history=1 store a same-subject `active→revoked` overwrite EVICTS the pre-scan revision, so a sequence/`STREAM.INFO` cutoff would DROP that subject and leave its holder un-revoked; a LastPerSubject read carries no upper cutoff and, draining to a freshly re-observed zero pending (never a stale local count), returns each subject's CURRENT last, so a concurrent overwrite is SEEN, never dropped. It enumerates exactly `cred.<lifecycleUid>.>`, `bysrc.<issuerKeyId>.<id>.>`, `stage.>` (operation-intent discovery), or `session.>`. The barrier's family enumeration and the expiry sweep are executable reads, not prose. The tool-result profiles below add only their listed auth-store verbs and families; no untrusted profile gains an auth-store grant | mediated |\n| Tool-result consent record (§13.19) | the trusted auth mint writer, never its derived host writers | `$KV.cotal_auth_<space>.consent.*` publish; retained auth leader-read authority checks the recorded consent. The revocation writer has no consent write grant | mediated; consent schema, authenticated holder/target and expiry checks |\n| Tool-result fresh-store creation (§13.19) | a short-lived host-private create-only provisioner | `$JS.API.INFO` and `$JS.API.STREAM.CREATE.KV_cotal_auth_<space>` publish; own `_INBOX_<connId>.>` subscribe; no update/delete/purge, data write, consumer or stream read grant | mediated; only fresh controlled creation after durable private intent, closes after creation |\n| Tool-result revocation append (§13.19) | host-private revocation writer, never handed out | `$KV.cotal_auth_<space>.revocation.*.*` publish and own `_INBOX_<connId>.>` subscribe only. Canonical key is `revocation.<targetDigest>.<consentId>`; raw grants do not constrain operation headers, TTL, target or CAS | mediated; exact recorded-consent binding and expected-last-subject-sequence zero, no operation/TTL inputs, durable receipt, unknown persistence is not a safe retry |\n| Tool-result fixed-cut snapshot (§13.19) | host-private snapshot reader, never handed out | `$JS.API.INFO`, `$JS.API.STREAM.INFO.KV_cotal_auth_<space>` and `$JS.API.STREAM.MSG.GET.KV_cotal_auth_<space>` publish; own `_INBOX_<connId>.>` subscribe only; no data write, Direct Get, consumer or administration grant | mediated leader-served fencing read; finite committed-W cut, creation-owned uninterrupted custody and independent receipt cross-check, not the credential-ledger moving-tail enumeration. Raw body-selected MSG.GET retains stream-wide read and caller-selected foreign-subject reply-injection authority despite own-inbox subscription |\n| Remote manager-service registration and renewal (§13.1/§13.6) | the trusted auth path is the sole gate/ledger writer and host JWT issuer; a user manager presents only the server-authored closed view | exactly one staged `{ owner, managerActor, lifecycleUid, instanceId }` family: `svc.manager.<instanceId>`, the stage-pinned contract artifacts, `epgate.manager.<instanceId>`, and `epcred.manager.<instanceId>.<credentialId>`. `prepare` freezes/stages; `activate` creates the matching service record and releases host-signed material only after ledger + gate finalization; `renew` is bounded, rechecks the live ledger scope, and can replace material only inside that family. Descendant provisioning is a mediated same-owner request revalidated by the host. No row grants signer material, generic stream/KV/consumer authority, another instance, or a public/managed-agent exchange path | mediated, closed family; revocation/renewal failure denies new authority and unsafe restarts while retaining live agents only within their independently valid lifetimes |\n| Environment bootstrap request and recovery (§13.1/§13.6) | the ephemeral `environment-bootstrap` caller, issued only by the external hosting authority | the literal instance describe/bootstrap/bootstrap-status rows and native own-caller reply/inbox rows above; read-only describe binds the current authority epoch, `bootstrap` durably pins the one admitted caller and five public keys before preparation, `bootstrap-status` reads only that reservation; no other endpoint, command, caller, store or manager profile | direct request, mediated preparation/recovery; expiry and terminal state never permit reuse |\n| Environment manager supervision (§13.1/§13.6) | the admitted supervisor identity under fixed `environment-manager-supervisor` | exact own instance lease create/CAS, manager-bucket STREAM.INFO/leader MSG.GET and API.INFO for binding/read, own presence/roster watch and flow control, existing manager liveness serve/reply, own inbox; no auth-store or registration/repair/contract/governance writes, reads or scans | direct liveness/lease duties, host-mediated registration; no reuse of `remote-manager` grants |\n| Environment manager goal writes (§13.1/§13.6) | the admitted goal-writer identity under fixed `environment-manager-goal-writer` | native goal/coordination grant rows for the manager with the auth-store own-gate MSG.GET belt removed; no auth-store read/scan/write or consumer access | direct goal duties under native barrier revoke and verified eviction; no new authority-family writes |\n| Environment manager graceful deregistration (§13.6) | the admitted executor asks; trusted host alone executes | closed deregistration request through the authority command, current proof/epoch and host-committed registration revision, native own-instance gate-generation read and revision-pinned delete; no guest store credential or foreign selector | host-mediated, idempotent observation; cannot delete a successor or substitute signer-only repair |\n| Environment manager authority request (§13.1/§13.6) | the admitted manager's recorded executor identity under fixed `environment-manager-executor` | literal instance describe/authority command rows and native own-caller reply/inbox rows above; the authenticated caller, proof, epoch, admission revision and finite expiry bind every closed inner operation to this environment and manager family, with at most the one admitted child lifecycle | direct request, host-mediated effects; no guest signing, ledger write or foreign family reach |\n| Environment admission, preparation and terminal cleanup (§13.1/§13.6) | the external hosting authority alone | auth-owned `epgate.manager.<instanceId>` carries its immutable `authorityFamily` marker at every state and is the issuance fence before bootstrap mint; operation-retained staging stays under `stage.<opId>.…`; the bootstrap `cred.<managerUid>.<credentialId>` row, root source chain and activation revocation/eviction; the existing manager `svc`/`epcred` and lifecycle retirement families bind the recorded owner, instance and manager/child UIDs; termination aborts an unactivated registration then retires, retaining the gate's family marker, before recording private admission ended; private admission/reservation and credential-custody records retain CAS outcomes and terminal state, with no guest store credential or caller-selected target | mediated; cleanup survives host restart and guest loss; retention, observed provider termination and authority retirement remain separate facts |\n| Auth-ledger enumeration (the SEALED scanner profile, the credential-ledger row's enumeration seam) | the trusted auth process's DEDICATED self-minted scanner principal; opened for the process itself, NEVER handed out (full rationale in the credential-ledger row above) | exactly `$JS.API.INFO` + `$JS.API.STREAM.INFO.KV_cotal_auth_<space>` + `$JS.API.CONSUMER.CREATE.KV_cotal_auth_<space>.cotal-ledger-scan.$KV.cotal_auth_<space>.>` + `$JS.API.CONSUMER.INFO.KV_cotal_auth_<space>.cotal-ledger-scan` + `$JS.API.CONSUMER.MSG.NEXT.KV_cotal_auth_<space>.cotal-ledger-scan` + `$JS.API.CONSUMER.DELETE.KV_cotal_auth_<space>.cotal-ledger-scan` + its connection-scoped `_INBOX_<connId>.>` subscribe, and NOTHING else (no records-stream grant, no KV write, no `DIRECT.GET`, no `$JS.ACK`: an `AckPolicy.None` scan acks nothing); `cotal-ledger-scan` is the ONE pinned literal consumer name every auth-stream scan serializes on, and this profile plus the records scanner below are the ONLY DYNAMIC-ENUMERATION `CONSUMER.CREATE` holders on the two authority streams (the provisioning row's pre-created full-tail reader durables, CREATE+DELETE by the provisioner and INFO/MSG.NEXT/ACK bind by the read mediator, are the one other records-stream consumer authority, and the reader-config seam REFUSES an authority-control record kind so no reader durable can target the `oblig.` subtree the records scanner owns), re-audited mechanically per this section's closing clause | mediated |\n| Obligation enumeration (the SEALED records scanner profile, the acceptance-obligation row's enumeration seam, ONE instance per space) | the trusted process's DEDICATED self-minted records-scanner principal; opened for the process itself, NEVER handed out (full rationale in the acceptance-obligation row below; every scan over the literal name serializes process-wide per space, so a second instance can never interleave with a live scan and hand back a partial result, and the scanner handle is immutable once branded) | exactly `$JS.API.INFO` + `$JS.API.STREAM.INFO.KV_cotal_records_<space>` + `$JS.API.CONSUMER.CREATE.KV_cotal_records_<space>.cotal-records-scan.$KV.cotal_records_<space>.oblig.>` (the CREATE filter is confined to the `oblig.` subtree) + `$JS.API.CONSUMER.INFO.KV_cotal_records_<space>.cotal-records-scan` + `$JS.API.CONSUMER.MSG.NEXT.KV_cotal_records_<space>.cotal-records-scan` + `$JS.API.CONSUMER.DELETE.KV_cotal_records_<space>.cotal-records-scan` + its connection-scoped `_INBOX_<connId>.>` subscribe, and NOTHING else; `cotal-records-scan` is the ONE pinned literal consumer name, disjoint from the auth scanner's (one scanner instance, lock, and literal name PER STREAM) | mediated |\n| Work-pool enqueue | the endpoint's canonicalizer (from accepted decisions only) | `epw.<endpoint>.>` publish, create-per-subject (`Nats-Expected-Last-Subject-Sequence: 0`; the acceptance identity is the subject, §13.2) | mediated |\n| Work-pool reconciliation probe | the endpoint's canonicalizer | leader-served `$JS.API.STREAM.MSG.GET.EPW_<space>` (body-selected `last_by_subj` on the exact item subject; the probe is FENCING, read service above: a follower-served `DIRECT.GET` that misses the live entry re-arms settled work, so that form is NOT granted) + the CAS-winner read row above (`dec` + `wrk` last-by-subject), together they decide the §13.6 predicate: accepted, **`now < workExpiry`** (an expired item is never re-enqueued; it is terminally settled `expired` with its `wrk` fact and acked without effect), no terminal, no live entry ⇒ re-enqueue for the item's REMAINING TTL; a worker likewise MUST check `now < workExpiry` before lease/effect and refuse expired work | mediated |\n| Virtual-endpoint activation watch | the endpoint's activator principal (holder of its activation capability, §13.6) | exactly `$JS.API.CONSUMER.INFO.EPW_<space>.<poolD>` (the per-pool occupancy snapshot; request/reply, so watching is bounded polling) PLUS its own connection-scoped reply inbox `_INBOX_<connId>.>` (never the account-wide default); the instance START is a mediated, target-bound seam resolved by the supervisor's own authority, never a broker grant; NOTHING else: no `CONSUMER.MSG.NEXT`/`$JS.ACK` (watching is never draining), no `STREAM.MSG.GET.EPW_<space>` (no reconciliation authority), no consumer create/update/delete, no `epw.>` publish | mediated |\n| Work-pool consume + ack | the pool's owning endpoint ONLY (workers hold NO pool grant, §13.5) | **bind-only** on the provisioner-pre-created exact-filter `poolD` (grammar above): `$JS.API.CONSUMER.INFO.EPW_<space>.<poolD>`, `$JS.API.CONSUMER.MSG.NEXT.EPW_<space>.<poolD>`, `$JS.ACK.EPW_<space>.<poolD>.>` (ack only after committed terminal state); NO consumer create, NO stream-wide read | mediated |\n| Lease issue / fencing advance | the pool's owning endpoint (`lease` command) | its `lease` record keys (§13.7 grammar), via the record-writer seam | mediated |\n| Lifecycle mapping / teardown | minting manager's commit path; lifecycle-pinned deprovisioner | the **unsplit** alias CAS head `$KV.cotal_records_<space>.lifecycle.<owner>.<actor>` (one atomic key, NOT `.spec`/`.status`-split; the authoritative current mapping and the only `mappingRevision` source, activation/retirement serialize here by CAS, §13.7; NEVER-DELETED, three states `active \\| retiring \\| retired`, transitions only inside the §13.1 operations) + the create-only space-global UID reservation `$KV.cotal_records_<space>.uid.<lifecycleUid>` (§13.1: won BEFORE any gate or head write; NEVER-DELETED); leader-consistent current-mapping read `$JS.API.DIRECT.GET` is NOT used for authority reads of this key (the records bucket may follower-serve; a fresh mapping read is a leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` last-by-subject get on the head key; leader-served for read-your-writes, granted to the trusted mapping-reader/mediator profile, not a follower-served `DIRECT.GET`; that reader profile ALSO holds exactly `$JS.API.STREAM.INFO.KV_cotal_records_<space>` so it can shape-prove at bind time that the stream it leader-reads is the primary, un-mirrored, non-evicting records store (§13.12); a reader that cannot prove its store's shape MUST refuse to serve authority reads); optional append-only per-UID audit `$KV.cotal_records_<space>.lifecycle.<owner>.<actor>.<lifecycleUid>`; teardown: exact lifecycle-keyed names only | mediated / broker-pinned delete |\n| Acceptance obligation (reservation/drain, §13.8) | the admission mediator (per endpoint; the canonicalizer holds NO raw `oblig.` grant) | create-only winner + monotonic revision-pinned CAS on `$KV.cotal_records_<space>.oblig.<targetUid>.<endpoint>.<cO>.<cA>.<cUid>.<id>` (§13.7; the key derives from the broker-authenticated request subject plus the create-fence currency reads of §13.8, never from a body field; proof issuance only after the post-create recheck); its winner/settle reads are FENCING, leader-served `$JS.API.STREAM.MSG.GET` on the obligation key and on the EPF decision subject; its currency reads are FENCING, leader-served `$JS.API.STREAM.MSG.GET` on the target's `lifecycle` head AND on the endpoint's `govern` head (§13.6: the govern head read is what surfaces both a staged `pendingPolicyKey` (which pauses policy-admitted proof issuance) and the enforced policy selector the mediator follows to the immutable `policy.<endpoint>.<digest-hex>` version; the mediator reads govern and policy for its OWN endpoint only, the confined-reader identity bind) PLUS the immutable `policy.<endpoint>.>` version it names; PLUS create-only publish on the endpoint's EPF decision subjects for the TERMINAL REJECTION settle only (§13.8: its own recheck refusals and the retirement/policy drains, which settle through it); the broker cannot distinguish a rejection payload from an acceptance, and rejection-only is NOT subject-expressible (both decisions MUST share the create-only decision subject for first-wins settlement), so this grant's residual is explicit per D32: a compromised mediator can forge a decision for ITS endpoint INCLUDING AN ACCEPTANCE, an escalation to injecting executed work, never merely reject/stall (the same class of trust already placed in that endpoint's canonicalizer), and never beyond its endpoint (the decision-publish row is endpoint-literal); obligation enumeration (the §13.1 retirement barrier's `oblig.<targetUid>.>` discovery + quiescence recheck, and the mediator's own `oblig.*.<endpoint>.>` policy-movement drain, §13.6) runs through a SEALED records scanner, the same seal as the auth-ledger scanner above: this profile holds NO `$JS.API.CONSUMER.CREATE` (nor INFO/MSG.NEXT/DELETE) on `cotal_records_<space>`, because a consumer-create request BODY is not subject-ACL confinable: an extended `CONSUMER.CREATE.<records>.<name>.<oblig filter>` grant still admits a body with `durable_name` and a push `deliver_subject`, a DURABLE exporter of the whole `oblig.` subtree that SURVIVES the credential's connection close and revocation (nats-server#8274; reproduced live against the prior grant). The fence-free `LastPerSubject` enumeration `CONSUMER.CREATE` lives in exactly ONE profile: a sealed records scanner the trusted process opens for itself and NEVER hands out (its credential, connection, and seed reach no caller; the same process-memory residual class as the auth-ledger scanner), pinned to ONE literal consumer name under a FORCED pull/ephemeral/`AckPolicy.None`/`DeliverPolicy.LastPerSubject`/memory config, bind-verified before use and unconditionally deleted after, its CREATE filter confined to the `oblig.` subtree, and the injected scanner bonded to its exact space so a hand-assembled or foreign-space scanner never enumerates; its fencing `STREAM.MSG.GET` rows are stream-level grants whose read exposure is space-wide, explicit per D32 (the terminal-cleanup row's same read residual); its reply inbox is connection-scoped (`_INBOX_<connId>.>`, never the account-wide default); the rows are NEVER-DELETED, a WRITER discipline the broker cannot fully enforce: the raw KV publish grant is operation/header-blind, so a compromised mediator can overwrite its own endpoint's row to a valid `terminal` value (hiding cleanup debt) or emit DEL/PURGE markers, where every reader refuses a deletion marker loud as corruption (§13.12 retention floor) and the records stream denies stream-API message-delete/purge, leaving the valid-row overwrite as a second explicit D32 residual, exactly parallel to the decision-forge residual and confined the same way (its own endpoint's rows only) | mediated |\n| Terminal pool cleanup (§13.1 barrier) | the retirement cleaner profile: minted per (retirement `op` × endpoint), its grant listing the EXACT pools of this operation's EFFECTIVE INVENTORY, DISCOVERY-ONLY: the target's accepted `oblig.<lifecycleUid>.>` pool routes (the barrier takes no caller-supplied hint, so every listed pool is one the target holds accepted work on), never a pool wildcard, never space-wide EPW rights, DISTINCT from every owner/agent/endpoint profile (never the revoked owner's credential), bounded-lived and, once the pool is proven quiescent (every prior owner ACK drained through `AckWait`, and a fresh consumer read shows zero `num_pending`/`ack_pending`; a fire-and-forget ACK confirmed with `AckSync`, never assumed), REVOKED and cluster-verified-EVICTED (its own principal) BEFORE any frontier records (§13.1 order), so no in-flight cleaner can ACK a redelivery after the alias is reused | runs only AFTER the target's obligation drain reached quiescence (§13.1 order) and BEFORE the frontiers; bind-only on each named pool's provisioner-pre-created durable: `$JS.API.CONSUMER.INFO.EPW_<space>.<poolD>`, `$JS.API.CONSUMER.MSG.NEXT.EPW_<space>.<poolD>`, `$JS.ACK.EPW_<space>.<poolD>.>` (re-proving at bind, per the work-pool row, that the durable's filter is exactly the named pool's subtree, pull mode, unlimited delivery ceiling), plus its own connection-scoped reply inbox `_INBOX_<connId>.>` (never the account-wide default) and leader-served terminal-observe reads `$JS.API.STREAM.MSG.GET.EPF_<space>` on `wrk.>`/`dec.>` item subjects, a STREAM-level grant whose read exposure is space-wide, explicit per D32; the cleaner holds NO lease or records authority, NO `wrk` (or any EPF/EPW) publish, NO consumer create/update/delete, NO raw stream DELETE: for each delivered message it hands the item's coordinates and requested disposition to the retirement settlement executor (next row; cleaner-supplied coordinates never authorize, the executor re-derives them from the durable acceptance), then re-reads and codec-validates the executor's lease-derived terminal, and ACKs ONLY a message whose item is durably terminal (a live, unexpired, foreign-target item is NEVER settled or ACKed, and the barrier refuses to close frontiers while one remains unsettled); this profile's explicit D32 residuals are terminal-free ACK suppression across its WHOLE EFFECTIVE INVENTORY (every discovered pool: a raw `$JS.ACK` cannot be broker-conditioned on a prior terminal, so compromise can silently drop effective-inventory-pool deliveries without settlement) and the space-wide `STREAM.MSG.GET` read exposure; it can forge NO terminal and mutate NO lease (it holds no write grant at all) | mediated |\n| Retirement settlement (§13.1 barrier executor) | the retirement barrier's op-bounded executor: a DISTINCT per-operation principal (`local.epexe_<opId-hash>`, CONNZ principal-tagged) minted per (op × endpoint) over this operation's EFFECTIVE INVENTORY bound to the durable intent (`opId`, target lifecycle; the pools are the target's accepted `oblig.<uid>.>` routes, DISCOVERY-ONLY (no caller-supplied hint)), its settlement code running on ITS OWN connection, live only for that operation and revoked + cluster-verified-evicted by the barrier at the same fence as the cleaner, BEFORE any frontier records; never the cleaner profile, never the barrier's standing connection, never a standing grant | the settlement seam is EFFECTIVE-INVENTORY-CLOSED: for every item the cleaner hands it, the executor re-derives the authority coordinates from the item's durable acceptance decision (a FENCING leader-served read; cleaner-supplied coordinates never authorize) and refuses a ref whose endpoint or pool is outside its EFFECTIVE-INVENTORY spec (the discovered pools), a decision that is not an accepted pool admission, an `expired` request before the item's OWN `workExpiry`, and a `retired` request for an accepted target that is not the intent's lifecycle (the confused-deputy closure: a cleaner chooses refs but can never borrow this authority beyond that effective inventory or the retirement lifecycle); it settles by CASing the item's `lease.<endpoint>.<pool>.<acceptance>.spec` record to a settled state, where the ONLY settlements it may INITIATE are `expired` (bound to the item's own horizon) and `retired` (re-bound to ITS operation's retiring target through the acceptance) and an ALREADY-settled lease DOMINATES (a crashed owner's `committed` lease is derived and its terminal published verbatim, never overwritten, never contradicted), then publishes/observes the exact lease-derived `wrk` terminal create-only (first terminal wins, §13.8 cancellation ordering) for the cleaner to validate; its authority is lease-record CAS plus `epf.<endpoint>.wrk.<pool>.>` publish on its effective-inventory pools plus the leader-served fencing reads its own code path performs (`STREAM.MSG.GET` on the facts stream and on the records store, plus the records store's bind-probe `STREAM.INFO` and `$JS.API.INFO`; NO work-stream read: the settlement path always settles or expires through the lease key before any EPW live-entry probe, so that read is unreachable and ungranted) and its connection-scoped reply inbox, and NOTHING else (no consumer authority anywhere, no work-enqueue publish, no auth-store access), and it carries the write residual the bounded cleaner does NOT: KV subject permissions cannot distinguish CAS from overwrite or DEL/PURGE markers, and the `wrk` publish is payload-blind, so a compromised executor can forge a lease settlement or work terminal within its WHOLE EFFECTIVE INVENTORY (every discovered pool; the per-item checks above bind honest execution, not a compromised bearer), explicit per D32, op-bounded and effective-inventory-confined, never standing, never beyond that inventory | mediated |\n| Drain commit applier (§13.8 accepted-self recovery) | a per-op, per-repair principal (`local.epapl_<opId-hash>`, CONNZ principal-tagged) the retirement drain mints ONLY after the commit key passes the CLOSED self-commit class: the key's kind must resolve in the canonical frozen kind registry to a NON-authority definition whose targeted `spec`/`status` half is registered to the §13.8 commit-path writer, at exact arity (which structurally excludes every authority HEAD, including the 3-token lifecycle head) with every qualifier token validated; a key outside the class refuses BEFORE any credential exists (the confused-deputy closure: a forged accepted-self row cannot turn `oblig.`/`govern.`/`policy.`/`uid.`/`frontier.`/a lifecycle head/an unregistered kind into a granted coordinate) | exactly ONE `$KV.cotal_records_<space>.<commitKey>` publish row plus its connection-scoped reply inbox; NO reads, NO wildcards. It executes the mediator-validated command verbatim: the resolved, canonically digest-verified intent bytes at the pinned base revision, written by guarded CAS; a CAS loss reports the another-writer conflict and the drain's re-enumeration re-classifies (landed / superseded), never a blind retry. NAMED residual: KV subject permissions cannot distinguish CAS from overwrite or DEL/PURGE, so within its one granted key a compromised applier can overwrite or delete for the credential's short life — the confinement is the exact key, the closed class, and the op-bounded lifetime, never write semantics. RETIREMENT-FENCE residual (§13.1/§13.13): no credential-ledger row backs this bearer, so the retirement fence guarantees KILL-LIVE (cluster-verified eviction of any live connection before the frontier), never deny-new — the connection is minted non-reconnecting so a KICK is durable in one round, and a fresh connect with a still-unexpired held bearer+seed after that point-in-time scan is the accepted residual, dominated by data-account signing-seed compromise (signing-key rotation is the only true deny-new) | mediated |\n| Drain route reconciler (§13.8 accepted-pool repair) | a per-op, per-repair principal (`local.eprec_<opId-hash>`, CONNZ principal-tagged) the retirement drain mints only to execute a MEDIATOR-DERIVED closed repair command: the mediator reads the item's durable acceptance decision itself (a leader-served fencing read), binds it to the obligation row (fingerprint/sourceSeq/route/horizon), and derives the exact EPW item subject plus the canonical acceptance item bytes (§13.6); the executor re-validates the exact six-token item shape for its own space and holds NO derivation authority (row-supplied coordinates or bytes never reach a grant) | exactly ONE `cotal.<space>.epw.<endpoint>.<pool>.<cOwner>.<cActor>.<cUid>.<id>` create-only publish row plus its connection-scoped reply inbox; a lost create is benign (a concurrent enqueue won; the drain re-reads establishment either way, so a no-op executor still fails closed); the payload-blind enqueue residual is confined to the one item subject for the credential's short life. RETIREMENT-FENCE residual (§13.1/§13.13): no credential-ledger row backs this bearer, so the retirement fence guarantees KILL-LIVE (cluster-verified eviction of any live connection before the frontier), never deny-new — the connection is minted non-reconnecting so a KICK is durable in one round, and a fresh connect with a still-unexpired held bearer+seed after that point-in-time scan is the accepted residual, dominated by data-account signing-seed compromise (signing-key rotation is the only true deny-new) | mediated |\n| Drain effects canceller (§13.8 option-(i) retirement cancel) | a per-op, per-repair principal (`local.epcan_<opId-hash>`, CONNZ principal-tagged) the retirement drain mints only to execute a MEDIATOR-DERIVED effects-cancel repair: the mediator reads and row-binds the acceptance decision itself and derives the exact completion subject (the `eff` marker or the goal `result` coordinate; the executor re-validates that exact shape for its own space); the cancelled terminal is built by the CORE validated builders, which refuse a foreign or absent target — a retirement cancels only ITS OWN target's accepted work — and never fabricate success (the effects union's `cancelled` member, or the goal union's first-class `cancelled` state with the digest-bound retirement attribution) | exactly ONE completion-subject create-publish row plus its connection-scoped reply inbox; CREATE-ONLY, so first-terminal-wins is structural (a racing real completion that landed first wins and the cancel loses its create harmlessly; the drain re-reads the winner either way, so a no-op executor still fails closed); the payload-blind single-subject create residual is confined to the one marker for the credential's short life. RETIREMENT-FENCE residual (§13.1/§13.13): no credential-ledger row backs this bearer, so the retirement fence guarantees KILL-LIVE (cluster-verified eviction of any live connection before the frontier), never deny-new — the connection is minted non-reconnecting so a KICK is durable in one round, and a fresh connect with a still-unexpired held bearer+seed after that point-in-time scan is the accepted residual, dominated by data-account signing-seed compromise (signing-key rotation is the only true deny-new) | mediated |\n| Auth endpoint rail (the `auth` listener, §13.2) | the auth service's dedicated LISTENER credential: serve + derived replies on the `ep.one.auth` class rail, standing with the plane. The surface is GENERIC — \"retire a lifecycle (owner, actor, lifecycleUid)\" — never caller-specific; the TARGET rides the subject as the `handle` triple (`ep.one.auth.retire-lifecycle.handle.<tO>.<tA>.<tUid>.<cO>.<cA>.<cUid>.<nonce>`) and caller attribution is the SUBJECT-derived, broker-ACL-enforced caller triple. The reply target is DERIVED from the parsed request (responder instance + caller triple + nonce), so no caller- or payload-supplied reply target can arrive at all — the bound-reply rule became structural rather than a check. Serve-time authz is the RAIL-TIME serve-issuance-gate check, fresh per request: ONE leader-served `STREAM.MSG.GET` of `epgate.<serveEndpoint>.<serveInstanceId>` — coordinates the caller NAMES but which do NOT authorize — requiring (a) the row is present and not `retired`, (b) `row.principal == principalKey(callerOwner, callerActor)` (THE PRINCIPAL CROSS-CHECK: a caller may only be authorized by its OWN serve registration; naming a foreign row buys a refusal, never an authorization), and (c) `row.processEpoch == serveEpoch` (a superseded predecessor after a restart is refused). An absent or TTL-expunged row reads ABSENT and refuses fail-closed. This binding is ALIAS-LEVEL, not incarnation-level: the gate is keyed by the PERSISTED `instanceId` and its row carries no lifecycle uid, so a same-principal predecessor presenting the current epoch still passes — binding the publishing incarnation would require a gate-row schema change. The four-outcome idempotence table answers in operator vocabulary (already-retired = success; the same stable opId resumes; a foreign operation refuses naming it; a stale incarnation refuses naming the current one), and every refusal is a COMPLETE no-op stated as such | subscribe `ep.one.auth.>` QUEUE-QUALIFIED (queue group `auth`; §13.9 forbids a plain subscribe of the class rail) + publish `ep.reply.auth.<instanceId>.<epoch>.*.*.*.*` (REPLY PLANE ONLY: the request and reply planes are disjoint in the grammar, so the listener credential cannot express a request subject at all — the self-forge is closed structurally, not by carving replies out of a shared subtree) (replies ONLY: the handler only ever responds on the DERIVED reply subject, and the reply plane cannot express a request subject at all, so a request is unpublishable by the listener credential, closing the self-forge where a compromised listener publishes a request as an authorized caller and passes its own subject-derived check) + `$JS.API.INFO` + the ONE serve-issuance-gate read row + its connection-scoped inbox; NO store writes, NO consumer authority, NO scanner/plane reach — every executing right stays with the plane's own registry and retirement deps (the drain rides the plane's ONE sealed records scanner) | mediated **NOW A CONFORMING ENDPOINT (Cotal #399, closed): the plane registers `svc.auth.<instanceId>`, publishes contract artifacts, and serves the reserved `describe`, so a generic client discovers and invokes this command the way it would any other registered endpoint (the two rows immediately below). The rail answers the v1 envelope; a legacy `{op,args}`/`{ok,data,error}` body is refused `unsupported-version`.** |\n| Retirement requester (per-despawn, §13.2) | an EPHEMERAL one-shot credential the space manager mints per despawn (`retirement-requester` profile, five-minute window): request + reply ONLY, for exactly ITS OWN caller triple AND exactly ONE grant-pinned TARGET incarnation (the `handle` triple is literal in the grant; the per-request nonce is the only wildcard token), so a leaked requester cannot be re-aimed at another lifecycle. The manager derives a STABLE opId from the retiring lifecycleUid, so a despawn retry, a same-name-spawn nudge, and the auth service's boot resume all drive the SAME operation. The requester holds no executing right — a leaked credential can only ask the rail to retire a lifecycle, and the rail's fresh serve-issuance-gate check (including the principal cross-check) + idempotence table bound what that ask can do | publish exactly `ep.one.auth.retire-lifecycle.handle.<tO>.<tA>.<tUid>.<cO>.<cA>.<cUid>.*` (its minting manager's own caller triple, its one target) + subscribe its own reply-plane filter `ep.reply.*.*.*.<cO>.<cA>.<cUid>.*` and its connection-scoped inbox; nothing else | mediated **`handle`-MODE DEVIATION, stated explicitly (Cotal #399): this row is NOT redemption-minted.** `handle` is normatively redemption-minted only - its triple pinned at redemption from an issuer-signed capability artifact, carrying attenuation, conferral through the trusted auth service, and ledgered `sourceChain` lineage. **This path has NO issuer-signed artifact, NO redemption step and NO `sourceChain`**: the row is built directly from the minting manager's own coordinates under root authority. `handle` is used because it is the ONLY mode with arity 3 (every other mode resolves against the CURRENT mapping, the wrong semantics for retiring a NAMED incarnation), and the reader-facing invariant - the validator re-checks only currency - IS honoured by the serve-time mapping check. What is absent is delegation lineage and artifact revocation; there is no independent issuer/holder boundary on this one-shot path whose revocation would change this requester's authority. Genuine redemption-shaping is tracked at #399. |\n| Registered auth instance (Cotal #399, the M4 conformance closure) | the auth service's own boot registration, over the plane's registration credential (§13.1) | the plane registers `svc.auth.<instanceId>` through the standard `registerServiceInstance` path (the same record shape and registration barrier every other endpoint uses), publishes its `retire-lifecycle` contract artifacts to the content-addressed contract store, and serves the reserved `describe` alongside the command: a generic client's `resolveService` now discovers this endpoint, its closure digests, and its current instance/epoch the way it would any other registered service, closing the round-8 `#399` gap named in the two preceding rows; subscribe `ep.one.auth.>` QUEUE-QUALIFIED (queue group `auth`) + describe reply on the same reply-plane rows as any other registered endpoint + the registration-barrier and contract-artifact publish rows shared by every `registerServiceInstance` caller; no additional store authority beyond that shared registration path | mediated |\n| Retirement requester, describe + registered-endpoint call (Cotal #399, the M4 conformance closure) | the same `retirement-requester` profile above, now calling through the generic client (`resolveService` + `invokeCommand`) instead of a hand-built subject | in addition to the exact-mode `retire-lifecycle` request row already granted above, the profile carries the baseline wildcard-endpoint `describe` row (`epDescribeAllGrantRow`, pinned to this caller's own triple) and a bounded contract-store direct-get row (`$JS.API.DIRECT.GET.<EPC stream>.<space>.epc.>`) so the requester can resolve the endpoint's registered contract digests before it calls; the request itself is still minted in `exact` mode, target-pinned to the one incarnation named at mint time; publish the same exact-mode request row as above + the describe wildcard row + the contract-store direct-get row; subscribe its own reply-plane filter and connection-scoped inbox; nothing else | mediated |\n| Governance head (registration linearization) | the provisioner-registration principal | the **unsplit** governance head `$KV.cotal_records_<space>.govern.<endpoint>` (§13.7): it reads the head FRESH under the frozen registration gate (a FENCING read, read service above: leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` last-by-subject on the head key, never the follower-served `DIRECT.GET` the records bucket would allow) and is the head's ONLY writer (slot-take CAS in phase 1, promote CAS after the spec publish); the SAME principal holds the write on `$KV.cotal_records_<space>.policy.<endpoint>.>` (each immutable policy version is published exactly once, before the stage CAS that names it). The immutability of a policy version is a TRUSTED-WRITER INVARIANT, not a broker-enforced subtraction: KV create/update/delete all publish to the one `$KV.…policy.<endpoint>.<digest>` subject, and NATS subject permissions cannot distinguish the create-CAS header or the `KV-Operation` header, so a subject grant cannot forbid an overwrite or DEL. The invariant is upheld by the writer's create-only CAS plus every reader's SELF-CERTIFICATION (§13.7: the value must digest to the key), so a changed-byte overwrite is REFUSED on read; the residual, confined to this prefix, is that a buggy or compromised provisioner could still DEL or same-byte-overwrite an enforced version and (history 1) destroy its availability, at which point admission pauses fail-closed rather than admitting under a lost policy. No agent, endpoint, observer, admin, or host profile holds any grant. The head is NEVER-DELETED (the `lifecycle`-head discipline): no grant permits DEL/PURGE on `govern.>`; a reader treats only TRUE ABSENCE as a virgin head, and a deletion marker refuses loudly as corruption (§13.12 retention floor), never as absence | mediated |\n\nTerminal pool cleanup settlement is lease-fenced across the two profiles above: the executor\nCASes the item's lease (or observes the winning settled lease), publishes/observes the exact\nlease-derived `wrk` terminal, and only then does the cleaner, after re-reading and\ncodec-validating that terminal, ACK the delivery. A `wrk` create that bypasses the lease CAS is\nnon-conformant: it can contradict a racing commit.\n\nAn `eff` completion fact `epf.<endpoint>.eff.<cO>.<cA>.<cUid>.<id>` is a CLOSED two-member\nunion carrying a REQUIRED `outcome` discriminant on EVERY member (the goal union's `state`\nbar, applied to effects: a member is never structurally assignable to the other, and every\nreader is forced to read the outcome). The RAN member is\n`{ v: 1, id, fingerprint, caller, sourceSeq, ts, outcome: \"ran\" }`; the RETIREMENT-CANCELLED\nmember is `outcome: \"cancelled\"` plus exactly `cancelled: { opId, target }` — the same\nidentity spine, plus the binding to the retiring target's lifecycle and the retirement\noperation that cancelled it. A fact missing the discriminant, or claiming one outcome while\ncarrying the other's fields, refuses. A reader that sees `cancelled` KNOWS the effect did not run; the member is never\na forged success. Both members' caller triple and `id` are bound by the subject, and their\n`fingerprint` and `sourceSeq` MUST equal the accepted decision's. The cancelled member may be\nwritten ONLY for an acceptance whose own `target` names the retiring lifecycle (a retirement\nnever cancels a foreign target's work), publishes CREATE-ONLY on the SAME subject the real\nmarker would use — so first-terminal-wins is structural: a racing real completion that lands\nfirst wins and the cancel loses its create harmlessly, and vice versa — and is produced by\nthe drain's per-op canceller profile (§13.9). An ACTION needs no new member: the `goal….result`\nunion already carries the first-class `cancelled` outcome state, and a retirement-cancelled\ngoal terminalizes through it with the same acceptance-fingerprint binding and the retirement\nattribution in its digest-bound payload (`data.cancelledBy = { opId, target }`). An\neffects-route drain compares the PARSED fact against the acceptance and treats EITHER bound\nmember as established; an action's drain instead requires the parsed `goal….result` fact whose\n`fingerprint` matches the acceptance. Subject presence alone never proves completion: a bare,\nmalformed, or mismatched fact refuses the drain loud (§13.8).\n\nRaw `STREAM.MSG.GET` and `CONSUMER.MSG.NEXT` authority carries a caller-selected reply subject.\nFor every trusted profile holding those APIs, D32 includes confused-deputy response injection:\ncompromise can direct fetched API/message bytes onto a foreign subject even though its\nconnection-scoped inbox prevents subscribing there. This is injection, not foreign read access,\nand requires a future fixed-destination mediation boundary to remove.\n\nDeletes beyond these rows: only the lifecycle-keyed deprovisioner (exact names, §13.1) and\nstream retention.\n\nA **mediated** row means the raw storage grant is held only by a narrowly scoped writer\nprincipal (per endpoint, never a universal writer), with authenticated caller binding,\nidempotent request semantics, and bounded failure/backpressure; CAS headers, fingerprint\nrules, schema validity, and digest-correct bytes are *enforced* there. A **direct** row means\nthe broker guarantees writer/key containment only, and the row **explicitly downgrades**\nCAS/schema/header/byte correctness to a conforming-client guarantee; readers of direct-row\nstate fail loud on invalid content. No profile (agent, observer, admin, host) holds generic\n`$JS.API.>`/`$KV.>`/`$O.>` authority over control-surface state, for the contract store that\nmeans the REAL subjects and APIs: **write** on `cotal.<space>.epc.>` belongs\nto the contract publisher alone (create-only per digest subject); **read** is the\nsubject-scoped last-by-subject Direct Get of the reader row above, never a body-selected\nform and never a consumer, because there is nothing to replay: one message per digest\nsubject IS the store, with verify-on-read as the tamper\nboundary; and the **stream-management surface** of `EPC_<space>`\n(`$JS.API.STREAM.{UPDATE,DELETE,PURGE,MSG.DELETE}.…`) is held by NO profile, publisher\nincluded, stream lifecycle belongs to space setup under operator provisioning authority\nonly, which is what \"immutable once published\" rests on (a `$OBJ.>` deny matches no NATS\nsubject and audits nothing).\nThe matrix is re-audited mechanically (decoded-credential fixture + live positive/negative\nprobes, with predicates over the real `$O.`/`$JS.API` subject forms) at every phase that\nadds a resource or changes ownership.\n\n**Writer table (core kinds, mediation decided, D7: authoritative CAS/schema record writes\nare mediated by separately scoped spec/status writer principals; an endpoint holds no raw\noverwrite grant on its own record keys).** `svc`, spec: the provisioner/registration path,\n**mediated** (CAS + schema enforced at registration); status: the owning instance's commit\npath, **mediated** with **epoch currency enforced at the writer**: the writing epoch is\nread from the broker-authenticated `epr` ingress subject (§13.2, the instance's serve\ncredential pins the epoch token there, so a stale process CANNOT claim the successor's\nepoch: the value is attested by the grant, never by payload), and the writer validates it\nagainst a FRESH read of the authoritative lifecycle mapping's `processEpoch`,\nrejecting a non-current epoch (`expired`), monotonicity against the stored status epoch\nalone is NOT sufficient, because between the takeover CAS (mapping N→N+1) and the completed\nrevoke/evict barrier the superseded N would still equal the stored status epoch and pass a\nbelow-stored check, and additionally rejects a below-stored epoch (`conflict`). The record\nkey is restart-stable and\ncannot carry the epoch (§13.1), so this epoch-pinned-ingress-plus-fresh-equality mediation\nis the record's only stale-writer fence.\n`signer`, spec+status: the space operator's registry tooling as the scoped writer\nprincipal, **mediated**. `handle`; keys are **issuer-namespaced**,\n`handle.<issuerKeyId>.<id>`, so two issuers can never collide or cross-revoke; spec: the\nissuer through the record-writer seam, create-only; status/revocation: issuer or space\noperator, **mediated and monotonic** (revoked never un-revokes; the signature stays the\ncontent authority; mediation enforces key grammar, CAS, and schema). `contracts` index, the instance, **direct** (explicitly advisory and\nnon-authoritative; `describe` is authoritative; readers fail loud on invalid state).\n`goal`/`cp` projections, status: the owning instance's commit path, **mediated**. Lifecycle\nmapping records (§13.1), the minting manager's commit path, **mediated**, CAS-only. The\n`govern` head (§13.7), the provisioner-registration principal, **mediated**, CAS-only (the\nmatrix row above).\nCanonical acceptance, work-pool enqueue, lease state, and contract-artifact publication,\n**mediated** per the matrix above.\n\n**Trait seam.** Core owns the fail-closed pre-effect verification interfaces (guard call,\npriced-proof verification, governed-attachment verification); policy engines, token formats,\nand payment rails remain extensions behind those seams.\n\n### 13.10 Receipts and signing trust anchors\n\n**Receipts.** A receipt binds a request to its outcome, signed and non-repudiable, for\nmetering, disputes, and pipeline causality; payment semantics stay opaque to core.\n\n`Receipt` = `{ v: 1, requestId, sourceSeq (the accepted submission's sequence, the\nexecution identity its subject carries, §13.2), space, endpoint, command, instance: { id, instanceId, epoch },\ncaller: { id, lifecycleUid }, schemaDigests: { input, output }, argsDigest, outcome: { ok,\ncode? }, resultDigest?, ts, signer: { keyId }, sig }`, canonical JSON, Ed25519-signed\n(`space` per the unconditional artifact rule below).\nLifecycle and epoch are recorded as **evidence**, never redemption authority. A command\ncarrying `ai.cotal.priced` MUST verify an independently verifiable payment proof in the\n`auth` slot before effect (never a bare \"settled\" assertion) and emit a receipt fact\n(`epf….receipt.<cOwner>.<cActor>.<cUid>.<id>.<sourceSeq>`, the caller- and\nexecution-scoped subject of §13.2; receipts are create-only per subject). A priced command\nis therefore journal-class: its receipt derives its identity from the accepted submission's\ndecision fact and its outcome from the committed terminal, never from emitter-supplied\nparameters, so a command with no acceptance fact has no receipt to emit; a conforming\nimplementation refuses to serve `ai.cotal.priced` on an ephemeral command (an\nadmission-time refusal at serve construction, never a first-request surprise). Receipt\nretention: default 90 d, ≥ the idempotency horizon (outcome-stated by the §13.12 retention\nfloor).\nVerification: signature against the anchor registry + digest recomputation; forged or\nrequest-mismatched receipts fail loud. Receipts MAY be emitted for unpriced commands.\n\n**Trust anchors.** One per-space registry covers every signed artifact of this section,\nauthorization slots, capability handles, checkpoint resumes, trait definitions and\nattachments, session grants, receipts. Anchors are `signer.<keyId>` records: spec =\n`{ keyId, publicKey (Ed25519), owner (the principal or reverse-DNS domain the key belongs\nto), roles ⊆ [handles, traits, receipts, resume, sessions, authz-slots, obligations,\npayments, consents], scope: per-role structured ceilings, for a `handles`-role key the **full grant\ndimensions**, in the handle-grant shape itself: the endpoints/domains, and per entry the\nmaximal commands, authorization modes, target patterns, instance ids, and read subtrees the\nkey may issue for (a handles- or receipts-role key without a dimension ceiling has that\ndimension closed, not open); for other roles the endpoints/domains it may attest for,\nvalidFrom, validTo }`, status = revocation. `issuer-authority` is defined by exactly this\nrecord: a verifier resolves the artifact's keyId FRESH at verification and enforces the role\nAND its scope under the §13.6 containment order (`handle.grants ⊆ anchor.scope`), a\nhandles-role key scoped to `com.acme.>` cannot issue for `manager`, a receipts-role key\nscoped to one endpoint cannot attest as another, and a handles-role key whose scope names no\n`handle`-mode targets cannot issue actor-pinned grants. Verification (fail closed): resolve the key,\nreject unknown keys, out-of-window use, role mismatch, or revocation (immediate for new\nverifications; effected work is not retroactively unwound). Rotation registers a successor\nand closes the predecessor's window; overlap is permitted for handoff. Third-party trait\nauthorities register under their reverse-DNS domain claim. Trust roots never merge across\nspaces.\n\n**Signature encoding (normative, D28).** For every signed artifact: the signature input is\nthe UTF-8 bytes of the RFC 8785 canonical JSON of the artifact **with its `sig` field\nabsent**; the signature is Ed25519 (nkeys); `sig` carries it base64url-encoded (unpadded).\nVerification recomputes the canonical form, resolves `signer.keyId`/`issuer.keyId` in the\nanchor registry, and fails closed on any mismatch.\n\n**Replay and claims matrix (normative, per artifact type).** Every row below additionally\nand unconditionally requires `space`, the signing `keyId` (`issuer`/`signer` per shape), and\n`sig` (the §13.10 encoding): an artifact missing any of the three is invalid before its\nreplay rule is ever consulted, and each artifact type is a discriminated schema, a verifier\ndispatches on the type, never duck-types the claims.\n\n| Artifact | Required claims | Replay rule |\n| --- | --- | --- |\n| Private tool-result consent (§13.19) | consent id, space, target (owner, actor, lifecycleUid), same-owner interactive holder, window of at most 24 hours, signing keyId and sig (§13.10) | holder-bound; create-only issuance and revocation records; canonical START frontier and current revocation/lifecycle checks per §13.19 |\n| Capability handle | id, space, issuer, holder (principal+UID), structured grants, iat, exp (nbf, parentDigest, epoch as applicable) | reusable within TTL, holder-bound; revocable if sturdy |\n| Checkpoint resume | checkpoint token, goal id, holder (principal+UID), iat, exp, nonce | **one-use** (journaled by create-only CAS); duplicate = `conflict` |\n| Session grant | sessionId, subjects, holder (principal+UID+processEpoch), serving instance+epoch, window, iat, exp, nonce | **one-use** redemption (holder epoch fresh-checked), then live; dies with either side's epoch |\n| Guard obligation | goal/request id, attenuations, iat, exp | bound to its goal/request; reusable within it |\n| Payment proof | per the priced contract's declared policy | default one-use per request id |\n| Trait attachment | endpoint, command, contractDigest, traitUrn, value, signer, ts | revision-bound evidence; replaced only by an authorized contract revision |\n| Receipt | per §13.10 shape (ts, signer; no exp/nonce) | evidence, never authority; replay-irrelevant |\n\nEvery verifier rejects out-of-window use (where `exp` applies), wrong-holder presentation,\nand unknown/revoked keys.\n\n### 13.11 The hard cut\n\nThis section is an intentional hard cut on the pre-1.0 line per §11. The version marker is\nthe grammar itself: the `ep`/`epe`/`epf`/`epj`/`ept`/`epw`/`eps` subject kinds and the\nversioned envelope are disjoint from every v0.3 control subject and shape, and the old rails\nare removed, subjects, envelopes,\nhandlers, credential grants, minting paths. No compatibility adapter, dual serving, or\ntranslation window exists. A credential minted before the cut can publish only into dead v0\nsubjects: nothing subscribes them, no post-cut handler is reachable from them, no trusted\nreply can be elicited (a pre-cut grant matches no endpoint-surface subject by construction,\nverified adversarially with captured pre-cut credentials from every old profile). The one\nstructural exception is the pre-cut `admin` profile, whose space-wide `P.>` subscribe\npredates and therefore MATCHES the new rails: **admin credentials MUST be re-minted at the\ncutover** to the post-cut admin shape (Appendix B: messaging-plane subjects only, no\n`ep*`/`eps`/`epc` subscribe), and the pre-cut admin credential is revoked with the cut;\nthe hard-cut guarantee is not honest without it. The wire\n`protocolVersion` (§6, §11) targets `0.4` at the completion of this revision's migration, per\nthe §11 convention that the advertised version is the migration's normative target, and a\nv0.4-conformant participant MUST advertise it (the optional-field era ends at the marker\nboundary); `1.0` is a separate, later stability declaration (§11).\n\n### 13.12 NATS + JetStream binding\n\n**Broker floor.** The control surface REQUIRES NATS server ≥ 2.12 (message schedules, atomic\ncreate-CAS, counters) AND a `max_control_line` large enough for the deployment's\nmaximum-capability CONNECT line. The two floors are checked at the tier that can see them:\n\n- **Clients** check the server version from the pre-auth INFO and fail loud below 2.12 or\n when schedules are unavailable (including the offline-assets downgrade mode). The\n control-line limit is NOT discoverable pre-auth; an oversized CONNECT is silently dropped\n and looks like a network fault, so a client's obligation is bounded reconnect attempts\n plus the named diagnostic on a repeated pre-auth drop (\"CONNECT may exceed the broker's\n max_control_line; have the operator verify it\"), never an infinite retry loop.\n- **Operator tooling** (doctor/setup) asserts the cause before any credential is minted:\n read `max_control_line` over the system account (`$SYS.REQ.SERVER.PING.VARZ`) from\n **every server of the cluster the credential may connect to**; the ping is fanned out,\n the response set is checked complete against the expected server count, and a partial\n response set is a FAILED assertion, never a pass, and require, on each server,\n `max_control_line ≥ (largest encoded CONNECT line of the §13.9 fixture set) + margin`.\n The fixtures are **byte-reproducible** (concrete maximum-length identities, the full\n grant set at the policy ceiling, the maximum-capability agent credential and the\n maximum-command serve credential, the encoded credentials, the resulting CONNECT\n lengths), so the floor is a measured quantity; the reference deployment's configured value\n is 65536; a derived number, not an assertion. The 16 KiB policy gate remains a distinct\n mint-time cap on credential authority, refused loudly at minting. The same assertion pass\n checks `max_payload ≥` the largest serialized **bounded decision fact** fixture (the\n maximum `RejectionFact`/`QuarantineFact` under the token and detail bounds, §13.4) AND\n `max_payload ≥` the 256 KiB contract-artifact document bound plus envelope margin\n (§13.7; a contract artifact is one message on its digest subject), so\n \"the rejection fact always fits by construction\" and \"an artifact is a single message\"\n are measured floors, not assumptions.\n\nNo sweeper fallback exists. Only 2.12 schedule semantics are assumed (same-subject\nreplacement; NOT the 2.14 stop-plus-publish path).\n\nPer-space resources, created at space setup (`STREAM.CREATE` remains denied to agents):\n\n| Resource | Captures / holds | Retention notes |\n| --- | --- | --- |\n| `EPJ_<space>` stream | `cotal.<space>.epj.>` (submissions, untrusted) | Limits; **native dedupe not relied upon**; submitters never set `Nats-Msg-Id` (§13.4; stream-wide header dedupe is a cross-caller suppression vector on a shared untrusted stream). A zero duplicate window is NOT server-accepted (`0` normalizes to the 120 s default; the minimum is 100 ms), so the config sets the server minimum and the guarantee is the header rule: a hostile header suppresses only another non-conformant header-bearing write; retention ≥ recovery/redelivery lag |\n| `EPF_<space>` stream | `cotal.<space>.epf.>` (canonical facts) | Limits; acceptance via create-only CAS (`Nats-Expected-Last-Subject-Sequence: 0`); `allow_direct=true` (NON-fencing subject-confined reads only: every §13.9 matrix fact read is FENCING and leader-served `STREAM.MSG.GET`, §13.9 read service); retention ≥ horizons, outcome-stated by the retention floor below |\n| `EPE_<space>` stream | `cotal.<space>.epe.>` (events, progress) | Limits; space policy |\n| `EPT_REQ_<space>` stream | `cotal.<space>.ept.*.*.*.*.schedule` (instance schedule REQUESTS, §13.2) | Limits; message schedules **DISABLED**; client-set scheduling headers are inert bytes here; retention ≥ writer recovery lag |\n| `EPR_<space>` stream | `cotal.<space>.epr.>` (record-write ingress, §13.2) | Limits; epoch-pinned publish grants (§13.9); consumed only by the record writer; retention ≥ writer recovery lag |\n| `EPT_<space>` stream | `cotal.<space>.ept.*.*.*.*.armed` + `….fire` (authoritative schedules + fires, §13.2) | `AllowMsgSchedules`; only the timer writer publishes `.armed` (§13.9); each schedule targets its sibling `.fire` subject (ADR-51 forbids target = publish subject); retention ≥ max deadline + margin |\n| `EPW_<space>` stream | `cotal.<space>.epw.>` (work pools; one item per subject, §13.2) | WorkQueue; provisioner-pre-created non-overlapping exact-filter per-pool consumers (§13.9) with **`max_deliver=-1` pinned** (a finite delivery ceiling strands exhausted items outside `num_pending`/`num_ack_pending` and falsifies the §13.6 admission occupancy; the occupancy reader re-checks the pin at every read because MaxDeliver is editable post-create); **`allow_direct=false`**: EPW has NO non-fencing subject-confined reader (pool workers drain the WorkQueue via `CONSUMER.MSG.NEXT`, never a subject read), and its ONLY subject read is the reconciliation probe, which is FENCING and MUST be leader-served `STREAM.MSG.GET` (§13.9 read service; an acked item leaves the WorkQueue, an in-flight one remains readable, which is exactly the §13.6 predicate, and a stale follower miss would re-arm settled work). Disabling Direct Get on EPW makes that leader-served requirement STRUCTURAL: no reader (including virtual-endpoint activation reconciliation, §13.6) can take the follower path even by mistake. This differs from EPF, which keeps `allow_direct=true` because it DOES have non-fencing subject readers (the §13.9 last-by-subject fact reads); EPF's fencing CAS-winner read opts into the leader by caller choice |\n| `WFJ_<space>` stream | `cotal.<space>.wfj.*` (the workflow STEP JOURNAL, §14.4: **one subject per RUN, `cotal.<space>.wfj.<runId>`, not one per entry**) | Limits, file storage, **no `max_age`** and no finite count/byte limit that evicts (an evicted prefix is not a shorter journal, it is a run that re-performs effects it already performed, and a run that sleeps for a month resumes by re-reading it; retirement is by subject purge, deliberately); **`allow_direct=false`** (a resume must read its own predecessor's last appends, and Direct Get is follower-servable, so a stale miss there reads as \"this step never ran\"). Deliberately outside the `ep*` plane letters: the journal is a runtime layer over the control surface, not part of the endpoint contract. Every append is fenced by `Nats-Expected-Last-Subject-Sequence` on the run's own subject (§14.4); a run's driver holds publish on exactly its own run's subject plus a per-takeover replay durable filtered to it, and there is no space-wide `wfj.>` publish grant |\n| (sessions: core-only, no stream) | `cotal.<space>.eps.>` | never captured; bounded in-memory window |\n| `cotal_records_<space>` KV | records: the §13.7 core-kind key grammars (`svc`, `signer`, `handle`, `contracts`, `goal`, `cp`, `lease`, `lifecycle`, `govern`, `uid`, `policy`, `oblig`, and the §14 kinds `run`, `answer`, `notice`, `migration`) | per-key CAS; `.spec`/`.status`-split keys EXCEPT the unsplit atomic keys `lifecycle.<owner>.<actor>`, `govern.<endpoint>`, `uid.<lifecycleUid>`, `policy.<endpoint>.<digest-hex>`, and `oblig.>` (§13.1/§13.7/§13.8/§13.9); `allow_direct=true`, but the heads and every fencing read are leader-served `STREAM.MSG.GET` (§13.9 read service). **No age retention on authority keys:** `lifecycle` heads, `govern`, `uid` reservations, `policy` versions, and `oblig` rows are NEVER-DELETED (no grant permits DEL/PURGE; an age-evicted reservation would reopen UID reuse, an evicted obligation would orphan accepted work); a deletion marker on any of them refuses loudly as corruption, never as absence. **Shape is proved at bind, not assumed:** the stream MUST be primary (never a mirror/sourced copy) and MUST carry no bucket-wide silent-eviction limit (no `max_age`, no finite `max_msgs`/`max_bytes`: under `DiscardOld` a finite global limit evicts a prior authority key's latest row the moment an unrelated key is written); every trusted consumer of this store (the minting authority, the mapping reader, the mediator) verifies exactly this via `STREAM.INFO` when it binds and refuses to serve otherwise |\n| `cotal_auth_<space>` KV | the credential ledger (`cred.<lifecycleUid>.<credentialId>` + issuance gates `gate.<lifecycleUid>` + the disjoint endpoint families `epgate.<endpoint>.<instanceId>` / `epcred.<endpoint>.<instanceId>.<credentialId>` + the staging family `stage.>` + source gates `srcgate.<issuerKeyId>.<id>` + lineage index `bysrc.…` + native-key issuance evidence `natkey.<userNkey>`, §13.1) + session ledger (`session.<sessionId>`, §13.6) | trusted auth path ONLY; no agent, endpoint, observer, admin, or host profile holds any grant (§13.9 matrix); **`allow_direct=false`** (every fence is a leader-served revision-pinned CAS write; Direct Get's follower/mirror reads would defeat read-your-writes, §13.1); CAS + monotonic states. **No bucket-wide age retention:** `gate.`, `epgate.`, `srcgate.`, and `session.` authority keys persist until their lifecycle/handle/session is explicitly terminal (an age-evicted `open` gate would silently reopen minting, or drop a `frozen`/`retired` fence); only `cred.`/`epcred.`/`bysrc.` rows carry a per-key TTL bounded by the credential TTL (NATS per-key message TTL, ≥ 2.12), never a bucket MaxAge; `stage.` rows follow their operation's retention, never a ledger row's. **Shape is proved at bind** (the records-store rule above, plus `allow_direct=false`): primary, un-mirrored, no bucket `max_age`, no finite `max_msgs`/`max_bytes`; the trusted auth path verifies this via `STREAM.INFO` when it binds and refuses to serve otherwise |\n| `cotal_issued_<space>` KV | issued-authority evidence (§13.15): `v1.<owner>.<actor>.<uid>.<generation>` (immutable evidence), `attempt.v1.…` (the one-field attempt row), `bysource.v1.<sha256>.…` (the reverse index from a source gate to the issuances depending on it) | Limits, file storage, no stream-wide age eviction, **`allow_direct=false`** (every read is a fence); create-only evidence, revision-CAS attempt. **Bounded by per-message TTL:** `allow_msg_ttl=true` and no subject delete markers; each row carries its own TTL to its generation's horizon plus the retention margin (§13.15), and nothing else removes it, so no row goes while its generation can authorize anything (a run admitted under it keeps its ceiling in its admission, §14.8). A store without `allow_msg_ttl` predates bounded retention: every provisioner, issuer and resolver checks both stores' shape with `STREAM.INFO` when it binds and refuses it, before it reads or writes either, and it is recreated, never adopted. Immutability is BROKER-ENFORCED the way the EPC store's is: `allow_rollup_hdrs=false, deny_delete=true, deny_purge=true`, set once at creation and verified by every provisioner that binds, so a holder of the issuer's own key row cannot replace evidence or empty the bucket with a `Nats-Rollup` header, a message delete, or a purge |\n| `cotal_accepted_<space>` KV | accepted rows (§13.15): `accepted.v1.<acceptedToken>`, one per issuance, written by the issuer at release | Limits, file storage, `allow_direct=true`: the client's per-key `DIRECT.GET` is the discovery read; create-only, with the same three broker-enforced flags and the same per-message TTL retention as the evidence store: a row lives until the horizon of the generation it names plus the retention margin |\n| `cotal_admission_<space>` KV | run admissions and revocations (§14.8): `admission.v1.<endpoint>.<runId>`, `revoked.v1.<endpoint>.<runId>` | Limits, file storage, no age eviction, `allow_direct=false`; both keys create-only and the marker permanent, BROKER-ENFORCED by `allow_rollup_hdrs=false, deny_delete=true, deny_purge=true` (a run-admitter's own key row admits no `Nats-Rollup` replacement of the admission, and no purge empties another run's row); retained while the run, its program, its journal or its lineage is resumable |\n| `EPC_<space>` stream | `cotal.<space>.epc.>` (content-addressed contract artifacts, one per digest subject, §13.7) | Limits, no age eviction (artifacts are permanent); create-only mediated publication (`Nats-Expected-Last-Subject-Sequence: 0`); `allow_direct=true` (the subject-scoped last-by-subject read IS the fetch path; non-fencing, verify-on-read); permanence is BROKER-ENFORCED: `deny_delete=true, deny_purge=true` (the broker rejects the message-delete and purge APIs even from a stream-API-holding principal). Permanence is the COMBINATION of these flags, the retention floor's no-early-removal rule (below: the flags alone stop delete/purge but not age eviction or a whole-stream teardown), verify-on-read pinning WHAT a subject carries, and the stream-management surface held by no profile (§13.9); no single flag makes deletion structurally impossible |\n\n**Retention floor (one-use-identity facts).** A stream or bucket whose messages carry\none-use identity, that is decision facts realizing the §13.4 idempotency horizon, goal\nterminal facts and tombstones (§13.6), receipt facts (§13.10), and the never-deleted\nauthority heads (`lifecycle`, `govern`, the auth-bucket gates), MUST retain every protected\nmessage until its governing horizon, stated by OUTCOME: NO removal cause may drop a\nprotected fact early. That forbids not only age eviction below the horizon but every\nconforming alternative that erases it while `MaxAge` still passes: a finite\n`MaxMsgs`/`MaxBytes`/`MaxMsgsPerSubject` with `DiscardOld`, a per-message TTL,\nrollup/compaction, or a retention-policy change; for these families finite count/byte\nlimits MUST fail loud or `DiscardNew` rather than evict protected history, and message TTL\nand rollup MUST be disabled on protected subjects (a per-key TTL is permitted only on\nnon-protected keys, e.g. the auth bucket's `cred.`/`bysrc.` index rows above and the\nissued-authority rows, whose TTL ends after their generation's horizon (§13.15), never on a\nprotected fact, head, or gate). NO principal, including operator, setup, and system tooling,\nnot only §13.9 profiles, may `MSG.DELETE`/`PURGE`, `STREAM.DELETE`, or issue a\n`STREAM.UPDATE` that weakens any of these limits; the never-deleted heads and gates carry\nan UNBOUNDED horizon. A KV writer MUST NOT publish a DEL/PURGE marker for a never-deleted\nkey, and a reader that encounters one treats it as corruption, never as absence. (Root can\nalways destroy a broker; such an act is explicitly non-conformant, not outside this\nclause.) `CONSUMER.DELETE` is distinct and permitted: it removes a reader cursor and can\nnever mutate stored facts. Concretely: `EPF_<space>` retention ≥ max(idempotency horizon,\nresult retention, receipt retention), because the acceptance fact is the durable\nreconstruction source for receipts, while the raw submission stream is age-evicted by\ndesign.\n\nClaim pools are pull consumers on `EPW` with `AckExplicit`, held **only by the pool's owning\nendpoint** (§13.5): `ack_wait` is the broker's redelivery-to-owner timer and nothing more;\nthe authoritative lease token and deadline live in the owner's lease record, never in the\nitem value (stored bytes are work identity and input only), and the owner acks only after\nthe committed terminal state. Filtered replay of events/facts uses pinned single-filter\nconsumer creates (the CHAT-history containment mechanism, §8/§9). Timer scheduling is\n**mediated** (§13.2, §13.9): instances publish only `.schedule` REQUESTS into the\nschedules-disabled `EPT_REQ` stream, where a client-set `Nats-Schedule-Target` (or any\nscheduling header) is inert bytes and the timer writer rejects a request carrying one, this\ncloses the ADR-51 confused deputy, in which a direct publisher confined only to \"some\nsubject the schedules stream captures\" could target ANOTHER instance's `.schedule` (installing\nor replacing its schedule state, since schedule headers are copied to the target verbatim) or\nits `.fire`. The timer writer alone publishes the authoritative schedule on `.armed`, with\n`Nats-Schedule-Target` = the sibling `….fire` subject derived from the authenticated request\nsubject's own tokens; and **fire handling is the trusted seam** behind it, a `.fire`\nconsumer acts only on a fired message matching a current authoritative\nschedule it owns (`timerId` + generation + deadline, §13.2) AND whose broker-authored\nscheduler-origin header (`Nats-Scheduler`, the schedule's subject, set by the server on\nfire) equals its own exact sibling `.armed` subject, discarding anything else as\nforged. Replacement is the writer's same-subject publish on `.armed` (server rollup); fired\nmessages appear on `.fire` carrying `(timerId, generation)`.\n\n### 13.13 Plane ownership (the sealed-scanner claim)\n\nAt most ONE authority plane per space may hold the sealed scanners (§13.9's seventh-round\nseal). One process MAY hold the planes of several spaces, each with its own\nclaim row, scanner connections and fence; the exclusion below is per space. The scanners' serialization is process-local, so two same-space auth processes would\ninterleave the literal enumeration consumers' critical sections and return PARTIAL\nenumerations: a drain declares quiescence over undrained obligations and the retirement\nfrontiers close over live work. The exclusion is broker-visible, not host-local:\n\n- **The claim row.** One exact, never-deleted auth-KV key (`plane`, subject\n `$KV.cotal_auth_<space>.plane`) holds `{ v, generation, claimId, state: held | released,\n ledger, records, openedAt }`, where `ledger`/`records` are the two ownership-bearing sealed\n scanner connections' broker identities `(serverId, cid, userNkey)`. The barrier profile is\n the row's SOLE writer, at exact arity (never `plane.>`); reads are leader-served. The\n barrier's own identity is deliberately NOT in the row: barrier liveness is irrelevant to the\n literal consumers and could only falsely block a reclaim.\n- **Open order.** Ensure stores; open BOTH candidate scanner connections NON-RECONNECTING (the\n tuples must be stable and disappearance must be final) and keep them INERT (no scan\n capability exists or escapes); take the claim by broker-atomic create (virgin key) or\n revision-CAS (a `released` row, or a `held` row proven dead as below). Only the WINNER\n constructs the branded scanners; a loser closes both candidates and refuses with\n operator-legible copy. The brief dual connected-credential window before the CAS is inside\n the trusted signing-seed residual; there is no dual SCAN authority because the capability\n does not exist before the win.\n- **Plane credentials.** The two plane-owned scanner connections authenticate with\n NON-EXPIRING user JWTs. The separate host-private tool-result custody profile (§13.19)\n adds two more non-expiring, non-reconnecting connections, one reader and one writer.\n No plane claim is implied by custody. These are three profiles and four standing\n connections in total. For each, an expiring\n credential would have the broker hard-disconnect at expiry, and a renewal cannot be\n presented without the reconnect the non-reconnecting shape forbids — an expiry would fence\n the plane on a timer. The credentials never leave process memory, and the account signing\n seed co-resident in the same memory is strictly stronger authority, so the marginal\n exposure is the existing trusted-process residual class; revocation remains service-stop +\n seed rotation. Service stop closes owned sockets; a copied JWT and user seed remain usable\n until signing-key removal, no longer bounded by the ordinary 900-second credential expiry.\n Every other authority credential, including the short-lived tool-result CREATE provisioner,\n keeps the short-expiry + in-process-renewal boundary. Custody accepts no reconnect or\n re-adoption: any real loss, broker restart or upgrade included, leaves gate 1 permanently\n unavailable for that space until a separately authorized retirement/reprovision protocol exists.\n- **Reclaim is liveness-only.** A `held` row is reclaimed only when BOTH claimed tuples are\n conclusively ABSENT under a COMPLETE connection sweep, adjudicated by the delivery daemon's\n read-only oracle over the privileged delivery-admin rail (the auth process holds no `$SYS`;\n the D5 rail split). The closed oracle verb takes exactly the two claimed tuples and returns\n two bound verdicts (`live | gone | unknown`) plus sweep completeness, echoing the queried\n identities; any live, unknown, incomplete, malformed, or foreign-echo answer REFUSES the\n takeover (at most one plane: dual-refuse is safe, dual-proceed is not). There is NO TTL, NO\n heartbeat, and NO \"did the last sealed scan finish\" bit: a mid-scan crash drops the\n non-reconnecting connections, a complete sweep proves them gone, and the successor's\n fail-closed pre-clean (§13.9) makes its full re-scan safe. A paused-but-live process still\n holds its TCP connections and therefore still holds the plane (no pause hazard).\n- **The single-server proof.** Connection absence alone cannot distinguish a RESTARTED\n claimed server (`server_id` is per-broker-run; genuinely gone, and requiring its reply\n forever would turn every whole-stack crash into a permanent reclaim wedge) from a\n PARTITIONED one (live, unreachable; treating its absence as death authorizes a split-brain\n steal). A `gone` verdict is therefore valid ONLY under the single-nats-server-process\n boundary, proven per observation from the responding server's OWN topology declaration in\n the `$SYS` reply envelope — never inferred from which servers happened to reply: every\n reply must declare NO cluster membership and exactly one distinct server may have replied.\n Any cluster self-report, multi-server observation, or reply without the declaration reads\n `unknown` and refuses. Only a SUCCESSFUL, well-formed page counts toward the sweep: a reply\n carrying an API error, a malformed or empty server envelope, a non-string cluster\n declaration, an envelope/data server-id mismatch, or a structurally incomplete data page\n poisons the whole observation (every verdict `unknown`). Each sweep's reply inbox carries a\n per-call collision-resistant nonce, so concurrent sweeps can never satisfy or falsely\n complete each other's rounds; and the auth plane closed-parses the oracle's result (exact\n keys at every level) before reasoning over it. NAMED residuals: a leafnode- or\n gateway-extended account is outside the cluster self-report, so such topologies are out of\n contract for the space's account; a backup restored onto a fresh broker can present a\n still-running foreign predecessor's `serverId` as dead. A clustered/multi-server deployment\n requires an authoritative server incarnation/roster authority in place of this proof.\n- **Holding invariant.** The winner re-validates the claim (state `held`, its `claimId`, its\n `generation`, AND both pinned scanner tuples — a row rewrite preserving the identifiers but\n swapping a tuple is a lost claim, never \"still ours\") BEFORE every sealed scan (refuse to\n enumerate) and AFTER it (discard the enumeration), inside the serialized critical section.\n An owned scanner disconnect is a FENCING event, and the fence is FATAL to the WHOLE\n authority plane: scan exposure is invalidated immediately, the sibling closes, every\n authority operation (connect authorization, credential mint) refuses from that moment, and\n the service goes DOWN loud rather than serving from a half-dead plane a successor may be\n reclaiming (in a process serving several spaces, that space's service goes down and the\n others' planes are unaffected); a still-live sibling correctly blocks a successor until it is closed or proven\n absent.\n- **Clean close.** Scan-capable clients close FIRST, then the row CASes `held → released`\n (never released while either scanner can still act), then the barrier. A crash leaves\n `held`; the successor reclaims through the oracle. A `released` row is claimed without an\n oracle round. A close whose release did not commit (the row is no longer this plane's, or\n the write failed) still closes the barrier and then reports the failure to its caller.\n- **Operator faces.** The three refusal states carry DISTINCT copy: a live peer (\"stop the\n other auth process\", with the space and connection identities), an inconclusive observation\n (fail-safe wait/retry wording that never says \"stop the other process\"; when the oracle rail\n is down it names the delivery daemon and the restart order), and a mid-life scanner death\n (a deliberate fail-closed stop naming the restart path). An unparseable claim row refuses\n loudly and is never overwritten automatically. Every claim refusal also carries the\n `ai.cotal.auth.plane-claim-refused` detail (§13.3), whose `reason` names the state\n (`corrupt`, `live-peer`, `unknown`, `concurrent`, `fenced`, `released`, `lost`), so a host\n never parses the copy to tell contention from corruption.\n- **Host belt.** Launchers additionally claim an exclusive per-space pidfile, published\n ATOMICALLY and PRE-POPULATED: the claimant writes its pid to a unique temp inode, then\n publishes it as the slot with an atomic no-overwrite `link(2)` — no create-then-write window\n exists for a sibling to misread, and an empty slot is impossible to publish. A live holder\n is yielded to; a provably dead holder's slot — and an empty (pre-protocol crash shape) one —\n is reclaimed exactly once; unattributable content is never stolen. A cheap belt only, never\n the exclusion.\n\n### 13.14 Conformance (control surface)\n\nA conformant endpoint (v0.4) MUST:\n\n1. Serve only under a credential whose serve grants match its registered name, stable\n instance id, and registered command set (publish-side grants pinned to the current\n epoch); register its service record before serving; advance the epoch by CAS on takeover\n and stop serving when superseded; a takeover is complete only after the §13.1 barrier\n (revoke + cluster-verified eviction of the superseded credential).\n2. Answer `describe` authoritatively, intersected only against the trusted authorization view\n (or declared-public), failing closed when that view is unavailable.\n3. Publish contract artifacts content-addressed and immutable; validate args/replies at\n runtime within the schema profile and budgets.\n4. Reply only on the reply rail derived from the authenticated request subject; ignore\n payload/transport reply targets; let attribution ride the reply subject.\n5. Enforce the envelope invariants (version/op/class/target/sender, catalog codes, monotonic\n attenuation); treat the subject, never the body, as the authorization boundary; resolve\n targets by `(alias, lifecycleUid)` against current mappings immediately before effect.\n6. Route effects by delivery class; journaled effects only from canonical accepted facts\n through the mediated writer; fingerprint-bind ids first-wins; hold the declared horizons,\n retentions, and floors.\n7. Validate every Cotal-owned commit through the mediated path (fencing token + unexpired\n lease + lifecycle + epoch as applicable); lose CAS loudly.\n8. Implement advertised composites per §13.6: the single action vocabulary, authorization\n linearized at acceptance, one-use resumes, generation- and scheduler-origin-validated\n timers (a fire counts only against its own sibling `.armed`, §13.12) with durable\n reconciliation, fail-closed governed traits, bounded sessions.\n9. Fail loud below the broker version floor (from the pre-auth INFO), with bounded\n reconnects and the named pre-auth-drop diagnostic (§13.12); the `max_control_line` floor\n is asserted by operator tooling (§13.12), never by the client, which cannot inspect it.\n10. Connect successfully while presenting the normative maximum-capability credential\n fixture for its profile (§13.9), the only test that exercises the control-line bound.\n\nA conformant caller (v0.4) MUST: hold a lifecycle-pinned credential and never present another\nlifecycle's artifacts; choose ids/goalIds/nonces within the token grammar and the 1024-byte\nsubject bound and reuse ids only per the idempotency rules; declare `class` and\n`replyExpected` and honor `contract-mismatch`/`conflict`; freeze scatter expectations from the\nregistry and classify partial results; verify digests of fetched artifacts and signed\nartifacts against the anchor registry, failing closed; refuse to resolve a **describe descriptor**\nwhose `protocol.v` it does not implement (the marker rides the descriptor and the service record,\nnever the cluster document, which carries no `protocol`), and never automatically repeat a `write`\ncommand (§13.7) — whatever `id` the re-issue carries — except on an outcome that proves\nnon-execution (§13.3).\n\n### 13.15 Issued authority\n\nThe caller triple (§13.1) says WHO is calling. It does not say what the credential they are\ncalling with was granted, and a host that performs an effect on a caller's behalf needs that:\nthe ceiling as the issuer accepted it, immutable, and bound to the request by the broker rather\nthan by anything the caller or a mutable ledger says. This section defines that binding.\n\n**The reference.** An issued authority is `{ space, owner, actor, uid, generation }`: the\ncaller triple plus a **generation**, 32 lowercase hex characters. The first 8 are the\ngeneration's **horizon**, the unix second at and after which it authorizes nothing, in big-endian\nhex; the last 24 are issuer-chosen entropy (96 bits). A generation is an identifier, never a\nbearer secret. It is chosen by the issuer, never by the client, and is never reused: a reference\nis created once or refused. The horizon rides the generation, so the broker pins it on the\nrequest subject with the rest of the rail, and nothing written to a store can move it.\n\n**The rail.** An issued credential's request-publish and reply-subscribe rows ride the\nversioned rail (§13.2), with its generation pinned literally beside its triple. A request\narriving on `ep.v1` therefore carries a broker-confined generation, and a request arriving on\nthe legacy rail carries none. A body field, a header, or a policy reference supplied by the\ncaller establishes no binding.\n\n**Issuance.** Before an issued credential's material is returned, the issuer MUST persist its\n**evidence** in `cotal_issued_<space>`: `{ version: 1, ref, sources, permissions, expiresAt? }`,\nwhere `permissions` is the credential's final effective permission ceiling (publish and\nsubscribe, each an explicit `all`, `none` or `patterns` allow plus a deny list, imported from the\nnative permission fragment so an omitted list can never read as a narrow one) and `sources` are\nthe gate coordinates the issuance depends on. `expiresAt`, when present, is no later than the\ngeneration's horizon. Issuance is `prepare → release`: the evidence and\na `prepared` attempt row are written create-only, the issuer performs its own finalization, and\nthe attempt row is CAS-advanced to `active` at the revision the prepare observed. A prepare that\nloses its create is refused; a release whose CAS loses is `aborted`. The evidence store is\nappend-only at the broker (§13.12: unlimited per-key history, no rollup header, no message delete,\nno purge; a row ends only by its own TTL, below), and the evidence and source-index rows are read as the FIRST message on their key, so a\nlater write on the same key by a holder of the issuer's bucket-wide row is inert to every\nresolver; only the attempt row advances, by CAS. The issuer also writes the\n**accepted row** (`cotal_accepted_<space>`, keyed by a token the launching party chose) naming the\nreference, create-only. A client learns which generation it was bound under by reading that one\nrow over a per-key `DIRECT.GET` grant its ceiling carries; it never trusts what it proposed or\nwhat a file says, and it refuses a row naming another owner, actor or lifecycle.\n\n**Retention.** Every row of a generation in either store (its evidence, each attempt state, each\nsource-index row and its accepted row) is written with a per-message TTL (`Nats-TTL`) that keeps\nit until the generation's horizon plus a retention margin of 60 seconds, and no longer. Nothing\nelse removes it. No resolution, renewal or retirement reads or writes a generation's keys at or\nafter its horizon; it refuses the generation as expired first. A key the broker removed, and\nanything later written on it, is therefore never read as that generation's row. The margin\ncovers the clock difference between a writer, the broker and a reader. It need not cover how long\na resolution takes, because the horizon is checked again after the last read. A credential minted\non a generation by a static issuer (a static incarnation's credential, an operator instrument)\nexpires no later than the horizon. A static incarnation's generation has a horizon 30 days after\nits issuance; each renewal of its credential is capped at it, none is minted at or after it, and\nthe incarnation is respawned to continue. A run admitted under a generation keeps its ceiling in\nits admission (§14.8), so removing the generation's rows after the horizon ends no run.\n\n**Renewal.** A renewal of an issued credential keeps its generation only when the ceiling being\nminted is byte-identical (RFC 8785) to the recorded evidence; a changed ceiling is refused as a\nrenewal and is a fresh issuance on a fresh generation, which the client adopts only through a\nnew connection. Refreshing a credential file never switches the generation of an already\nconnected transport. A renewal at or after the generation's horizon is refused before the store is\nread.\n\n**Resolution.** A host that admits an effect under an issued authority resolves it: the\ngeneration is before its horizon, the evidence exists, the attempt row is `active`, the evidence\nis unexpired, every source is live, a second read of the attempt row returns the same revision,\nand the generation is still before its horizon after that read. Any other outcome refuses. A\nretirement of a generation at or past its horizon writes nothing, since every reader already\nrefuses it. The\none source shape this revision issues against is a static incarnation's credential ledger family\n(`cred.<lifecycleUid>` on `cotal_auth_<space>`), whose liveness is its issuance gate not being\n`retired`; a lifecycle terminal retires every issuance indexed to that family\n(`bysource.v1.…`), so a retired incarnation's generations refuse to resolve afterwards.\n\n**User-auth issuance.** On a user-auth space the issuer of an eligible actor's `manager-caller`\nview connection is the auth service, at its callout, and the material is the user JWT the callout\nreturns. Interactive rows retain their issuance path. A managed-agent row is eligible only when its\ncurrent persona-derived scope contains `run` AND a fresh read of its direct parent principal's row\nfinds `run` in that same owner's current grant. An admin parent's containment bypass is not a `run`\ngrant. A missing, malformed, foreign-owner or no-run parent grants no issuance. The existing\n`authorizeManagerCaller` instance gate and `VIEW_REQUIRED_SCOPE` remain unchanged. No request kind,\nview, signer or authority door is added, and ordinary command grants still derive from signed\n`act.scope`, contained against the current child row. The issued view carries the per-key\naccepted-row read beside its instance-pinned rows. It chooses\nthe generation, whose horizon is the bearer's expiry, persists evidence whose permissions are the set it signs and whose one source is\nthat row, `{ space, bucket: \"cotal_actors_<space>\", key: \"actor.<owner>.<actor>.<lifecycleUid>\" }`,\nreleases it, and writes the accepted row, all before it returns the JWT. The accepted token is the\nfirst 32 lowercase hex characters of SHA-256 over `\"cotal.accepted.v1\\0\"` followed by the\nconnection's inbox nonce: the client chose the nonce and derives the token from it, and no token is\nread from a request body. The source is live while the auth service's actor ledger holds a row for\nthat owner and actor carrying that lifecycle UID; a revoked row, or a re-grant under another UID, is\na dead source at the next resolution. Only the auth service attests this shape; every other host\nrefuses it as a coordinate it cannot attest. A reconnect under the same nonce finds the existing\naccepted row. When the row names the same triple, the generation is before its horizon, and the\nceiling being minted is byte-identical to the recorded evidence, the callout renews that generation; otherwise it refuses the connect, and the\nclient adopts a fresh generation only through a new connection under a new nonce. A managed\nissuance's single source is the child's own actor row and lifecycle, not its parent. A managed seat\nmissing either eligibility predicate keeps the legacy manager-caller mint for ordinary commands,\nand `run-start` refuses with `permission-denied`. Without a signed `run` capability the broker\nrefuses the publish. With signed `run` but no eligible parent, the manager returns\n`ai.cotal.ep.unbound-caller-authority`. Failed\nissuance never retries on the legacy rail. The `agent` profile and every other view keep that rail.\n\n**Platform-owned user supervisor.** A trusted host composition MAY issue the closed manager-service\nregistration material for one ordinary derived owner without that owner's IdP proof. This is an\nin-process administrative door, not a user-token exchange. Its recorded assignment MUST name one\nowner, space, account, manager instance, lifecycle UID, revision and finite expiry, and MUST carry\nonly `supervise`. The host MUST authenticate platform-admin authority and re-read the assignment\non every request. The worker's door MUST be bound to that owner and refuse another owner by name.\nIt MUST NOT export an administrative bearer, signer, mint surface, human exchange or cross-owner\nenrollment. The existing fixed manager actors, public nkeys and registration proof remain unchanged.\n\nThe host MUST cap every returned credential at the assignment expiry and refuse issuance after the\nassignment ends. The supervisor and executor registration ceilings MUST be persisted through the\nexisting issued evidence and accepted-row stores before material is returned, with expiry as their\nrecorded lifetime and as their generation's horizon. The recorded permission set MUST be byte-identical to the native permission set\nsigned by the authority plane at issuance and every renewal. Renewal MUST resolve and confirm the\noriginal ceiling and MUST NOT widen it. These JWTs are signed by the authority plane, not the\nuser-token callout. These registration\ncredentials hold no caller rail, so no generation claim is added to their request subjects. The\nother standing duties retain their endpoint gate and credential-family protocol.\n\nWhen the platform ends an assignment, the host MUST record it `ended` and then end its issuance at\nthe authority plane. Ending retires the instance's manager gate (`retired`, op kind `retirement`)\nand retires the issued supervisor and executor generations. Both are terminal rows. From then on,\nevery door that accepts this material MUST refuse it by name, even when the material has not\nexpired. Stock registration refuses on the retired gate. Prepare, activate, `renew` and\n`renewStandingBundle` refuse on the retired generation, read on every call before anything is\nsigned, so a stale host read that still reports the assignment `assigned` reopens nothing. The\ndoor reports `platform supervisor assignment for owner <owner> has ended`. The material's own\nbroker connection lives until its capped expiry: its gate row is writable under its own grant, so\na client that bypasses stock registration can still rewrite that one row. Live eviction remains the\nhost's retirement barrier.\n\n**Compatibility.** A command whose semantics require the binding (this revision: `run-start`\nand `run-cancel`, §14.8, and `run-start-keyed` and `run-submission-status`, §14) MUST refuse a legacy-rail request\nwith `permission-denied` carrying the detail kind\n`ai.cotal.ep.unbound-caller-authority` naming the caller triple, never route it through the\nhost's own authority. The signerless resume and answer restrictions in §14.8 also apply, including\nthe managed-seat legacy answer exception. Commands without these restrictions serve both rails. Origin (that a request on\na generation-pinned subject was published by the grant holder) is a property of the grant set,\nnot of this section: no peer-held profile pairs a write with a raw stream read on one stream, and\nmediated reads remain the remedy.\n\n### 13.16 Delegated user intent\n\nA host platform that runs a `platform-control` service view MAY let that view's manager (the\nholder) execute one launch or one retirement that a signed-in user asked for, while the intent and\nthe resulting agent stay the user's. This subsection adds no exchange view, profile, holder grant or\nstanding delegation, and changes no other clause. A host that does not implement the\n`platform-control` service view, or holds no intent store, MUST refuse both requests below as\n`unimplemented`, and stock dispatch MUST refuse both kinds as `unimplemented`.\n\n**Admission.** A user admits an intent with one closed `delegated-user-intent` request on the host's\nauthenticated human route, the transport the `manager-service` typed requests use. The host MUST\nverify the user's IdP token, derive the owner from the verified subject as it does for a signed-in\nhuman, and read the named actor's ledger row fresh; the row MUST carry `spawn`. The host MUST NOT\nstore, forward or record the token, and MUST NOT read, require, synthesize or write `supervise`. The\nrequest carries the space, the assigned account public key, the user's actor, one platform control\ninstance id, a request id, and one operation: `launch` with one managed-agent enrollment target\nminus its token digest, or `retire` with one `{ owner, actor, lifecycleUid }`. An unknown field,\nincluding an owner, IdP token, scope, serve epoch or token digest, MUST be refused as `bad-request`\nwith no effect. For a launch, the host MUST read the account's platform-control assignment and that\ninstance's manager gate fresh and refuse unless the assignment is `assigned` for this account and\nnames that instance and the gate is open under the platform serve principal, and the requested scope and channel lists MUST lie within\nthe user's actor row under the managed-agent envelope rule. For a retirement, the target owner MUST\nequal the derived owner, and the target lifecycle MUST be one that the host's own record shows a\ndelegated launch on that instance produced and enrolled, for a launch target whose actor equals the\nretirement target's actor; the host MUST compare the launch's target actor, never the user actor\nthat admitted the launch. Any other lifecycle MUST be refused. The host generates\nthe intent id from at least 128 bits of entropy, never from caller input. It binds the account, the\ninstance id, the assignment's lifecycle UID and revision, the gate's process epoch (null for a\nretirement whose launching holder is gone), the one target, the user's principal `<owner>.<actor>`\nas parent, and an expiry at most 300 seconds ahead, and creates the record create-only.\n\n**Execution.** The holder executes an intent with one closed\n`manager-delegated-user-intent-execution` request on the host platform's own route for that holder;\nthe `platform-control` envelope does not carry this kind and refuses it as an unknown kind. The\nrequest names the intent id, the space, the fixed `cli` actor constant that keys the registration\nproof, the account, the assignment revision, the instance id, the manager lifecycle UID, the serve\nepoch, the registration proof, the identities, and one target: the launch target's actor with the\nSHA-256 digest of an actor token the holder generated, or the retirement's `{ owner, actor,\nlifecycleUid }`. The host MUST read the record fresh and refuse as `failed-precondition` an absent\nrecord, an admitted record past its expiry, and a consumed record unless the request is a retry of\nthe execution that consumed it (below). It MUST refuse as `permission-denied` any difference from\nthe record in account, instance id, manager lifecycle UID, assignment revision, operation, serve\nepoch or target. It MUST re-read the assignment and refuse as `permission-denied` one that is\nabsent, revoked, or differs from the record in space, account, instance id, manager lifecycle UID or\nassignment revision. It MUST re-read the gate, refuse a gate whose principal is not the platform\nserve principal, refuse a gate epoch other than the request's as `conflict`, and require the\nhost-keyed current registration proof. Every check completes before any effect. The host then MUST\nCAS the record from `admitted` to `consumed` at the revision it read, and that same write MUST pin\nthe execution: the request id, the serve epoch, the lifecycle UID (host-selected before the CAS for\na launch, the target's for a retirement), the launch's token digest or the retirement's\noperation id, and the host incarnation `{ instanceId, processEpoch }` that executes it. A lost CAS is `conflict` and nothing is enrolled or retired. Because the reads are not\nfences (§13.1), the host MUST repeat the assignment and gate checks for a launch after the CAS and\nbefore any effect, and on a refusal MUST compensate the launch (below) before it ends the record\n`aborted`; a change that lands after that second read is ordered after the execution. An intent\nexecutes at most once and confers nothing after it executes.\n\n**Recovery.** From the CAS on, the host owns the pinned execution, whoever presented it. It MUST\ndrive every consumed record to one outcome, `enrolled`, `retired` or `aborted`, at the pinned\nlifecycle UID, including after a restart or a lost answer. For a launch, the host's first effect\nafter the post-CAS checks MUST be the issuance activation of the alias at the pinned lifecycle UID\n(§13.1), before any ledger row or durable, so that UID has an active head and an open issuance gate\nbefore anything is granted under it. Every launch that ends without `enrolled` after its consuming\nCAS MUST be compensated before it is marked `aborted`, whichever flight observed the refusal,\nbecause a flight that resumes the execution cannot tell whether an earlier flight began the\nactivation: the retirement sequence below at that UID, with that UID's activation completed or\nadopted immediately before the terminal barrier. Before that activation the compensator MUST read\nthe head and the issuance gate at that UID. Once a retirement there has begun, because the head is\nretiring or retired at that UID or the gate is frozen or retired by `managedRetirementOpId` of that\nUID, the compensator MUST NOT run or adopt an activation and MUST go to the terminal barrier, which\nresumes that operation from its durable intent.\nOnly the barrier's answer that the lifecycle is retired at that UID is terminal confirmation; a\nnot-started answer MUST NOT be read as one. When that activation is refused because the alias is\nactive or retiring at another UID, the record MUST keep no outcome and the compensation MUST be\nretried. A request\nwhose request id and serve epoch, and a launch's token digest, equal the pin is a retry of that\nexecution: it passes the same checks except the consumed state, writes no second CAS, and MUST\nreceive that execution's answer. The alias stays held until the record has an outcome, and after a\nsweeper's claim until the release below.\nThe host MUST run each execution in one in-process flight keyed by the intent id, and a retry MUST\njoin that flight or read the record's outcome; a retry MUST NOT run the post-CAS checks, the\nenrollment writer or the retirement sequence itself. Every record write after the consuming CAS\nMUST be a revision-pinned CAS, and a flight MUST answer only from an outcome its own write set or\nfrom the outcome it reads after that write lost, never with material it did not commit. Recovery\nfollows the executor and sweeper roles of §13.7. Only the pinned incarnation is the executor, and\nonly the executor MAY run the enrollment writer for the record. Any other incarnation, including\nthe same instance after a restart advanced its process epoch, is a sweeper. A sweeper MAY act only\non a consumed record with no outcome whose executor it believes gone, because that instance's\nserving issuance gate is absent, not open or at another process epoch. It MUST first claim the\nrecord with a revision-pinned CAS that names its own incarnation and changes nothing else, and\nMAY then take only the terminal edge that removes authority: the compensation above, then\n`aborted`, for a launch, or the retirement sequence below, then `retired`, for a retirement. The\nsequence's terminal barrier freezes the issuance gate at that UID before it retires the lifecycle\n(§13.1), so an executor that a wrong belief left running can mint nothing there and cannot set the\noutcome. A consumed record holds its target alias `(owner, actor)` from the consuming CAS, and an\noutcome its executor writes releases it. After a sweeper's claim the alias MUST stay held after the\noutcome until the executor's own flight, having stopped before any further effect and revoked any\ngrant at the pinned UID, records the release, or until an operator releases it by hand; no door\nreleases it. Before each effect and before its outcome write, the executor MUST re-read the record\nand stop on a claim it did not write. While an alias is held, the host MUST refuse a launch\nadmission for it and MUST refuse, from either enrollment door, any enrollment of it other than the\nholding execution's own, as `failed-precondition` with no write.\n\n**Ownership.** A delegated launch MUST be enrolled under the record's owner with the record's\nparent, through the same writer, managed-agent envelope walk, lifecycle-keyed durables and\nmembership the host uses for that user's own managed-agent enrollment, with the host selecting the\nlifecycle UID. It MUST NOT be enrolled under a platform owner token or any owner other than the\nrecord's, and the manager MUST refuse material naming another owner. The holder is not on the\nagent's delegation chain and gains no ledger row, scope or grant from the launch.\n\n**Retirement.** A delegated retirement runs in order: revoke the managed grant at the target\nlifecycle UID only and complete the resumable release with that UID unchanged; close the provider\nhandle the host's runtime record holds for that UID, holding the alias while that record is\n`create-unknown`; run the auth-owned terminal barrier with `managedRetirementOpId(lifecycleUid)`\nthrough the same operation the host's managed retirement door runs; free the alias only after\nterminal confirmation. The launching holder is gone when its assignment is absent, revoked or at\nanother revision, its gate is not open, or its gate epoch is not the launch's. A retirement admitted\nwhile the launching holder is gone is bound to no live epoch, and the host MUST execute it itself\nthrough the same sequence; a retirement bound to a holder that is gone before it executes expires\nunexecuted. Once a holder's execution has consumed a record, the host MUST finish the sequence\nwhether or not the holder remains. A failed or uncertain step keeps the alias held, and a retry is\nthe same operation.\n\n**What stays.** Under the `platform-control` view itself the holder still enrolls, retires,\nvalidates and authorizes only same-owner descendants, and a `u_` principal's spawn request or admin\nauthorization against a platform manager is refused as before. A spawn the holder starts without a\nconsumed intent is not delegated and gains nothing from this subsection. A delegated agent MUST NOT\nbe restarted or launched again from a consumed intent. A host MAY support rebinding the same child\nafter a holder restart through §13.18. This does not authorize another enrollment or handoff.\n\n### 13.17 Managed lifecycle handoff\n\nThis section is additive. It covers one case: a managed\nagent already enrolled through the §13.1 managed-agent enrollment operation, whose child runs where\nthe enrolling manager's filesystem is not visible (a sandbox, a container, another host).\n\n**One enrollment.** The child MUST NOT request enrollment, agent provisioning, or an enrollment\nredeem, and MUST NOT mint an actor token or a lifecycle UID. It presents the lifecycle UID the host\nselected at enrollment. A launch that needs any other UID or token is a new enrollment, not a\nhandoff.\n\n**Custody.** The raw actor token stays in the custody of the manager that generated it until that\nmanager releases it to the lifecycle's own child, and only to that child. The manager MUST NOT send\nit to the host or to any party other than the runtime transport that delivers it into that child,\nand the host's ledger keeps only its SHA-256 digest. The manager MUST NOT copy, link, or name any\nfile from its own workspace, secret store, launch material, or temporary directory into the child.\n\n**The handoff.** The manager releases one closed handoff document, `kind`\n`cotal-managed-handoff/v1`, carrying by value: `space`, `owner`, `actor`, `lifecycleUid`, `server`,\n`tlsRequired`, `authProvider`, `idp { url, issuer, audience }`, `exchangeUrl` (the enrollment's pinned\nexchange base), `sentinelCreds`, `actorToken`, `subscribe`, `allowSubscribe`, `allowPublish`, and an\noptional `policy { events: \"required\" }`. It MUST NOT carry a signing seed or key, an issuer or\ncallout record, the auth service's loopback capability, the owner-derivation secret, a provisioner,\ndeprovisioner, delivery, membership, supervisor, or other manager credential, a control token, or a\npath on the manager's filesystem. A reader MUST refuse an unknown field. The runtime delivers the\ndocument into the child as one private (0600) file named by `COTAL_MANAGED_HANDOFF_FILE`, never in\nargv or in an inherited environment value, alongside `COTAL_MANAGER_INSTANCE` naming the launching\nmanager. The child's entry point MUST read the file into memory,\nremove it, and drop the variable before it does anything else, including parsing or refusing its\nown arguments, printing help, loading extensions, or refusing an unsupported runtime version, so\nevery outcome leaves no file. It MUST NOT forward the variable or the file into any process it starts.\n\n**Refusal before any plane.** The runtime passes the expected `space`, `owner`, `actor`, and\n`lifecycleUid` beside the file and sets `COTAL_MANAGER_INSTANCE` to the launching manager's\ninstance id. The child MUST refuse, before any broker connection and before any exchange request,\nwhen `COTAL_MANAGER_INSTANCE` is absent (`COTAL_MANAGED_HANDOFF_FILE requires\nCOTAL_MANAGER_INSTANCE`) or malformed, or when the handoff's values differ from them or the\ndocument is malformed. A newer CLI child under an older manager or runtime that omits\n`COTAL_MANAGER_INSTANCE` therefore refuses every delegated launch, so managers and the CLI must be\nupgraded together. A refusal MUST NOT echo the document's contents.\n\n**Launch choices.** The manager MUST refuse, before enrollment, a spawn choice that only its own host\ncan honour, such as resuming a session held on that host, a working directory on its filesystem, or\na tool server it runs. Such a choice is never dropped silently.\n\n**Exchange.** The child obtains bearers only through the existing pinned HTTPS agent-bearer exchange\nat `exchangeUrl`, presenting the raw actor token. The service matches its SHA-256 digest against the\nledger as for any managed agent. Nothing about the exchange changes.\n\n**Readiness.** Readiness is observed from mesh presence of the exact principal and incarnation, as\nfor any managed launch. A runtime create whose acknowledgement is lost or ambiguous MUST leave the\nlaunch held and reported as uncertain. It MUST NOT be reported as exited without an observed exit or\nclose, and MUST NOT be retried into a second create, enrollment, or handoff for that lifecycle. A\nprovider answer that no resource exists is not an observed exit or close. A lifecycle is handed off\nat most once.\n\n**Fenced close.** The child's runtime resource is keyed by lifecycle: `cotal-` followed by the first\n32 lowercase hex characters of the SHA-256 of the UTF-8 bytes of the compact JSON array\n`[\"<space>\",\"<owner>\",\"<actor>\",\"<lifecycleUid>\"]`, with no whitespace. For space `s2420`, owner\n`u_aaaaaaaaaaaaaaaaaaaaaaaaaa`, actor `probe` and lifecycle UID `aaaaaaaaaaaaaaaaaaaaaaaaaa` the key is\n`cotal-ffa44aae523faeee4ab7689a699b392e`. A close by that key completes only when no create for that\nlifecycle can still materialize: the create was answered before the close, or the close fences the\nkey so a later create is refused. Until then the close stays pending and the launch is not exited.\nA runtime MAY issue the create as a durable provider operation keyed by that key and close the\nresource through the identifier the provider returned in its authenticated response to that create,\nkept in a durable record the host can read without the enrolling manager. Only that response binds\nan identifier to the key: an identifier derived from the key, or found by name or by listing\nresources, MUST NOT be closed or adopted as the lifecycle's resource. While the create's response is\nunknown, no identifier is bound, the launch stays held as under Readiness, and a close completes only\nas above.\n\n**Retirement.** A handed-off lifecycle retires only through the existing managed path, in this order:\nthe host-owned prepare-retirement for the UID-exact target with the operation id\n`managedRetirementOpId(lifecycleUid)`; the fenced close of the child's runtime resource through the\nhandle known for that lifecycle; then the auth-owned terminal barrier with the same operation id.\nAfter the enrolling manager is gone, the host runs the same three steps itself, ending at the managed\nretirement door. There is no participant stop kind and no second retirement protocol, and no runtime\nclose or adopt may be keyed on the agent name alone. A runtime MAY host a handed-off child only where\nthe host can perform the fenced close by lifecycle without the enrolling manager. A failed or\nuncertain step keeps the alias held. A manager preservation cut that holds a handed-off lifecycle is\nrefused before any child stops because the local resume path cannot reconstruct it. Optional\nsame-child recovery under §13.18 is separate from that cut. A manager stop after a refused cut\nretires that lifecycle through these steps.\n\n**Owner form.** A handoff serves whatever owner the enrollment returned. It neither requires nor\nexcludes any owner form.\n\n### 13.18 Delegated child recovery\n\nThis optional contract lets the same registered manager instance regain control of an existing\nchild from a §13.16 user intent after its manager process is lost. It does not grant a new launch,\nmove the child, or transfer authority to another instance or assignment. A host or runtime without\nthis support MUST refuse recovery. It MUST NOT ignore recovery fields and execute an ordinary\nlaunch instead. Declaring the types or accepting a document is not runtime support.\n\n**Preparation.** A supporting host MAY accept `recoveryPlan` inside the launch `execute` object of\n`manager-delegated-user-intent-execution`. It contains `runtimeKind`, `launch`,\n`localStoreBindingDigest` and `localStoreIdentityDigest`. `launch` contains `agent`, `events` and\n`sourceDigest`, with optional `model` and `variant`. It carries no prompt, private file path,\ncredential, owner assertion or provider identifier. The ordinary request and target keep their\nexisting validation. The host MUST derive the owner, parent, registration and assignment from its\ncurrent authority, not from the plan.\n\nThe same consuming CAS that pins the original execution MUST retain an immutable descriptor:\n`{ v: 1, intentId, origin, target, runtimeKind, runtimeKey, launchIdentity, authorityDigest,\nlocalStoreBindingDigest, localStoreIdentityDigest }`. `target` is `{ owner, actor, lifecycleUid }`.\n`origin` binds `space`, `accountPublicKey`, `managerInstanceId`, `managerLifecycleUid`,\n`assignmentRevision`, `enrollmentRegistrationRevision`, `enrollmentRegistrationDigest`,\n`enrollmentServeEpoch`, `intentId` and `target`. The runtime key is the §13.17 lifecycle key.\n`launchIdentity` retains the launch fields and optional role, plus `spawner` and `authorityParent`.\nFor this user-intent path, both principals MUST equal the original user's parent, not the platform\nholder. The descriptor cannot be installed after enrollment as an independent write. A consumed\nor enrolled record missing its descriptor or later preparation evidence MUST remain a visible\nhold. The §13.16 executor and sweeper rules still govern incomplete enrollment.\n\n**Custody and identity.** Before provider dispatch, the host MUST confirm the manager persisted its\nlocal token and sentinel in the assigned durable store. Proof fields are digests only:\n`storeBindingDigest`, `storeIdentityDigest`, `actorTokenDigest` and `sentinelDigest`. The original\nsentinel digest is pinned with the enrollment response. A changed store, absent material or\nincompatible authority MUST hold recovery; it cannot trigger initialization, reminting or copying\nanother manager's credentials. Recovery changes none of §13.17's custody rules.\n\nThe runtime MUST retain a protected observation of the child's original execution identity beside\nthe authenticated create response. Rebinding requires a fresh observation of that same execution.\nA resource identifier, roster presence, copied nonce or resource listing alone is insufficient.\nA changed child or guest incarnation MUST be refused. A provider without verifiable same-child\nidentity cannot enable recovery. No rebind may call create, enrollment or handoff again.\n\n**Transport.** Requests use the separate closed `manager-delegated-recovery` family on the host's\nholder route, not an inner `platform-control` request. The envelope contains `v: 1`, `kind`,\n`actor: \"cli\"`, `space`, `accountPublicKey`, `assignmentRevision`, `instanceId`,\n`managerLifecycleUid`, `currentRegistrationRevision`, `serveEpoch`, `registrationProof`,\n`requestId`, the five public `identities`, `operation` and `body`. The existing manager envelope\nvalidator applies, including the `sha256:` registration-proof prefix, nkey and lifecycle grammars.\nThe operation body is closed:\n\n| Operation | Body |\n| --- | --- |\n| `confirm` | `intentId`, `target`, `expectedIntentRevision`, `localProof` |\n| `scan` | Empty, or `scanBinding` and `cursor` together |\n| `claim` | `intentId`, `target`, `expectedRecoveryRevision`, `expectedOrigin`, `attemptId`, `scanBinding` |\n| `settle` | `claimId`, `expectedRecoveryRevision`, `settleId`, and either `observation: \"bound\"` with `executionIdentityDigest`, or `observation: \"held\"` with `reasonCode` |\n| `finish` | `scanBinding`, `finishId`, `expectedScopeRevision` |\n| `watch` | `afterRevision` |\n\nRevisions, epochs and counts are nonnegative safe integers. Scan, claim, attempt, settlement and\nfinish identifiers use the lifecycle-token grammar; `requestId` keeps the manager envelope's\nidempotency-token grammar. Content digests are 64 lowercase hexadecimal characters, distinct from\nthe prefixed registration proof. Unknown fields,\nraw credentials and inconsistent target or scope bindings MUST be refused before effects.\n\nEvery reply echoes the envelope's version, kind, space, account, assignment, instance, manager\nlifecycle, registration revision, epoch and request id, plus the operation and `ok`. A success\ncontains only `result`; a refusal contains only `error { code, reasonCode? }`. Results are closed:\n`confirm` returns the intent, target, new revisions and `prepared: true`; `scan` returns its binding,\nrecords, nullable next cursor and completion flag; `claim` returns its claim id, attempt id, record\nand claim epoch; `settle` returns its claim id, settle id, revision and observation; `finish` returns\nits finish id, scan id, scope revision and `admission: \"open\"`; `watch` returns a revision and\n`scanInvalidated`. Callers MUST validate the echoed coordinates before using a result.\n\nA recovery record contains `intentId`, `intentRevision`, `recoveryRevision`, `target`, `phase`,\n`descriptor`, `descriptorDigest`, `authority`, `localProof`, `startedAt`, `executionIdentityDigest`\nand `reasonCode`. The last seven fields may be null while evidence is incomplete. Phases are\n`incomplete`, `prepared`, `create-unknown`, `eligible`, `bound`, `retiring` and `terminal`. Eligible\nor bound records require the descriptor, its digest, retained authority, local proof, original\nbirth time and child execution identity. Descriptor and authority digests cover canonical JSON.\nAn authority record keeps the existing retained-authority shape and original user parent. A birth\ntime is a canonical ISO instant, not the successor's startup time. A page holds at most 1024 records;\na retained authority list holds at most 64 entries.\n\n**Inventory and fencing.** A scan binding contains `scanId`, `accountPublicKey`,\n`managerInstanceId`, `managerLifecycleUid`, `assignmentRevision`, `currentRegistrationRevision`,\n`currentServeEpoch`, `sourceRevision`, `memberCount` and `membersDigest`. The digest covers the\ncanonical ordered list of `[intentId, recoveryRevision, descriptorDigest]` triples, including null\ndescriptor digests. A scan MUST close a durable same-instance launch-consumption fence and retain\none immutable membership snapshot atomically with that fence. Every page reads that snapshot.\nThe caller MUST verify the full count and digest and reject duplicate members. An incomplete scan\ncannot certify an empty inventory. Concurrent retirement and enrollment compensation MUST advance\nthe scope revision and invalidate affected scans; retirement cannot be blocked by this fence.\n\nClaims and later writes MUST use durable, revision-checked CAS. Every effect MUST also recheck the\ncurrent registration and assignment. Only the same origin instance, manager lifecycle and assignment\nmay continue under its newly registered epoch. A sibling instance, reassignment, mismatched target\nor stale epoch MUST be refused. Claim and settlement retries are content-bound to their attempt\nand settlement ids. Losing a reply does not permit a new create or release an alias. A successor\nmay replace a prior claim only after authoritative registration fencing and a successful new CAS.\n\n`finish` MUST verify current authority, complete membership and each current disposition before it\nopens launch consumption. No missing, held or newly retiring member may be skipped. Watch messages\nare revision hints, not authority or permission to act on a stale snapshot. Failure or loss of the\nwatch requires a new authority check and scan.\n\n**Manager recovery.** The manager MUST reserve every held alias and reconstruct managed rows only\nfrom verified bound handles, original authority and locally derived secret references. It MUST NOT\nfabricate a local working directory, control endpoint, static credential or restart form. Recovery\nruns before goal terminal inference and run-driver takeover. While held, existing goals retain\ntheir identity and observed state, standing credential renewal continues, and new execution remains\nclosed. Actual deadlines and revocations still apply. Failure to recover cannot retire a live\nchild implicitly. User-intent retirement continues through §13.16; old-epoch terminal grants remain\ninvalid, and a fresh terminal session still requires a supported terminal transport.\n\n### 13.19 Private tool results\n\nThis optional, additive contract permits a verified human to consent to one holder reading a\nmanaged agent's future tool results through the endpoint control surface. It adds no public event\npayload: public `events.<owner>.<actor>` MUST continue to withhold `TOOL_CALL_ARGS` and\n`TOOL_CALL_RESULT`. Tool arguments, transcript scraping, a private HTTP result path and provider\ncredentials in a client or sandbox are outside this contract.\n\n**Activation.** Acceptance of this subsection is not implementation or enablement. A deployment\nMUST NOT enable this path until the auth and host, Core and Manager, connector-core, and browser\ncaller owners have each landed and qualified their part, and a stock release carries those parts.\nA product surface additionally MUST qualify its own freshness and viewer checks. The prerequisites\nof §13.19.4 remain mandatory; without either, the serving commands MUST answer `unavailable`.\nNo numeric revocation bound, immediate cutoff, restart guarantee or per-sign-in cutoff may be\nadvertised without those prerequisites. The informative [design rationale](docs/design/private-tool-results.md)\nretains the owner order and activation checklist.\n\n#### 13.19.1 Authority and records\n\nThe endpoint name is `tool-results`. Its three commands, `tool-result`, `tool-result-consent` and\n`tool-result-revoke`, MUST use `handle` authorization mode. Their schemas MUST be closed, with one\nschema per answer state, and frozen at declaration. Malformed requests and unknown fields MUST be\nrefused as `bad-request` before any effect.\n\n**Human proof and consent.** The host MUST parse `auth_time` and `amr` from the verified IdP token.\nConsent requires `auth_time` in integer seconds, not in the future and at most 300 seconds old,\nand `amr` including a password sign-in. Refresh, device and unmarked sessions MUST be refused as\n`permission-denied`. The host MUST hold the consent signing key. The `consents` signing-anchor role\n(§13.10) is scoped to `tool-results`; a verifier MUST enforce that role and scope. A signed consent\nMUST name one target `(owner, actor, lifecycleUid)` and one holder, an interactive actor principal\nof the same owner, with a window of at most 24 hours. The host MUST record each consent id it signs\ncreate-only. A consent does not confer per-sign-in or per-browser-session control.\n\n**Record families.** Consent issuance records and per-consent revocation records are distinct from\nthe connector's bounded result journal. A revocation row MUST be create-only in the space auth\nstore and retained until the consent's expiry plus the store's marker retention. Revocation MUST\ndistinguish known, refused and unknown outcomes. An unknown outcome MUST be read back before any\nretry and MUST NOT be repeated automatically. The journal MUST follow §13.19.2, §13.19.3 and\n§13.19.5; it is not a public event log.\n\n**Serving issuance.** The closed `manager-managed-agent-tool-result-serving` request kind carries\nonly operations `issue` and `renew` on the existing managed-agent manager-authority envelope,\nincluding its serve epoch. The host MUST require scope `supervise`, verify the current Manager\nregistration, and check the ledger to require that the target is a current managed child of that\nManager. A failed authority check MUST be refused as `permission-denied`. Resume is not supported.\nThe host MUST register the serving instance and return its grant, serving credential and the\n§13.19.4 revocation snapshot. The Manager MUST install the material as a 0600 file named by a\ngeneric launch-material field. Connectors MUST use that generic field, without Manager-specific\ncode. Retirement MUST also deregister the instance. Renewal MUST occur before expiry; installation\nor renewal failure MUST remove the serving material rather than continue with failed material.\n\n**Caller view.** Redemption MUST verify the consent, require presenter equality with its holder,\ncheck the current durable revocation record and target lifecycle state, and read the current\nserving registration. The caller credential MUST be limited to the three commands on that one\ninstance, the stock `describe` of that same instance, and the caller's own reply subject. The\nredemption MUST bind one space, account, instance and epoch, and its response MUST name the space,\ninstance and epoch. Consent-bound caller authority MUST be checked against current durable\nrevocation and target lifecycle state at redemption and again at every native callout or\nconnection issuance, including each reconnect. A credential minted before revocation MUST NOT\npermit a new connection after that revocation. Native issuance records alone do not implement\nthis consent view or its current-state check. Invalid consent, wrong presenter, revoked consent or\nan inactive target lifecycle MUST be refused as `permission-denied`; unavailable authority state\nMUST be refused as `unavailable`.\n\n#### 13.19.2 Capture frontier\n\nAfter verifying a consent, the connector MUST sample a durable source position `P` with the\nsource's end operation. Sampling `P` is the linearization point. Every record already in the source\nat that call MUST lie at or before `P`, including unread records, a read in progress, replay after\na restart and ordinary backlog. The reference source operation is `DurableSource.end()`.\n\nThe connector MUST record the holder's consent life generation when the consent arrives and\ncompare it again after every asynchronous step, including verification, the end call and frontier\nplacement, and immediately before committing the consent. Revoke or replacement MUST advance that\ngeneration. An in-flight activation for an old generation MUST refuse and commit nothing. Token\nregistration and pre-capture classification MUST be serialized with that commit. An unresolved\nfrontier MUST grant no eligibility. Expiry and snapshot checks do not replace this lifetime fence.\n\nThe emitter MUST place `P` against each read using source-only position comparison, through a\nfrontier operation equivalent to the reference emitter's `queueTerminal` placement. The reference\naddition is `queueFrontier`, using the existing `boundary` comparison. A START record is eligible\nfor that consent only when its canonical durable position lies after `P`; physical tool execution\ntime MUST NOT determine eligibility. If `P` cannot be placed, the connector MUST drop the frontier\nand refuse the consent as `failed-precondition`. A source whose end operation answers later than\nthe call may only exclude more calls. A RESULT MUST be captured only into an entry its START\ncreated; a RESULT MUST NOT create an entry.\n\n#### 13.19.3 Audience\n\nAt START, each journal entry MUST record the fixed set of consent ids eligible for it. That set\nMUST NOT grow. A lookup MUST NOT return the entry to holder `h` unless an id in its set remains\nactive, unexpired and unrevoked and names `h`. Revoking, expiring or withdrawing consent `c` MUST remove\n`c` from every entry; an entry with an empty set MUST be deleted. Replacing a holder's consent MUST\nrevoke the old consent before applying the new frontier, discarding results visible only through\nthe old consent. A newly consented holder MUST NOT read results captured before its own frontier.\n\n#### 13.19.4 Revocation bound\n\nBoth prerequisites below MUST hold before the serving commands can be available:\n\n1. A sealed, owner-reviewed, bounded read MUST obtain the complete revocation snapshot for the\n target from the stream leader, through a watermark taken after `T0`. Native issuance-row write\n authority MUST NOT be treated as consumer-create or stream-read authority. The snapshot read\n authority MUST be granted and reviewed separately.\n2. A bound `delta` on connector-to-host clock difference MUST be established and enforced. A\n configured token tolerance is not evidence of measured or enforced skew.\n\nThe host MUST take `T0` from its clock, in milliseconds, before the snapshot read starts, read the\ncomplete snapshot under prerequisite 1, and set the serving credential expiry to\n`floor(T0 / 1000) + 600` seconds. Signing, writing and installing MUST NOT extend that expiry. If\nsigning happens more than 30 seconds after `T0` or the expiry has passed, issuance MUST refuse as\n`unavailable` and write nothing.\n\nImmediately before answering a lookup or committing a consent, the connector MUST read the\ninstalled file and require that its own clock is before expiry and the consent id is absent from\nthe snapshot. Otherwise it MUST revoke locally under §13.19.3 and refuse release. An expired file\nMUST be refused as `expired`; a snapshot-revoked consent MUST be refused as `permission-denied`.\n\nLet a revocation be acknowledged at host time `Tr`. If `T0 > Tr`, the snapshot MUST include it and\nevery release MUST refuse it. If `T0 <= Tr`, expiry is at most `Tr + 600` seconds, so with\n`|connectorNow - hostNow| <= delta`, no release may occur at host time `Tr + 600 + delta` or later\n(`Tr` and `delta` expressed in seconds for this bound).\n\nA restarted connector may re-apply a revoked consent inside that window. An already connected\ncaller keeps its transport until eviction or its own credential expiry. Eviction can have an\nunknown outcome and acts on the whole principal. Neither case permits a result past the bound.\nThe host and the Manager installing the file are trusted. This bound is not an immediate cutoff,\na restart non-restoration guarantee or a per-sign-in cutoff.\n\n#### 13.19.5 Receiver answers\n\nBefore invoking, the caller MUST run the stock instance-addressed `describe` on the one redeemed\ninstance and verify its contracts and digests. It MUST refuse an answer from another instance or\nan epoch different from the redemption. This bootstrap requires the narrow, separately reviewed\nsame-instance `describe` grant in §13.19.1. It MUST NOT use class discovery, scatter or a homemade\ncontract. Stock `describe` carries no `bind`, because it produces the binding (§13.3).\n\nEvery subsequent private command MUST carry `bind` naming the redemption's instance and epoch.\nA missing `bind` MUST be refused as `bad-request` before the handler touches the journal. The\n§13.3 pre-effect incarnation check MUST refuse another epoch of the same instance as `expired`\nbefore any handler runs. The caller MUST learn the instance and epoch only from redemption. A\nbrowser caller MUST be Node-free, MUST NOT scatter, guess or silently change the target or epoch,\nand MUST NOT resend after an accepted or unknown effect. It MUST drop its binding on account,\nspace or epoch change.\n\n`tool-result` MUST answer one of these closed states:\n\n| State | Fields beyond the state |\n| --- | --- |\n| `available` | Thread id, tool call id, content, truncated flag, byte count, error flag and capture time |\n| `pending` | Thread id and tool call id |\n| `not-shared`, `missing`, `expired` | None |\n\nThe `expired` answer state belongs to a successful `tool-result` reply. It is distinct from the\n`expired` refusal code for an expired serving file (§13.19.4) or a mismatched epoch (§13.3).\n\nEmpty or falsy content such as `\"\"`, `\"0\"`, `\"false\"` and `\"null\"` MUST be treated as a result.\nContent MUST be inert text bounded to 64 KiB of UTF-8. The journal MUST hold at most 256 entries,\nretain each for at most one hour and MUST NOT store arguments.\n\n---\n\n## 14. Workflow runs (v0.5)\n\n### Keyed submission prerequisite\n\n`run-start-keyed` is a distinct registered command. Its envelope ID is the immutable submission\nidentity. `run-submission-status` accepts only a submission ID and derives its namespace from\nthe authenticated caller owner, actor and lifecycle UID. Both require issued reach, pinned\ncontracts and an exact-instance/epoch bind. Old credentials gain no reach by reconnecting.\nLegacy `run-start` remains unchanged and is never an automatic fallback.\nA keyed request's `deadlineMs` is at most 30000. A host refuses a larger value as `bad-request`\nbefore any read or binding. This maximum is a request budget. It does not show that a publish\nhas settled or that a credential is still valid. The process that receives the request measures\nthe budget on its own monotonic clock from its own receive sample; that reading is never\npersisted, sent or compared with another process's clock. The caller's authority expiry is\nchecked separately on the wall clock. A request that outlives a credential still has an unknown\noutcome.\n\nThe admission authority writes one `submission.v1.<endpointToken>.<callerDigest>.<id>` binding\nin the existing write-once admission store. `callerDigest` is the canonical SHA-256 digest of\n`[owner,actor,lifecycleUid]` without its `sha256:` prefix. The closed value records the caller\ngeneration, semantic fingerprint, accepting instance/epoch, host-minted run ID, frozen\nadmission digest and original callback deadline. That deadline is a wall-clock projection of the\ncallback's window, rounded down. It is a record only: no host enforces or recovers from it. Bindings are permanent, including terminal\nruns. Capacity exhaustion refuses new submissions rather than deleting authority history.\nThe manager takes its stopping and launch-capacity refusals, and reserves the launch, before it\nreads or writes the binding, so such a refusal writes nothing. It says nothing about an earlier\nattempt under the same key, which may already be bound, admitted or activated;\n`run-submission-status` takes no launch reservation and reads it. A launch that still fails after admission\nleaves `admitted` with no run, and nothing in this prerequisite launches or repairs it.\n\nInitial authorization and evidence validation precedes the binding CAS. Before each admission\nattempt, the original binding winner rechecks that same authority. These fallible freshness\nreads may leave permanent binding-only reconciliation debt after the binding exists. They\nnever replace its frozen admission. Only that winner may create its admission, with at most\nthree classified transient attempts in the original callback deadline and authority window.\nThe admission bytes, timestamp, ceiling and\nprovenance remain fixed. A failed create is classified by a leader read of that exact admission\nkey. Matching bytes recover success, authoritative absence permits another same-callback\nattempt, and unreadable or conflicting state holds. The timer bounds waiting and starting\nfurther attempts, not broker acceptance of an already-issued publish. Such a publish may land\nlater with the original frozen bytes. No new admission attempt starts after the request budget\nor authority window ends. After admission, the activation check uses only the manager's remaining\nmonotonic request budget, without rechecking the caller's wall-clock expiry. Earlier admission\nabsence never proves that this pending effect cannot land.\nNo later callback, duplicate, restart,\noperator or read repairs a binding-only submission.\n\nStatus reports `unbound`, `binding-only`, `admitted`, `activated` or `indeterminate`, with the\noriginal bound run and callback deadline when available. Absence is observation-time only.\n`activated` means a run status record was observed, including a completed or failed run. It\ndoes not mean currently running or occupying an active lane. Read native `run-status` for\nlifecycle state. Terminal bindings remain permanent and duplicates never launch them again.\nThe scheduler preserves its original reservation and never allocates a replacement run or\nadopts another instance/epoch from these reads. A later repair protocol requires its own fence\nand review. This prerequisite introduces no second scheduler or generic cancellation.\n\nA **workflow run** is one execution of a program in the Cotal workflow language, hosted by a\n**driver** (an endpoint, in the reference deployment the manager daemon) that performs the\nprogram's effects against the mesh and records every one of them in a per-run **step journal**.\nThis section defines the run's wire footprint: the record it is described by, the stream its\njournal travels on, the records its effects file, and the grants its driver holds. The\nlanguage, the journal entry, and the rules of resume, migration and fork are defined in\n[`spec/cotal-lang.md`](spec/cotal-lang.md), which this section incorporates by reference: an\nimplementation of this section MUST implement that document.\n\n### 14.1 Roles and identity\n\nThe **driver** is the one principal that executes a run: it validates and runs the program, calls\nthe effect handler, appends to the journal, and writes the run's records. It is hosted by an\nendpoint, and every §14 key leads with that `<endpoint>` token so a per-endpoint enumeration and a\nretirement drain (§13.1) both work by prefix. A **run id** (`<runId>`, an id token, §13.2) is minted\nby the driver when the run starts, is never caller-supplied, and is **never reused**: re-running a\nprogram from part of a run's history is a **fork**, and a fork is a new run under a new id whose\nrecord names its parent (§14.3). A run has exactly one **authoritative appender** at a time; §14.4\nis what makes that true.\n\nA user-auth run's durable actions MUST use the owner established by its authenticated admission.\nThe trusted host derives the run-stable actor and lifecycle uid from the run id and retains that\nowner on resume. Grant construction and effect dispatch MUST use the same triple. A supplied\nowner token is not admission evidence. The existing static/local path retains its `local` owner.\nThese identity rules do not authorize exporting host mediator or operator credentials to a driver.\n\nA run that names an explicit placement instance gains instance-rail reach on that one instance\nonly: `describe`, `resolve-cwd` and `spawn`, and owner-mode `turn` pinned to the run's own owner.\nA placed seat is mapped only by the instance hosting it, so the host MUST address that seat's turns\nto its placement instance, never the class rail. Static/local issuance adds no instance row when\nthe program has no placement. Auth-service-issued mediators retain their admitted host-instance\nplacement (§14.8), including for an unplaced program; unplaced seats still use the class rail.\nOn that rail a target-unmapped refusal (§13.3) states only that the members a call reached hold no\nmapping, not that the seat is down.\n\nUnanswered pinned-host discovery before submission, with no accepted goal recorded, reports\nthat host unreachable (L4002). Permission and contract refusals retain their own meaning. A\nreply lost after submission remains governed by goal reconciliation.\nA migration keeps the original seat's recorded host through its new binding and later takeover.\nA receiving placement request cannot move that seat or invent a host missing from older records.\nRefusing that placement leaves the kept hand-over available for a later valid spawn.\n\n### 14.2 The language and its version\n\nPrograms, values, primitives, the step key grammar, the input hash, the request id and the entry\nschema are those of [`spec/cotal-lang.md`](spec/cotal-lang.md). The language carries a\n**`languageVersion`**, bumped when a revision changes what a program means (its PRNG, a builtin,\nnumeric behaviour, walker scheduling) and deliberately not the package or wire version; a run pins\nthe version it started under (§14.3) and a resume under another version is refused\n(`spec/cotal-lang.md` §8.4). A wire revision of this document therefore never invalidates an open\nrun, and a language revision never requires one here.\n\n### 14.3 The run record\n\nA run is described by the `run` record kind (§13.7): `run.<endpoint>.<runId>`, `.spec`/`.status`\nsplit, mediated, written by the driver's commit path only.\n\n- **Spec** (create-only, decided once): `{ v: 1, run, pins, createdAt, forkedFrom? }`. `pins` is\n the **resolved pin set** the run started under, `{ seed, startedAt, yieldEvery, stepBudget,\n effectCeiling, languageVersion }` (`spec/cotal-lang.md` §8.3): every one selects which effects run,\n so a resume MUST read them back and bind to them, and MUST refuse a caller value that differs.\n `startedAt` is the run's **logical epoch**, and a resuming host's own clock never moves a\n replayed program. The RESOLVED value is pinned, never the default: a default is a property of the\n interpreter, and the interpreter is the thing that may have changed between attempts. A spec that\n already exists MUST refuse a second start under the same id. A fork (`spec/cotal-lang.md` §11.3)\n is a new run with its own id and its own spec, and the child's spec names its lineage:\n `forkedFrom` is `{ run, step }`, the parent run and the step key the cut excluded, written with\n the spec and absent on a run started fresh. Absence reads as \"lineage unknown\" (a child recorded\n before the field existed), never as \"not a fork\". A later revision that adds a field to the spec\n half does so as its own binding revision, never by rewriting a spec that exists.\n- **Status** (last-value-wins, CAS-written): `{ v: 1, observedSpecRevision, state, holder, epoch,\n fencingToken, journalHigh, at }`. `state` is one of `running`, `released`, `completed`, `failed`,\n and `released` and `failed` are different facts: a failed program has a result and the journal has\n it, a released run has none, because its driver stopped holding it (`spec/cotal-lang.md` §9.2,\n L5012). `holder`, `epoch` and `fencingToken` name the driver that holds the run and the lease\n (§13.6 work pool) it holds it under. `journalHigh` is the highest journal ordinal (§14.4) the run\n is KNOWN to have reached, written at each activation and after each append the driver makes\n while the run is `running`, before that append resolves to the interpreter: it is the one anchor\n OUTSIDE the journal, so a replay whose last ordinal is below it has lost records from the\n journal's tail, which nothing inside the journal can see, and the driver MUST refuse to resume it.\n Interior loss is the journal's own ordinal chain's.\n\n**Turn notices.** A run's `turn` reaches its seat through the hosting manager, and the seat reads\nit with its own self-mode `turn-pending`. The manager MUST publish a turn notice to the seat\nwhenever the set that seat's `turn-pending` would answer changes: on accepting a turn, on its\nyield, cancellation or deadline, and once per seat holding a turn after the boot reconcile. The\nnotice is published by the manager's serve connection on the seat's own reply rail (§13.2), under\nthe reserved nonce `turn-pending-notice-v1`:\n`ep[.v1].reply.manager.<instanceId>.<epoch>.<owner>.<actor>.<uid>[.<generation>].turn-pending-notice-v1`,\non the versioned rail exactly when the seat's credential is an issuance (§13.15). Only that\ninstance's serve credential may publish it, every baseline seat credential may read its own, and\nno new grant exists for it. Its body is `{ \"v\": 1 }` and carries no turn, so a seat MUST treat the\nnotice only as a reason to pull; the pull's answer is the authority. A notice is at-most-once, so\nthe manager MUST repeat it, at most every 5 seconds, while the oldest turn it would serve a seat has\nnot yet been served to that seat by a `turn-pending`. A seat MUST subscribe before its first pull,\nand MUST pull again after a reconnect while it holds a turn, since a lost notice of that turn's\nending is not repeated. A seat MUST NOT\npull on a timer while it is connected and its last pull succeeded, except under a manager whose\n`turn-pending` answer lacks `notices: true`, which predates notices and is pulled every 15 seconds.\nA pull that fails because the manager is unavailable or unanswered MAY be retried at that same\ninterval until one succeeds; a refusal MUST NOT be retried on a timer.\n\n### 14.4 The step journal on the wire\n\nThe journal of a run is carried by the per-space **`WFJ_<space>` stream** (§13.12) on **one subject\nper run**, `cotal.<space>.wfj.<runId>`. An implementation MUST create the stream with limits\nretention, file storage, no `max_age`, and `allow_direct=false`, and MUST NOT let any removal cause\nevict a live run's prefix (§13.12 retention floor). Retirement of a run's journal is by subject\npurge.\n\nEvery message on the subject is one **journal record**, JSON, one of two kinds. Both envelopes are\nCLOSED: a reader MUST refuse a record that carries a field outside the shape below, and MUST refuse\nan unknown `kind`, because a journal is replayed by whoever holds the run next and a field one\nwriter meant and another ignores is a divergence nothing would name:\n\n- **activation**: `{ v: 1, kind: \"activation\", run, n, holder, fencingToken, epoch, replayedTo, at }`,\n the successor's first act, and the only record the runtime layer writes that is not a step.\n- **step**: `{ v: 1, kind: \"step\", run, n, at, entry }`, where `entry` is a language journal entry\n (`spec/cotal-lang.md` §10.1) carried verbatim: the wire layer MUST NOT read inside it. A step is\n appended TWICE, once `pending` before its effect is dispatched and once settled after; a reader\n folds by the entry's key and the last record wins.\n\n`n` is the record's **ordinal** in the run's journal, from 0, and a replay MUST require\n`records[i].n === i`: the chain is the only check that sees a record removed from the middle of a\nsubject, since counting cannot and no anchor at the front can. A writer MUST stamp `run` with the run\nthe subject names; its grant covers exactly one subject (§14.6), which is what enforces it. A reader\nSHOULD refuse a record whose `run` names another run; the reference reader relies on the grant and\ndoes not re-check it.\n\n**The activation barrier.** A run has exactly one authoritative appender at a time, and the STREAM\nis the acceptor: every append MUST carry `Nats-Expected-Last-Subject-Sequence` for the run's own\nsubject, so a publish lands only if the subject is exactly where the publisher believed it was, and\nthere is no read-then-publish window because there is no read. Takeover is replay-then-activate:\n\n1. The successor replays the run subject from the beginning, through a **per-takeover replay\n durable** it creates on the stream (`wfj_<runId>_<takeoverId>`, filtered to the run's subject,\n explicit ack, deliver-all, memory storage) and deletes when done. `<takeoverId>` is an id token\n (§13.2) minted by whoever hands the driver its lease and its journal grant (§14.6), one per\n takeover of a run and never reused for that run; the driver does not choose it, because a consumer\n name is one subject token that no grant pattern covers in part, so it has to be known when the\n grant is minted. The last replayed record's stream sequence is the only authoritative head there\n is (`STREAM.INFO`'s `last_seq` is stream-wide, and its subject filter answers counts, not\n sequences).\n2. Its first act is an **activation record** appended at that expected sequence, and it drives\n nothing before that record lands. Its authority is checked against the activation the journal\n already holds: a lower `fencingToken` is refused (stale lease); an equal token is refused unless\n `holder` AND `epoch` are the same (one process picking its own run back up); a higher token\n activates.\n3. Once the activation lands the subject has advanced, so any append still in flight from the\n superseded driver carries a stale expectation and the server rejects it.\n\nTwo CAS refusals are two different states and MUST NOT be conflated. A refused ACTIVATION means \"my\nreplay is stale\": the successor has driven nothing, the records that beat it are more prefix, and it\nMAY re-replay and activate again while it still holds the lease. A refused APPEND after an\nactivation that won means \"someone else activated\": that driver IS superseded, MUST stop, and MUST\nNOT refresh the sequence and retry, because a retry at the new head is the defect the barrier\nexists to prevent. A driver publishes one entry at a time from one serial queue per run and\nadvances its head only from each acknowledgement; once the bytes have gone out, any outcome without\none poisons the queue and nothing behind it reaches the wire (a record refused before it is sent,\nfor example one that cannot be serialized, fails only itself).\n\nThe journal is a language artifact, and its contents are decided by the language: a driver MUST\nawait the durable append of a `pending` entry before dispatching the effect it names, MUST settle\nthe entry from the handler's outcome, and MUST keep the settling append outside the handler's\nfailure domain, so a refused append is a durability failure (L5010) that stops the run and is never\nrecorded as the effect's failure (`spec/cotal-lang.md` §10.5). A cancelling scope's `cancel.issued`\nrecords whether the driver has discharged the intent against the world; the record states the\nintent and its discharge, and how a driver disposes of a losing arm's live work is a driver policy\nthis revision does not fix.\n\n### 14.5 Answers, notices, migrations\n\nThree record kinds carry the payloads a run's effects file (§13.7 for the grammar and the\nsentences that defend each shape). Their derived id tokens all take one form: **the unpadded\nbase64url of the SHA-256 over the strict RFC 8785 canonical JSON of the named object, 43\ncharacters**, which is an id token by construction. The reference implementation's canonicalizer is the one\n§13.7's `*Digest` fields use.\n\n- **`answer`**, `answer.<endpoint>.<token>.<answerId>`, atomic, create-only: `{ v: 1, token,\n answerId, value?, artifact?, by, at }`, filed BEFORE the checkpoint token is presented; the\n one-use settle fact (§13.6) then NAMES the id it accepted. For a checkpoint a run performed the\n `answerId` on a `resumed` settle is REQUIRED (§13.6 leaves it optional for other checkpoints): a\n run's handler reads the answer under the id the settle names, never by looking for \"the answer to\n this token\", and refuses a resumed settle that names none. `answerId` = the digest id of\n `{ token, by, value: value ?? null, artifact: artifact ?? null }`, so a retry of the same answer\n lands on the same key with the same bytes and two different answers race on the settle, which is\n what the settle is for. `by` is the answerer as the run's own authorization knows them, never the\n presenting principal (the driver, for every answer) and never a field in the answer request. A\n baseline managed seat reaches the answer door only through the self-targeted row above, after the\n manager has matched its exact caller incarnation to the pending relay for this open pause.\n An **amendment** is an answer filed after the pause settled: same key grammar under the token\n the pause settled under, with `supersedes` naming the `answerId` the settle accepted. It is filed\n through the same door and credential pinning as an answer, and nothing is presented, so the pause\n stays settled, the one-use settle is untouched, and the run never reads the record. Its\n `answerId` is minted fresh for each filing (32 random bytes, base64url, the first 43 characters)\n and is never derived from its content: a participant who returns to an earlier position files\n what an earlier filing said, and a content id would make the create-only write take it for a\n retry of that filing and record nothing. A step that is still open, or that settled\n without accepting an answer, has nothing to amend and is refused. The run surface lists a settled\n step's amendments beside its accepted answer in the order the records bucket committed them (each\n record's revision); `at` is the filer's clock and never decides the order. The last one listed is\n the step's current recorded position, and the accepted answer remains what the program acted on.\n A pause in a branch that lost a `race`, or one cancelled after it accepted an answer, settled\n with an answer the program never read: the run surface lists that answer as not acted on and\n names the branch the race took.\n- A held `once` step (`spec/cotal-lang.md` §7.8) is answered like a checkpoint, addressed by its\n step key; the driver presents the hold id (`spec/cotal-lang.md` §7.8) as the token, whatever kind\n the step is, and reads the step's accepted answer and amendments under the same id once it\n settles. The run's pause authority covers that id only while the step is pending with its hold\n bound.\n- **`notice`**, `notice.<endpoint>.<runId>.<addresseeId>.<noticeId>`, split: spec `{ v: 1, run,\n step, addressee, fact, at }` (create-only; `fact` is the language's bounded decision record and\n is checked against its bound BEFORE any record is written), status `{ v: 1, consumedAt, by,\n observedSpecRevision }` (create-only: the consumption is established once, by the turn that\n carried it). `addresseeId` = the digest id of `{ agent }` (the addressee's name); `noticeId` = the\n digest id of `{ requestId, addressee }`, where `requestId` is the `notify` step's request id, so\n one call to N agents files N notices and a re-run after a crash lands on the same ones. A driver\n that performs the addressee's turns MUST render an unconsumed notice ahead of its next turn and\n MUST NOT deliver it as a channel message. The reference driver performs that rendering: its turn\n plane is durable (`spec/cotal-lang.md` §6.5), and a relayed turn carries the addressee's\n unconsumed notices as its rendered context and marks them consumed with the turn's outcome.\n- **`migration`**, `migration.<endpoint>.<runId>.<migrationId>`, split: spec `{ v: 1, run,\n fromHash?, toHash, at, consumedThrough, orphans[], overrides[], actor }` (create-only), status\n `{ v: 1, appliedAt, by, observedSpecRevision }` (create-only). `migrationId` = the digest id of the\n spec without `at`, so a dry walk re-run after a crash files no second migration for one decision.\n `orphans[]` is `{ step, kind, verdict, code? }` per journal entry the new source no longer reaches,\n with the verdicts and refusals of `spec/cotal-lang.md` §11.2; `fromHash` is the caller's claim\n and is absent when not supplied, because the run record carries no program hash to verify it\n against. A migration never rewrites a journal.\n\n### 14.6 Driver grants\n\nGrants are DERIVED (§13.7, §13.9), and a run driver's are minted **per run and per takeover\nattempt**, never per space:\n\n- publish on exactly `cotal.<space>.wfj.<runId>`;\n- create, bind (info, next, ack) and **delete** its own replay durable `wfj_<runId>_<takeoverId>`\n on `WFJ_<space>`, named per takeover because a durable remembers how far it delivered and a\n successor needs the prefix from the top, and because a consumer name is one subject token that no\n pattern covers in part, so the takeover id belongs to the credential;\n- and, as the standing per-kind mediated writer path of §13.9 rather than anything minted per run,\n the commit path for the `run`, `answer`, `notice` and `migration` keys of its own endpoint.\n\nThere is no wildcard form of any of these, on purpose: a space-wide `wfj.>` publish would let one\nrun's driver append to another run's journal, which is not a read leak but a corruption (the other\nrun would replay a step it never took), and the barrier's premise is exactly one authoritative\nappender per subject. The provisioner holds `STREAM.CREATE`/`STREAM.INFO` on `WFJ_<space>` and\ncreates it at space setup; agents never hold `STREAM.CREATE` (§13.12).\n\n### 14.7 Conformance (workflow runs)\n\nA conformant driver (v0.5) MUST:\n\n1. Validate a program against `spec/cotal-lang.md` before running it, and run it with the language\n semantics that document defines, under a pin set resolved once and read back on every resume.\n2. Mint run ids itself and never reuse one; a fork is a new run under a new id.\n3. Append every journal record on the run's own subject under the subject-sequence fence, replay\n before activating, activate under an authorized lease tuple, stop on a refused append after\n activation, and never retry an append at a refreshed head.\n4. Write a `pending` entry durably before dispatching its effect, settle from the handler's outcome,\n and treat a refused append as a durability failure that stops the run rather than as the effect's\n outcome.\n5. Require the ordinal chain and the run id on replay, refuse a replay below the recorded\n `journalHigh`, and refuse to resume without the recorded pins or under a different language\n version.\n6. File answers, notices and migrations under their derived ids, create-only, and render notices\n ahead of the addressee's next turn rather than as channel messages.\n7. Hold only the per-run, per-takeover grant family of §14.6.\n8. Admit every run under §14.8 before launching it, check every channel effect against the\n admitted ceiling and the current revocation state, and never continue a run whose admission is\n missing, unreadable, mismatched or revoked.\n\n### 14.8 Run admission\n\nA hosted run performs channel effects on a caller's behalf. What it may do in channels is the\n**admitted ceiling**: the caller's issued permission ceiling (§13.15) as resolved at admission,\nrecorded once per run, and never widened afterwards.\n\n**The record.** Before the driver is launched and before a successful start reply, the hosting\nendpoint writes `admission.v1.<endpoint>.<runId>` in `cotal_admission_<space>`, create-only,\nunder a one-shot `run-admitter` credential pinned to that one run:\n`{ version: 1, space, endpoint, runId, instanceId, caller, ceiling, provenance, admittedAt }`.\nThe store is write-once per key at the broker (§13.12: one message per subject under `discard:\nnew`, no rollup header, no message delete, no purge), so the admitter's own key row can neither\nreplace the admission nor remove it once written, and a marker, once written, stays.\n`caller` is the admitting request's broker-authenticated caller, generation included; `ceiling`\nis the resolved evidence's `permissions`, verbatim; `provenance` is\n`{ kind: \"issued\", ref, resolvedRevision }` for a hosted admission or\n`{ kind: \"operator\", by, reason }` for a local one (below). A run-start arriving on the legacy\nrail is refused as §13.15 says. On an open mesh, which issues no authority, the endpoint hosts no\nrun. The driver holds no row on this store; the mediator and operator profiles hold its leader-\nserved read only.\n\n**Enforcement.** The trusted host re-reads the admission, leader-served, before every channel\neffect: opening a wait, each fetch on it, each re-read of a recorded match, and a conclave's\nchannel writes. A concrete channel is checked against the ceiling with the §3 matcher: a\npublish requires `chat.<owner>.<actor>.<channel>` under the caller's own triple to be allowed by\n`ceiling.publish`; a read requires every subject `chat.*.*.<channel>` matches to be covered by\n`ceiling.subscribe`. Deny wins; an explicit `none` is deny-all; a generated channel name is\nchecked after it is derived and no wildcard is invented to admit it. `notify` writes agent-\naddressed notices and is not channel publication; spawn and turn keep their separately checked\ndelegated authority.\n\n**Revocation.** `revoked.v1.<endpoint>.<runId>` is the run's revocation marker: create-only,\nidempotent, written under the same `run-admitter` profile, never removed. A revoked run performs\nno further channel effect, its open waits refuse at their next fetch (the linearization point is\nthe leader-served read the host makes before returning any channel bytes), and no resume,\ntakeover or boot reconcile continues it. An answer to one of its open checkpoints or asks MUST be\nrefused before anything is filed: the host reads the marker leader-served before it files the\nanswer record, and that read orders the answer against the revocation. A marker the host cannot\nread refuses the answer too. Revocation authorizes no new resource and no cleanup\nbeyond what the run's own journal already justifies. Caller disconnect or credential expiry after\nadmission does not revoke a run.\n\nThe issuing host accepts the closed `manager-run-revoke` request through its authenticated\nmanager-service authority door. The door verifies the IdP identity and reads that actor's current\nledger scope. Revocation requires that verified owner to equal the recorded admission's\n`caller.owner`, or that actor's fresh scope to carry `admin`. An assigned platform control manager\nis not an admin grant. The request accepts no owner, caller, `by` or timestamp assertion. The host\nchecks the current manager registration proof, space, account and process epoch, and requires the\nadmission to name that manager instance. It derives `by` as `<verified-owner>.<actor>` and writes the\nsame marker as a signer-holding host: `{ version: 1, runId, reason, by, revokedAt }`. A repeat returns\nthe existing marker, including its original attribution and time, without an overwrite.\n\n| Issuing-host request kind | Operation-specific input | Result |\n| --- | --- | --- |\n| `manager-run-admission` | `run: { runId, subject }` | the immutable admission and revision |\n| `manager-run-attempt` | one `attempt` or `operator` | fixed JWTs for manager-held public nkeys |\n| `manager-run-revoke` | `revoke: { runId, reason }`, with non-empty reason | `{ v: 1, kind, requestId, runId, revocation }`, naming the stored marker |\n| `manager-run-cancel` | `stage: \"inspect\"` or `\"commit\"`, `subject`, `cancel: { runId, reason }` | `{ v: 1, kind, requestId, runId, stage }` plus `authority` for inspect or `result` for commit |\n\nEach request carries the same registered-manager envelope: `v`, `kind`, `space`, `actor`,\n`instanceId`, `managerLifecycleUid`, `requestId`, `registrationProof`, `accountPublicKey`,\n`processEpoch` and public `identities`. Unknown fields refuse. These are issuing-host requests,\nnot endpoint commands. CLI and MCP revoke verbs require a separate served-command path.\n\n**Cooperative cancellation.** The ephemeral, untargeted `manager.run` command `run-cancel` accepts\nonly `{ runId, reason }`. The reason MUST be well-formed Unicode encoding to 1 through 512 UTF-8\nbytes. The request MUST ride the issued v1 instance rail and carry a bind naming the receiving\ninstance and current process epoch. Its deadline MUST be positive and at most 30,000 ms, measured\nfrom the original receive observation. A missing or different bind refuses; no epoch is repinned.\n\nA signer-holding manager accepts only the original admission's owner, actor and lifecycle UID,\nresolved under a currently live issued generation that permits this request subject. The generation\nneed not equal the admitting generation. A signerless manager asks its issuing host to inspect the\nrequest the host itself observed. That host accepts the original triple, or an independently\nattested interactive actor of the admitted owner with `run`, or an interactive actor with `admin`.\nAn actor name, managed seat, platform assignment or manager forward is not interactive authority.\nThe issuer checks current source liveness and issued permissions in every case. The local operator\nrevoke path above is separate.\n\nThe admission MUST be readable before cancellation. An absent admission yields an undetailed\n`permission-denied`; an unreadable admission or torn run record yields `unavailable`. Reads of the\nadmission, marker and run holder are leader-served. The manager's existing endpoint inventory\nreader supplies these reads even after revocation; it holds no checkpoint-answer writes. A\nrun-scoped read-only operator also remains issuable for status inspection after revocation, with\nthe admission's instance and endpoint checks unchanged. Revoked runs receive no new drive or\nanswering authority. A\nterminal completed or failed record returns an observation without writing a marker. A running\nrecord held elsewhere refuses before a write unless a marker already exists, in which case the\nreply reports `not-driven-here` without stopping a local handle. An absent run record, a spec\nwithout status, and a released run remain distinct from another holder's running attempt.\n\nThe closed `run-status` view also carries optional `revoked: { by, reason }` and\n`revocationUnreadable: string`, with the same meaning as the run list. The marker is read\nindependently of the recorded state. A running record with a marker does not prove cessation;\na released record with a marker cannot resume. A failed marker read MUST be reported as unreadable,\nnot as marker absence or permission to resume. A terminal record remains terminal whether or not\nit has a marker.\n\nThe `run-status` view also carries optional `programHash`, the language's hash of the run's\nrecorded program, which is the value the run list carries for that run. It is read from that run's\nprogram record alone. It is absent when the run has no recorded program. A program record that\ncannot be read or parsed MUST be reported as `programUnreadable: string`, with no `programHash`,\nand never as a hash or as an absent program.\n\nA `run-status` request MAY carry `journal: { offset }`, a row offset into the journal. The reply\nthen carries `journalTotal`, the journal's row count, and its `journal` holds the rows from\n`offset`, in journal order, that fit in one reply under the serving connection's payload limit: at\nleast one row while any remain, and none when `offset` is at or past the end. A record that does not\nfit in a reply with no rows, or a single row that does not fit, MUST be refused\n`resource-exhausted`. A request without `journal` returns the whole journal in one reply.\n\nEach cancellation intent is keyed by the full served subject, not just the envelope id. A pending\nintent prevents a new local launch but does not stop an existing drive. Only an observed durable\nmarker permits the manager to call the current eligible drive's cooperative `cancel(reason)`\nhandle. The manager rechecks an activated slot's recorded epoch, fencing token and holder before\nselecting that handle. A marker observed for a run promotes all its lingering local cancellation\nintents; keys are not aliased. A read failure or unknown write does not clear a pending intent.\nA definite no-dispatch refusal can clear only its own intent after confirming marker absence.\nIf its budget expires before that confirmation, the local launch block can remain even though\nno write was dispatched.\n\nAt a channel effect, a fresh revoked admission together with the same manager-local\nmarker-observed intent raises `Cancelled` rather than the ordinary revocation failure. This\nclassification does not signal the root or replace the current-holder check. Pending intent\nalone cannot reclassify a refusal; a local operator revoke without a cancellation intent keeps\nits existing failure behavior. If the required post-marker holder read fails or its original\nbudget expires, the manager MUST NOT signal a handle without the holder check or infer a stopped\ndrive from the marker alone. The marker can remain beside a running parked effect. The outcome remains unknown; a\nlater explicit cancellation request makes its own current observations.\n\nCancellation reaches the root signal in both language engines and the compiled worker bridge,\nincluding a cancellation latched before worker startup. It is separate from boundary release at\nmanager shutdown. A cancelled runtime drive reports `released` with a `Cancelled` reason; its\nstatus projection can lag its journal and handle outcome. Cancellation is cooperative: it does\nnot prove model or tool preemption, process interruption, resource cleanup or another host's\ncessation. Already-started external effects can still complete.\n\nThe reply contains `runId`, `authority` (`original`, `owner-interactive` or `admin`), optional\n`revocation: { by, reason, revokedAt }`, `duplicate` and `observed`. `duplicate` is false for a\nconfirmed new marker, true for a confirmed existing marker, and null when the write outcome was\nlost but a marker was subsequently read. The original stored marker is never overwritten.\n`observed` contains `processEpoch` and `phase`: `terminal`, `launch-abandoned`, `stop-requested`,\n`stopped` or `not-driven-here`. When read, it includes `recordedState`, `runEpoch`, `fencingToken`\nand `holder`; `driveOutcome` appears only when the local handle's outcome was observed. Budget\nexpiry after a stop request is not proof of cessation.\n\n**Issuer cancellation custody.** Inspection grants no later commit. The issuer independently\nobserves issued, untargeted instance requests for `run-cancel`, checks their closed input, and\nretains the original body fingerprint and deadline. The fingerprint includes the envelope id,\narguments, class, operation contract digests, bind and deadline. Identical redelivery does not\nextend that deadline. A different valid body under the same subject poisons that observation.\nThe manager's forward MUST match the observed body, instance, epoch and registered command.\n\nCommit atomically claims the observation before asynchronous authorization and store preparation,\nthen rechecks it at the actual marker dispatch boundary. The marker writer issues one conditional\nput, not a create helper that can retry after a deletion read. The closed commit result is one of:\n\n- `{ kind: \"committed\", outcome: \"created\" | \"existed\", revocation }`;\n- `{ kind: \"refused-before-dispatch\", code }`;\n- `{ kind: \"outcome-unknown\", code }`.\n\nThe code is `permission-denied`, `failed-precondition`, `deadline-exceeded`, `resource-exhausted`\nor `unavailable`. A lost transport result is unknown. The manager's earlier unknown history stays\nunknown even if a restarted or different issuer reports no observation. There is no cross-restart\nor multi-issuer exactly-once guarantee.\n\nObservation tombstones last for the issuer process lifetime, with no eviction. The default limits\nare 64 per caller triple, 256 per owner and 10,000 total; configuration MUST keep caller capacity\nat most owner capacity and owner capacity below the total. Static-addressed observations count\ntoo. Exhaustion refuses new identities rather than forgetting existing uncertainty. Inspection,\nclaims and equal redelivery cannot replenish these lifetime counters.\n\n**Resume, fork, local, restore.** A resume, takeover or reconcile continues under the ORIGINAL\nadmission and the current marker; the resuming caller's own authority is not consulted and cannot\nwiden it; a run with no admission stays parked, named in the host's log. A fork is a new run and\nneeds its own admission under the forking caller. A local drive (`cotal run start --local`) is\nadmitted from operator evidence named on the command line (the read and publish channel sets, or\n`none`), never from the host's own scope. The admission and revocation stores are retained with\nthe run, program and journal state they authorize; a restore that lacks them recreates them empty,\nand no run is taken back under authority the host cannot read.\n\n**User-auth runs.** A user-auth run is hosted by a signerless participant manager, and its issuing\nhost writes the admission. The issuing host admits a run-start whose caller has a derived user owner\nonly when that owner is the manager's registered owner, the owner whose `supervise` grant registered\nthe instance, so every user-admitted run on a participant manager belongs to that one owner. A\ncaller-requested resume and every principal answer or amendment ride the versioned rail. The manager\nforwards the request subject it served with the attempt or operator issuance it asks for, and the\nissuing host re-parses that subject, requires a user caller's owner to be the run's admitted owner\nfor a resume and the registered owner for an answer, resolves the caller's own issuance as live, and\nrequires its publish ceiling to permit that subject. The issuing host subscribes to the run-start,\nresume and answer request subjects itself, and to the keyed `run-start-keyed` and\n`run-submission-status` request subjects (§14), and never replies on any of them. It admits a forwarded run-start,\nand issues for a forwarded resume or answer, only when it observed a caller publish that request and\nhas not admitted or issued for it before, so a manager cannot forward a request its caller never\nsent. For a resume or answer it reads what that request's envelope asked for and issues only that: a\nresume attempt for the run its `runId` names, and an answering issuance for the endpoint the answer\nnames, the manager's own when it names none, for the run and step its `runId` and `stepKey` name,\nthat amends when the request set `amend: true` and answers when it did not. The\nmanager's request names that run and step, never a token. Every manager instance's pauses share one\ntoken namespace, so the issuing host requires the run to be admitted on the manager's instance and\nreads the pause's token off that run's journal, under a read it mints for that one run, before it\npins the token into the issuance. When the request carries a `bind` (§13.2) naming\nanother instance or epoch than the manager's current registration, it issues nothing, since that\nmanager refuses the request unrun. It issues nothing either for a request whose `class` or pinned\n`inputDigest` and `outputDigest` differ from the command's declaration in the manager's registered\ncluster (§13.7), which that manager also refuses unrun. An answering operator issuance always carries\nthe served subject. An amendment's issuance marks its pause with `amend: true`, and the issuing host\nthen requires that pause settled `resumed` with an accepted answer instead of waiting. A legacy-rail\nanswer is accepted only from a\nmanaged seat of that owner whose actor-ledger row is live, on the relay path of §14.5. A boot\nreconcile forwards no subject and continues under the original admission. A run's own caller holds\nno actor-ledger row, so when a participant manager asks its issuing host whether a caller of a run it\ndrives holds `admin` (§13.2), it asks for that run's admitted caller, whose current row decides. The\nissuing host pins every run mediator it signs for a participant manager, at issuance and at renewal,\nto a placement on that manager's own instance, the only instance such a run may place a spawn on.\nThe participant manager refuses a program that places a spawn on any other instance with\n`unimplemented`. This revision hosts no user-auth run on the signer-holding host's own manager.\n\n---\n\n## Appendix A: Reference implementation map\n\n| Spec section | Source |\n| --- | --- |\n| §2 Identity | `packages/core/src/identity.ts` |\n| §3 Subjects | `packages/core/src/subjects.ts` |\n| §5 Envelopes, §6 Presence, §7 Channels | `packages/core/src/types.ts` |\n| §8 Streams | `packages/core/src/streams.ts`, `packages/core/src/endpoint.ts` |\n| §9 Security | `packages/core/src/provision.ts` |\n| §10 Join link | `packages/core/src/link.ts` |\n| §13 Endpoint control surface | `packages/core/src/` (endpoint rails, envelope, contracts; lands with the control-surface campaign) |\n| §13.15 Issued authority | `packages/core/src/issued-authority.ts` (reference, evidence store, accepted row), `issuer-session.ts`, `endpoint-subjects.ts` / `endpoint-grants.ts` (the versioned rail) |\n| §14 Workflow runs, [`spec/cotal-lang.md`](spec/cotal-lang.md) | `packages/lang/src/` (the language, journal, keys, pins), `packages/core/src/run-record.ts`, `run-journal.ts`, `checkpoint-answer.ts`, `run-notice.ts`, `run-migration.ts`, `endpoint-binding.ts` (WFJ, grants), `run-admission.ts` (§14.8), `implementations/runtime/src/` (driver, migrate, fork), `implementations/manager/src/run-hosting.ts` (admission) |\n\n## Appendix B: Profile ACLs\n\nThis appendix is normative for the NATS binding. *(The operator-facing summary of these\ngrants is [docs/identity-and-auth.md](docs/identity-and-auth.md).)* Names below use these\nplaceholders:\n\n- `P = cotal.<space>`\n- `CHAT = CHAT_<space>`, `DM = DM_<space>`, `TASK = TASK_<space>`\n- `DLV = <Plane-3 per-member delivery stream>`; `INBOX = <mixed pre-auth fan-out stream>` (the durable-backstop handoff, §8): fan-out writes `INBOX` (`dinbox.<owner>.<actor>.<uid>`; lifecycle-bound from v0.4, so an inactive-gap or predecessor entry can never migrate to a same-name successor), the trusted reader re-authorizes and transfers to `DLV` (`dlv.<owner>.<actor>.<uid>`, same binding), and the agent binds its own `DLV` DELIVER consumer (filter pinned to its own triple). An agent gets **no** grant on `INBOX` (the mixed pre-auth store).\n- `KV = KV_cotal_presence_<space>`\n- `CHKV = KV_cotal_channels_<space>`; `DLVKV = <delivery lease/readiness KV>`\n- `MEMKV = KV_cotal_membership_<space>` (the derived channel-membership feed, §8)\n- `<owner>.<actor> = the authenticated principal` (§2): `<owner>` and `<actor>` are its two tokens; the dot-form is the wire/KV form, the dash-form `<owner>-<actor>` is the durable-name form\n- `connId = the authenticated connection id` (the connection nkey in static mode; the client-chosen nonce in user mode); distinct from the principal, and keys ONLY the reply inbox\n- `role = authenticated agent role`\n- `chatHistD = chathist_<owner>-<actor>-<uid>`, `dmD = dm_<owner>-<actor>-<uid>`, `dlvD = dlv_<owner>-<actor>-<uid>`, `svcD = svc_<role>` (per-instance durables are lifecycle-scoped from v0.4: keyed on the dash-form + lifecycle UID, §8/§13.1; `svcD` stays role-scoped)\n- `inbox = _INBOX_<connId>.>`\n\nGrouped placeholders such as `<CHAT|DM|TASK>` mean one concrete subject per listed token.\n\n### Agent\n\n`sub.allow`:\n\n- `inbox`\n- `P.live.<manager|delivery>.<owner>.<actor>.>` (replies to its own plane liveness probes, §6.1)\n- `P.ep.reply.*.*.*.<owner>.<actor>.<uid>.*` (exact arity; the agent's own endpoint reply rail: every endpoint's replies to THIS caller triple + nonce, §13.2; replies never ride the per-connection `inbox`)\n- `P.epe.…`; the exact fully-qualified event subtrees of every minted read capability\n (§13.9 event-read row), incl. the caller's own per-goal subtree\n `P.epe.*.*.*.goal.<owner>.<actor>.<uid>.>`; the live tail of watch, granted per\n capability, none by default\n- `P.chat.*.*.<ch>` for every `allowSubscribe` channel, the **live read boundary**: native core-sub join/leave is a `sub.allow`-bounded subscribe to this subject (wildcard sender owner+actor), so an agent whose ACL permits a channel joins it alone with no manager. Wildcards preserved (e.g. `P.chat.*.*.team.>` for `allowSubscribe: team.>`); a `team.>` grant matches strictly deeper channels, not the bare `team`; a `>` grant is read-all chat in the space on credential compromise\n\n`pub.allow`:\n\n- `P.chat.<owner>.<actor>.<ch>` for every `allowPublish` channel (post ACL; none by default)\n- `P.inst.*.*.<owner>.<actor>` (DM any recipient, forge-locked to me as sender)\n- `P.svc.*.<owner>.<actor>` (anycast any role, as me)\n- `P.live.<manager|delivery>.<owner>.<actor>` (plane liveness probe, as me, §6.1; the agent holds no `live` serve filter)\n- endpoint request forms per minted capability (§13.9): every agent gets the baseline set\n (`describe` on all endpoints; the delivery endpoint's durable join/leave/list commands;\n self-targeted manager commands with authz-mode `self`, including `run-answer`, which the manager\n narrows to an ask or escalation pending on that exact seat incarnation); the `spawn` capability adds the\n manager endpoint's lifecycle commands with authz-mode `owner`; `child`/`ledger` forms and\n wider target patterns only per explicitly minted capability. The caller triple\n `<owner>.<actor>.<uid>` is pinned in every granted form\n- control-surface durable reads (contract artifacts, decisions, goal results, receipts,\n event catch-up, record reads): **NO raw JetStream read grant of any kind**, no\n `DIRECT.GET`, no consumer `CREATE`, no bind-only `MSG.NEXT`/`ACK`, on `EPC`/`EPF`/`EPE`/the\n records KV. Per §13.9 \"Mediated reads\", every JetStream read delivers stored bytes to a\n caller-chosen destination the broker does not confine (push `deliver_subject`, pull\n `MSG.NEXT` reply, `DIRECT.GET` reply are the same vector), so an untrusted caller holds none\n of them. The caller reads through the trusted read mediator via a read command (an endpoint\n request form, above) and receives its own caller-scoped facts over its reply rail\n `P.ep.reply.*.*.*.<owner>.<actor>.<uid>.*` (already in `sub.allow`); the mediator owns the\n reader consumers and re-authorizes each read. Live event progress is the caller's own core\n subscription to granted `P.epe.…` subtrees within `allowSubscribe` (bytes land only on its\n own subscription, never a caller-chosen subject)\n- `$JS.API.INFO`\n- `$JS.API.STREAM.INFO.<CHAT|KV|CHKV|DLVKV>`: CHAT plus the world-readable presence/registry/lease KVs only; **not** DM/DLV/EPC (an agent reaches those by name — its own pre-created `dmD`/`dlvD`, or a subject-scoped `DIRECT.GET` on EPC — and `subjects_filter` is a request-body field, so INFO there would only leak inbox/delivery subject metadata). `TASK` rides the `role` gate below, not this row.\n- `$JS.API.CONSUMER.CREATE.<CHAT>.<chatHistD>.<P.chat.*.*.<ch>>` for every `allowSubscribe` channel (history reads; the single filter the server pins to the body, the agent's only CHAT consumer create. The live tail is the core `sub.allow` subscription above, not a JetStream consumer)\n- `$JS.API.CONSUMER.INFO.<CHAT>.<chatHistD>`\n- `$JS.API.CONSUMER.MSG.NEXT.<CHAT>.<chatHistD>`\n- `$JS.API.CONSUMER.DELETE.<CHAT>.<chatHistD>`\n- `$JS.API.CONSUMER.INFO.<DM>.<dmD>`\n- `$JS.API.CONSUMER.MSG.NEXT.<DM>.<dmD>`\n- `$JS.ACK.<DM>.<dmD>.>` (DM inbox: BIND-ONLY its own pre-created `dmD`, never create)\n- `$JS.API.CONSUMER.INFO.<DLV>.<dlvD>`\n- `$JS.API.CONSUMER.MSG.NEXT.<DLV>.<dlvD>`\n- `$JS.ACK.<DLV>.<dlvD>.>`, the **durable backstop**: BIND-ONLY its own pre-created per-member DELIVER consumer `dlvD` (the trusted reader's re-authorized handoff, §8). The agent holds NO grant on the mixed pre-auth `INBOX` fan-out stream.\n- `$JS.API.DIRECT.GET.<KV>` (the on-demand presence read, §6)\n- `$JS.API.CONSUMER.CREATE.<KV>.>`\n- `$JS.API.CONSUMER.INFO.<KV>.>`\n- `$JS.FC.>`\n- `$KV.cotal_presence_<space>.<owner>.<actor>`\n- `$JS.API.STREAM.MSG.GET.<CHKV>`\n- `$JS.API.DIRECT.GET.<CHKV>` (the one-shot registry read of the headless CLI commands, which connect on the user's bearer on a user-auth mesh; the same reply-subject vector as the consumer create below)\n- `$JS.API.CONSUMER.CREATE.<CHKV>.>`\n- `$JS.API.CONSUMER.INFO.<CHKV>.>`\n- `$JS.API.STREAM.MSG.GET.<DLVKV>` (delivery lease/readiness; read-only, non-gating)\n- if `role` is set: `$JS.API.STREAM.INFO.<TASK>`, `$JS.API.CONSUMER.INFO.<TASK>.<svcD>`,\n `$JS.API.CONSUMER.MSG.NEXT.<TASK>.<svcD>`, `$JS.ACK.<TASK>.<svcD>.>` (stream-level state is\n gated with the bind grants, so a role-less agent holds nothing at all on `TASK`)\n\n`pub.deny` (the agent binds these consumers, never creates them; its only consumer-create grant is the pinned per-channel `chatHistD` history create):\n\n- `$JS.API.CONSUMER.CREATE.<DM>`\n- `$JS.API.CONSUMER.CREATE.<DM>.>`\n- `$JS.API.CONSUMER.DURABLE.CREATE.<DM>.>`\n- `$JS.API.CONSUMER.CREATE.<TASK>`\n- `$JS.API.CONSUMER.CREATE.<TASK>.>`\n- `$JS.API.CONSUMER.DURABLE.CREATE.<TASK>.>`\n- `$JS.API.CONSUMER.CREATE.<DLV>`\n- `$JS.API.CONSUMER.CREATE.<DLV>.>`\n- `$JS.API.CONSUMER.DURABLE.CREATE.<DLV>.>`\n\nA bare/multi-filter consumer create on `CHAT` is **not** explicitly denied (that would also deny the\npinned `chatHistD` create the agent needs), so it is default-denied (the agent holds no such allow),\nleaving the single-filter history consumer above as the agent's only CHAT consumer.\n\n### Observer\n\n`sub.allow`:\n\n- `P.chat.>`\n- `inbox`\n\nApplication publish is denied. `pub.allow` contains only read/control verbs needed to read\nCHAT history, presence, and channel registry:\n\n- `$JS.API.INFO`\n- `$JS.API.STREAM.INFO.<CHAT>`\n- `$JS.API.STREAM.INFO.<KV>`\n- `$JS.API.CONSUMER.CREATE.<CHAT>`\n- `$JS.API.CONSUMER.CREATE.<CHAT>.>`\n- `$JS.API.CONSUMER.INFO.<CHAT>.>`\n- `$JS.API.CONSUMER.MSG.NEXT.<CHAT>.>`\n- `$JS.API.CONSUMER.DELETE.<CHAT>.hist_<readerId>_<n>` for each `n` in `0..7`\n- `$JS.ACK.<CHAT>.>`\n- `$JS.API.CONSUMER.CREATE.<KV>.>`\n- `$JS.API.CONSUMER.INFO.<KV>.>`\n- `$JS.API.STREAM.INFO.<CHKV>`\n- `$JS.API.STREAM.MSG.GET.<CHKV>`\n- `$JS.API.CONSUMER.CREATE.<CHKV>.>`\n- `$JS.API.CONSUMER.INFO.<CHKV>.>`\n- `$JS.API.STREAM.INFO.<MEMKV>`\n- `$JS.API.STREAM.MSG.GET.<MEMKV>`\n- `$JS.API.DIRECT.GET.<MEMKV>` (the membership snapshot read: paged batched Direct Gets that bind no consumer, since this profile may delete none)\n- `$JS.API.CONSUMER.CREATE.<MEMKV>.>`\n- `$JS.API.CONSUMER.INFO.<MEMKV>.>`\n- `$JS.API.STREAM.INFO.<DLVKV>`\n- `$JS.API.STREAM.MSG.GET.<DLVKV>`\n- `$JS.FC.>`\n\nThe membership feed (`MEMKV`) is read-only for this profile and, per §8's membership-feed\nparagraph, display-only and not part of the contract a client must implement.\n\nThe profile's only `CONSUMER.DELETE` rows name its eight history readers on `CHAT`,\n`hist_<readerId>_<n>`. A static credential's `readerId` is its user nkey, which its holder proves by\nsigning. Under the auth callout the inbox id is a nonce the client chooses, so the callout sets\n`readerId` to `<serverId>_<clientId>`: the admitting server's id and the client id that server\nassigned the connection, both in the callout request and in the server's `INFO` to the client. A\nreconnect is a new connection with a new `readerId`.\n\nA history read creates its consumers under one of those names, one at a time, and deletes each when\nits step ends, so one connection holds at most eight history readers on a stream however often it\npolls. Each create carries a description unique to that step. A create whose config equals the\nconsumer already under the name returns that consumer, delivery state included, so a client MUST\nNOT read through a consumer that does not carry its own step's description. A client MUST NOT delete\na consumer it finds under one of its names: another holder of the same credential, a process that\nstopped mid-read, or the client itself may have left it, and nothing the client holds tells which. It\nreads under a free name instead. After a delete fails without saying the consumer is gone, the\ndelete may have run with its answer lost and the name may be taken again, so the client keeps that\nname out of use until the reader's inactive threshold has passed.\n\nThe profile holds no other `CONSUMER.DELETE`. Its watch consumers are client-named ordered consumers\n(`oc_<nuid>_<serial>`, renamed on every rebuild), so the only expressible delete grant for them is\nstream-wide, and a stream-wide grant lets one holder delete another principal's watch cursors and\nthe delivery daemon's `fanout` durable. The broker removes these consumers at their inactive\nthreshold (five minutes after the last interest), and a client MUST treat a refused delete of its\nown watch consumer as that outcome rather than as a failure.\n\n### Admin\n\nAdmin has observer grants, with `sub.allow = [P.chat.>, P.inst.>, P.svc.>, inbox]`, the\ngod-view is the **messaging plane only**, enumerated: it deliberately excludes `P.ep.>`,\n`P.epe.>`, `P.epf.>`, `P.epj.>`, `P.ept.>`, `P.epr.>`, `P.epw.>`, `P.eps.>`, and `P.epc.>`\n(a space-wide `P.>` would plain-subscribe every `ep.one` request rail, collecting reply\nnonces the queue-qualified-only rule exists to protect, and every core-only session\nframe; §13.2, §13.11). Plus DM history read grants:\n\n- `$JS.API.STREAM.INFO.<DM>`\n- `$JS.API.CONSUMER.CREATE.<DM>`\n- `$JS.API.CONSUMER.CREATE.<DM>.>`\n- `$JS.API.CONSUMER.INFO.<DM>.>`\n- `$JS.API.CONSUMER.MSG.NEXT.<DM>.>`\n- `$JS.API.CONSUMER.DELETE.<DM>.hist_<readerId>_<n>` for each `n` in `0..7`, its DM history readers\n- `$JS.ACK.<DM>.>`\n\nAdmin still has no application publish grants.\n\n### Scoped host profiles (formerly `manager`)\n\nThere is **no allow-all credential**. The privileged host duties are split into scoped,\nsingle-function profiles, each granting only the verbs its function needs and none other:\n\n- `provisioner`: pre-creates the per-instance lifecycle-scoped durables (`dm_…-<uid>`,\n `svc_…`, the per-member `dlv_…-<uid>` handoff) AND the trusted control-surface consumers of\n the §13.9 matrix; `poolD`, `effD`, and the read mediator's reader durables\n (`decD`/`goalD`/`eveD-n`/`recD-n`, owned by the mediator, never by callers, §13.9\n \"Mediated reads\"), all PULL with exact full-tail filters; and mints scoped credentials;\n ephemeral onboarding authority. It also publishes `$SYS.REQ.USER.INFO` to observe its own\n native connection identity through the configured system account's import, with replies on\n its existing scoped inbox. It holds no arbitrary-user/account query or system credential;\n the response is not a permission ceiling, lifecycle or authorization to apply changes.\n- `deprovisioner`: target-pinned teardown of ONE retired lifecycle's footprint, minted per\n teardown with the target's `(principal, lifecycleUid)` in every exact-name grant; it can\n delete only lifecycle-keyed names, so it structurally cannot reach a same-name successor\n (§13.1). The footprint is the `dm_`/`dlv_` durables, the read-ACL row, and the durable\n membership row for each concrete channel the teardown names (one exact `memberKey` grant per\n channel). A wildcard channel is refused at mint. The manager names the launch's concrete read\n channels plus the channels the delivery daemon's read-only `lifecycleMemberships` admin verb\n lists for that exact `(principal, lifecycleUid)`. When that inventory cannot be read, rows on\n other channels stay retained, the teardown logs the inventory as incomplete, and retirement\n remains held pending retry rather than releasing the alias. The daemon MUST NOT hold that verb\n behind its other admin commands. Requests that arrive together MAY share one read of the members\n bucket, provided that read began after each of them arrived. Before it asks for that inventory,\n the manager MUST fence the lifecycle: it narrows the lifecycle's read-ACL row to an empty\n `allowSubscribe` with a compare-and-set update of the existing row, keeping its ceiling and never\n creating a row, under a deprovisioner credential pinned to that lifecycle. The daemon MUST read the\n lifecycle's exact ACL row immediately before a `durableJoin` writes the row that creates or reopens\n its membership, and again after that write. It MUST refuse the join when the channel is not within\n that row, and after the write it MUST first remove the row by its exact key. Every other membership\n write, such as a leave's tombstone or an activation, MUST update only the revision it read and MUST\n NOT recreate a removed key. A row of a fenced lifecycle that the inventory does not list is then\n never kept, whichever daemon process wrote it. The daemon also keeps its own fence, for a manager\n that does not narrow: once it takes a lifecycle's inventory request, it MUST refuse every\n `durableJoin` and `durableLeave` bound to that lifecycle, and it MUST begin the read only after the\n joins and leaves of that lifecycle already running have finished.\n- `supervisor`: the always-on agent-lifecycle daemon (the manager process's own connection). It\n is the manager endpoint's serve credential (§13.9) and the ONLY holder of the capabilities for\n the delivery endpoint's admin commands (below).\n- `delivery`: the server-side Plane-3 infra: fan-out, trusted-reader re-authorization, and the\n membership/ACL records the durable backstop authorizes against (§7). One process MAY hold this role\n for several spaces as one lane per space. Each lane presents only its own space's `delivery`\n credential, which that space's account signs, on connections of its own, and holds its own\n delivery lease, Plane-3 bindings and `$SYS` scan target; no credential, connection or lease is\n shared across spaces or accounts. It is the `delivery`\n endpoint's serve credential (§13.9); its admin commands, `reloadCreds`, the explicit adoption\n step of standing credential renewal (the daemon re-reads its re-signed creds file, pins the\n identity, swaps its connection, and reconnects the membership feed's rw connection, replying\n with the adopted JWT windows); `reloadStoreIdentity`, the store-identity challenge that\n names the SecretStore the daemon reloads from (the workstation root only when `--creds` is\n `<root>/.cotal/<spaceSegment(space)>/delivery.creds`; the file's own directory otherwise, an injected coordinate,\n the declared identity of an injected adapter, or the workstation root of the canonical arm; never a\n `findCotalRoot` ancestor walk). The first-party workspace filesystem adapter declares its workstation\n root, so passing that store explicitly names the real operator layout without an ambient coordinate.\n A filesystem identity is `{kind: \"fs\", root, id}`: `id` is a random value the store records once in\n `store.id` inside its own directory (`.cotal/store.id` for a workstation root, beside a `--creds`\n file otherwise, so that directory must be writable or already hold one). No key of a filesystem\n store and no `--creds` file may be its `store.id`, under that name or any other the filesystem\n resolves to the same file (a case-insensitive spelling or a link, found by device and inode), and a\n `store.id` that is a symbolic link or holds anything but a lowercase UUID is refused, because the id is published and a\n secret stored there would be published with it. Two filesystem identities\n match only when both `root` and `id` match, because a root is a local path and two hosts can mount\n different directories at one path. An answer whose filesystem identity has no `id` is refused. Uninjected `--creds`\n that names one real workstation while process cwd resolves another is refused at start, because\n membership-rw still uses `findCotalRoot`; a `--creds` path that is not under any `.cotal` tree is not that\n case. A manager whose remint store diverges is not that daemon's renewal owner: it starts and\n serves the space and skips the remint rather than being refused, including a daemon that bound\n after manager start. Matching that store identity is necessary but NOT sufficient to own the\n renewal, since the comparison carries no holder and no tiebreak and every manager sharing one\n store satisfies it; the owner is the manager that also holds the space's renewal lease, so a\n daemon's credentials have exactly one renewal owner at a time. And `evictPrincipal`, force-drop of a denied principal's live\n connections (system-account CONNZ scan → per-server KICK → re-scan verify, fail-closed on\n partial scans and on owners outside the principal namespace); carry a capability requirement\n minted to the `supervisor` profile **and to the trusted auth path** (§9/§10), which is the\n executor of the §13.1 takeover / terminal-retirement / handle-revocation barriers and calls\n `evictPrincipal` on each revoked credential's `holderPrincipal` (§13.1) as their eviction\n step; agents are broker-denied. `evictPrincipal` is\n wired into those barriers, not\n a standalone admin convenience. `evictPrincipals` is the same eviction for a set of at most 256\n distinct principals in ONE shared sweep: one CONNZ scan for the set, a KICK for every matching\n connection with at most 16 KICK requests in flight, and one re-scan per verify round covering\n every principal still pending. Every KICK settles before the re-scan that verifies it. Its reply\n is one `EvictionResult` per principal in request order, each read as `evictPrincipal`'s\n (an under-reported scan leaves every principal it would have decided `verifiedGone:false,\n scanComplete:false`). Frozen-gate reconciliation and an endpoint re-registration (§13.1) each\n verify-evict their whole holder set through it, so neither costs one sweep per family holder,\n and KICKing a live family costs one broker round trip per 16 live connections. A\n daemon that does not serve it refuses the verb, and the repair or re-registration then leaves\n the gate frozen. Its READ-ONLY twin `principalLiveness` answers whether one\n principal still holds a live connection (the same CONNZ sweep, observer credential only — the\n KICK credential is never opened on that path), reporting `live` / `gone` / `unknown` with scan\n completeness as a separate field and a reply bound to the exact principal queried. It exists\n because eviction cannot serve as its own precondition: a repair that must REFUSE while a holder\n is alive would, using `evictPrincipal` to find out, kill the holder before it could refuse.\n `gone` requires a complete, single-server-proven sweep (§13.13); an under-reporting sweep is\n `unknown`, which never authorizes. The former\n `delivery-admin` control tier is deleted with the v0 rail (§13.11).\n- `membership-rw`: the derived channel-membership graph feed reader/writer.\n- `operator`, `purger`, `teardown`, `channel-writer`, `control-caller-*`, `deployer`, `probe`: the\n human-CLI and maintenance surfaces, each scoped to its verbs. `teardown` also lists stream names,\n so space deletion finds the transfer buckets (§8), and holds `STREAM.INFO` and `STREAM.DELETE` on\n each transfer stream named at its mint. It also holds one non-fencing direct get on the records\n bucket, `DIRECT.GET.KV_cotal_records_<space>.$KV.cotal_records_<space>.run.*.*.status`, and no\n other read or write of it, so space deletion names the workflow runs it removes. The ephemeral teardown connection may read only its own\n broker user/account identity before native impact or deletion; this grants no other principal lookup.\n- `issuer`: an issuance window (§13.15), minted by the party holding the space signer; the issued\n and accepted stores plus one auth-store liveness read. A lifecycle terminal's retirement and every\n issuance other than the one below mint it per window, one-shot. An auth service, and each\n callout-only replica on its own, MAY hold one `issuer` session per account, space and\n authority-plane lifetime for the user-auth issuance its callout performs. A callout-only replica\n is one space's membership of that space's callout queue group, and one process MAY hold several,\n one session each; a process serving several spaces as their full auth service likewise holds one\n session per space. That session is private to its host and never shared across accounts or\n spaces. Its credential keeps the profile's five-minute\n expiry and is replaced with freshly minted credentials before it expires. Its connection never\n reconnects: it is closed and drained on a fence, a shutdown or a loss, and the next issuance dials\n a new one. Each issuance on it makes its own source, gate and accepted-row reads and its own\n create-only and CAS writes under the request deadline, and no issuance reuses what another read.\n A write in flight when the connection is lost has an unknown outcome and is never sent again.\n- `run-admitter`: one run's admission record or revocation marker (§14.8), minted per run for\n 60 seconds; two exact keys and nothing else.\n- `transfer-writer`: one carried resume transcript (§8), minted per CLI call for five minutes, or on\n a user-auth space exchanged per call as the `transfer-writer` view; the object's chunk and meta\n subjects in one instance's transfer bucket and a last-message direct get on each.\n- `transfer-reader`: one manager instance's `transcript-receive` or sweep (§8), minted per call for\n five minutes; its own transfer bucket's stream and nothing of any other instance. A remote manager\n receives it from the host's `transferReader` authority operation, which binds it to the\n authenticated manager's own instance.\n- `manager-service` is NOT a generic host profile: on a per-user-auth space only the\n loopback/operator exchange may issue this closed, one-owner/one-fixed-manager-actor/one-instance\n view to a signed-in user with ledger scope `supervise` (§13.1/§13.6). It reaches exactly the\n staged manager registration, contract, status, gate, credential, and same-owner descendant\n provisioning family; public exchange, managed-agent secret exchange, plain user bearers, and all\n other instances are refused.\n- `platform-control` is NOT a generic host profile either. It is the §13.1 service view a host\n issues, through its authority context's in-process door only, to one platform-run control\n manager per assigned account, under a `p_` platform owner and the host's current assignment. It\n reaches the same one-instance family as `manager-service` and same-owner descendants only. It\n never carries a human identity, never reads or implies `supervise`, and every exchange refuses it.\n\nStanding host credentials are **bounded and renewed**: one-shot profiles carry minutes-scale\nexpiry; `supervisor`/`delivery`/`membership-rw` carry a 24h expiry with the manager as the named\nrenewal owner (self-remint for its own credential; same-nkey re-sign + explicit `reloadCreds`\nadoption for the seed-less daemons); the two system-account credentials (`membership-observer`,\n`connection-evictor`) carry a 30d expiry and are renewable ONLY by a system-account rotation +\nbroker restart; no persisted system-account minting secret exists, by design. On per-user-auth\nspaces, static `agent`/`observer`/`admin` minting is retired entirely (the flip): agent identities\nexist only as owner+actor principals under a logged-in user, and the elevated profiles of this\nappendix are reached per-connection via the exchange-authored view claim instead (§10). The flip is\ndeny-new: a static\ncredential signed before it (or minted out-of-band with the account signing key) remains\nbroker-valid until signing-key rotation, which is the revocation lever for static material; the\nguarantee therefore applies to spaces that never issued static user-facing credentials.\n\nThe optional host-only `account-census` user has a fixed expiry of at most five minutes. Its only\npublish grant is `$SYS.REQ.ACCOUNT.<accountId>.CONNZ`; its only subscription grant is\n`_INBOX.cotal-account-census.<accountId>.>`. It has no KICK, account-event or response grant.\nThe account id is the DATA account public key. A registered SYS signer mints the user; the service\nclient never receives that signer or this credential. A pinned single-page observation is not a\nterminal retirement verdict. Incomplete or malformed observations remain unknown.\n\nThe live channel subscribe depends on none of these; it is broker-enforced via `sub.allow`, so\nself-serve live join works with no host present; only the durable backstop and its membership writes\nrequire a privileged host. None of these profiles is ever issued to ordinary agents. On the v0.4\nendpoint surface, every host profile's grant rows are **generated from the §13.9 ownership matrix**\n(matrix → grants, never the reverse): a profile with no matrix row holds no `ep*`, `$O.`, or\ncontrol-surface `$JS.API` authority, and `provision.ts` (`permissionsFor`) is the generated artifact\nthis appendix summarizes, not an independent authority. This appendix spells out the `agent`,\n`observer`, and `admin` profiles that make up the wire-facing security claim.\n\n## Appendix C: Normative references\n\n| Reference | Used for |\n| --- | --- |\n| RFC 2119, RFC 8174 | requirement keywords |\n| RFC 8259 | UTF-8 JSON envelopes (§5) |\n| RFC 4648 | base32 instance-id encoding (§2) |\n| RFC 8032 | Ed25519 keypairs behind nkeys (§2) |\n| RFC 8785 | JSON Canonicalization Scheme: every `*Digest` (§13.7), the program hash, input hashes and derived ids (§14, [`spec/cotal-lang.md`](spec/cotal-lang.md)) |\n| [ECMA-262, 14th edition (ECMAScript 2023)](https://262.ecma-international.org/14.0/) | the syntax and pure semantics the workflow language is a subset of ([`spec/cotal-lang.md`](spec/cotal-lang.md) §2) |\n| [NATS client protocol](https://docs.nats.io/reference/reference-protocols/nats-protocol) + [JetStream](https://docs.nats.io/nats-concepts/jetstream) | the v0 transport binding (§8) |\n| [NATS decentralized JWT auth](https://docs.nats.io/running-a-nats-service/configuration/securing_nats/auth_intro/jwt) + nkeys | identity and authorization (§2, §9) |\n\n## Appendix D: Change log\n\nNormative revisions of this document, newest first. Dated snapshots per §11; the wire\n`protocolVersion` is the compatibility signal, not these dates.\n\n| Date | Revision |\n| --- | --- |\n| 2026-10-28 | **A retiring lifecycle's fence is its ACL row (Appendix B).** The fence of the next entry lived only in one daemon's memory and was checked before a join wrote its row, so a join whose ACL lookup outlived the fence, a join from a still-connected seat after a daemon restart, or a join a quiesced predecessor finished after its successor's inventory each kept one row of a retired lifecycle. The manager now narrows the lifecycle's ACL row to an empty `allowSubscribe` before it asks for the inventory. The daemon re-reads that exact row before and after the write that creates a membership row, and removes the row and refuses the join when the channel is no longer within it. Other membership writes only update the revision they read. The daemon's own refusal and its wait for running writes stay, for a manager that does not narrow, as on a hosted daemon serving older managers. No wire change. |\n| 2026-10-28 | **A lifecycle's memberships stop changing once its inventory is requested (Appendix B).** A seat's eviction closes its connection but does not settle the daemon's own work: a `durableJoin` already running, or one queued on `ctl.delivery` and authorized after the inventory against the still-live ACL row, could commit a row the inventory never listed, and retirement then kept it. Once the daemon takes a lifecycle's `lifecycleMemberships` request, it MUST refuse every `durableJoin` and `durableLeave` bound to that lifecycle, and it MUST begin the read only after the ones already running have finished. No wire change. |\n| 2026-10-27 | **The membership inventory is not held behind other admin commands (Appendix B).** A manager stop retires many lifecycles at once, and each retirement asked the delivery daemon for its `lifecycleMemberships` inventory after its eviction. The daemon answered its admin commands one at a time, so the inventories waited behind every other seat's eviction, missed their deadline, and left rows retained. The daemon now MUST NOT hold that verb behind its other admin commands. Requests that arrive together MAY share one read of the members bucket, provided the read began after each of them arrived, so every answer stays as complete as a read of its own. No wire change. |\n| 2026-10-27 | **One auth service process MAY serve several spaces in full (§10, §13.13, Appendix B), additive.** One process may serve several spaces' exchange and JWKS as one full auth service per space. Each space's exchange is served on listeners of its own and mints only from that space's keys and ledger; each space keeps its own authority plane, claim row, scanner connections and fence, and a fence downs that space's service alone. Such a process holds one `issuer` session per space, never shared across spaces or accounts. |\n| 2026-10-27 | **Issued-authority rows are bounded by their generation's horizon (§13.12, §13.15).** The two issued-authority stores held every issuance forever, so their size was the cumulative number of exchanges. A generation now carries its horizon in its first 8 hex digits, and its last 24 are 96 bits of issuer entropy, so the 32-hex grammar is unchanged. The `issuer` gains only `STREAM.INFO` on the accepted store, so every issuer and resolver verifies both stores' shape when it binds. Every row of a generation in either store carries a per-message TTL to its horizon plus a 60-second margin, and both stores set `allow_msg_ttl` with no subject delete markers; `deny_delete`, `deny_purge` and the per-key shapes are unchanged. Every resolution, renewal and retirement refuses a generation at or past its horizon before it reads the store, and resolution checks the horizon again after its last read, so a removed key re-created later is never read. Horizons: the bearer expiry for a user-auth issuance, the credential expiry for an operator instrument, the assignment expiry for a platform supervisor duty, and 30 days after issuance for a static incarnation, whose renewals are capped at it. A store created before this revision is refused at bind and recreated. **Breaking pre-1.0 authority change: minor.** |\n| 2026-10-27 | **One delivery process MAY serve several spaces (Appendix B), additive.** One process may hold the `delivery` role for several spaces as one lane per space. Each lane presents only its own space's `delivery` credential on its own connections and holds its own delivery lease, Plane-3 bindings and `$SYS` scan target, never shared across spaces or accounts. The single-flight lease, its responder verdicts and the admin commands apply per lane unchanged. |\n| 2026-10-26 | **An operator instrument reads its pinned manager's `resolve-cwd` (§13.2, Appendix B), additive.** The folder question a managed launch asks had no caller that could make its check on a static mesh: `resolve-cwd` was carried by a `spawn` holder's `manager-caller` view and by no operator instrument, so every folder typed at that question was refused at the broker. Both instrument tiers now carry it on the instance their mint pins, beside the `spawn` row of the same `manager.spawn` capability class. The standing agent `spawn` set is unchanged, and no class, scatter or other-instance row is added. |\n| 2026-10-26 | **One callout process MAY serve several spaces (§10, Appendix B), additive.** A space's callout requests are served inside that space's dedicated auth account, so a responder holds one subscription per auth account it serves. One process may hold one subscription and one set of signing keys per space it serves. A response for a space must be signed only with that space's keys, and a bearer must be validated only against the issuer and audience of the space whose request it arrived on. Connect-limit buckets are per space, so a connect to one space never spends another's allowance. A callout-only replica is one space's membership of its queue group, and one process may hold several, one `issuer` session each. |\n| 2026-10-26 | **A held `issuer` session for user-auth issuance (§13.9, §13.15).** An auth service, and each callout-only replica on its own, may hold one `issuer` session per account, space and authority-plane lifetime for the user-auth issuance its callout performs, in place of one session per connect. It keeps the five-minute expiry and is replaced before it expires. It never reconnects, and it is closed and drained on a fence, a shutdown or a loss. Each issuance still makes its own reads and writes, and a write in flight at a loss is never sent again. Retirement at a lifecycle terminal and every other issuance window stay one-shot. The `issuer` principal is no longer one-shot only. |\n| 2026-10-26 | **Spawn readiness for a launch that waits for the operator (§13.6 item 6), additive.** A spawn whose agent application waits for the operator before its session joins, such as at a session picker, succeeds once its process runs, and its result's `waitingFor` names the screen. An `uncertain` result MAY carry `details[].kind = ai.cotal.goal.entity-running` when the owner saw the entity still running at the deadline. A reader that does not read `waitingFor` sees such a launch succeed before its session joins. |\n| 2026-10-23 | **A revoked run takes no answer (§14.8).** An answer to an open checkpoint or ask of a revoked run, or of a run whose marker cannot be read, is refused before anything is filed. The leader-served marker read before the answer record orders the answer against the revocation. |\n| 2026-10-23 | **A failed run records its cause (§13.7), additive.** A `failed` run status MAY carry `failure: { code?, message }`, the error the program failed with, so a reader of the record learns why without the host's log. It is optional on read and absent from every other state. |\n| 2026-10-21 | **Own-DM-only reader (§8), additive.** A client may read its DM inbox holding only its own `dm_` durable: it binds an existing durable, never creates one, refuses when it is missing, keeps the §5 sender check, and issues only CONSUMER.INFO, MSG.NEXT and ack requests on that durable. No credential profile is added. |\n| 2026-10-21 | **Handler refusals before any effect (§13.3), additive.** A handler that refuses before its command's first effect has started SHOULD carry `not-executed`, and one that refuses after an effect may have started MUST NOT carry it. |\n| 2026-10-21 | **User-mode chat sessions (§10, §13.1, §13.9), additive.** The auth service becomes a minting authority for chat sessions only. It admits one session per holder hash under the human's own `cli` grant, pins that grant, issues bearers of at most 900 s that it re-checks before and after signing, and mints the plain `agent` leaf with the session's lists. Three auth-bucket writer families (`chatholder`, `chatowner`, `chatsweep.cursor`) join the trusted auth path. |\n| 2026-10-21 | **Retirement-only manager composition (§13.1), additive.** An optional composition takes its own per-instance liveness lease before reading any lifecycle, slot or gate row. It records each slot as retired, already-retired, skipped-not-owned or held, never counts the latter two as retired, and introduces no new principal, credential profile or grant. |\n| 2026-10-19 | **A spawn-scoped `manager-caller` view reads its launch options (§9, §10), additive.** A person who may spawn on their own Manager could not read what a launch there needs: `status`, `models` and `resolve-cwd` were not in the view unless the actor held `admin`, and `resolve-cwd` was in no view at all. A view whose actor holds `spawn` now carries those three on its one pinned instance. A `run`-only or no-scope view gains nothing, `ps` and `slots` stay with `admin`, and no class, scatter or other-instance row is added. The standing `spawn` set is unchanged. |\n| 2026-10-19 | **Observer and admin history readers are deletable (Appendix B), breaking.** Each history read on these profiles left its consumers to the broker's five-minute inactive threshold, because the profiles held no `CONSUMER.DELETE` (#691). A dashboard polling history filled the stream's consumer limit, and every later read was refused with \"maximum consumers limit reached\". The observer now holds `CONSUMER.DELETE` on `CHAT` for `hist_<readerId>_<n>`, `n` in `0..7`, and admin holds the same names on `DM`. These are the connection's own history-reader names and no other consumer's: `readerId` is a static credential's nkey, or under the auth callout the server's id and the client id it assigned the connection, never the inbox nonce a client chooses. A history read uses them, deletes each reader when its step ends, and never deletes a consumer it finds under one of them. A credential minted without these rows cannot clean up, so a current client fails its history read and says to remint the credential. |\n| 2026-10-19 | **Private tool results (§13.19), additive; accepted, not implemented or enabled.** Defines the consent anchor role, managed-child serving request, consent and revocation record families, canonical START frontier, fixed audiences, exact-instance binding and bounded inert result journal. Revocation depends on a separately reviewed complete leader snapshot and an established enforced clock-skew bound; absent prerequisites answer `unavailable`. Activation requires every owner's qualified part and a stock release. Public tool arguments and results remain withheld. `protocolVersion` is unchanged. |\n| 2026-10-07 | **A role outside the token grammar is refused (§3), breaking.** A role was sanitized like every other routing token, so ` probe ` reached the `probe` queue and `pro.be` reached `pro_be` while the message kept the spelling sent, and an anycast to `*` was stored on a subject no role consumer matches. A client now refuses a role that is not one `[A-Za-z0-9_-]` token, both for the role it holds and for an anycast target, and refuses `*` as an anycast target. Existing `svc_<role>` durables keep their names, since they were always named from the sanitized token. |\n| 2026-10-07 | **A refusal for a target with no current mapping says that nothing ran (§13.2), additive.** It stays `expired` and now carries `outcome: not-executed` and `details[].kind = ai.cotal.ep.target-unmapped`. A manager resolves targets against the agents it hosts, so in a space with several managers the class queue could hand a targeted `despawn` to a sibling, which refused it the same way it refuses a retired target, with no outcome. The caller could not tell \"this agent is gone\" from \"this manager does not host it\", and repaired neither. With the marker a class-rail caller re-resolves and re-issues within its split-repair bound, and a target retired everywhere still ends in the same `expired` refusal once that bound runs out. A caller that ignores the marker sees the old code. |\n| 2026-10-04 | **Managed lifecycle handoff (§13.17), additive.** A managed agent already enrolled through §13.1 may run where the enrolling manager's filesystem is not visible. The manager releases one closed `cotal-managed-handoff/v1` document by value into that one child, carrying the issued owner, actor, lifecycle UID, sentinel, pinned exchange base, and the raw actor token, which the host never receives. The child's entry point removes the handoff file and its variable before it parses its arguments or does anything else, refuses a mismatched owner, actor, or lifecycle UID before any plane opens, never enrolls or mints, and uses the existing agent-bearer exchange unchanged. The manager refuses a spawn choice only its own host can honour before enrolling. Readiness stays presence-observed, a lost create acknowledgement stays held as uncertain and is never retried, a provider's answer that no resource exists is not an exit, and a close by the lifecycle-derived key is fenced against a create that could still land. A provider resource is bound to that key only by the provider's authenticated answer to its create, never by a derived identifier, a name or a listing. Retirement reuses prepare-retirement, then the known runtime handle's fenced close, then the terminal barrier, including after the manager is gone. A preservation cut that holds a handed-off lifecycle is refused, and a manager stop after a refused cut retires it. |\n| 2026-10-04 | **Platform control authority (§13.1, §13.6, §13.9), additive.** A closed server-authored `platform-control` view, beside the unchanged human `manager-service` view, lets a host run one pooled control manager per assigned account. Its holder's owner is a host-derived `p_` platform owner token, disjoint from every `u_` owner. The host's fresh platform-control assignment authorizes it in place of a ledger `supervise` scope. One closed envelope carries the existing typed manager requests through an in-process door of the host's authority context, served on no listener. The unchanged registration proof, process epoch, and all-duty renewal renew and fence it. Its host-owned maintenance reaches only the assigned instance under its own gate. An account has one assignment and so one control instance, which keeps its instance id and lifecycle UID across restarts and enters a deployment only after the assignment's named predecessor manager has left through its own path, read and never written by the host. It refuses human tokens, takeover of another owner's instance, local or custodial runtime, generic signing, exchange issuance, and cross-owner descendants. The reference host is `startAuthService` in `@cotal-ai/auth`. |\n| 2026-10-02 | **Plane liveness (§6.1), additive.** A credentialed peer can ask whether the manager or delivery plane has a bound responder, on `live.<plane>.<owner>.<actor>` with the reply under `<request>.reply.<nonce>`. The reply is `LivenessAnswer`: `plane`, a `ResponderState` verdict, and an optional opaque per-bind `instance` token that distinguishes responders without identifying them. Only the broker's no-responders answer grades `unbound`; every other failure to get a readable reply grades `unknown`. Agents gain the per-plane request and reply rows; the `delivery`, `supervisor` and remote-manager supervisor credentials gain their plane's serve filter and bounded reply grant. A responder binds again on every connection that replaces the one it bound on, and the manager is not `bound` while its service connection is closed or disconnected. |\n| 2026-09-28 | **The `auth` endpoint becomes a conforming registered endpoint (Cotal #399), closing the two gaps the prior two rounds named.** The plane's boot registers `svc.auth.<instanceId>` through the standard `registerServiceInstance` path and publishes its `retire-lifecycle` contract artifacts to the content-addressed contract store, so the endpoint now serves the reserved `describe` and answers the v1 envelope (`ep.v1`) instead of the legacy `{op,args}`/`{ok,data,error}` body this document states are deleted; a legacy body is refused `unsupported-version` as envelope validation, never an ACL denial. The requester side moves from a hand-built subject to the generic client (`resolveService` + `invokeCommand`), still minted in `exact` mode target-pinned to one incarnation at mint time, and gains the baseline `describe` row plus a bounded contract-store direct-get row so it can resolve the endpoint's registered digests before it calls; a body target that disagrees with the exact subject triple is refused `target-mismatch`. Two new §13.9 rows record the registered instance and the requester's describe/store-read grants. |\n| 2026-09-27 | **Id-less messages are not publish-deduplicated on the durable plane (§8).** The reference Plane-3 fan-out writer and membership-transfer frame publish carry no `Nats-Msg-Id` for a message whose `id` is `\"\"`, so two distinct id-less posts on a durable channel both reach a member and a redelivery of one id-less post may surface twice; a message with a real id keeps its idempotent publish key unchanged. Classification: reference-binding behaviour, no wire-envelope or schema change, protocolVersion unchanged. |\n| 2026-09-09 | **Issued authority and run admission (§13.15, §14.8).** A caller's request may ride a versioned rail (`ep.v1`) that pins the credential's issuer-accepted **generation** beside its triple; the issuer persists the generation's immutable permission ceiling as evidence before returning material, and a client learns its generation from an issuer-written accepted row. A hosted workflow run is admitted under the caller's resolved ceiling, recorded once per run in a dedicated store the driver cannot write, checked before every channel effect, and revoked by an independent marker; resume, takeover and reconcile continue under the original admission, a fork is a new admission, and a local run is admitted from operator evidence named on the command line. `run-start` on the legacy rail is refused by name. Three new per-space stores, two new one-shot profiles (`issuer`, `run-admitter`), and an admission read on the run mediator and operator profiles. **Breaking pre-1.0 authority change: minor.** |\n| 2026-08-24 | **Remote user manager authority.** A closed server-authored `manager-service` view permits one registered user-auth participant to operate one opaque manager instance only when their live actor-ledger row carries the dedicated `supervise` scope. `supervise` is distinct from `spawn` and `admin`; public and managed-agent exchanges refuse the view, and plain user bearers remain unprivileged. The host, never the participant, issues public-nkey JWT material through a lifecycle- and instance-bound, typed, replay-safe `prepare → activate → renew` protocol. The family is confined to one derived owner, fixed server-selected manager actor, lifecycle UID, instance registration/contracts/status, gate, and credential rows; descendant provisioning is host-validated for the same owner only. Revocation and renewal deny new material and unsafe restarts fail-closed while retaining live agents only within their independently valid authority. **Breaking pre-1.0 authority change: minor.** |\n| 2026-08-19 | **Receiver deduplication MUST NOT use the empty string as a key (§4), and id-less deliveries are individually addressable (§8).** Two distinct received messages MUST NOT be treated as one logical delivery solely because both carry `id: \"\"`; each remains independently deliverable, and copies that cannot be correlated by wire identity may surface more than once on an at-least-once path. The publisher's §5 obligation to supply a unique string id is unchanged; an absent or non-string id remains a malformed envelope, now enforced at each delivery pump (durable terminate, live drop, history and recall skip). §8 adds that the absence of a usable receiver dedup key does not relax acknowledgement ownership: a JetStream-consumed copy with `id: \"\"` that is surfaced or handled MUST be acknowledged independently, and the reference implementation realizes that through a per-delivery receive key (never wire identity, never dedup authority) at its drain and in-flight seams. Plane-3 durable fan-out still derives its publish msgID from `CotalMessage.id`, so distinct `id: \"\"` messages can be collapsed inside the broker's duplicate window on a durable channel before the receiver sees them; that path is its own tracked change and this revision's guarantee is scoped to the receiver. Classification: normative receive-side semantics, no wire-envelope or schema change, `protocolVersion` unchanged. |\n| 2026-08-18 | **v0.5 binding revision: workflow runs (§14), additive.** A deployment MAY host durable workflow runs: programs in the Cotal workflow language, defined by the new normative reference [`spec/cotal-lang.md`](spec/cotal-lang.md) (language version `1`: the syntax table, values and the boundary rule, the library, the effect primitives with their hashed projections, the four concurrency scopes and the clock-decided `race`, the step key grammar, journal entry schema, input hash and request id, resume, migrate and fork), whose every effect is recorded in a per-run step journal on the new per-space `WFJ_<space>` stream (one subject per run, no age eviction, no Direct Get, every append fenced by the run subject's own sequence, replay-then-activate takeover with a fencing-token authorization tuple, an ordinal chain and a `journalHigh` anchor). Four core record kinds join §13.7: `run` (split; the resolved pin set on the spec half, holder/lease/`journalHigh` on the status half; driver-minted, never-reused ids), `answer` (atomic, content-derived id, keyed per answer because every presenter is the driver), `notice` (split; addressee keyed by a digest of the name; consumption as status), `migration` (split; content-derived id; application as a create-only status). Driver grants are per run and per takeover, with no wildcard form. `languageVersion` is pinned per run and moves independently of the wire version. No existing kind, subject, grant row or shipped datum changes. |\n| 2026-08-16 | **A caller declares the incarnation it resolved against, and a responder that is not it refuses before any effect.** A class-addressed request is delivered to one member of a queue group, and the member that answers need not be the one the caller's `describe` resolved against. The caller could only detect that AFTERWARDS, from the reply subject, by which point the command had run: the split was observable but never preventable, and the reference client's recovery repeated the command. `bind` (§13.3) is the caller's declaration of `{ instanceId, epoch }`, checked by the responder against its own identity at the pre-effect seam, ahead of the governed gate and every handler. A mismatch is `failed-precondition` for a different instance and `expired` for another epoch of the same one, both carrying `details[].kind = ai.cotal.ep.bind-refused` and, per §13.3, `outcome: not-executed`. **ADDITIVE**: `bind` is MAY, a responder that does not implement the fence ignores it under §5 and executes, so the caller-side check remains the only protection in a skewed pair and `protocolVersion` stays 0.4. It confers nothing and narrows only, so it satisfies monotonic attenuation: a request carrying it reaches exactly the instances the subject already routes it to, and can only make one of them refuse. Absent on `describe` (the bootstrap that produces the bind) and on the scatter rail (which addresses every incarnation by construction); on the `inst` rail it MUST name the subject's instance and adds the epoch the subject grammar has no token for. Attribution still comes from the reply subject, never from this block: it is what the caller bound, not a claim about who answered. |\n| 2026-08-16 | **A command declares whether repeating it is safe, a responder reports whether a refusal already executed, and the two are separated from idempotency by `id`.** Three gaps that only bite together. **(1) `effect` (§13.7).** Nothing in a resolved command distinguished a read from a mutation — every manager command declares `class: \"ephemeral\"`, and `traits` carries no repeat-safety — so a client deciding whether to retry had nothing to consult, and the reference client repeats a mutation on a split. Precisely: the automatic repeat belongs to the high-level helper, not to the primitive — `invokeCommand` raises the post-reply currency refusal and stops, and the `invokeService` wrapper around it catches exactly that code, re-resolves, and invokes a second time. Measured on a live broker under a forced instance split, counting at the handler rather than on the wire, the repeated command executes TWICE. `effect` is `read` or `write`, with `read` defined OPERATIONALLY — repeating it changes nothing the command is TRYING to change, and the only excluded difference is the incidental trace of having been called (request ids, spans, logs, metrics, timing) — because the intuitive definition, indistinguishable to every observer, is satisfiable by no real command and would make the field decorative. The state in question is not only the endpoint's own: a command whose intended effect lands elsewhere is still a `write`, and `evictPrincipal` fixes that boundary, since dropping live broker connections while leaving the endpoint's own records untouched is the point of calling it. **(2) `error.outcome` (§13.3).** A refusal code cannot say whether the effect happened: the same code is correct for a request that ran and one that never left. `outcome` is emitted by the RESPONDER, which is the only party that knows — `not-executed` when it refuses before the handler, `executed` when it refuses after, `unknown` when it cannot tell. It describes a reply and only a reply — a caller-side refusal is not an `EndpointReply` and carries no `outcome` field — but it does NOT follow that the caller knows nothing, and the first cut of this amendment wrongly collapsed four distinguishable local cases into `unknown`. A refusal raised BEFORE publication is `not-executed`: the request never left, and calling that `unknown` suppresses a retry that is provably safe even for a `write`. A refusal raised while HOLDING a reply — the §13.2 post-reply currency check is the case in this document — takes what it knows from that reply: `ok:true` means the handler ran, and an `ok:false` reply carries the responder's own `outcome`, which the caller adopts rather than overwrites. A **broker-attested no-responders answer** on the reserved sentinel is also `not-executed`: it is positive evidence that the subject had zero subscribers, trusted only on that sentinel because the same status on an ordinary reply subject is a responder's own claim. Only \"no reply observed at all\" (deadline, transport failure after publication) is `unknown`. And **a reply proves the request was HANDLED, never that it was EXECUTED** — the version, class, target, sender, authz, contract, and guard checks all publish `ok:false` having executed nothing. It is also not a goal's terminal state (§13.6 owns that) and must not be used as one. **(3) Repeat versus resubmission (§13.8).** `effect` and \"idempotent by `id`\" are different axes and were unreconciled. They are now separated by CONVERGENCE rather than by token: a **resubmission** is a re-send the responder converges onto the decision it already recorded, a **repeat** is one it accepts as new work, and `effect` governs repeats whatever `id` they carry. Defining the split by the token instead left a hole — a post-horizon re-send under a reused `id` is accepted as new work, so it executes, while formally escaping a prohibition written as \"under a fresh `id`\". Reusing the token is how a caller ASKS for convergence; it is not the answer. Within the horizon `id` is what convergence is keyed on — and `id` is the whole key on the ephemeral rail but only ONE of the effect-defining dimensions the journal fingerprint binds — endpoint, command, `id`, `goalId`, `class`, args, both contract digests, the authorization mode, the target, `auth`, and the caller — where same id + different args is neither dedup nor a fresh call but a loud `conflict`. **Both rails are bounded by a horizon**, realized by decision-fact and result retention rather than by a clock, and outside it neither rule applies: the `id` carries no history, a re-send under it is a fresh call that WILL execute, and the same `id` with different args is no longer a `conflict`. A finite horizon is what keeps the decision store finite, so this is a fact callers must hold rather than a hole to close — and because a repeat is defined by acceptance rather than by token, a post-horizon same-`id` re-send of a `write` is exactly what §13.7 forbids a client to make automatically. A command idempotent by `id` is therefore NOT thereby `read`: safe to resubmit is not safe to repeat — and the dangerous reading is a reasonable one, since an operator who retries after a timeout mints a fresh `id` because the old request is gone. **NON-ADDITIVE, and versioned as such:** a client that ignored `effect` would keep performing exactly the retry the field exists to stop, so it rides `protocol.v` — the marker that ALREADY EXISTS on the service record spec and the describe descriptor, never a new field on the cluster document, which has no `protocol` and where §7 would drop it unread by exactly the clients this must stop. An instance whose clusters declare `effect` registers and describes at `v:2`; `v:1` descriptors stay valid, carry no `effect`, and every command served under one reads as `write`. The caller-side refusal of a `protocol.v` it does not implement is a requirement this cut CREATES, not one already met: today `describe`'s pinned output schema fixes `descriptor.protocol.v` to the constant `1`, so an unamended responder cannot publish a `v:2` descriptor at all, and the registry reader refuses a service record that is not `v:1` — but the resolving caller validates neither, and the shape it reads does not carry `protocol`. The responder-side fence is what protects old clients today, and only until this cut widens that constant. **Release order was the wrong instrument and is withdrawn**: a same-release ordering rule has no observable runtime meaning, since a release is not a deployment and an already-running v1 caller is unchanged by whatever a new artifact contains. **The cutover rule is §11's, and §13.7 does not state one.** Moving to `protocol.v: 2` IS a non-additive discovery change, so the §11 rule for one (previous row, landed first) is the sole authority on how it rolls out. §13.7 carries only what is specific to `2`: a caller that resolves a descriptor whose `protocol.v` it does not implement MUST fail the resolve (`unsupported-version`) and MUST NOT invoke against it — a descriptor it cannot read is no descriptor, and reading it as `v:1` reinstates the repeat — and implementing that refusal is what makes a caller count as having ADOPTED the section for §11's condition. Two intermediate drafts had to be withdrawn to reach that: one sited the cutover in §13.7 as a same-release ordering clause, which has no observable runtime meaning because a release is not a deployment; the next stated the cutover in BOTH sections, which is a single-source-of-truth defect, since two normative statements of one rule agree until either is edited and then silently become two conformance rules. The reason it cannot be sited here is the durable part: the condition is a property of the whole deployment, and a responder cannot evaluate it — no in-band negotiation, no caller version on the wire — so a rule stated here would bind the one party unable to check it. |\n| 2026-08-16 | **A non-additive discovery change is an out-of-band deployment cutover and rolls out CALLER-FIRST (§11).** The preceding §11 rule says v0 has no in-band capability negotiation and that deployments agree out of band; this says what that obliges when a discovery change CANNOT be ignored safely — where an unamended client that drops the new field per §7 would then behave in the very way the change exists to prevent, so no default value repairs the direction that matters. The obligation rests on the DEPLOYMENT, because neither participant can discharge it: a responder cannot tell an amended caller from an unamended one, since no request carries a caller version and `describe`'s answer is read by the caller without a version check. So every caller adopts the new rules BEFORE any responder registers or describes at the new version, and the two halves SHOULD ship in SEPARATE releases — **a release is not a deployment**, and an already-running caller is unchanged by whatever a new artifact contains, so the order of two source edits proves nothing about the processes on the wire. `protocol.v` on the registered service record is the observable marker: \"has any responder cut over\" is a checkable registry property, while \"has every caller adopted\" is the out-of-band agreement §11 already requires. **The residual is stated rather than engineered around**: an early cutover exposes unamended callers to exactly what the new version prevents, and within v0 nothing in band detects it — closing that needs negotiation v0 does not have, and the v1 marker owns it. Prose only: no schema, no wire field, no code. |\n| 2026-08-14 | **The auth-admin rail moves off the retired `ctl` surface onto the endpoint SUBJECTS (a subject-plane migration, NOT yet a conforming endpoint - see the residual below), and its authz description is corrected to what ships.** TWO defects on the same §13.9 rows, fixed together. **(1) The rail.** The rows served the auth plane's generic \"retire a lifecycle\" operation on `ctl.auth-admin.<owner>.<actor>` — a rail §13.11 retires in full and states MUST NOT be handled. New normative rows written onto a deleted rail are defects, not exceptions to it, so they are rewritten onto the v0.4 endpoint surface rather than given scoping language: `ep.one.auth.retire-lifecycle.handle.<tO>.<tA>.<tUid>.<cO>.<cA>.<cUid>.<nonce>`, served queue-qualified on the class rail, with the reply DERIVED from the parsed request (the bound-reply rule becomes structural — no caller- or payload-supplied reply target can arrive) and the request/reply planes disjoint, so the listener credential cannot express a request subject and the self-forge closes by grammar. The requester credential now pins its caller TRIPLE and exactly ONE target incarnation, so a leaked requester cannot be re-aimed. §13.11 is unchanged and gains no carve-out. **(2) The authz sentence.** These rows described serve-time authz as a space-manager-LEASE holder check; the implementation replaced that with the serve-issuance-gate check on 2026-07-22 without a spec change, so the normative text had been false since. It now describes what ships — a fresh leader-served read of `epgate.<serveEndpoint>.<serveInstanceId>` requiring presence, the declared epoch, and THE PRINCIPAL CROSS-CHECK (`row.principal` must equal the subject-derived caller principal), the last being new here: the two-token `ctl` subject could not express the caller beyond an alias, so the rail had accepted ANY registered instance's gate. The binding is stated as ALIAS-LEVEL, not incarnation-level: the gate is keyed by the persisted `instanceId` and its row carries no lifecycle uid, so a same-principal predecessor presenting the current epoch still passes; binding the publishing incarnation needs a gate-row schema change and is not attempted here. **NAMED RESIDUAL (Cotal #399) - THE RAIL IS NOT A CONFORMING ENDPOINT: it carries the endpoint SUBJECTS only. It still exchanges the pre-v0.4 `{op,args}` / `{ok,data,error}` bodies this document states are DELETED, registers no `svc.<endpoint>.<instanceId>` service record, does not serve the reserved `describe`, and has no contract/cluster artifact - so a GENERIC endpoint client can neither discover nor invoke this command. The exploitable half is closed in this change - the request carries a caller-chosen `id`, the responder echoes it on every reply, and the caller refuses any reply that does not echo, so a wrong-id `ok:true` cannot clear a retirement hold - but the versioned typed envelope, contract digests, `class`, deadline/`replyExpected` semantics, structured errors, service registration and `describe` are a separate cut tracked at #399, whose acceptance test is that a GENERIC client can discover and invoke the command. Recorded here rather than left implicit: serving a deleted envelope on the new rail is the same class of defect as serving on a deleted subject.** |\n| 2026-07-19 | **v0.4 amendment continuation: retirement cleaner inventory is discovery-only.** The terminal retirement barrier no longer accepts a caller-supplied `(endpoint, pools)` hint: the per-op cleaner and settlement-executor pool set is now DISCOVERY-ONLY, exactly the retiring lifecycle's accepted `oblig.<uid>.>` pool routes discovered from the just-drained obligation set. This SUPERSEDES the round-11 optional-hint clause (the 2026-07-15 row): the hint was a TRUSTED ADDITIVE AUTHORITY input that would mint a bounded per-op credential for a pool with no backing obligation, and the despawn rail never exercised it (always an empty hint), so it was grant-widening surface with no production caller. Every grant now scopes to exactly the pools the target holds accepted work on, and the §13.9 residuals cover only those discovered pools. The intent's `endpoints` field is removed from the closed operation-intent schema; a pre-change durable intent that still carries it fails the closed-schema check on resume (the v0.4 hard-cut window, where a clean broker holds none). |\n| 2026-07-16 | **v0.4 amendment continuation: connect-arm deny-new (production activation R1).** Every bearer carries its incarnation's root credential id (`act.credentialId`); the exchange mints the root credential RELEASE-LAST (active `cred.` row durable, gate finalize, lifecycle-head current-root CAS, bearer bytes last) and the connect authority requires the LIVE row (leader-served from the shape-proved primary auth store, re-proved on every rebind) plus root head equality, so revoking the row denies the next connect and a superseded or crash-orphaned root issuance never authenticates. The root credential is **incarnation-wide** (ratified): one row per incarnation, re-stamped (the same id) every exchange for its 90d life, never a fresh id per exchange, so one revoke denies every bearer of the incarnation, and a crash after the head CAS re-exports the same id by design (nothing unobserved to revoke; the only pre-release crash window is a durable unstamped row, denied by head equality). The authority store shape proof binds the stream to the actual KV bucket (exactly the one `$KV.<bucket>.>` subject + durable file storage, in addition to the primary/un-mirrored/non-evicting/`allow_direct` flags) at every bind and at boot ensure. Claimless bearers, revoked/expired/absent rows, and an unreadable authority store deny outright (no file-only fallback; a failed reader-credential renewal downs the reader immediately and denies). The head's current-root stamp moves only ABSENT to value: root rotation without the full family-revoke barrier is refused structurally. Named R1 residuals: a same-alias re-grant while the predecessor incarnation is live refuses the exchange (production issuance runs no takeover barrier yet), and the auth service's reader/mint-writer are seed-signed infra credentials (revoked by service stop or signing-seed rotation) pending the ledgered infra-mint family. |\n| 2026-07-16 | **v0.4 amendment continuation: retirement settlement authority split.** A seventh round (an independent cold read on the landed barrier plus the panel's authority ruling) split terminal pool cleanup across two profiles: the bounded cleaner keeps ONLY bind-scoped fetch, leader-served EPF terminal-observe reads, and ACK (its former own-pool `wrk` terminal-forge residual is REMOVED with the grant; its remaining residuals are terminal-free ACK suppression and the space-wide read exposure), while the op-bounded retirement settlement executor (a new §13.9 row) owns the intent-closed lease-record CAS and the lease-derived `wrk` terminal publish, carrying the relocated, intent-confined forge residual. Settlement is lease-fenced: an already-settled lease (a crashed owner's `committed`) dominates and is never overwritten. Effects-route completion is a new CLOSED `eff` fact (subject-bound caller and id; `fingerprint` and `sourceSeq` bound to the accepted decision), an action's completion requires the parsed `goal….result` fingerprint match, and subject presence never proves quiescence. The mediator's obligation-row residual is stated honestly (an operation/header-blind KV publish: valid-terminal overwrite or DEL/PURGE markers, refused loud by readers; the records stream denies stream-API message-delete/purge), and the caller-selected-reply confused-deputy injection residual is named for every raw `MSG.GET`/`MSG.NEXT` profile. |\n| 2026-07-15 | **v0.4 amendment (folds into the in-flight §13 revision below): lifecycle and admission fences.** Three-state lifecycle head (`active \\| retiring \\| retired`; currency only at `active`; `mappingRevision` = the head key's store revision), space-global never-deleted UID reservation (`uid.<lifecycleUid>`), per-kind issuance-gate operation intents and their allowed-transition sets, the locked terminal barrier order (obligation drain to quiescence before the exact-pool cleaner, both before frontiers), the §13.8 authority-head reservation/drain protocol (create-fence + proof-gated admission + per-class decision coordinates + writer≠target reclamation), the endpoint-wide admission-policy coordinate (the governance head + `policyRevision`) with drain-gated policy enforcement, the `ep` sentinel for untargeted admissions, and bind-time store shape proofs (§13.12). Refined per the re-verify round: the govern head's NORMATIVE policy selector `{ enforcedPolicyKey, enforcedPolicyRevision, pendingPolicy… }` with a stage/drain/promote mutation order (so the enforced policy is machine-selectable during the drain window), the `self`-class obligation's complete commit intent `{ commitKey, commitBaseRevision, commitValue, commitDigest }` (the pinned BYTES, not just a digest) with deterministic `accepted → terminal` recovery and full-intent create-join (an accepted-but-uncommitted row never blocks quiescence), the retirement barrier's cleaner-credential revoke + verified-eviction BEFORE any frontier records, the LIMITS-retention bind-time proof (a non-Limits authority store deletes rows on consumer ack), and the runtime gate parse rejecting impossible `retired`-under-takeover/registration state. A second re-verify round added: the head's `lastTakeoverOpId` (the epoch advance stamps the completing op, so a losing concurrent takeover never claims the winner's completion), the immutable revision-addressed admission-policy key (a mutable per-instance slot loses the old revision under history 1 during the drain), the `epgate.principal` and the rule that a ledger row's `holderPrincipal` is ALWAYS a CONNZ-attributable principal (the endpoint NAME forms the `epcred.` key in a separate field, never the eviction target), and the lifecycle barrier's session-pair teardown (a takeover revoking a `session.`-derived credential terminalizes the session and revokes the paired serving row). A third round (a convergent panel + independent cold read) added: the normative immutable `policy` record kind `policy.<endpoint>.<digest-hex>` (self-certifying content-addressed key; the govern selector names exactly this kind, replacing the per-deployment \"versioned key\" allowance), the CLOSED `commitValue` union (`{ enc: \"b64u\", bytes }` exact base64url value bytes, or `{ enc: \"ref\", key }` naming an immutable records key; `commitDigest` = `sha256:<hex>` over the raw value bytes), proof-issuance PAUSE for policy-admitted decisions while a `pendingPolicy…` is staged (which makes the policy drain converge and the after-final-enumeration no-admit rule hold for policy movement), the serving-principal JOIN into the lifecycle barrier's verified-eviction set (a session-pair teardown returns the paired serving row's holder principal and the barrier evicts it before the epoch CAS), and the torn-coordinate takeover guard (the intent capture re-proves head coherence, and the freeze CAS is preceded by a head-currency read, so a stale intent never freezes the winner's reopened gate). A fourth round (a convergent re-verify + independent cold read) added: the drain-window admission pause is now a NORMATIVE step of the §13.8 admission algorithm (the mediator's create-fence AND post-create recheck leader-read the govern head and refuse a policy-admitted decision while a `pendingPolicyKey` is staged, which also bounds the never-deleted `oblig` set during a long drain), the §13.9 matrix records the mediator's govern-head and policy-version read authority, the `policy` kind's immutability is stated honestly as a trusted-writer create-only-CAS invariant backed by read-time self-certification rather than a broker-level update/delete subtraction (KV operations share one subject), and the takeover barrier's crash-boundary recovery COMPLETES containment (revoke + reconcile + verified-evict every family holder) BEFORE it aborts a stale/torn freeze, so a crash after a partial revoke never leaves a revoked credential's connection live. A fifth round (panel + independent cold read on the B2 mediator) refined: `commitDigest` is the RFC-8785 canonical content digest of the committed value, `sha256:<hex>` (not a raw-bytes digest, so it is insensitive to a non-canonical storage stringify), and `commitValue`'s `b64u`/`ref` forms both resolve that same value; the policy publication is content-addressed by the same canonical digest (property-order-insensitive). The session expiry sweep now enumerates a marker-preserving stream read rather than the bucket's `keys()` (which filters DEL/PURGE), so a tombstoned session key is reported as corruption, not silently skipped. The terminal barrier's frontier record is pinned as the `frontier.<lifecycleUid>` kind (§13.7: create-only, never deleted, one key per retired lifecycle, recorded once under its own operation's `opId` before the gate/head terminals), and the exact-pool cleaner's `retired` disposition is a first-class `wrk` terminal fact carrying its operation and retiring-target binding. A sixth round (the D14 confinement review) pinned the two mediated-profile grant shapes: the admission mediator's enumeration consumer carries a deterministic (endpoint, connection)-bound name with name-literal CREATE/INFO/MSG.NEXT/DELETE rows (closing the name-wildcard cross-consumer reach; the own-name delete is what keeps the fixed name reusable across filters), both profiles' reply inboxes are connection-scoped (`_INBOX_<connId>.>`, never the account-wide default), and both payload-blind write residuals are named with equal explicitness: the mediator's own-endpoint acceptance-forge and the cleaner's own-pool `wrk` terminal-forge (work suppression or mis-settlement), each confined to its subject-expressible scope. A seventh round (the control-surface sealed-scanner seal) moved the dynamic-enumeration `CONSUMER.CREATE` off every standing/runtime credential (the takeover/retirement/handle-revocation barrier and the session sweep on `cotal_auth_<space>`, and the admission mediator plus the retirement obligation-drain on `cotal_records_<space>`) into dedicated SEALED scanners the trusted process opens for itself and NEVER hands out, because a consumer-create request BODY is not subject-ACL confinable (an extended name+filter grant still admits a `durable_name` + push `deliver_subject` exporter of every current/future row that survives connection close and revocation, nats-server#8274, reproduced live); each scanner is pinned to one literal consumer name under a forced pull/`LastPerSubject`/ephemeral/memory config, bind-verified before use and unconditionally deleted after, its CREATE filter confined to its subtree, space-bonded so a hand-assembled or foreign-space scanner never enumerates, and fence-free by construction (a `LastPerSubject` read carries no upper cutoff, so a same-subject overwrite during the scan is SEEN, not dropped). Its re-verify round hardened the seal from asserted to enforced: the scanner capability handle is immutable once branded (a swapped scan op throws rather than surviving the injection assert; that mutation vector was reachable only from inside the trusted process, the signing-seed residual class, never externally), every scan over a space's literal consumer name serializes process-wide (a second scanner instance can never interleave with a live scan and return a partial enumeration; cross-process duplication remains excluded by the one-authority-plane-per-space composition), every delivered subject is revalidated against the exact requested filter (an out-of-filter delivery from a foreign re-resolution of the literal name is refused loud; a foreign SAME-OR-NARROWER filter remains covered by the one-plane composition, not by this check), the two scanner profiles are explicit §13.9 matrix rows whose grant builders the mechanical matrix audit pins as the SOLE dynamic-enumeration `CONSUMER.CREATE` holders on the two authority streams (the provisioner's pre-created full-tail reader durables remain the one other records-stream consumer authority, and the audit pins that complete surface too), and the admission-mediator coordinate stays package-internal until a composition owns the one-records-scanner-per-space injection. An eighth round (the control-surface piece-2/4 wiring) landed: the record-reader provisioning seam is an ALLOWLIST over one canonical authority-def collection (a reader durable's kind must be a registered caller-readable record kind, so every authority-control kind and every unregistered kind refuse, and a dual-token kind whose atomic head is authority admits only a filter strictly deeper than the head, never one that can match or is shallower than the head key); that classification is runtime-frozen and the seam consults a private module-load snapshot, so a post-import mutation cannot remove the guard (the same integrity discipline is applied to every exported security-relevant collection: the baseline grant vocabularies, the credential-lifetime matrix, the session terminal states, the schema profile, and the broker floor are all frozen, and the minting-path consumers read private snapshots). The retirement barrier's cleaner authority is SPLIT into two per-operation credentials: a zero-write cleaner (its residual is terminal-free ACK suppression) and a settlement executor that alone holds the lease-record CAS and the lease-derived `wrk` terminal publish on the intent's exact pools plus the leader-served EPF and records fencing reads its own code path performs (NO EPW read: the settlement path settles or expires through the lease key before any EPW live-entry probe, so that read is unreachable and ungranted); the two are distinct CONNZ principals fenced independently before any frontier records, and the barrier runs settlement on the executor's own connection rather than its standing one. The retirement barrier is the `frontier.<lifecycleUid>` writer (the exact-arity `frontier.*` grant row), and the auth service's boot crash-resume finishes an owed retirement through the assembled deps (a per-endpoint short-lived drain client over the reviewed admission-mediator profile sharing the plane's sealed records scanner, and the per-op cleaner/executor split), fail-closed and loud like the takeover resume. Its re-verify round closed three composition gaps: the barrier now grants `STREAM.INFO` for exactly the CLOSED retirement-frontier stream set (the per-space lifecycle-data streams EPF/EPW/EPE/records, one source feeding both the intent validation and the grant, so a frontier read is never denied on a real broker nor a caller-selected arbitrary stream), the settlement executor drops the unreachable EPW live-entry read (the settlement path settles or expires through the lease key before any EPW probe, so that grant was dead), and the assembled drain completes every settleable obligation but fails CLOSED with an operator-legible frozen-not-lost message on accepted work that needs a confined commit-applier/route-reconciler authority (a scoped boundary whose full mechanics are a separate reviewed slice, never a broad records-write grant bolted onto the drain). A ninth round (the cross-process plane-ownership seal, §13.13) closed the last composition assumption the sealed scanners leaned on: at most one authority plane per space now holds them by a broker-visible claim, one exact never-deleted auth-KV `plane` row binding the two non-reconnecting scanner connections' broker identities, taken by create/revision-CAS with the candidates INERT until the win (no scan capability exists before it); a stale `held` row is reclaimed on LIVENESS ALONE (both claimed tuples conclusively absent under a COMPLETE connection sweep, adjudicated by the delivery daemon's closed read-only oracle over the delivery-admin rail; the auth process holds no `$SYS`), with no TTL, no heartbeat, and no sealed-scan-progress bit (a mid-scan crash reclaims; a paused-but-live plane keeps its connections and its ownership); the winner re-validates the claim before AND after every sealed scan (refuse or discard), an owned scanner disconnect fences the plane (invalidate exposure, close the sibling, never a transparent reconnect into a successor's consumer), clean close releases only after the scan clients are down, the three operator refusal faces carry distinct copy (live peer / inconclusive-fail-safe / mid-life fenced stop), and the launcher adds an exclusive-create pidfile belt. Its re-verify round hardened the reclaim and the fence: a `gone` verdict is valid only under the single-nats-server-process boundary, proven per observation from the responding server's own topology declaration in the `$SYS` reply envelope (any cluster self-report, multi-server observation, or missing declaration reads `unknown`; leafnode/gateway-extended accounts and backup-restore-onto-a-fresh-broker are named residuals; multi-server needs an incarnation/roster authority) — never inferred from which servers replied, which could neither be enforced by reply-counting (a partition shows one responder) nor flipped to require-the-claimed-server's-reply (a restarted server can never reply, the permanent-wedge horn); claim re-validation covers the two pinned scanner tuples (a tuple-only row rewrite is a lost claim); a scanner-death fence is FATAL to the whole authority plane (every authority operation refuses and the service exits loud, never a healthy-looking half-dead plane); the plane credentials' non-expiring boundary is normative (exactly the two non-reconnecting plane connections; every other authority credential keeps short-expiry + renewal); the claim row, connection tuple, oracle-query, and oracle-result schemas are closed exactly (unknown fields refuse, at every level); only successful well-formed CONNZ pages count toward a reclaim sweep (an API error, malformed envelope, non-string cluster declaration, id mismatch, or incomplete page poisons the observation); every sweep's reply inbox carries a per-call nonce (concurrent sweeps cannot cross-complete); the fenced plane's refusals are audience-split (a retryable unavailability to connecting agents, the state-3 restart copy to the operator's log and exit line); and the pidfile belt publishes atomically pre-populated (temp inode + no-overwrite `link(2)`; an empty slot is unpublishable and a pre-protocol one reclaims exactly once). A tenth round (the confined drain repairers) closed the retirement drain's accepted-work boundary functionally: the fail-closed applyCommit/reconcile interim is replaced by two per-op, per-repair principals — the COMMIT APPLIER (`local.epapl_<opId-hash>`, one exact records-KV publish row, minted only for a key inside the CLOSED self-commit class derived from the canonical frozen kind registry + the commit-path writer metadata, so a forged accepted-self row can never name an authority coordinate into a grant) and the POOL-ROUTE RECONCILER (`local.eprec_<opId-hash>`, one exact EPW item create-publish row, executing only a MEDIATOR-DERIVED closed repair command: the mediator reads and row-binds the durable acceptance decision itself and derives the exact subject + the §13.6 canonical acceptance item bytes, now a normative derivation so first enqueues and crash repairs are byte-identical) — each minted per repair, executed, closed, with the CAS-header and payload-blind residuals named per profile; an accepted self-commit now re-applies (or classifies landed/superseded) and an accepted pool route re-materializes, so a retirement with covered accepted work COMPLETES on resume, and an accepted EFFECTS route with no completion marker terminalizes through the RETIREMENT-CANCEL terminal (§13.8 option (i)): the effects completion fact becomes a closed two-member union (ran, or `cancelled: { opId, target }` — the same identity spine, never a forged success, written only for the retiring target's own acceptances), an action's goal union already carries the first-class `cancelled` state (the retirement attribution rides its digest-bound payload), the cancel publishes CREATE-ONLY on the SAME completion subject so first-terminal-wins is structural in both directions, and a third per-op principal (`local.epcan_<opId-hash>`, one exact completion-subject create row) executes the mediator-derived repair — so a retirement with in-flight accepted effects work now COMPLETES on resume with a reader-legible cancelled terminal instead of freezing. An eleventh round (the despawn→retirement trigger, the P1 closure) reserved the `auth-admin` control service (SPEC 13.2): the AUTH plane serves the GENERIC \"retire a lifecycle\" operation on the `ctl` grammar's subject-attributed rail (the delivery-admin discipline: broker-ACL caller attribution, bound replies, an unbound reply target dropped before processing), authorized at SERVE TIME by the fresh space-manager-lease holder check (one leader-served read of the manager bucket's single lease key; holder == the subject-attributed requester principal; DEL/PURGE markers and TTL-expunged rows read absent and refuse fail-closed — never mint-time trust, closing the post-lease-loss window), answering the four-outcome idempotence table in operator vocabulary with every refusal a stated COMPLETE no-op; the space manager triggers it per despawn through an ephemeral request-and-reply-only `retirement-requester` credential with a STABLE per-lifecycle opId (retries, same-name-spawn nudges, and boot resumes converge on one operation), holds the despawned name RESERVED-pending-retirement until the terminal (a same-name spawn refuses legibly and re-drives the request; the in-memory reservation's restart residual is named — the durable truth is the lifecycle head itself), and the retirement executes through the plane's own reviewed deps over its ONE sealed records scanner. The barrier's terminal cleaner/executor pool set is the operation's EFFECTIVE INVENTORY: the target's accepted `oblig.<uid>.>` pool routes discovered from the just-drained obligation set UNIONED with the intent's OPTIONAL trusted hint (the despawn rail passes none), superseding the round-8 \"intent's exact pools\" enumeration so an empty-hint despawn still settles every accepted pool item before the frontier; the durable-intent hint is a TRUSTED ADDITIVE AUTHORITY input (a hinted pool with no accepted obligation still receives a bounded per-op credential), and the compromised cleaner/executor residuals scope to that whole effective inventory, including any hint-only pool. |\n| 2026-07-10 | **v0.4 binding revision: endpoint control surface (§13).** One standardized typed surface for every endpoint (manager, delivery, wrapped third-party servers): class/instance/scatter rails with per-command broker enforcement and an authorization-mode gradient, lifecycle identity (recyclable alias + never-reused lifecycle UID + fenced process epoch, §13.1, §2/§6/§8 extensions), versioned envelope with structured errors and signed slots, three delivery contracts (ephemeral, split-key records, untrusted submissions → mediated canonical facts), verbs call/cast/watch/claim/scatter (claim owner-mediated: workers hold no pool grant), composites (action, checkpoint, guard, capability handle with redemption-pinned `handle`-mode targets, session, virtual endpoints), content-addressed cluster contracts + governed traits + describe, the ownership matrix (incl. exact reader/consumer/ack rows and pinned consumer-name grammars), takeover/retirement revoke-and-evict barriers over the full ledgered credential family (credential ledger, §13.1), mediated timer arming (request/armed/fire split with a scheduler-origin fire check), poison quarantine facts, an epoch-pinned record-write ingress plane (`epr`), a single-message digest-subject contract store (`epc`), pre-created pull-only reader consumers (no dynamic reader creates: a create's delivery target is body-set and unconfined), an alias CAS head for lifecycle activation, and receipts and trust anchors. **Hard cut:** deletes the v0 `ctl` rail, `ControlRequest`/`ControlReply`, the `self`/`manager`/`admin`/`delivery-admin` tiers, and the reserved `control.<instance>` subject. `protocolVersion` targets `0.4` at migration completion; `1.0` stays reserved as a later stability declaration. |\n| 2026-07-07 | Documentation revision, no wire change: layered authority statement (schema authoritative for shapes, prose for semantics), document-snapshot policy and this change log (§11), reciprocal links to the informative docs. |\n| 2026-07-03 | **v0.3 binding revision: owner+actor identity.** The wire identity becomes the two-token principal `(owner, actor)`: subjects carry the sender as `<owner>.<actor>`, and grants, durables, presence, and `from.id` re-key onto the pair (§2, §3, §6, §8, §9). The connection nkey remains only the transport credential (the per-connection reply inbox). Adds the per-user-auth authorization grammar and the owner-token format (§2, §9). Supersedes the single-id grammar. |\n| 2026-06-21 | **v0.3 binding revision: channel live delivery.** Channel live delivery moves from the mediated per-instance live-tail durable to native `sub.allow`-bounded core subscriptions, with an explicit per-channel `live`/`durable` delivery class and the per-member durable backstop (§4, §7, §8); membership moves to a privileged-written registry (§7). Supersedes the v0.2 single-durable live-tail. |\n| earlier | v0.2 and before predate change control: the v0.2 contract (single mediated live-tail durable binding) is superseded by v0.3 and kept only in history. |\n"
371
+ "body": "# Cotal Wire Specification\n\n> **Status:** Draft, v0.5 (pre-1.0). This document is the normative wire contract. Libraries\n> (including the reference TypeScript implementation) are thin clients over it; where a\n> client disagrees with this document, this document wins.\n>\n> **Layered authority.** Message *shapes* are defined by the machine-readable schema,\n> [`spec/cotal.schema.json`](spec/cotal.schema.json) (§5); this document's prose defines\n> *semantics*: routing, delivery guarantees, presence, authorization, and conformance. For\n> the reference implementation's operator surfaces (the CLI, the `cotal_*` tools), see the\n> [Reference docs](docs/README.md#reference); those describe the TypeScript implementation,\n> not this contract.\n>\n> **Editors:** Cotal maintainers. **Last updated:** 2026-10-19. Changes are tracked in\n> [Appendix D](#appendix-d-change-log); versioning rules are §11.\n>\n> **v0.5 binding revision: workflow runs.** A deployment MAY host **durable workflow runs**: programs\n> in the Cotal workflow language ([`spec/cotal-lang.md`](spec/cotal-lang.md), normative and\n> incorporated by reference) whose every effect is recorded in a per-run **step journal** so a run\n> resumes on any host by re-execution against its journal (§14). The revision adds one per-space\n> stream (`WFJ_<space>`, one subject per run, an append-only journal fenced by the run's own subject\n> sequence), four core record kinds (`run`, `answer`, `notice`, `migration`), a per-run driver grant\n> family, and the language reference; it changes no existing kind, subject, grant row or shipped\n> datum, so it is **additive** under §11: a v0.4 participant that ignores §14 conforms to v0.4\n> unchanged, and the advertised `protocolVersion` targets `0.5` once the v0.4 migration completes and\n> the §14 plane is served. Language semantics carry their own version (`languageVersion`, pinned on\n> every run record) and move independently of the wire version.\n>\n> **v0.3 binding revision: owner+actor identity.** An instance's wire identity moves from a single\n> id (the connection nkey, used as the sender token everywhere) to a two-token **principal**\n> `(owner, actor)` (§2): the human/account owner and the agent actor become distinct routing tokens,\n> so every subject carries the sender as `<owner>.<actor>` (§3), and grants, durables, presence, and\n> `from.id` re-key onto the principal (§6, §8, §9). The connection nkey survives only as the transport\n> credential, keying the per-connection reply inbox `_INBOX_<connId>` (§2, §10); the wire identity and\n> the connection credential are now distinct. Cross-owner **and** same-owner cross-actor forge/read\n> isolation is a normative confinement property (§9). `parseSubject` splits the tokens; a well-formed\n> split is necessary but not sufficient: a reader additionally rejects a non-principal owner token\n> (e.g. an old-shape alias carrying a raw nkey) at the surfacing boundary (§3, §9). The owner-token\n> *format* (`u_` + 26 base32-lower) is normative; its *derivation* from an owner's identity (login →\n> auth callout, or another identity adapter) is a pluggable edge, not fixed by this contract. This\n> supersedes the v0.2/early-v0.3 single-id grammar. As with the live-delivery revision, the advertised\n> wire `protocolVersion` (§6, §11) is the migration's normative target, not a claim that every surface\n> has cut over.\n>\n> **v0.4 binding revision: endpoint control surface.** Structured command traffic moves from the v0\n> `ctl` control rail to one standardized, typed, discoverable endpoint surface (§13): class +\n> instance + scatter rails with per-command broker enforcement, a versioned envelope, three\n> delivery contracts (ephemeral / record / journal), normative composites (action, checkpoint,\n> guard, capability handle, session), content-addressed contracts with governed traits, and\n> lifecycle identity (§13.1) extending §2/§6/§8. This is an intentional **hard cut** (§11,\n> §13.11): the v0 control grammar, envelope, and authority tiers are deleted, not dual-served.\n> The advertised `protocolVersion` targets `0.4` at the completion of this revision's migration;\n> `1.0` remains reserved as a later stability declaration, not part of this revision.\n>\n> **v0.3 binding revision: channel live delivery.** Channel *live* delivery moves from a single\n> mediated JetStream live-tail durable (`chat_<id>`) to native core-NATS subscriptions bounded by\n> `sub.allow`, with durability provided by an explicit per-channel `live`/`durable` delivery class\n> (§4, §7, §8). Join/leave becomes a direct subscribe/unsubscribe with no privileged mediation,\n> and channel membership moves off consumer topology to a privileged-written registry (§7). This\n> supersedes the v0.2 single-durable live-tail. The reference implementation migrates additively\n> (the legacy durable and the new core-sub path coexist behind `id` dedup until the legacy path is\n> removed), but that migration path is not itself normative. The advertised wire `protocolVersion`\n> (§6, §11) stays `0.2` until the core-sub behaviour ships; this revision is the normative target the\n> migration converges to, and the additive `deliveryClass` field is backward-compatible meanwhile.\n\nThe key words MUST, MUST NOT, REQUIRED, SHALL, SHOULD, SHOULD NOT, MAY, and OPTIONAL in\nthis document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119)\nand [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174).\n\nSections 3 to 7 define the transport-agnostic Cotal contract. Sections 8 to 10 define\nthe NATS + JetStream binding (v0). A conformant deployment implements one binding; the\nNATS binding is the only one defined today. External specifications this document relies on\nare listed in Appendix C.\n\n---\n\n## 1. Scope and terminology\n\nCotal is a wire interface for software, especially AI agents, to coordinate in real time\nas lateral peers in a shared pub/sub space, not as nodes in an orchestrator tree.\n\n- **Space**: an isolated coordination context. One space is one tenant boundary; messages\n in one space are not visible in another. NATS binding: one space = one account.\n- **Instance**: a connected participant, identified by a stable **instance id**. Also called\n an endpoint.\n- **Agent node**: an instance whose `kind` is `agent`, versus a plain `endpoint` such as an\n observer, logger, or dashboard.\n- **Peer**: any other instance in the same space.\n- **Channel**: a named multicast topic within a space, dotted and hierarchical.\n- **Service**: an anycast role reached by name (`svc`, §4).\n- **Endpoint (control surface)**: a daemon that registers a service identity, publishes\n typed contracts, and serves commands on the endpoint rails (§13).\n- **Broker**: the message router for a space. v0 assumes a single trusted broker.\n- **Delivery message**: a multicast, unicast, or anycast `CotalMessage`.\n- **Endpoint request**: a typed request/reply command addressed to an endpoint class or\n instance on the `ep` rails (§13). The v0 `ctl` control rail is deleted (§13.11).\n\n---\n\n## 2. Identity\n\nAn instance's wire identity is a **principal** = a pair of routing tokens `(owner, actor)`:\n\n- **`owner`**: the account that owns the instance: the human (or organization) an agent acts on\n behalf of. In an authenticated deployment it is a derived **owner token** (`u_` followed by 26\n base32-lower characters), a namespaced, nkey-disjoint token deterministically derived from the\n owner's stable identity (e.g. an IdP subject) by the deployment's identity adapter; the wire\n contract fixes the token *format*, not the derivation mechanism, which is a pluggable edge. In open\n dev mode the owner is the literal `local`.\n- **`actor`**: the instance's own handle within that owner (its agent id). Distinct actors under one\n owner are distinct principals and are confined from one another (§9), so one human's two agents\n cannot forge or read as each other.\n\nEach token is sanitized to `[A-Za-z0-9_]` (see §3) with `-` additionally reserved as the form\nseparator, so a principal has two unambiguous serializations: the **dot-form** `<owner>.<actor>` and\nthe **dash-form** `<owner>-<actor>`. The same principal MUST appear identically as: the\n`AgentCard.id` (§6, dot-form), the sender tokens in subjects (§3), the message `from.id` (§5,\ndot-form), the presence key (§6, dot-form), and the per-instance durable names (§8, dash-form).\n\n**The principal is distinct from the connection credential.** In the authenticated NATS binding the\nconnecting user is still an Ed25519 nkey (base32, 56 chars, prefix `U`, e.g. `UAQG...`), stable for\nthe lifetime of the connection, but it is **not** the wire identity. The nkey authenticates the\ntransport and scopes only the per-connection reply inbox `_INBOX_<connId>.>` (§10); the principal\nthat keys every subject, grant, and durable is carried by the minted grant, not by the nkey. This\nseparation is what lets a login (§9) mint a fresh connection whose nkey the client never sees while\nthe principal stays stable across reconnects.\n\n- A client that authenticates with a static credential MUST adopt the principal that credential's\n grant names; if a principal is also set explicitly (via the card) it MUST match, else the client\n MUST fail before publish.\n- A client that authenticates through the auth callout (user mode, §9) cannot know its connection\n nkey before connecting, so it chooses its own reply-inbox nonce (`connId`) and derives its\n principal from its bearer; the broker's minted grant, not the client's self-read, is the\n boundary.\n- Open dev mode MAY use `local` as the owner and an opaque stable actor, but open mode is outside\n the security claims in §9 and is not a conformant authenticated deployment.\n\nFuture binding, not v0: portable `did:key` identity plus signed envelopes so authenticity\nsurvives an untrusted relay. See the threat model in [docs/security.md](docs/security.md).\n\n---\n\n## 3. Subject layout\n\nEvery wire subject is rooted at `cotal.<space>`. `<space>` and every routing token except a role\nare sanitized: any character outside `[A-Za-z0-9_-]` maps to `_`. Sanitization is lossy; tokens\nMUST NOT be decoded back into display names.\n\nThe **sender** of every delivery is a principal (§2), carried as **two adjacent tokens**\n`<owner>.<actor>`. Routed kinds (`inst`) also carry the recipient principal as two tokens.\n\n| Purpose | Subject | Sender tokens | Delivery |\n| --- | --- | --- | --- |\n| Multicast | `cotal.<space>.chat.<owner>.<actor>.<channel...>` | 3–4 | §4 multicast |\n| Unicast | `cotal.<space>.inst.<recipOwner>.<recipActor>.<sndOwner>.<sndActor>` | 5–6 | §4 unicast |\n| Anycast | `cotal.<space>.svc.<role>.<owner>.<actor>` | 4–5 | §4 anycast |\n| Endpoint rails | `cotal.<space>.ep.<one\\|all\\|inst\\|reply>.…`, `cotal.<space>.ep<c\\|e\\|f\\|j\\|r\\|t\\|w\\|s>.…` | see §13.2 | §13 control surface |\n| Plane liveness | `cotal.<space>.live.<plane>.<owner>.<actor>` | 4-5 | §6.1 request/reply |\n| Trace | `cotal.<space>.trace.<instance>` | n/a | reserved |\n\nToken indexing is zero-based on `subject.split(\".\")`: `cotal` = 0, `<space>` = 1,\n`<kind>` = 2. The sender principal is recovered as the dot-form `<owner>.<actor>` (= the message\n`from.id`, §5), so a guard comparing `from.id` to the subject sender uses one value.\n\n**Two-token sender, and its asymmetry.** A reader MUST locate the sender by kind:\n\n- `chat`: sender owner at token 3, actor at token 4; the channel is everything after, tokens 5+,\n so it may be hierarchical (`team.backend`).\n- `svc`: route target at token 3; sender owner at token 4, actor at token 5.\n- `ep`: per-mode arities with the caller as the trailing identity tokens; §13.2 defines them.\n- `inst`: recipient owner+actor at tokens 3–4; sender owner+actor at tokens 5–6.\n\nThe two-token sender is what lets a native publish grant **forge-lock** the sender suffix (e.g.\n`inst.*.*.<myOwner>.<myActor>` permits a DM to anyone but only *as me*), so the broker enforces\nsender authenticity and a receiver need not re-verify a payload claim. A subject that does not match\none of these shapes (wrong prefix or wrong per-kind arity) MUST be treated as having no sender and\nMUST NOT be read as a delivery. `parseSubject` **splits only**: it recovers the tokens but does not\nvalidate that `<owner>` is a well-formed owner token; trust comes from the broker's forge-locked\ngrant, and a reader that surfaces content additionally rejects a non-principal owner token at the\nsurfacing boundary (§9). Reference implementation: `parseSubject` in\n`packages/core/src/subjects.ts`.\n\n**Channel tokens.** A channel is dotted; each segment is sanitized. The literal wildcards\n`*` and `>` are preserved only as whole segments for subscription and allow-list patterns;\n`>` is valid only as the final segment. A publish target MUST be concrete, with no `*` or\n`>`; a subscription MAY be wildcard. A channel is at most 4096 characters in total\n(`MAX_CHANNEL_LENGTH`): every grant line a channel mints rides the minted credential's\nCONNECT line (§13.9), so an unbounded channel is an unbounded connect.\n\n**Role tokens.** A role is an address, so it is never sanitized: it MUST be one\n`[A-Za-z0-9_-]` token. A client MUST refuse any other spelling, for the role it holds and for an\nanycast target, because a rewrite would route distinct spellings to one queue while the message\nkept the spelling sent. An anycast target MUST be concrete: `*` is valid only in subscribe and\nallow patterns such as `svc.*.<owner>.<actor>`.\n\n**Reserved prefixes.** Application messages MUST NOT use subjects beginning with `$JS.`,\n`$KV.`, `$SYS.`, `$O.`, or `_INBOX.`. (`$O.` is the Object Store data/meta subject prefix\nper ADR-20, `$O.<bucket>.C.>` / `$O.<bucket>.M.>`; `OBJ_<bucket>` is a stream NAME, not a\nsubject prefix.)\n\n---\n\n## 4. Delivery modes\n\n| Mode | Routing field | Semantics |\n| --- | --- | --- |\n| multicast | `channel` | delivered to every subscriber of the channel |\n| unicast | `to` | delivered to the named instance's inbox |\n| anycast | `toService` | delivered to one consumer of the named role |\n\nExactly one of `channel`, `to`, or `toService` MUST be set on a `CotalMessage` (§5).\n\n**Authenticated delivery kind.** A receiver MUST derive \"how was this addressed to me\"\nfrom the delivering subject kind (`chat` -> `channel`, `inst` -> `dm`, `svc` ->\n`anycast`), not from payload routing fields, which are advisory. (\"Delivery kind\", the\naddressing axis, is distinct from a channel's `live`/`durable` **delivery class**, §7.) A peer can put your id in\npayload `to`, but cannot publish on your private unicast subject. Reference:\n`MessageMeta.kind`.\n\n**Delivery guarantee: `live` and `durable` classes.** Channel delivery has two classes, fixed\nper channel and wire-observable (§7); the guarantee is defined here, its NATS realization is the\nbinding in §8. A receiver MUST derive its effective class from channel config (§7), not from\nper-message metadata (`MessageMeta` need not carry it); it MUST NOT assume one class.\n\n- **`live`** is native broker-subscription delivery and is **at-most-once**: a message reaches\n only the instances subscribed to the channel at publish time. An instance that is disconnected,\n busy, or not yet joined does not receive that message live and has no claim to the live copy\n later. There is no per-subscriber redelivery of the live copy.\n- **`durable`** is `live` plus a per-subscriber durable backstop and is **at-least-once for\n current members within retention**: the message is also retained for each member and delivered on\n that member's next connection or turn, remaining pending until acked. A crash or `ack_wait` expiry\n redelivers the durable copy. At-least-once is bounded by the channel's retention / `replayWindow`\n (§7): a message evicted by retention before ack may be lost; the guarantee is not unbounded.\n\nUnicast (`to`) and anycast (`toService`) are at-least-once via their own DM/TASK consumers (§8);\nthey have no channel membership and are not subject to the per-channel delivery-class mechanism. An\n`@mention` (§5) on a `live` channel additionally writes a durable copy to each mentioned target\n**authorized to read that channel** (its `allowSubscribe` covers the channel), so an authorized but\noffline target still receives it; an `@mention` MUST NOT deliver channel content to a target outside\nits read ACL. Durable mention routing resolves each lowercased name to a unique current instance id\nfrom presence at publish time; an ambiguous (multiple live matches) or unresolvable name yields no\ndurable copy, and authorization is checked against the resolved id's current `allowSubscribe`. A\ntarget authorized for a channel is **mention-reachable** there whether or not it is currently joined; this is intentional (an `@mention` can pull an authorized peer in) and is distinct\nfrom membership; a client SHOULD distinguish \"joined\" (actively subscribed) from \"readable /\nmention-reachable\" (in `allowSubscribe`) so an unjoined channel is not treated as \"cannot reach me\nhere.\"\n\nA message delivered both live and durable is **one logical delivery**: receivers MUST deduplicate\nby `id` across classes (§8); the durable copy owns ack/commit; and a previously seen `id` MUST NOT\nbe treated as authorization for a later durable copy (for example one that arrives after a leave).\nReceiver deduplication MUST NOT use the empty string as a key. Two received messages MUST NOT be\ntreated as one logical delivery solely because both carry `id: \"\"`; each otherwise-deliverable\nmessage remains independently deliverable. Because live, backfill, and durable copies with\n`id: \"\"` cannot be correlated by wire identity, an at-least-once path may surface the same logical\nmessage more than once. The existing §5 obligation for publishers to supply a unique string id is\nunchanged. An absent or non-string id remains a malformed envelope.\nReceivers MUST tolerate the `live` gap and rely on the `durable` backstop for catch-up on\n`durable` channels. Malformed JSON, spoofed sender payloads, and unparseable delivery subjects are\npermanent anomalies and MUST be terminated, not retried.\n\n**Ordering.** Cotal does not define global ordering across modes, channels, or consumers.\nImplementations MUST NOT depend on cross-subject ordering. Per-consumer delivery is ordered\nby the backing stream except where redelivery or explicit backfill interleaves older\nmessages.\n\n---\n\n## 5. Envelopes\n\nDelivery messages are UTF-8 JSON objects with this shape (`CotalMessage`):\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `id` | string | MUST | unique message id; NATS binding also uses it as `Nats-Msg-Id` |\n| `ts` | number | MUST | epoch ms |\n| `space` | string | MUST | space name |\n| `from` | `EndpointRef` | MUST | `{ id, name, role? }` |\n| `channel` | string | one-of | multicast target |\n| `to` | string | one-of | unicast target instance id |\n| `toService` | string | one-of | anycast target role |\n| `mentions` | string[] | MAY | lowercased peer names; wakes the mentioned peer. On a `live` channel it also routes a durable copy to each mentioned target authorized to read that channel (§4); it never delivers content outside the target's read ACL and is not a routing substitute for `channel`/`to` |\n| `parts` | `Part[]` | MUST | content |\n| `replyTo` | string | MAY | id of the message replied to |\n| `contextId` | string | MAY | thread/conversation correlation id |\n\n`Part` is one of the three core shapes, or an extension object whose `kind` is namespaced\nas described in §11:\n\n- `{ \"kind\": \"text\", \"text\": string }`\n- `{ \"kind\": \"data\", \"data\": <any JSON value> }`\n- `{ \"kind\": \"artifact\", \"name\": string, \"mediaType\": string, \"digest\": string, \"size\": number }`\n- `{ \"kind\": \"<reverse-DNS extension kind>\", ... }`\n\nA `data` part's `data` MUST be a JSON value at every depth; a publisher MUST refuse the part\nrather than serialize a value JSON cannot represent, naming the offending member's path (a\ntop-level `undefined` serializes to a keyless `{\"kind\":\"data\"}` object, and `NaN`, a `Date`,\nor a class instance would be silently rewritten rather than refused).\n\nAn `artifact` part REFERENCES bytes held outside the message. `digest` MUST be\n`sha256:<lowercase hex>` over the raw bytes and is the artifact's identity; the part carries no\nlocation, so resolution is the receiver's. `name`, `mediaType`, and `size` are the publisher's\nclaims: a receiver MUST NOT allocate from `size`, and MUST verify fetched bytes against `digest`\nbefore use.\n\n`EndpointRef` is `{ \"id\": string, \"name\": string, \"role\"?: string }`.\n\nOn receive, a client MUST verify `from.id` equals the subject sender (§3). On mismatch, a\nmissing `from`, or an unparseable delivery subject, the message MUST be rejected and never\nredelivered.\n\nEndpoint requests and replies (the control surface) use the versioned typed envelope of\n§13.3 (`EndpointRequest`/`EndpointReply`); they are not Cotal delivery messages. The v0\n`ControlRequest`/`ControlReply` shapes are deleted (§13.11).\n\nReceivers MUST ignore unknown object fields. Unknown conformant extension `Part.kind` values\nMUST be ignored unless the receiver explicitly supports that extension. Bare unrecognized\ncore-kind values are not conformant. Messages MUST fit the broker's configured maximum payload;\nbytes that do not fit move out of the message and are referenced by an `artifact` part (above).\nThe transport that serves those bytes is not defined by this document.\n\n**Schema.** The JSON Schema (draft-07) at\n[`spec/cotal.schema.json`](spec/cotal.schema.json) is **authoritative for message shapes**:\na conformant delivery message MUST validate against it, and where this document's field\ntables and the schema diverge on a shape, the schema wins. Delivery *semantics* (routing,\nguarantees, rejection) are defined by this document's prose. The schema is generated from\nthe reference source, [`packages/core/src/types.ts`](packages/core/src/types.ts)\n(`pnpm gen:schema`), and committed; `pnpm check:docsbundle` fails when the committed file\ndiffers from the generator's output. The published copy lives at\n`https://docs.cotal.ai/cotal.schema.json`.\n\n**Rejection reasons.** The three permanent anomalies in §4 are terminated, never redelivered.\nThese reason tokens are advisory (for logs and error surfaces); the action is uniform:\n\n| Reason | Trigger |\n| --- | --- |\n| `malformed-subject` | the delivery subject does not parse (§3) |\n| `sender-mismatch` | `from` is missing, or `from.id` does not equal the subject sender (§5) |\n| `malformed-json` | the payload is not valid UTF-8 JSON |\n\n---\n\n## 6. Presence and discovery\n\nPresence is a per-space directory keyed by instance id. NATS binding: JetStream KV bucket\n`cotal_presence_<space>` (§8).\n\n`Presence`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `card` | `AgentCard` | MUST | identity record |\n| `status` | `PresenceStatus` | MUST | `idle`, `waiting`, `working`, or `offline` |\n| `condition` | `PresenceCondition` | MAY | harness-reported structured condition. Missing means nothing was reported. A connector relays the harness signal and MUST NOT infer a condition itself |\n| `environment` | string | MAY | opaque reference whose meaning belongs to the provider that issued it. Core MUST NOT parse it |\n| `activity` | string | MAY | freeform current activity |\n| `statusSince` | number | MAY | epoch ms when the instance entered its current `status` and `activity`. A change to either moves it; a heartbeat or a repeated report does not, so `ts` dates liveness and `statusSince` dates the report. An offline record MUST NOT carry it: an observer that derives `offline` from a stale `ts` does not know when the peer left |\n| `activitySince` | number | MAY | epoch ms when the current `activity` was set. A status change or a heartbeat does not move it, so an activity left behind while the status flips every turn still reads as old |\n| `activeAt` | number | MAY | epoch ms of the last work progress the harness reported, such as a token or a tool call. Missing means the connector reports none. `ts` is the heartbeat, so a live instance whose turn stopped advancing keeps a fresh `ts` and an old `activeAt`. A connector relays the harness's events and carries the value on its next heartbeat |\n| `attention` | `AttentionMode` | MAY | global attention mode: `open` \\| `dnd` \\| `focus`. Advisory observability; `open`/absent ⇒ receives everything. Reset: `open` published on `SessionStart`, removed on the offline sweep |\n| `lifecycleUid` | string | MUST in auth mode from v0.4 | the current managed-lifecycle UID (§13.1); distinguishes a live instance from a same-name successor. Advisory for display; authority checks use the trusted lifecycle mapping, not presence |\n| `runtime` | `PresenceRuntime` | MAY | the OS process holding this record's mesh connection, as that process observed itself: `{ id, startedAt, source }`. `id` is an opaque CSPRNG token minted once per (OS process, `lifecycleUid`) scope and MUST NOT be reused or span two lifecycle UIDs. A new process or lifecycle scope MUST get a new id. `startedAt` is the epoch ms that OS process started, read in-process (`performance.timeOrigin`), shared by all endpoints in the process. A lifecycle registered later carries the process's age, not its lifecycle age. It MUST NOT date a launch request, registration, heartbeat, activity, separate parent or model harness process. `source` is the closed set `endpoint-process`; an observer treats any other value as unsupported. Status, activity, heartbeats and in-process reconnects within the scope leave it unchanged. An offline record keeps it, so `now - startedAt` dates a running process only while the record is live. It carries no pid, host, path, command line or environment. Missing means not reported, never zero |\n| `channelModes` | `Record<string, ChannelMode>` | MAY | per-channel attention overrides (`ChannelMode` = `quiet` \\| `muted`), keyed by concrete channel name. Advisory, **not** access control (the broker still authorises and delivers); a receive-side preference, reset on restart |\n| `ts` | number | MUST | epoch ms of last heartbeat |\n\n`AgentCard`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `id` | string | MUST | instance id (§2) |\n| `name` | string | MUST | display name; at most 128 characters (`MAX_NAME_LENGTH`, refused at the shared validator; an unbounded name rides the CONNECT line until the broker drops it silently, §13.9) |\n| `kind` | `agent` or `endpoint` | MUST | participation class |\n| `role` | string | MAY | service role |\n| `description` | string | MAY | one-line summary |\n| `tags` | string[] | MAY | capability tags |\n| `skills` | `AgentSkill[]` | MAY | `{ id, name, description? }` |\n| `meta` | object | MAY | free-form display metadata. Reserved flat string keys are `connector` (host harness name), `model` (pinned model), `provider` (effective provider serving the model, connector-reported), `host` (self-reported machine), `cwd`, `repo`, `branch`, `head`, `sessionKind`, `sessionId`, and `terminal` (`stream` or `none`, whether a terminal attaches to the seats this manager starts). All are advisory only |\n| `protocolVersion` | string | MUST from v0.4 | wire version spoken (§11); `\"0.4\"` for this revision. Advertisement is the marker at the v0.4 reachability boundary (§13.11): a participant that omits it is pre-0.4 (omission means the pre-0.4 line, where the field was optional) and MUST NOT be addressed on the `ep` rails. A change signal, not negotiation |\n\nAn instance MUST refresh its own presence entry on the heartbeat interval, default 2000 ms.\nThe liveness window defaults to 6000 ms. A peer whose `ts` is older than the liveness window\nis considered `offline`.\n\nLive clients MUST NOT heartbeat as `offline`. A graceful disconnect MAY publish one final\n`offline` presence record. Observers MUST also derive `offline` from stale timestamps and\nfrom KV delete/purge events. Offline peers MAY remain in local rosters for observability.\nAn instance MUST write only its own presence key, and the key MUST equal `card.id`.\nReaders MUST drop a record whose `card.id` differs from its KV key, whose `card.name` or\n`status` does not have the type given above, whose `ts` is not a finite number, whose\n`card.role`, `activity` or `attention` is present and not a string, or whose `condition` is present\nand is not an object with a string `code`, and SHOULD report the rejection on their recoverable\ndiagnostic path. A `condition` of `null`, a bare string or an object with no `code` is dropped.\nA reader that kept a record whose `ts` is missing or text such as `\"nope\"` could not age it past the liveness window, so it would\nshow its peer live after the key expired. Readers print the string fields as text, and an object\nsuch as `{\"toString\":null,\"valueOf\":null}` throws when converted, so one kept row would fail every\nreader's roster.\n\nA watch delivers every member's heartbeat to every watcher, so a space of K watching members moves\nK² deliveries per heartbeat interval. A participant that needs the roster only when it acts (an\nagent resolving a DM target, checking an `@mention`, listing who is present) SHOULD read it on\ndemand instead: batched Direct Gets over `$KV.cotal_presence_<space>.>` (`next_by_subj`, paged), which\nbind no consumer. A read applies the reader rules above, and a record whose `ts` is older than the\nliveness window reads `offline`. Only a read that completed supports an absence verdict; a failed\nread MUST NOT be reported as \"no such peer\". Observers that act on liveness transitions\n(supervision, delivery `@mention` resolution, dashboards) watch.\n\n`PresenceCondition`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `code` | `PresenceConditionCode` | MUST | `rate_limit` \\| `overloaded` \\| `auth` \\| `billing` \\| `budget` \\| `context` \\| `model` \\| `request` \\| `server` \\| `retrying` \\| `approval` \\| `input` \\| `failed` |\n| `source` | string | MAY | harness-native value, relayed verbatim |\n| `message` | string | MAY | free text from the harness |\n| `since` | number | MAY | epoch ms when the condition began |\n\n### 6.1 Plane liveness\n\nA credentialed peer MAY ask whether the manager plane or the delivery plane has a bound\nresponder in its space. The question is presence only. It does not read either lease bucket,\nand the peer does not need to own the plane it asks about.\n\n**Planes.** The set of planes is closed: `manager` and `delivery`. A client MUST refuse any\nother plane before it publishes anything.\n\n**Subjects.**\n\n| Purpose | Subject |\n| --- | --- |\n| Request | `cotal.<space>.live.<plane>.<owner>.<actor>` |\n| Reply | `cotal.<space>.live.<plane>.<owner>.<actor>.reply.<nonce>` |\n| Responder serve filter | `cotal.<space>.live.<plane>.*.*`, queue group `live.<plane>` |\n| Responder reply grant | `cotal.<space>.live.<plane>.*.*.reply.>` |\n\n`<owner>.<actor>` is the asking principal (§2). The plane rides the subject so a credential can\nbe scoped to one plane by the broker. A `live` subject is not a delivery: `parseSubject`\nrecovers no sender from it, and a reader MUST NOT treat it as one.\n\n**Request.** The body is empty. The caller names a reply subject under its own request subject,\n`<request>.reply.<nonce>`, with a fresh nonce per probe. A responder MUST drop, without\nanswering, any request whose reply target is absent or is not under `<request subject>.reply.`.\nIt SHOULD report that drop on its recoverable diagnostic path. It MUST NOT report it on a\nchannel that can end the process, and it keeps serving.\n\n**Reply.** `LivenessAnswer`, JSON:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `plane` | `manager` \\| `delivery` | MUST | the plane asked about; a caller MUST reject a reply whose `plane` differs from the plane it asked |\n| `responder` | `ResponderState` | MUST | `bound` \\| `unbound` \\| `stale` \\| `unknown` |\n| `instance` | string | MAY | an opaque token naming the responder that answered. Non-empty when present |\n\nA responder MUST put nothing else in the reply. In particular it carries no lease holder, pid,\nworkspace path, instance id, runtime or roster.\n\n`instance` is minted fresh each time a responder binds and is derived from nothing. It is not\nthe endpoint's principal, the lease row's `instanceId`, a pid, a host or a path. It lets a\ncaller that probes more than once tell two responders apart from one responder whose state\nchanged. The queue group hands one probe to one member, so a single answer samples one\nresponder and cannot report a split across instances.\n\n**Responder verdicts.** A responder grades only itself:\n\n- manager: `bound` while its v0.4 service endpoint (§13) is serving, otherwise `unbound`. A\n closed service connection is not serving, including while the manager re-dials it. A\n disconnected one is not serving either, including while the client reconnects it.\n- delivery: from its own shard lease row. Absent or not ready is `unbound`. A ready row held by\n a different instance than the responder is `stale`. A ready row it holds is `bound`.\n- A responder that cannot determine its state answers `unknown`.\n\n**Rebinding.** A responder MUST bind its serve filter again on every broker connection that\nreplaces the one it bound on. A filter left on a closed connection gets the broker's\nno-responders answer, which a caller grades `unbound` for a plane that is still served. Each\nnew bind mints a new `instance`.\n\n**Caller grading.** The caller grades the outcome of asking:\n\n| Outcome | `responder` | `instance` |\n| --- | --- | --- |\n| a reply that parses as above | the reply's `responder` | the reply's `instance`, if any |\n| the broker's no-responders status (503) | `unbound` | absent |\n| timeout, permission refusal, transport failure | `unknown` | absent |\n| a reply that does not parse | `unknown` | absent |\n\nOnly the broker's no-responders answer yields `unbound` without a reply. Every other failure\nto get a readable reply is `unknown`. A caller MUST NOT report `unknown` as either health\nstate. A caller using the NATS binding MUST request without the muxed inbox, so a\nno-responders status reaches it rather than surfacing as a timeout.\n\n**Grants.** An agent may publish the request subject for each plane under its own principal\nand subscribe `<request subject>.>` for its replies. It holds neither serve filter, so it\ncannot answer for a plane. The `delivery` profile holds the delivery plane's serve filter and\nreply grant. The `supervisor` profile holds the manager plane's pair, and the remote-manager\nprofile holds them only for its supervisor actor (`manager_<instanceId>`). No responder can\npublish a request subject, because its reply grant stops at the `.reply.` leaf. Appendix B\nlists the agent rows.\n\nReference implementation: `livenessSubject`, `livenessServeFilter` and `livenessReplyGrant`\nin `packages/core/src/subjects.ts`; `LivenessAnswer`, `parseLivenessAnswer` and\n`responderFromProbe` in `packages/core/src/liveness.ts`; `CotalEndpoint.serveLiveness`,\n`serveDeliveryLiveness` and `probeLiveness` in `packages/core/src/endpoint.ts`.\n\n---\n\n## 7. Channels\n\nA channel is addressable as soon as it is published to. Channel config is optional and lives\nin the per-space registry bucket `cotal_channels_<space>`, keyed by the concrete channel\ntoken.\n\n`ChannelConfig`:\n\n| Field | Type | Notes |\n| --- | --- | --- |\n| `replay` | boolean | history replay-on-join; overrides the space default |\n| `replayWindow` | string | backfill horizon matching `^\\d+(s\\|m\\|h\\|d)$`, e.g. `\"24h\"` |\n| `deliveryClass` | `live` \\| `durable` | per-channel delivery class (§4); overrides the space default |\n| `description` | string | one-line purpose; max 200 chars |\n| `instructions` | string | advisory usage text; max 2000 chars |\n\nSpace-wide defaults (`ChannelDefaults`: `replay?`, `replayWindow?`, `deliveryClass?`) live under\nthe reserved key `=defaults`. Effective replay is `channel.replay ?? defaults.replay ?? true`.\nEffective delivery class is `channel.deliveryClass ?? defaults.deliveryClass ?? \"durable\"`.\n`defaults.deliveryClass` MUST be written at space creation from the deployment profile\n(local/self-hosted ⇒ `durable`, persistence on by default; public/web-scale ⇒ `live`, durability\nopt-in per channel), so the effective default is always discoverable on the wire, never inferred\nfrom out-of-band context. The same effective config MUST be the single source of truth for live\njoin, durable fan-out, history read, and membership surfacing; an implementation MUST NOT resolve\nthe class differently in different paths.\n\nJoin subscribes the instance to the channel; leave unsubscribes it. A join target MUST be within\nthe instance's read ACL (`allowSubscribe`, §9); a join outside it MUST be refused by the broker on\nsubscribe. A client MUST NOT publish to wildcard channels, but a wildcard read ACL (`team.>`)\nauthorizes subscribing to any one concrete channel under it **without enumerating channels in\nadvance**. In the NATS binding, join is a native `sub.allow`-bounded core subscription to the\nchannel subject and leave is the corresponding unsubscribe; **no privileged mediation is\nrequired**: the broker enforces every subscribe against `sub.allow`, so an instance whose ACL\npermits a channel joins and leaves it on its own, with no manager present. Open mode behaves the\nsame (the client subscribes directly). Leaving the last channel is permitted: under the core-sub\nbinding an empty subscription set subscribes to nothing (the v0.2 \"empty filter subscribes to all\"\nhazard and its last-channel-leave refusal were artifacts of the multi-filter durable and no longer\napply). On a `durable` channel, join additionally establishes durable membership, a separate\n**privileged** step: the instance requests durable membership from the server-side delivery daemon (a\ndurable-join command on the `delivery` endpoint, §13, carrying the channel and its captured join\ncursor) and the daemon writes the membership record. This is decoupled from the live subscribe, so a self-serve live join never depends\non it: a `durable` channel still delivers live with no privileged writer present, and only its\ndurable backstop requires one. A locally created subscription that the\nbroker later refuses (the permission violation is asynchronous in the NATS binding) is NOT a\nsuccessful join: an instance MUST treat a join as effective only once the broker has accepted the\nsubscribe, and MUST drop the channel from its joined set on a late refusal (§12). Leave removes the\nmembership (see membership below).\n\nReplay / catch-up on join:\n\n1. Record the channel join watermark (the CHAT frontier) before the subscription is active, so\n live tail and backfill do not double-deliver.\n2. Subscribe to the channel subject (`sub.allow`-bounded; §8). The live copy now flows.\n3. If effective replay is on, read retained messages for that channel up to the watermark,\n through a single-channel history read bounded by the current read ACL (`allowSubscribe`, §8),\n optionally limited by `replayWindow`. History is ACL-bounded, not membership-gated: an ACL-holder\n may read a channel's retained content whether or not it is a current member (it could self-join\n and read regardless), so the confidentiality boundary here is the ACL, consistent with the live\n read.\n4. Surface backfilled messages with `MessageMeta.historical = true`.\n5. Deduplicate by `id` across the live tail, the backfill, and (on `durable` channels) the durable\n backstop, so a message surfaces once. Receiver deduplication MUST NOT coalesce copies solely\n because `id` is the empty string (§4).\n\n Informative: an implementation preserving an incarnation across a local restart may start step\n 3's read from the sequence that incarnation had reached, rather than from the retained window's\n start; a fresh joiner reads the window.\n\n`replay=false` is noise control, not confidentiality. CHAT history is readable only within an\ninstance's read ACL (`allowSubscribe`, §9); confidential content MUST use DM or anycast.\n\nChannel membership governs **durable-delivery inclusion** (who receives fan-out copies into their\nper-subscriber backstop) and is broker-known, not self-reported. It is NOT a confidentiality\nboundary tighter than the read ACL: `allowSubscribe` bounds what content an instance may read (live\nand history, §9), and an ACL-holder can self-join, so membership adds delivery semantics, not read\nconfinement. In the NATS binding, membership is a privileged-written record in the space registry\nplane under a key the agent's profile cannot write (NOT the agent's presence key), carrying per-member\njoin/leave cursors so a publish concurrent with a join or leave orders deterministically; it is NOT\nderived from consumer topology, and an agent MUST NOT self-assert its own membership. It is written by\nthe server-side delivery daemon in response to a durable-join command on the `delivery` endpoint\n(§8, §13, Appendix B), distinct from and not required by the self-serve live subscribe. The implementation MUST re-authorize every\n**durable-backstop** read of `(instance, channel, message)` against the instance's current read ACL\nand membership before surfacing content, so a channel dropped from the ACL or **left** is no longer\nsurfaced from the backstop: **leave is a hard read boundary for the durable backstop** (it does not\nrevoke the ACL: an instance may still re-subscribe live, or read ACL-bounded history, within\n`allowSubscribe`). Membership remains observability data for liveness/roster purposes and MUST NOT be\nused as a send authorization gate.\n\nOn a `durable` channel, membership carries the member's **join cursor** (the CHAT frontier captured\nat join, the same watermark used to deconflict the live tail and the backfill) and, on leave, a\n**leave cursor/tombstone**. The durable backstop is at-least-once (within retention)\nfor messages whose stream sequence is **> the member's join cursor and ≤ its leave cursor**, where each\ncursor is the CHAT frontier (the last sequence) captured at that transition; messages published before a\njoin or after a leave are not redelivered as durable and are reachable only via an ACL-bounded history\nread (within `allowSubscribe`). A rejoin takes a new join cursor, so messages published during the gap are not durably\nredelivered. A `durable` join is atomic across its two effects: the instance is durable-joined only\nonce BOTH the broker-confirmed live subscribe AND the membership write have succeeded, and on a late\nsubscribe refusal the membership record MUST be removed. If the live subscribe succeeds but durable\nmembership cannot be established (for example no privileged writer is present), the instance is\n**`joined live` with the durable backstop unestablished**: it MUST NOT be reported as `joined durable`,\nthe live subscription remains active, and the durable shortfall MUST be surfaced as an exceptional\ndelivery state (e.g. `durable backstop unavailable`), never silently.\n\n---\n\n## 8. NATS + JetStream binding\n\nBacking streams are created once at space setup. `STREAM.CREATE` is denied to agents in auth\nmode.\n\n| Stream | Captures | Retention | Required config |\n| --- | --- | --- | --- |\n| `CHAT_<space>` | `cotal.<space>.chat.>` | Limits | file storage, `max_msgs_per_subject=1000`, `discard=Old`, `allow_direct=true` |\n| `DM_<space>` | `cotal.<space>.inst.>` | Limits | file storage, no Direct Get |\n| `TASK_<space>` | `cotal.<space>.svc.>` | WorkQueue | file storage, no Direct Get |\n\n**Resume transfer bucket.** A manager instance that receives a carried resume transcript holds one\nJetStream Object Store bucket, `cotal_xfer_<space>_<instanceId>` (stream\n`OBJ_cotal_xfer_<space>_<instanceId>`): file storage, `discard=new`, `max_age=0`, rollup headers and\nDirect Get allowed, every other limit `-1`. An object is named `sha256:<hex>` for the transcript's\ndigest and is written in the stock Object Store layout with its `nuid` set to `<hex>`, so every\nattempt at the same bytes writes one chunk subject, `$O.<bucket>.C.<hex>`. Each chunk is a\nJetStream publish carrying `Cotal-Offset` (transcript bytes through this chunk), `Cotal-Chunk`\n(chunks through this chunk) and `Nats-Expected-Last-Subject-Sequence` (the previous chunk's stream\nsequence, `0` for the first); the acknowledged chain is the upload's only checkpoint, and a writer\ncontinues from its last chunk. The commit is the stock meta record, published with `Nats-Rollup:\nsub` and an expected last subject sequence. The target manager stages a committed object, verified\nagainst its digest, removes the object whole, and removes any transfer idle for ten minutes; no\nmessage expires by age.\n\nChannel **live** delivery is a native core-NATS subscription to `cotal.<space>.chat.*.*.<channel>`\n(wildcard sender owner+actor) bounded by `sub.allow` (§9), not a durable consumer; join/leave is the\nsubscribe/unsubscribe and needs no privileged mediation. The legacy v0.2 `chat_<owner>-<actor>`\nlive-tail durable is removed from this binding (it MAY coexist transiently during migration behind\n`id` dedup, but is not part of the contract).\n\nDurable consumers. Per-instance durables are keyed on the principal's **dash-form** `<owner>-<actor>`\n(a `.` is illegal in a durable name; see §2), so a durable name-scopes to exactly one principal:\n\n| Durable | Stream | Filter | Policy |\n| --- | --- | --- | --- |\n| `chathist_<owner>-<actor>-<uid>` | CHAT | one `cotal.<space>.chat.*.*.<channel>` per read | transient single-filter consumer for history reads (join-backfill / focus-recall); created per read scoped to one channel in `allowSubscribe`, then deleted; `AckNone`. History is ACL-bounded by the pinned filter, not membership-gated (§7, §9) |\n| `dm_<owner>-<actor>-<uid>` | DM | `cotal.<space>.inst.<owner>.<actor>.>` | provisioner-created in auth mode at lifecycle activation; bind only; `DeliverPolicy.ByStartSequence` with `OptStartSeq = activationFrontier + 1`, where the **activation frontier** is the DM-stream's last sequence captured at activation (`0` on an empty stream, so the start is `1`): `ByStartSequence` is inclusive and the lifecycle interval is half-open, so the consumer starts strictly AFTER the frontier, never `All`, which would replay a recycled alias's history and the inactive-gap backlog; `AckExplicit`; `ack_wait=60000ms` |\n| `svc_<role>` | TASK | `cotal.<space>.svc.<role>.>` | provisioner-created in auth mode; bind only; `AckExplicit`; `ack_wait=60000ms`. **Intentionally role-shared, not lifecycle-scoped**: anycast work belongs to the role, and successive holders draining one pool is the contract |\n\nFrom v0.4, each lifecycle's durable state lives in the **half-open interval**\n`(activationFrontier, retirementFrontier]` per stream: consumers start strictly after the\nactivation frontier (`OptStartSeq = frontier + 1`, table above; the frontier is captured\nAFTER any inactive alias gap), and terminal retirement records the\nretirement frontier before the alias is freed, so a successor lifecycle never receives the\npredecessor's pending backlog nor messages published while no lifecycle was active (§13.1).\n\nA client MAY read its DM inbox with nothing but its own `dm_<owner>-<actor>-<uid>` durable. Such a\nreader MUST bind only an existing durable and MUST NOT create one; a missing durable is a refusal,\nnot a fallback to any other credential or read path. It MUST apply the §5 sender check before any\nhandler sees a message. Its native requests are CONSUMER.INFO and MSG.NEXT on that durable plus\nacks under `$JS.ACK.<DM>.<durable>.>`; it needs no presence, registry, channel, delivery, history\nor account-level JetStream row. The credential profile for such a reader is not defined here.\n\nPer-instance durable names use the principal's dash-form `<owner>-<actor>` (both tokens\nfail-loud-validated, not lossily sanitized), so a durable name-scopes to exactly one principal (§2).\nThe authenticated wire identity is the principal, not the connection nkey. From v0.4, in auth mode,\nper-instance durable state is additionally **lifecycle-scoped** (§13.1): durable consumer names,\npending delivery cursors, membership rows, and ACL/ledger rows key on\n`(principal, lifecycleUid)` (dash-form `<owner>-<actor>-<lifecycleUid>`), terminal retirement\nrecords per-stream sequence cutoffs before an alias is reused, and a same-name successor\ninherits none of its predecessor's pending state: its consumers start after its OWN\nactivation frontier (which is ≥ the predecessor's retirement cutoff), the cutoffs bound the\npredecessor's interval, they are never the successor's start.\n\n**Durable backstop (§4).** The per-subscriber durable copy is a delivery contract, not a pinned\nlayout: each member has a private durable store, written on publish for a `durable` channel's current\nmembers and, for an `@mention` on a `live` channel, for each mentioned target authorized to read that\nchannel (its `allowSubscribe` covers it), so an authorized but offline target still receives it. The\nagent holds **no content-bearing read** on this mixed store. A **trusted reader** (the server-side\ndelivery daemon) pulls each pending entry, re-authorizes `(instance, channel, message)` against the\nmember's **current read ACL** and, for `durable`-channel fan-out entries, its **membership interval**\n(the message's CHAT sequence is `> joinCursor` and `≤ leaveCursor`; §7), not a current-member boolean,\nso a pre-leave entry stays deliverable and a post-`leaveCursor` one does not,\nand delivers each authorized copy to the member over an **at-least-once** handoff (its own\n`dlv_<owner>-<actor>-<uid>` DELIVER consumer, carrying the same ack semantics, not a fire-and-forget publish). The trusted reader MUST NOT ack or\ndelete the backstop entry until the member has confirmed the copy was surfaced or handled (or it has\nbeen transferred to an equivalent per-member at-least-once mechanism with the same ack semantics); on a\ndownstream nak, timeout, or crash before that confirmation, the entry remains pending and redelivers, so\na crash between the `dlv` handoff and the member surfacing the message cannot lose it, and `durable`\nstays at-least-once end-to-end, not maybe-once. Content\nfor a channel dropped from the ACL, or (for a durable channel) left, is never surfaced (at-least-once for\nthe member within retention; **leave is a hard read boundary for the backstop**); a `live`-channel\n`@mention` copy is delivered and `id`-deduped the same way. The read MUST run in this trusted component\nthe agent cannot bypass, because a self-bound consumer has no server-side per-message ACL/membership\nfilter. The store's stream/subject layout, the fan-out writer, the trusted reader, and the membership\nregistry are reference-implementation, not normative; a conformant deployment MAY realize the backstop\ndifferently as long as the §4 guarantee and the §9 checks hold.\n\nThe absence of a usable receiver dedup key does not relax acknowledgement ownership: a\nJetStream-consumed copy with `id: \"\"` that is surfaced or handled MUST be acknowledged\nindependently. The reference fan-out and transfer publishes carry no `Nats-Msg-Id` for an\n`id: \"\"` message, so id-less messages are not publish-deduplicated on the durable plane.\n\nPublishers MUST publish channel, unicast, and anycast delivery messages through JetStream and set\nthe JetStream message id to `CotalMessage.id` (`Nats-Msg-Id` on the wire). A JetStream publish is\nan ordinary subject publish that the stream also captures, so the same message reaches core\nsubscribers live (§4 `live`) and is retained for history and the durable backstop in one publish;\nthe publish path is unchanged from v0.2; only the live *read* moves to a core subscription.\nAck/nak/term semantics apply to JetStream-consumed copies (history, DM, anycast, and the durable\nbackstop): receivers MUST ack only after a message has actually been surfaced or handled, MAY nak\ntransient failures, and MUST term permanently invalid messages. The at-most-once `live` copy is not\nacked. A receiver still handling a copy MAY restart its ack wait with JetStream's in-progress ack\n(`+WPI`). An ack or in-progress ack addresses the stream sequence rather than one delivery of it,\nso a receiver SHOULD stop renewing a copy once its ack wait may have run out since the last\nrenewal, because the broker may by then have delivered that sequence to another consumer.\n\nHistory on join uses the pinned single-filter `chathist_<owner>-<actor>-<uid>` consumer create above, bounded to\n`allowSubscribe`; agents are not granted unfiltered Direct Get. DM and TASK MUST NOT enable Direct Get\nbecause it would bypass the consumer-create deny that is part of the confidentiality boundary.\n\nKV buckets are also streams and are pre-created:\n\n| Bucket | Holds | TTL |\n| --- | --- | --- |\n| `cotal_presence_<space>` | presence (§6) | 6000 ms |\n| `cotal_channels_<space>` | channel registry (§7) | none |\n| `cotal_membership_<space>` | derived channel-membership feed (below) | none |\n\n**Derived channel-membership feed (observability).** `cotal_membership_<space>` is a per-agent\n(key = `card.id`) derived view of who is subscribed to each channel: the **union** of an agent's\n`live` core-subscriptions (read by a privileged daemon from the broker's connection view) and its\n`durable` memberships (the members registry), each value `{ live: string[], durable: string[],\nobservedAt }` with `live` keeping subscription patterns (wildcards) the consumer expands at read time.\nIt exists so an observer can show silent readers and `live`-channel membership without a broker-admin\ncredential in the dashboard tier; it is written by a scoped privileged daemon and read only by the\nadmin/observer profile and by the `deployer` and `teardown` operator credentials, which check a\nmanifest's channels for other members. It is **DISPLAY-ONLY and broker-derived**: it MUST NOT be an\ninput to any delivery, ACL, or authorization decision (authority for those stays the broker's\n`sub.allow` and the members registry), and it is not part of the normative wire contract a client\nmust implement.\n\n---\n\n## 9. NATS + JetStream security and authorization\n\n**On by default.** A space is provisioned with decentralized JWT auth. Open unauthenticated\ndev mode is available but out of scope for the security claims here. *(Informative\noperator-facing views of this section: [docs/identity-and-auth.md](docs/identity-and-auth.md),\n[docs/channels-and-permissions.md](docs/channels-and-permissions.md); the threat model is\n[docs/security.md](docs/security.md).)*\n\n- **Account = space, user = agent.** A space is one NATS account. The **broker's** operator signs\n the account; an account signing key mints per-agent user JWTs. A broker (one nats-server trust\n root: one operator, one system account) MAY host several spaces — one account per space, every\n account signed by that one operator. Broker trust is therefore per-broker, never per-space: a\n space owns only its own account and references the broker's operator, and rotating or replacing\n broker trust is intrinsically broker-wide - it affects every tenant on the broker at once and\n cannot be scoped to a single space.\n- **Profiles are default-deny allow-lists.** Subject, stream, durable, and KV names are built\n from the same builders as §3 and §8. Exact profile shapes are in Appendix B.\n- **An agent's channel scope is three concepts**, each a list of channel names or wildcard\n subtrees (`team.>`): `subscribe`, the active read set, the channels it subscribes to at boot\n (now native core subscriptions; mutable at runtime by direct subscribe/unsubscribe with no\n mediation); it MUST be a subset of `allowSubscribe`. `allowSubscribe`, the read **ACL**, the\n channels it MAY read (default = `subscribe`), minted as native `sub.allow` subscribe grants over\n `cotal.<space>.chat.*.*.<channel>` (wildcards preserved, so an open ACL needs no enumeration) and\n as the matching per-channel history-consumer create grants. `allowPublish`, the post **ACL**,\n the channels it may publish to; **default-deny** (a chat publish grant is minted only for a\n declared channel).\n\nEvery grant below is keyed on the agent's **principal** `<owner>.<actor>` (§2), except the reply\ninbox, which is keyed on the **connection** `<connId>`: the connection nkey (static mode) or the\nclient-chosen nonce (user mode, §9). This is the one place the wire identity and the connection\ncredential diverge (§2): the principal keys subjects/durables/presence; the connId keys the inbox.\n\n| Profile | Application publish | Read surface | Notes |\n| --- | --- | --- | --- |\n| `agent` | own `chat.<owner>.<actor>.<ch>` for each `allowPublish` channel (post ACL, default-deny), `inst.*.*.<owner>.<actor>`, `svc.*.<owner>.<actor>`; endpoint request forms per minted capability (`ep.one`/`ep.all`/`ep.inst` with the capability's authz-mode/target pattern, caller triple `<owner>.<actor>.<uid>` pinned; `describe` by default; `epj` submissions for journaled capabilities; §13.9); own presence key | own `_INBOX_<connId>.>` + own endpoint reply rail (`ep.reply.*.*.*.<owner>.<actor>.<uid>.*`, exact arity); channel live tail via native `sub.allow` subscriptions to `chat.*.*.<channel>` per `allowSubscribe` (wildcards preserved); `STREAM.INFO` (stream-level state only, no body read) on `CHAT` and the world-readable KVs, plus `TASK` when the credential carries a `role`; presence and channel-registry KV watches, including create/info/delete of their client-managed ordered consumers on those two streams only; CHAT history via single-filter `chathist_<owner>-<actor>-<uid>` creates, one per `allowSubscribe` channel (ACL-bounded); own lifecycle-scoped `dm_…`/`svc_…` bind-only; durable backstop via own bind-only lifecycle-scoped `dlv_…` DELIVER consumer, **no** grant on the mixed pre-auth fan-out stream; granted record-key/event-topic read subtrees per capability | read bounded by `allowSubscribe`; ordered-consumer cleanup cannot delete KV records or streams; durable copies re-authorized (current ACL + membership + lifecycle) by the trusted reader before the `dlv` handoff; no Direct Get; DM/TASK/DLV create denied. The `manager-caller` view narrows this endpoint control set to `ep.inst.manager.<managerInstanceId>.<command>` only, plus the exact instance `describe`, contract reads, own reply/progress rows, and own inbox. It carries no agent messaging, delivery, class, or scatter rows. When the actor holds `spawn`, the view also carries `status`, `models` and `resolve-cwd` on that instance, the reads a launch there needs; a view without `spawn` gains none of them, and no view gains `ps` or `slots` from `spawn`. |\n| `observer` | none | chat, CHAT history, presence, channel registry | DMs invisible |\n| `admin` | none | whole space live tap plus DM history | plaintext god-view, opt-in |\n| `transfer-writer` | one carried transcript's chunk and meta subjects in one manager instance's transfer bucket (§8) | a last-message Direct Get on those two subjects | one-shot per CLI call, minted after the transcript is hashed; no consumer and no other object |\n| `dm-reader` | `CONSUMER.INFO` and `CONSUMER.MSG.NEXT` on its own lifecycle-scoped `dm_…`, and its `$JS.ACK` subtree | own `_INBOX_<connId>.>` | no message publish, presence, channel, CHAT, `dlv_`, `$JS.API.INFO` or stream INFO row; bound to the bearer's expiry |\n| `transfer-reader` | the stock delete marker on its own transfer bucket's meta subjects | its own `OBJ_cotal_xfer_<space>_<instanceId>` stream: info, message get, its push consumer, purge | one-shot per `transcript-receive` or sweep; no other instance's bucket |\n| scoped host profiles | least-privilege per function | least-privilege per function | The former allow-all `manager` is **deleted**; its host duties split into scoped, single-function creds (`supervisor`, `provisioner`, `delivery`, `membership-rw`, `operator`, `purger`, `teardown`, `channel-writer`, …). No allow-all credential exists. Appendix B summarizes them; the concrete grant lists are **generated from the §13.9 ownership matrix** into `provision.ts` (the matrix is the single oracle; `provision.ts` is its artifact, Appendix B its summary). |\n\nA Manager with explicit `execution: \"none\"` MUST construct no Runtime or connector workload.\nIt MAY use the existing genuine auth-local authority path, or the existing pooled signerless\nremote authority path. These authority paths MUST NOT be mixed. A local NONE instance MUST\nrequire its hosting user-auth marker, signing trust and user-mode mesh record before binding.\nIts persisted native instance, serve principal, owner checks and registration gates are unchanged.\nExecution capability MUST be immutable per instance; an existing unclassified local identity or\nretained seat/turn inventory MUST refuse NONE admission. Startup MUST NOT silently convert a\nruntime instance or adopt a sibling's workload.\n\nNONE status MUST report no runtime, custody, class spawn, workflow hosting or terminal sessions.\nLaunch and workflow requests MUST refuse before allocation or workload effects. Launch reads\nMUST refuse before resolving a Runtime, connector or host path. Targeted requests retain normal\nlifecycle-mapping validation; an instance with no managed mapping does not fabricate a target.\nNONE MUST refuse model inspection before connector or harness resolution. Caller-driven persona,\nhistory purge, transcript transfer, preservation, resume, turn-yield, cancellation and self-stop\nwrites MUST refuse before their effects. NONE MUST NOT start a transcript receiver or sweep.\nNative registration, lease, credential renewal, session-ledger and goal maintenance MAY still\nwrite their own control state autonomously; NONE is not a read-only broker or filesystem mode.\nNative ps remains this instance's managed map, not a presence or HTTP-session inventory.\n\nThe `resolve-cwd` launch read is limited by execution mode. A manager whose runtime delegates\nseats outside its host MUST refuse it with `failed-precondition` before any filesystem lookup.\nThe refusal MUST be independent of the requested path's existence, type and symlink target,\nand MUST NOT return a host name or canonical path. Such a runtime cannot use a manager-host cwd.\n\nOn such a runtime, a caller-supplied persona `config` override MUST be refused before resolving,\nchecking or reading its host path. Every path shape MUST receive `failed-precondition` and the\nsame message: `delegated execution cannot use a manager-host persona config path; select a named persona`.\nThis applies to `resolve-agent` and `spawn`, including starts submitted through library or workflow\nhosts. A named persona remains subject to the manager's catalog visibility rules. A validated\nresolved manifest may use its own host-materialized persona resource; public requests MUST NOT\nbe able to supply that internal resolved authority as a config override.\n\nDM and TASK confidentiality, and the CHAT read boundary, close the leak paths:\n\n1. Replies and pull responses ride a per-connection inbox prefix, `_INBOX_<connId>.>`, which\n `sub.allow` permits alongside the agent's channel read grants (next item) and nothing else. In user\n mode the client picks `<connId>` (a nonce) and the callout scopes the inbox to it, so a\n wildcard-inbox subscribe that would sniff peers' DM deliveries is refused. Re-authorized durable\n copies do NOT ride the inbox; they ride the agent's own lifecycle-scoped `dlv_<owner>-<actor>-<uid>` DELIVER consumer\n (item 5, §8).\n2. **Channel live reads are bounded by `sub.allow`.** `allowSubscribe` is minted as native subscribe\n grants over `cotal.<space>.chat.*.*.<channel>` (wildcards preserved); the broker refuses, per\n subscribe, any channel subject outside the ACL. There is no per-channel consumer name to confine,\n so an open ACL (`team.>`, `>`) grants selective single-channel join with no enumeration and no\n read-breakout. A `>` grant is read-all chat in the space by design (credential compromise reads\n all chat), so it suits trusted/local deployments, not least privilege.\n3. A consumer create on the bare/multi-filter subject is not ACL-constrainable, so the provisioner\n pre-creates `dm_<owner>-<actor>-<uid>`, `svc_<role>`, and the per-member `dlv_<owner>-<actor>-<uid>` handoff\n durables. Agents bind their own `dm_…-<uid>`/`svc_<role>`/`dlv_…-<uid>` only (never\n create); the mixed pre-auth fan-out store is read by a trusted reader, not the agent (§8, item 5).\n Those bare/multi-filter create forms are not granted to agents (default-deny), with explicit\n create-denies on `DM_<space>`, `TASK_<space>`, and the `DLV` stream; on `CHAT_<space>` the only\n consumer-create an agent holds is the pinned single-filter history create (next item), so a broad\n CHAT create-deny is intentionally absent: it would also deny that pinned create.\n4. CHAT history reads are bounded to `allowSubscribe`: a consumer create on the extended subject\n `$JS.API.CONSUMER.CREATE.<stream>.<name>.<filter>` carries a single filter the server pins to the\n request body, so an agent is granted exactly one such create-subject per `allowSubscribe` channel\n and can read history of no other channel. The unfiltered Direct Get grant is not given to agents.\n5. **The durable backstop is read by a trusted reader, not the agent.** The agent holds no\n content-bearing read on the mixed pre-auth fan-out store; a trusted reader (the server-side delivery\n daemon) MUST re-authorize `(instance, channel, message)` against the member's current read ACL and,\n for `durable`-channel fan-out entries, its current membership, before handing the authorized\n copy off to the member's own lifecycle-scoped `dlv_<owner>-<actor>-<uid>` DELIVER consumer:\n broker ownership of an inbox (\"this is agent A's\") is not authorization, since the store can hold\n messages for channels A has since dropped from its ACL or left, and a self-bound consumer cannot\n filter per-message on membership. Fan-out-on-write is routing, not an authorization check; for a\n durable channel a `leave` is a hard read boundary on the backstop. History/backfill reads are instead\n self-served and bounded by the current read ACL (the pinned single-filter create above), consistent\n with the live read. An `@mention` durable copy is written only to a target authorized to read the\n channel, so `mentions` cannot carry content outside a target's read ACL.\n6. **\"Current read ACL\" is the effective broker-accepted credential.** An ACL narrowing takes effect\n when the credential/permissions are updated and enforced by the broker (re-mint / reconnect /\n revocation), not as an instantaneous global value; until then an existing broad credential remains\n broad. Both the broker `sub.allow` checks and the trusted-reader re-checks are evaluated against that\n effective credential.\n\nThis binding provides containment and authenticity under a single trusted broker: an agent\ncan emit only as itself and only to its declared `allowPublish` channels, and read only its own\nDMs and chat *content* within `allowSubscribe` (and, for `durable` content, its current\nmembership), enforced by the server. It does not provide\nnon-repudiation, does not survive an untrusted relay, and DMs are plaintext to the broker and\nto `admin`. The read bound is on **content**, not metadata: agents hold `STREAM.INFO` on CHAT\n(for the join watermark, the recall drop-marker, and channel-list counts), so a `subjects_filter`\nquery leaks chat subject *metadata* (channel names, sender ids, and per-subject counts) for\nchannels outside `allowSubscribe` (channel names are already public via the registry). A\ncredential minted with a `role` also holds it on TASK, under the same gate as that role's\n`svc_<role>` bind grants, so a `subjects_filter` there leaks anycast subject metadata\n(`svc.<role>.<owner>.<actor>`, who anycast which role) to an operator-chosen role profile. DM,\nDLV, and EPC carry **no** agent `STREAM.INFO` grant: `subjects_filter` is a request-body field no\nACL can narrow to counts alone, so INFO there would enumerate who DMed whom, and no agent-side\nreader needs it (§13.1 reaches DM and DLV by durable name, EPC by subject-scoped `DIRECT.GET`).\nHiding the remaining metadata is deferred strict-containment work.\nSee [docs/security.md](docs/security.md).\n\n**Consumer-delivery confused deputy on the read grants.** A JetStream consumer delivers stored\nbytes to a **caller-chosen destination the broker does NOT confine to the requester's\n`pub.allow`**: a push consumer's `deliver_subject`, and a pull `MSG.NEXT`/`DIRECT.GET`\nrequest's reply subject, are set in the request body and the server's internal client publishes\nthere regardless of the requester's publish permissions. The v0.3 read grants above,\nCHAT-history `CONSUMER.CREATE`, the bind-only DM/DLV/TASK `MSG.NEXT`, and the KV watch creates\n(Appendix B); therefore let an agent redirect content it may legitimately READ onto a subject\nit may NOT publish to: e.g. replay a stored CHAT message whose `from.id` is another sender onto\n`inst.<victim>.<thatSender>`, where the recipient derives the DM sender from the subject and\nsurfaces it as a genuine DM from a principal who never sent it. The §13.9 \"Mediated reads\" rule\napplies here: **no untrusted agent holds a raw consumer `CREATE`/`MSG.NEXT` or `DIRECT.GET` on\n`CHAT`/`DM`/`TASK`/`DLV` or the KV buckets**; those reads are served by the trusted\nreader/mediator (§8) onto the agent's own confined rail. Which of these read paths require\nmediation and which are provably safe depends on whether a redelivered message retains its\noriginal captured subject and how the receiver's subject-derived kind check (§12) then\nclassifies it; the reference implementation determines this by test and pins the exact grants.\nOn the v0.3 rails without this mediation, read containment holds only against a *conforming*\nclient; the broker does not enforce it.\nSee [docs/security.md](docs/security.md).\n\n---\n\n## 10. Connection and onboarding\n\nJoin link grammar:\n\n```text\ncotal://[token@]host[:port]/space[?channel=a,b] plaintext\ncotals://[token@]host[:port]/space[?channel=a,b] TLS required\ncotal://user:pass@host/space user/password auth\n```\n\n- Default port is `4222`.\n- `channel` and `channels` query parameters are equivalent comma-separated channel lists.\n- Credentials in `userinfo` are parsed out and passed to the NATS client as connect options;\n they are not left inside the server URL.\n- Bare `userinfo` with no `:` is a token. `user:pass` is username/password.\n- `cotals://` means `nats://host:port` plus TLS-required connect options.\n- Credentials (`creds`) are mutually exclusive with token and username/password auth.\n- A client MUST set `inboxPrefix` to `_INBOX_<connId>` before any request, pull consumer, or KV\n watch operation, where `<connId>` is the connection identifier (the connection nkey in static\n mode; the client-chosen nonce in user mode, §2/§9), NOT the owner+actor principal, which the\n client may not know pre-connect.\n\nAuthenticated onboarding has two bindings. **Out-of-band credential minting** provisions a per-agent\ncredential ahead of connect (the static path). **Auth-callout onboarding** validates a user bearer at\nconnect time and mints the scoped data-account JWT then (user mode, §2/§10): the client presents a\ndeny-all sentinel credential plus its bearer, the callout derives the owner+actor principal and grants,\nand re-binds the connection into the data account. A space's callout requests are served inside that\nspace's dedicated auth account, so a responder holds one subscription per auth account it serves. One\nprocess MAY serve several spaces, holding one such subscription and one set of signing keys per\nspace; a response for a space MUST be signed only with that space's keys, and a bearer MUST be\nvalidated only against the issuer and audience of the space whose request it arrived on. A process\nMAY likewise serve several spaces' exchange and JWKS, as one full auth service per space: each\nspace's exchange MUST be served on listeners of that space's own and mint only from that space's\nkeys and ledger, and each space keeps its own authority plane (§13.13). The owner-token *derivation* (how a bearer maps to\nan owner token) is a pluggable identity adapter (any OIDC/IdP via a thin bridge), not fixed by this\ncontract; the callout *mechanism* and the resulting grants are. From v0.4 every minted connection also carries its **lifecycle UID** (§13.1): the manager\nmints it for managed agents at provision, and the callout/exchange attaches it as a claim at\nconnect for user-mode connections, so the caller-UID token in every endpoint-rail grant is\nauthority-assigned, never client-chosen. Every bearer additionally carries its incarnation's\n**root credential id** (`act.credentialId`, §13.1). The exchange ensures the ACTIVE\n`cred.<lifecycleUid>.<credentialId>` ledger row exists BEFORE the bearer bytes are released\n(the row durable first, the issuance-gate finalize CAS, the lifecycle head's current-root CAS\nlast), and the connect authority proves the presented id against the LIVE row, leader-served\nfrom the shape-proved primary auth store: the row MUST be `active`, unexpired, and bound to the\nconnecting principal and lifecycle, and a root-issued credential MUST additionally equal the\nlifecycle head's current root credential. A claimless bearer, a revoked, expired, or absent row,\nand an unreadable authority store all DENY the connect. The root credential is\n**incarnation-wide**: ONE `cred.<lifecycleUid>.<credentialId>` row per incarnation, re-stamped\n(the same id) on every exchange for the incarnation's lifetime, never a fresh id per exchange.\nRevoking that one row is the per-credential revocation lever and denies EVERY bearer of the\nincarnation at the next connect (deny-new; evicting an already-live connection is the lifecycle\nbarriers' job, §13.1). Because the id is incarnation-stable, a crash after the head's current-root\nCAS re-exports the SAME id on the next exchange (that id IS the incarnation's live root, so there\nis nothing unobserved to revoke); the only pre-release crash window is a durable active-but-\nunstamped row, which the head-equality check denies. Rotating an incarnation's root credential is\nexclusively a lifecycle barrier's job, never a bare re-mint. A bearer MAY carry a server-authored\n**view** claim, selected only by the exchange and re-authorized against the live grant ledger at\nevery connect. The callout then mints the connection as that closed profile instead of `agent`.\nElevated views such as `admin`, `purger`, `channel-writer`, and `deployer` remain human-only. The\nnarrowing `manager-caller` view MAY be minted by either the human or managed-agent exchange and is\nserved on both exchange faces. It adds no capability beyond the launch reads §9 lists for a `spawn`\nactor's view. Its required `act.managerInstanceId` binds\nevery manager request to one exact live registered instance and is valid with no other view. The\nexchange selects from read-only observations of manager issuance gates and service registrations.\nIt refuses zero or ambiguous candidates and refuses an unavailable owner-specific remote manager\nrather than falling through to a co-located manager. An explicit selector must name a live candidate.\nOn the public exchange face, once the caller's credential and ledger actor grant have verified\n(for a human exchange, the IdP JWT and the interactive actor grant; for an agent exchange, the\nmanaged actor secret and its ledger row), a `manager-caller` request that fails only manager\nselection MUST return its selection refusal reason on 401 without spending the per-peer probing\nbudget. The public face tracks those authenticated selection refusals in two rolling windows per\nprincipal (derived owner for human exchanges, `owner.actor` for agent exchanges) keyed by\nprincipal and request class (`pinned` when the request names `managerInstanceId`, `unpinned` when\nit does not, never by the requested instance id): each class counts only its own selection\nrefusals and, once its window is full, refuses requests of that class (including ones that would\nhave succeeded) with 429 and that class's remedy before running manager selection, while leaving\nthe other class open. On the loopback face, an authenticated unpinned refusal caused by no live\nmanager or ambiguous candidates returns its own reason without spending the shared probing budget.\nA trusted host composition MAY instead select its genuine local Manager up front for an unpinned\ninteractive human exchange. It MUST apply the same native local identity, open gate, serve principal,\nregistration revision and epoch checks, and MUST refuse an absent, unreadable or noncandidate local\nManager without reading or substituting remote candidates. This policy MUST NOT be request-selectable,\nchange explicit selectors, rebind managed or issued callers, or add command authority. Without the\nhost opt-in the default selection above is unchanged.\nThe auth service lists the same observations to a signed-in human at `POST /manager-instances` on\nboth faces: it verifies the same IdP proof, derives the owner the same way, and answers every manager\ngate of that owner using the same candidate checks as selection. A listed candidate is registration evidence, not proof that the instance answers, and a\nfailed read is unavailable, never an empty list.\nThe `session-caller` view carries a required `act.session` claim `{endpoint, sessionId, epoch, exp}`\n(exp in unix seconds) and is valid with no other view; `act.session` is valid only with it. It needs no\nledger scope: the redeemed §13.6 session grant is the authority. The human exchange accepts it only\ntogether with a `sessionGrant` body (each without the other is a 400), and the trusted auth path MUST\nleader-read the `session.<sessionId>` row from the dedicated sessions store before it signs. It MUST\nrefuse unless the row is `active`, `row.grantSig` equals the presented grant's signature, the row's\nholder principal and lifecycle are the bearer's owner, actor and `lifecycleUid`, the endpoint and\nserving epoch equal the presented ones, `row.exp` is in the future, and the serving manager's issuance\ngate is a candidate for this owner with a process epoch equal to the row's. The stamped `exp` is the\nrow's, and the bearer TTL is bounded by it. The callout MUST re-run the same check, without the\nsignature comparison, against a fresh read at connect. It mints the `session-caller` profile for that\none session and binds the minted connection's expiry to the grant's, which is the static arm's\nexpiry, rather than the bearer's. The auth service's host-issuer connection performs both reads and\nholds only `STREAM.INFO` and the leader-served `STREAM.MSG.GET` on `KV_cotal_sessions_<space>`: no\nDirect Get and no write on that store.\nThe `transfer-writer` view carries a required `act.transferWriter` claim `{instanceId, hex}` and is\nvalid with no other view; `act.transferWriter` is valid only with it. It needs ledger scope `admin`,\nthe scope of the `transcript-receive` row it serves. The human exchange accepts it only together with a\n`transferWriter` body (each without the other is a 400), and the callout mints the `transfer-writer`\nprofile for that one object of that one instance's transfer bucket (§8).\nOn a public exchange face, `channel-writer`, `channel-purger`, `manager-caller`, `session-caller`, and\n`transfer-writer` MAY be issued. `admin`, `purger`, `deployer`, and `manager-service` MUST remain loopback-only. A\nmanaged-agent secret exchange MUST refuse every view other than `manager-caller`.\nThe service-only `service-endpoint` view (§13.1) is not selectable on either ordinary exchange\nface. Its dedicated authority path checks native service custody rather than an enrolled actor row.\nThe `dm-reader` view needs no ledger scope and MUST remain loopback-only. It rides only a\npurpose-bound IdP proof. The proof carries the bridge's dedicated `dmReaderAudience`, which is\nexplicit configuration and MUST differ from the ordinary audience. It also carries\n`purpose: \"dm-reader\"` and the `actor`, `lifecycle` and `space` claims. The exchange MUST refuse\nunless the request names `view: \"dm-reader\"`, `actor` equals the requested actor, `lifecycle`\nequals the current ledger row's lifecycle UID, and `space` equals the bridge's space. Every other\ndoor that takes a human IdP proof MUST refuse any token carrying a `purpose` claim. At this release\nthose are the other `/exchange` forms, `/manager-instances`, `/manager-service-authority`, the three\nchat-session routes, `/tool-result-human-proof/verify` and `/tool-result-consent/issue`. The\nbearer's expiry, and with it the connection's, is bounded by the proof's.\n\n**Connect limits.** The auth service MAY limit connects per actor and per owner, charging a bearer\nwhose signature verifies to the principal it names even after it expires, and per client host for a\nbearer that does not verify. Buckets are per space: a process serving several spaces MUST keep a\nseparate set for each, so a connect to one space never spends another space's allowance. A callout that refuses a connect for a limit MUST answer with a signed\ndenial whose reason starts with `RATE_LIMITED retry-after <n>s`, and MUST do so before it reads the\nledger or records an issuance. While an actor or its owner is limited, an exchange for that actor\nMUST answer 429 with the body `{code: \"RATE_LIMITED\", retryAfterSeconds, limit, error}`, where\n`retryAfterSeconds` is a positive integer and `limit` is `\"actor\"` or `\"owner\"` for the bucket that\nran out, and a `Retry-After` header carrying the same number. It MUST NOT count that answer against\na refused-exchange budget. A client that receives it SHOULD NOT exchange or connect as that actor\nagain until those seconds have passed.\n\n**User-mode chat sessions.** The auth service is a minting authority for chat sessions only\n(§13.1). A signed-in human opens one with a fresh IdP proof and the SHA-256 of a holder secret the\nclient keeps in memory. The service derives the owner, draws the actor `chat_<26 base32>` and a\nfresh lifecycle UID, and pins the human's own `cli` grant: its lifecycle UID, head revision and the\nRFC 8785 digest of its row. The session's read and post lists MUST be contained in that grant, and\nits lifetime is at most 8 hours and never extended. A request that names an owner, actor, UID,\nscope, view or profile refuses. The holder index `chatholder.<owner>.<holderHash>` is created\nbefore any lifecycle write and only advanced by revision-pinned CAS (`reserved`, `provisioning`,\n`active`, `retired`), so a retry with the same holder hash converges on the same session and a\nretired hash never admits again. A `pending` session row authorizes nothing. Each bearer exchange\npresents the holder secret. Its TTL is at most the least of 900 s, the IdP proof's remaining life\nand the session's remaining life. The bearer is released only after the session row, the holder\nindex, the parent pin and the session's own lifecycle head and root credential are read current\nboth before and after signing. The callout mints a chat principal as the `agent` profile with the\nsession's lists and no role, capability, endpoint capability or view. It refuses a chat bearer\nthat carries a view or a scope, or whose row is not `active`, names another lifecycle, holds a\nmoved parent pin or has a holder index that is not `active`. Retirement settles the session's\nlifecycle through the §13.1 barrier before the per-owner quota row `chatowner.<owner>` releases its\nslot. The auth service's sweep retires expired sessions the same way. It acts on an unfinished\nadmission only after a 60 s quiet period, which is never the evidence: it fences the holder index\nfirst, drives the bound UID to a terminal gate, and releases the slot last. A pass makes at most 256\nof its own reads, runs at most 4 retirements at once and never waits for one. A retired row is\ncompacted 24 hours after its expiry, once the UID's footprint is removed again. The routes are\n`POST /chat-session/open`, `/chat-session/bearer` and `/chat-session/retire`, on both exchange\nfaces, with the same IdP proof check and the same capability rule as `/exchange`. Every refusal on\nthem carries its effect outcome: `not-executed`, `executed` or `unknown`.\n\n---\n\n## 11. Versioning and extensibility\n\n- Wire contract version is v0.2 as advertised today. `AgentCard.protocolVersion` (§6) carries\n this string. The two v0.3 binding revisions (channel live delivery and owner+actor identity,\n see the header) and the **v0.4 endpoint control surface** (§13) are the normative targets the\n reference implementation is converging to. The control surface is an intentional **hard\n cut on the pre-1.0 line** (§13.11): the v0.3 control grammar and envelope are removed from\n this contract, not dual-served, a breaking revision, permitted pre-1.0, shipping under an\n explicit new version marker per this section's rule; the marker is the disjoint endpoint\n subject grammar and versioned envelope. The advertised `protocolVersion` bumps to `0.4` when\n the control-surface migration completes (one campaign, one merge); a version string is not a\n per-surface cutover claim. **`1.0` is deliberately deferred**: it is a stability declaration\n to outside implementers, made separately once the contract has settled (further pre-1.0\n arcs (presence/addressing, multi-space, federation) may still break the wire). **The wire `protocolVersion`\n is the compatibility signal**; dated document snapshots (below) are navigation artifacts, not\n negotiation; an implementation MUST NOT treat a document date as an interop key.\n- **v0.5 (workflow runs, §14) is an additive revision.** It adds a per-space stream, four core\n record kinds, a per-run grant family and a normative language reference, and changes no existing\n kind, subject, grant row or shipped datum; a participant that ignores §14 conforms to v0.4\n unchanged. Two versions ride it and they are deliberately distinct: the wire `protocolVersion`,\n which targets `0.5` when the plane is served, and the language's own `languageVersion` (§14.2),\n which is bumped when a program's MEANING changes and is pinned per run, so a language revision\n never forces a wire revision and a wire revision never invalidates an open run.\n- v0 has no in-band capability negotiation. Deployments MUST agree on the binding and\n version out of band. A participant advertises the version it speaks via\n `AgentCard.protocolVersion` (§6) as a one-way change signal, optional before the v0.4\n marker, MUST from v0.4 (§6, §13.11); v0 defines no behavior on a mismatch beyond rejecting\n messages it cannot parse.\n- **A non-additive discovery change is an out-of-band deployment cutover, and it rolls out\n CALLER-FIRST.** A discovery change is non-additive when an unamended client that ignores it per\n the unknown-field rule below would then behave in a way the change exists to prevent — for such\n a change, ignoring is not a safe default and no default value repairs it. Every caller in a\n deployment MUST implement the new version's rules BEFORE any responder in that deployment\n registers or describes at that version. The two halves SHOULD therefore ship in **separate**\n releases — the caller side first and adopted across the deployment, the responder's emission only\n after — and shipping them in one release does not make a deployment safe, because **a release is\n not a deployment**: an already-running caller is unchanged by whatever a new artifact contains,\n so the order of two source edits says nothing about the processes on the wire. This rule exists\n because the preceding one leaves a responder no way to detect the hazard itself: with no in-band\n negotiation and no caller version on the wire, a responder cannot tell an amended caller from an\n unamended one, so the obligation rests on the deployment rather than on either participant. The\n observable marker is the discovery protocol's `protocol.v` on the registered service record\n (§13.7) — \"has any responder cut over\" is a checkable registry property, while \"has every caller\n adopted\" is exactly the out-of-band agreement this section already requires. **The residual is\n real**: a deployment that cuts a responder over early exposes its unamended callers to whatever\n the new version exists to prevent, and within v0 nothing in band detects it. Closing that needs\n negotiation v0 does not have, and the v1 marker below is where it belongs.\n- New message families, subjects, and routing kinds are added in the core contract,\n generalized for all deployments, not in one example.\n- Receivers MUST ignore unknown object fields and MUST NOT treat an unknown field as an\n error.\n- A future v1 MUST either keep v0 subjects backward-compatible or use an explicit new\n version marker in subjects, credentials, or deployment config.\n\n**Document snapshots.** Published revisions of this document are dated snapshots\n(`YYYY-MM-DD`, the **Last updated** date above): the current revision is canonical, and a\nsuperseded one stays retrievable from the repository history (the git history and tagged\nreleases of `SPEC.md`), so a client built against it can still be audited. The snapshot\ndate advances on any normative change; the wire `protocolVersion` moves only per the\nchange process below.\n\n**Change process.** This document is the change-control point: a change lands here first,\ngeneralized into `core`, and the reference implementation follows. Additive changes (a new\noptional field, a new namespaced `Part.kind`, a new subject) are backward-compatible and ship as\na minor bump, since receivers ignore what they do not recognize. Changing the meaning of an\nexisting field or subject, or removing or renaming one, is breaking. **Pre-1.0**, a breaking\nchange ships as a minor bump of the v0.x line under an explicit new version marker in\nsubjects, credentials, or deployment config (the v0.4 endpoint grammar is such a marker);\n**post-1.0**, it ships as a major bump. `1.0` itself is a stability declaration, made\ndeliberately and separately from any wire change.\n\n**Extension namespacing.** Core `Part.kind` values, `meta` keys, and `tags` are bare and reserved\nto this spec (`text`, `data`, `artifact`, and future core additions). A non-core extension MUST namespace its\ncustom `Part.kind` values and `meta` keys reverse-DNS, under a domain its author controls, e.g.\n`{ \"kind\": \"com.acme.snapshot\" }` or `meta[\"com.acme.region\"]`; Cotal's own non-core extensions\nuse `ai.cotal.*`. This keeps third-party names from colliding with each other or with future core\nnames, with no central registry.\n\nReserved future work: signed envelopes, `did:key` identity, auth-callout bootstrap tokens,\nmanager profile scoping, and federated/untrusted relay bindings. (Revocation/TTL for minted credentials is no longer future work on the control\nsurface: v0.4 defines it normatively via the credential ledger and the lifecycle barriers,\n§13.1.)\n\n---\n\n## 12. Conformance\n\n*(An informative build-order walkthrough of this checklist is\n[docs/build-a-client.md](docs/build-a-client.md).)*\n\nA conformant authenticated NATS client MUST:\n\n1. Use one stable principal `<owner>.<actor>` as its wire identity everywhere: subject sender\n tokens (§3), `from.id` (§5), presence key (§6), durable names (dash-form, §8); and treat the\n connection credential (nkey) as distinct, keying only its reply inbox (§2).\n2. Publish only on subjects whose sender tokens are its own principal `<owner>.<actor>` (§3).\n3. Publish delivery messages as UTF-8 JSON through JetStream with `msgID = id` (§8).\n4. Set exactly one routing field on each delivery message (§5).\n5. Reject any received delivery message whose `from.id` does not match the subject sender, and whose\n subject `<owner>` is not a well-formed principal owner token: a subject that split-parses but\n carries a non-owner in the owner slot (e.g. a raw nkey, an old-shape alias) MUST NOT be surfaced\n as a delivery (§3, §5).\n6. Derive delivery kind (channel/dm/anycast) from the subject, not payload routing fields (§4).\n7. Ack only surfaced/handled messages and terminate permanent anomalies (§4, §8).\n8. Write only its own presence key on the heartbeat interval (§6).\n9. Set the per-instance inbox prefix before transport operations (§10).\n10. Treat unknown fields as ignorable (§11).\n11. Resolve a channel's effective delivery class (`live`/`durable`) from channel config, not from a\n deployment assumption, and use one resolution across live join, durable fan-out, history read,\n and membership surfacing (§4, §7).\n12. On a `durable` channel, tolerate the at-most-once `live` gap and catch up via the durable\n backstop; deduplicate by `id` across the live, backfill, and durable copies (§4, §8). Receiver\n deduplication MUST NOT coalesce copies solely because `id` is the empty string (§4).\n13. Join and leave a channel's **live** subscription by subscribing/unsubscribing under `sub.allow`\n with no privileged mediation; treat a live join as effective only once the broker accepts the\n subscribe, and drop it on a late permission refusal. On a `durable` channel, additionally establish\n durable membership via the privileged provisioner; if it cannot be established, report `joined live`\n with the durable backstop unestablished, never `joined durable` (§7, §9).\n14. Bound history/backfill reads by the current read ACL, and re-authorize every durable-backstop read\n against the current read ACL (and, for `durable`-channel entries, membership) before surfacing\n content, treating a leave as a hard read boundary on the backstop (§7, §9).\n\nTest vectors use these sample principals (`<owner>.<actor>`); `<ownerA>` = `u_aaaaaaaaaaaaaaaaaaaaaaaaaa`,\n`<ownerB>` = `u_bbbbbbbbbbbbbbbbbbbbbbbbbb` (owner tokens are `u_` + 26 base32-lower, §2):\n\n- Alice: `<ownerA>.alice`\n- Bob: `<ownerB>.bob`\n- Reviewer role: `reviewer`\n\nSubject parsing. `parseSubject` **splits only** (§3): it recovers tokens by prefix and per-kind arity\nbut does NOT validate the owner token: a well-formed *split* is necessary, not sufficient, for a\nsubject to be surfaced as a delivery. The last row shows an old-shape alias that split-parses yet MUST\nbe dropped at the surfacing boundary (§9):\n\n| Subject | Result |\n| --- | --- |\n| `cotal.main.chat.<ownerA>.alice.team.backend` | `kind=chat`, `sender=<ownerA>.alice`, `rest=team.backend` |\n| `cotal.main.inst.<ownerB>.bob.<ownerA>.alice` | `kind=inst`, `sender=<ownerA>.alice`, `rest=<ownerB>.bob` (recipient) |\n| `cotal.main.svc.reviewer.<ownerA>.alice` | `kind=svc`, `sender=<ownerA>.alice`, `rest=reviewer` |\n| `cotal.main.ctl.manager.<ownerA>.alice` | no sender; v0 control subject, retired (§13.11): nothing serves it and it MUST NOT be handled |\n| `cotal.main.chat.<ownerA>.alice` | no sender; malformed (owner+actor but no channel token) |\n| `cotal.main.chat.UAQGWOEVJKMIO4WXSYOTLARXYOZTCXFK67JASEH6AFFFYK6FOPSKQCAD.team.backend` | split-parses (`kind=chat`, `owner=UAQ...QCAD`, `actor=team`, `rest=backend`) but MUST be dropped: `UAQ...QCAD` is not a principal owner token (§3, §9) |\n\nSample multicast message:\n\n```json\n{\n \"id\": \"018f1d0a-0000-7000-9000-000000000001\",\n \"ts\": 1710000000000,\n \"space\": \"main\",\n \"from\": {\n \"id\": \"u_aaaaaaaaaaaaaaaaaaaaaaaaaa.alice\",\n \"name\": \"alice\",\n \"role\": \"planner\"\n },\n \"channel\": \"team.backend\",\n \"mentions\": [\"bob\"],\n \"parts\": [{ \"kind\": \"text\", \"text\": \"Can you review this?\" }],\n \"contextId\": \"ctx-1\"\n}\n```\n\nSample unicast message changes only the routing field:\n\n```json\n{\n \"id\": \"018f1d0a-0000-7000-9000-000000000002\",\n \"ts\": 1710000001000,\n \"space\": \"main\",\n \"from\": {\n \"id\": \"u_aaaaaaaaaaaaaaaaaaaaaaaaaa.alice\",\n \"name\": \"alice\"\n },\n \"to\": \"u_bbbbbbbbbbbbbbbbbbbbbbbbbb.bob\",\n \"parts\": [{ \"kind\": \"text\", \"text\": \"Direct note.\" }]\n}\n```\n\nInterop scenario:\n\n1. Provision a space and credentials for Alice and Bob.\n2. Alice and Bob connect with inbox prefixes `_INBOX_<connId>` (per-connection, §2).\n3. Both write presence and join `team.backend`.\n4. Alice multicasts on `team.backend`; Bob receives with `kind=channel`.\n5. Alice unicasts to Bob; Bob receives with `kind=dm`.\n6. Alice anycasts to `reviewer`; exactly one reviewer receives with `kind=anycast`.\n7. A late joiner joins `team.backend`; replayed messages arrive with `historical=true` and\n live-tail duplicates at or below the join watermark are ack-dropped.\n\n---\n\n## 13. Endpoint control surface (v0.4)\n\nEverything on the mesh that serves structured commands (the manager daemon, the delivery\ndaemon, a wrapped MCP server, a third-party service) is an **endpoint**: a daemon that\nregisters a service identity, publishes its contracts, and answers `describe`. There is no\nspecial-cased service in this contract: `manager` and `delivery` are endpoint names like any\nother, and no subject or envelope in this section knows them. This section supersedes and\n**deletes** the v0 control rail (`ctl.<service>.<owner>.<actor>`, `ControlRequest`/\n`ControlReply`, the `self`/`manager`/`admin`/`delivery`/`delivery-admin` service tiers, and the\nreserved `control.<instance>` subject). The cut is hard (§13.11): no v0 control subject,\nenvelope, handler, or grant survives, and a pre-cut control credential cannot reach a post-cut handler.\n\nLayering: identity and transport are §2/§3, extended by the lifecycle identity below; §13.1\nidentity; §13.2 grammar; §13.3 envelope; §13.4 delivery contracts; §13.5 verbs; §13.6\ncomposites; §13.7 contracts and discovery; §13.8 distributed guarantees; §13.9 authority\nboundary; §13.10 receipts and signing anchors; §13.11 the hard cut; §13.12 the NATS binding;\n§13.13 plane ownership; §13.14 conformance.\n\n### 13.1 Lifecycle identity\n\nThe principal `owner.actor` (§2) is a **recyclable routing alias**: despawning an agent frees\nits actor name, and a later spawn may legitimately reuse it. An alias is therefore never\nsufficient *authority* identity on this surface. Two further identity components exist:\n\n- **Lifecycle UID** (`lifecycleUid`, one token `[a-z0-9]{26,32}`, ≥128 bits of CSPRNG\n entropy in a fixed canonical encoding): an unguessable, never-reused\n identifier of one managed lifecycle under a principal. The UID is entropy, never order:\n no allocator counter exists, and what is durable and monotonic is only the never-used\n set. Before anything else, the minting authority (the manager for managed agents; the\n provisioner for endpoint daemons and operator credentials; the auth service for user-mode chat\n sessions only, §10) **reserves the candidate UID\n space-globally**: a create-only write of the reservation key `uid.<lifecycleUid>`\n (§13.7), never deleted for the life of the space. A create conflict burns the candidate\n and draws a fresh one (the alias head alone cannot reject the same UID under a different\n alias, and the `gate.`/`cred.` families key by UID alone, so uniqueness must be\n space-wide); a DEL/PURGE marker on a reservation is corruption, never reusable absence.\n A reservation carrying `kind: \"native-service-uid\"` is reserved for service custody. Its\n closed shape is `{ v:1, kind, native:{accountPublicKey,space,lifecycleUid},\n assignment:{owner,actor,endpoint,instanceId,duty:\"serve\"},\n creation:{operationId,requestDigest} }`. Its embedded UID must equal its key. The actor is\n `svc_` followed by the lowercase base36 encoding of the unsigned SHA-256 of RFC-8785\n canonical JSON `[1,accountPublicKey,space,owner,endpoint,instanceId,\"serve\"]`, padded to\n 50 characters. Ordinary executors MUST refuse this reservation before mutation or\n idempotent root reuse and MUST NOT project it into an ordinary audit. Ordinary connect\n and currency paths also refuse it. No reservation creation, service credential release\n or terminal service transition is enabled by this reserved shape. Legacy ordinary audit\n bytes and their existing validation remain unchanged. Mixed-version writer exclusion\n and restore reconciliation remain prerequisites for any future service admission.\n A separate package-internal read-only service prerequisite accepts only the canonical active\n marked head, open native `gate.<uid>` generation1 and active exact root row, with all three\n `serviceCustody:{v:1,uidDigest}` mirrors matching the complete closed immutable reservation.\n Head `managerInstance` MUST equal reservation assignment `instanceId`, and native\n `processEpoch` is exactly1, independently of endpoint serving gate/witness epochs. Full\n configured account/space/UID/assignment, derived actor, root key/current stamp/holder,\n `sourceChain:[\"root\"]` and unexpired millisecond root expiry are checked with sealed\n primary leader-served readers. Account identity is trusted host configuration: sealed readers\n do not attest the broker account or detect a cross-account pair of legitimately constructed\n handles. Missing or mismatched native gate evidence refuses even if an endpoint gate exists.\n Creating/cancelling states and their RootPlan recovery cannot\n authorize through this active-only reader. It confers no writer, bootstrap, abort, rotation\n or terminal authority and makes no atomic multi-key snapshot claim. Ordinary readers stay\n closed to every marked service row.\n A package-internal custody writer, reached in the product only through the service endpoint\n host's decide and revoke (whose proposals nothing in the product creates), may advance one sealed\n reservation. Bootstrap order is reservation, pending-root endpoint gate, `service-creating`\n head, native gate created frozen at generation0 under the creation operation and opened at\n generation1, RootPlan `{credentialId,expMs}` fixed once by head CAS at\n `now + ROOT_CREDENTIAL_TTL_MS`, planned active root by zero-history create, identical-bytes\n native gate touch, then the active head stamp. The endpoint gate is re-read at open, before the\n plan, root and stamp steps and before every write attempt of those steps; a revoked endpoint\n stops bootstrap. Cancellation is\n endpoint-first: endpoint deny-new (on a registration freeze it revokes approval and keeps the\n registration op), `service-cancelling` head (an active head's stamp and its\n root row's expiry become the preserved plan), native gate frozen under the cancel operation,\n then root disposition. An unstamped planned root MUST be fenced only by a zero-history create\n of revoked bytes or a CAS of the exact active row; a stamped root is retained. Every result is\n nonterminal. An absent reservation leaves endpoint deny residue and reports unconfirmed; a\n foreign or tombstoned reservation refuses before any write. Each write is a per-key create or\n revision CAS under a genuine plane-claim hold re-read before and after it plus a fatal latch.\n This is local readiness control, not broker writer exclusion. Each broker request is bounded\n by `min(5s, remaining live authority)`, where live authority is the invocation's original\n deadline. In bootstrap, once the plan step has fixed or read the RootPlan, live authority is\n also bounded by the plan expiry. Cancellation keeps only its own deadline, so an accepted\n cancellation can still proceed after the root expires. A request still in flight at the\n live-authority bound ends held; the writer stops waiting for it but does not cancel it at the\n broker. CAS re-decisions, native gate re-pins and\n unknown-outcome rounds are capped at 4, 8 and 3, and an unknown outcome is classified by a\n leader read before any reissue. Endpoint-gate reads and writes are the writer's own leader\n reads and conditional writes built from pure package-internal rows, so no endpoint-gate\n request starts after an invocation returns. Bootstrap's final active-root proof is bounded the\n same way, but it is a sequence of read-only leader reads behind one wait: when that wait ends\n at its bound, the abandoned proof can still issue its remaining reads after the invocation\n returns. Those reads write nothing. An already-active head reaches that proof before any plan\n clip, so bootstrap MUST hold `plan-expired` rather than report an active root whose expiry a\n final synchronous check, made after its last read with no await before the return, observes.\n This does not make the result fresh when the caller receives it. The held check is the closure captured when the hold was\n acquired, not the hold's mutable guard field. A frozen activation native gate is valid only at\n generation0; any other frozen activation form holds. The deadline and reservation are\n caller-supplied original material, not durable host authentication.\n Only then does the ordinary minting authority mint **before the entity is reachable**,\n persisting a CAS-fenced\n mapping\n `{ owner, actor, lifecycleUid, managerInstance, processEpoch,\n state: active | retiring | retired, currentCredentialId?, lastTakeoverOpId?, op? }` (closed\n schema; the\n embedded `owner`/`actor` MUST equal the key's alias tokens, so a key-mismatched row\n never authorizes; `currentCredentialId` is absent until the credential ledger releases\n a root under the reopened gate; `lastTakeoverOpId` is the opId of the takeover operation\n that LAST advanced `processEpoch` (the epoch advance and this stamp are ONE head CAS, so a\n completion is bound to exactly one operation: a resuming barrier confirms the completed head\n carries ITS opId, and a LOSING concurrent takeover that captured the same pre-takeover\n coordinates finds a foreign opId and refuses, never claiming the winner's completion; absent\n until the first takeover); `op` is required at `retiring` and forbidden elsewhere)\n under the alias's **CAS head key** (§13.7:\n the **unsplit** `lifecycle.<owner>.<actor>` head key HOLDS this mapping as one atomic\n record, the single authoritative current mapping and the only source of `mappingRevision`,\n §13.9; the UID-suffixed `lifecycle.<owner>.<actor>.<lifecycleUid>` key is optional\n append-only audit, never the authority). `mappingRevision` IS the head key's store\n revision, learned from the publish ack or from the leader-served read that returned the\n mapping (one read returns `{ mapping, revision }`); the value carries NO revision field,\n and a body-supplied revision is never a CAS coordinate. Head states: `active` is the\n ONLY current state. `retiring` is the containment phase of the terminal barrier (below),\n bound to the retirement operation's `op.opId`; it is non-current and NOT replaceable.\n `retired` is terminal and asserts the barrier COMPLETED (the cleanup proof), which is\n what makes replacing a retired predecessor safe. **Every currency seam fails closed on\n both non-`active` states**: target resolution, the process-epoch reads gating\n record/status writes, admission/start, and supervision derive current authority only\n from `state: \"active\"`; `retiring` and `retired` alike yield no current mapping and no\n current epoch. Activation is the head CAS (create-only for a virgin alias;\n revision-pinned from a `retired` predecessor), so two concurrent mints for one alias\n serialize there and exactly one activates; the loser terminalizes its own orphan gate\n and burns its reserved UID, never deleting either (`currentCredentialId` is a public key\n identifier/fingerprint plus authority epoch, never secret material). A supervised restart\n of the same entity **preserves**\n the UID (revoking/rotating the connection credential and advancing the process epoch); a\n terminal despawn, explicit stop, or supervision escalation retires the UID through the\n terminal barrier *before* the alias is freed. A retired UID is never reactivated\n (`retired → active` for the SAME UID is forbidden; only the ALIAS is replaceable, by a\n freshly reserved UID); recycling cannot move to the reservation, which is never freed.\n- **Process epoch** (`incarnation`, an unsigned integer): the fenced ownership epoch of the\n process currently animating an identity, advanced by CAS on every takeover or restart. At\n most one live epoch owns an identity; a superseded process MUST stop serving and its commits\n are rejected (§13.8). **The epoch fences egress only**: reply, event, timer, session, and\n record-write-ingress publish grants pin it (§13.9), but request subjects deliberately omit it; a caller cannot\n know the serving epoch, so **no subject-level fence for ingress exists or can exist**. An\n un-revoked superseded serve credential remains a member of the class queue group and can\n consume (and externally effect, and never validly answer) one call in N. Takeover therefore\n carries a **normative barrier, in order**: freeze issuance for\n the lifecycle in the credential ledger (below) → revoke EVERY active credential-ledger\n row under the lifecycle prefix, every root (the superseded `currentCredentialId` and any\n earlier unexpired root: each root mint, initial or rotation, writes its own ledger row)\n and every ledgered descendant (handle-redemption-minted and per-session credentials,\n §13.6), via the deployment's auth\n authority, verifying the updated revocation state is enforced on EVERY server of the\n cluster before proceeding (fail-closed on partial acknowledgment: an unrevoked-anywhere\n credential can reconnect there) → evict the live connections of every revoked\n credential's `holderPrincipal` (from its ledger row, above)\n cluster-wide and verify the re-scan found none, the barrier executor (the trusted auth\n path) holds the delivery endpoint's `evictPrincipal` capability for exactly this step\n (Appendix B: granted to the barrier executor, not only `supervisor`); `evictPrincipal`:\n system-account CONNZ scan → per-server KICK → re-scan verify, fail-closed on partial\n scans; Appendix B) → **only THEN advance the process epoch by CAS (N→N+1), reopen the gate\n at the new generation, and activate the successor's serve subscription**. The epoch CAS is\n LAST, not first: a superseded process is revoked and evicted before the successor's epoch\n exists, so it cannot publish a reply or event in a window between the CAS and the eviction;\n the egress epoch is honest attribution precisely because no live predecessor egress survives\n the barrier. (A reply the predecessor emitted for an in-flight call before eviction reaches\n a caller only within that caller's own deadline and from a not-yet-evicted process; the\n barrier's job is that no such process remains once the successor answers.) Where\n revocation or verified eviction is unavailable (e.g. static credential material\n pre-rotation, Appendix B), takeover MUST fail loud rather than proceed.\n\n**Retirement-only composition.** A manager instance MAY run as a retirement-only composition of\nits own commit path. Its first durable act MUST be to acquire the per-instance liveness lease of\nits own persisted logical `instanceId`; it MUST NOT read a lifecycle, slot or gate row before\nthat lease is held, and it MUST exit without effect if the lease is held by another process. It\nMUST NOT register or serve the endpoint, hold the renewal lease, accept spawn or launch, adopt or\nrestart a seat, or run the resume path. It drives only the terminal retirement of non-retired\nlifecycles whose slot names its own logical `instanceId` as owner, through the same operation\nidentity an ordinary instance would use, then releases the lease and exits. For every slot it\nreads it records one outcome: `retired`, `already-retired`, `skipped-not-owned` (the slot names\nanother owner or none), or `held` (the slot or its head could not be read or parsed, or the\nterminal did not complete). A `skipped-not-owned` or `held` slot is never counted as retired.\nIt is the minting manager's commit path for the purposes of the §13.9 lifecycle-mapping writer\nrow; no other principal, credential profile or grant is introduced.\n\n**Credential ledger (normative).** Ingress has no epoch fence, so revocation is only as\ncomplete as the set of credentials it covers, and the lifecycle's `currentCredentialId` is\nnot that set. Every credential the trusted auth path mints **derived from** a lifecycle (the\nshort-lived credential of a handle redemption, the two per-session credentials of a session\nredemption, §13.6) is recorded at mint time in a durable, auth-owned **credential ledger**\nrow `{ credentialId, holderPrincipal (the `<owner>.<actor>` whose connections the barrier evicts; the credential id is NOT the principal, and eviction is by principal), lifecycleUid (the holder's), sourceChain: [root |\nhandle.<issuerKeyId>.<id>… | session.<sessionId>], the FULL verified lineage: for a\nhandle redemption, EVERY handle in the presented `parentDigest` chain (§13.6), never only\nthe leaf, state: active | revoked (monotonic), exp }`, keyed\n`cred.<lifecycleUid>.<credentialId>` so both barriers enumerate a lifecycle's full descendant\nfamily by key prefix. Each mint additionally writes one reverse-index key\n`bysrc.<issuerKeyId>.<id>.<lifecycleUid>.<credentialId>` per chain member, so **revoking a\nsturdy handle revokes every credential minted under it or under any of its descendant\nhandles**; a credential redeemed through a child handle carries the parent in its\n`sourceChain`/`bysrc` keys, so parent revocation reaches it without walking handle records.\n**Source gates.** The same fence applies per issuing handle, because a handle's revocation\nstate lives in the records bucket while credential indexes live here, and two buckets share\nno order: each sturdy handle has an auth-bucket gate `srcgate.<issuerKeyId>.<id>`\n(`{ state: open | frozen }`, CAS). Handle revocation CASes the source gate to `frozen`\n**before** it enumerates `bysrc.`, and a redemption, after writing its `cred.`/`bysrc.`\nrows, revision-pinned-CASes the source gate of EVERY handle in the presented chain (plus the\nlifecycle gate below), releasing only if all are still `open` at their observed revisions. An\nin-flight redemption under a handle being revoked therefore either finishes before the freeze\n(its rows are in the enumeration) or loses a CAS and never releases. **Handle revocation\ncarries the SAME cluster-wide eviction as a lifecycle barrier** (§13.9 `evictPrincipal`):\nafter freezing the source gate and enumerating `bysrc.`, revocation revokes every descendant\ncredential AND verifies revocation enforced on every server, then evicts and re-scans the live\nconnections of every revoked credential's principal, fail-closed, an already-connected\ndescendant credential is never silently left with live grants. The handle status write is\nacked only after that eviction is verified complete.\n\nAn unledgered mint MUST NOT occur (the ledger write precedes credential\nrelease, fail-closed), and the rule carries a mechanical audit invariant in the style of the\n§13.9 matrix grep test: every credential the auth authority has ever released MUST resolve\nto a `cred.<lifecycleUid>.<credentialId>` row; an issuance path that cannot show its ledger\nrow is non-conformant, auditable by diffing issued-credential ids against the ledger.\n\n**Issuance gate (normative).** \"Freeze issuance\" is a durable transition, not an assertion:\neach managed-agent lifecycle has a gate key `gate.<lifecycleUid>` in the same auth KV,\n`{ state: open | frozen | retired, generation, op? }` (CAS). A `frozen` gate MUST carry a\ndurable **operation intent** `op = { opId, kind: activation | takeover | registration |\nretirement, successor? }`: after a crash the intent alone\ndecides WHICH operation a frozen gate belongs to and what may advance it, a retry or\nreconciler resumes the SAME `opId`, and a writer that is not that operation's executor\nMUST NOT advance, reopen, or terminalize the gate.\n**A crash can leave the gate frozen under an operation whose executor no longer exists**, and\nfail-closed then blocks every restart while protecting nothing. An operator-facing reconciler\nMAY complete that dead operation's obligation — resuming its SAME `opId` and reopening at the\nUNCHANGED coordinate with `generation` advanced by one — but ONLY after it has AFFIRMATIVELY\nverified that the gate's freeze-holder principal is gone, via the same liveness machinery the\nbarrier's eviction trusts (`principalLiveness`, §13.9). A holder that is alive, or whose\nliveness cannot be proven, MUST refuse; a timeout or an incomplete sweep is unknowability and\nMUST NOT be read as death. The affirmative check is a PRECONDITION ON TOP OF the barrier's own\nverified eviction, never a replacement for it. A `retired` gate RETAINS the\nterminalizing operation's intent as audit, and an idempotent terminal retry succeeds only\nfor that SAME operation. **Successor coordinates are per-kind and derivable, never loose\nprose**: an `activation` or `retirement` intent carries NO `successor` (an activation's\nsuccessor IS the head mapping the same operation writes; a retirement has none); a\n`takeover` or `registration` operation's successor artifacts are durably keyed by its own\n`opId` (the `stage.<opId>.` staging family and the operation's audit rows), so\n`{ opId, kind }` alone resumes deterministically. The gate MAY carry a `successor` summary\ntoken for those two kinds, but the staged rows are authoritative and a resumer MUST NOT\nact on a summary that the staged rows do not corroborate. **Allowed transitions are also\nper-kind**: a gate is BORN `frozen` only under an `activation` intent (and only for a UID\nwhose `uid.` reservation already exists); `open → frozen` belongs to `takeover`,\n`registration`, and `retirement`; `frozen → open` (reopen) belongs to `activation`,\n`takeover`, and a `registration` abort, NEVER `retirement` (a retirement freeze never\nreopens); `frozen → retired` belongs to `activation` (a head-CAS loser terminalizing its\nown orphan gate) and `retirement`, NEVER `takeover` or `registration` (those abort by\nreopening). An implementation MUST refuse a transition whose gate op kind is outside these\nsets, before any CAS is attempted. The `opId` is an identifier, never a\nbearer capability: a resumer re-authenticates as the operation's executor, and possession\nof the id alone grants nothing. `retired` is terminal, a retired\nlifecycle never mints again. `frozen` is **not** terminal, because a supervised restart\npreserves the UID (§13.1) and must mint the successor process's root credential: the\ntakeover barrier freezes at generation `G`, completes revoke + verified eviction of the\nfamily, and only then CASes the gate to `open` at generation `G+1`; the reopen is the\nbarrier's own final step, so no credential of generation `G` is ever live when generation\n`G+1` mints. A gate reopen by anyone but the completing barrier is non-conformant.\n**Endpoint instances use a disjoint gate family, distinguished by explicit prefix and\nnever by token arity**: the endpoint issuance gate is `epgate.<endpoint>.<instanceId>`,\n`{ state: open | frozen | retired, generation, processEpoch, registrationRevision,\nnameAuthorityRevision, principal, op? }` (the endpoint fence coordinates of §13.5/§13.7, plus\n`principal`: the serving instance's own CONNZ-attributable connection principal, recorded at\nregistration), and\nendpoint-derived credentials ledger under `epcred.<endpoint>.<instanceId>.<credentialId>`\nwith the same row schema, mint protocol, gate discipline, and never-delete rules as\n`cred.`/`gate.`. An interrupted endpoint registration repair MAY journal verified evictions\nunder the disjoint cursor key `eprepair.<endpoint>.<instanceId>`. A cursor MUST bind the exact\nregistration `opId`, the observed frozen-gate KV revision, and the sorted distinct holder set.\nA holder is appended durably only after its eviction verifies, and the holders one eviction sweep\nverified are appended before the next sweep is attempted. A retry MUST repeat the freeze-holder\nliveness precondition, MAY skip only holders in a cursor whose complete binding still matches, MUST\nrestart from empty progress on any mismatch, and MUST reopen only after every current holder\nverifies. Cleanup occurs after reopen; a cursor that\ncannot be deleted cannot authorize a later freeze because that freeze has a different gate revision.\n\nA standalone user-authorized service gate adds `authorityFamily: \"service\"` and a required\n`serviceAuthority` value. Its closed fields are `v: 1`, `assignmentDigest`, native\n`lifecycleUid`, `state: pending-root | approved | revoked`, `rootCredentialId`, `rootExpiresAt`,\n`approvalDigest`, `approvalExpiresAt`, `callerCeiling`, `activationIssued`, and optional\n`registration: {operationId, requestId, requestDigest, processEpoch, registrationRevision,\nnameAuthorityRevision, registrationProof}` and\n`pendingRegistration: {operationId, requestId, requestDigest}`. Expiries use Unix seconds.\nThe completion stamp's coordinates must equal the gate's. A positive registration revision\nrequires a completion stamp. A pending identity is present only under its matching registration\nfreeze, and activation cannot be recorded while that identity is pending.\nA pending-root value has null root and approval fields, an empty ceiling, no registration and\n`activationIssued: false`. An approved value binds the native root and immutable approval;\nonly approval expiry may be null. Revocation retains any existing binding. An activated value\nrequires the registration stamp. A service value without its family, or the family without\nits value, is invalid. Existing nonservice gates do not acquire this authority. A §13.6 session\nnever serves on a service gate: the session's serving-gate read refuses the service family before\nit returns a pin or stages a ledger row.\n\nService registration freeze requires live approval and `activationIssued: false` at the gate CAS.\nUnder that freeze, a complete leader read must prove the issuance family empty. Active, revoked,\nmalformed or deleted credential evidence is inconsistent with pre-activation state and blocks\nregistration and recovery. Failed or partial reads never prove emptiness.\nGate transitions retain approval, root and activation fields. A new registration freeze retains\nthe prior completion stamp and records the new operation's request identity and digest. Successful\nreopen writes the new completion stamp and resulting coordinates in the same CAS. A definite\nabort-reopen preserves the prior stamp. Both paths remove the pending identity. Recovery binds\nthe recorded operation; an open surface alone cannot establish which request completed.\nA separate post-reopen writer cannot attach a completion stamp.\nServing release requires live approval,\nrecorded activation and a finite credential expiry bounded by the service access lifetime,\nnative root expiry and approval expiry. Release rechecks the fixed expiry after asynchronous\nstaging and commit; expired material is refused and never given a new expiry. A registration recovery that reopens an already revoked\napproval does not authorize serving release. Standalone service authority does not support\nsibling credential duties. Native root validation, owner consent, activation and coordinated\nretirement remain requirements of the trusted host; parsing this value does not establish them.\n\nNative application-service name bindings use `servicename.<endpointToken>` in the primary auth store.\nThe closed record has `v:1`, `kind:\"service-name\"`, accountPublicKey, space, endpoint, owner,\nclaimReference, requestId and requestDigest. The trusted host authenticates operator authority and\nverifies the namespace claim before creation. A stored assertion alone proves neither of those checks.\nCreation requires zero retained key history. Only an identical request can recover the binding;\nchanging its owner, claim or request identity does not update it. Owner and binding revision are read\nfrom one leader snapshot. Transfer and release are unsupported. Native auth, delivery and manager\nnames remain with their existing control authorities and cannot be application-service bindings.\n\nNative service caller policy is stored at `servicepolicy.<granteeUid>` in the primary auth store.\nIts closed value is `{v:1,accountPublicKey,space,grantee,grants}`; grantee is the exact owner, actor\nand lifecycle UID. A grant contains its immutable id, endpoint and source instance, approval digest,\nnormalized capabilities, source and parent references, and status. Source and parent references\nname immutable grant ids at their original grantee UIDs. Source instance is provenance; native\ncapability route and instance fields still determine request reach.\n\nInitial policy and create-only service authority writes require zero prior key history at the\nwrite CAS. A deletion or purge marker, including one arriving after an absence read, MUST refuse\nrecreation. An additional pre-read is not this fence.\n\nA new grant is appended at the observed policy revision. An existing id cannot change its capability\nor provenance and cannot become active again after revocation starts. Revocation first records\n`{state:\"revoking\",operationId,phase:\"cutoff-required\"}` at that revision. Unrelated writes preserve\nthis intent. Repeated same-operation reads do not advance it or establish terminal retirement.\nDeleted, malformed or unreadable policies are not empty policies. Stored syntax and successful CAS\ndo not establish current grantee, service, granter or ancestor authority; the native host must verify\nthose before committing or using a grant. Neither a policy row nor a deny-new intent proves live\nconnection absence.\n\nNew caller-policy appends MUST reserve serialized status-growth headroom for every grant\nsimultaneously under the unchanged 2 MiB policy limit. Compute canonical policy bytes plus each\ngrant's nonnegative remaining growth to the largest supported closed status, including a\n512-character marker and maximum safe-integer revision/time fields. Refuse before the append CAS\nif that worst-case total exceeds the limit. This is not a retroactive repair of older near-cap\npolicies: their bytes and grant history remain unchanged, append refuses insufficient headroom,\nand revocation can still fail the byte bound. Such residue blocks service writer/admission\nenablement pending a separately authorized compatibility protocol. No cap raise, pruning,\nreactivation or terminal absence claim follows from the headroom check.\n\nNative service host operations keep five closed record families in the primary auth store:\n`svcop.<operationId>` (one request's binding), `svcprop.<proposalId>` (a proposal),\n`svccap.space` (the space's pending-proposal capacity), `svcasg.<endpointToken>.<instanceId>`\n(one selector's assignment) and `svchost.admission`. The operationId is the first 32 lowercase hex\ncharacters of SHA-256 over `cotal-service-host-op`, NUL, space, NUL and requestId, so one id\nnamespace covers every host request in a space. A binding stores the canonical request digest; a\nreused requestId with any other body is a conflict and is never rebound. Every create requires zero\nretained key history, and a deletion or purge marker at any of these keys refuses and is never\nrecreated. No record carries a TTL, and none is deleted or purged. A live operation or proposal\nbecomes terminal only by a CAS on the same key, after every write it depends on is durable.\n\nEach write is one create or one exact-revision CAS on one key; there are no multi-key batches.\nAn invocation writes only its scope: the exact keys its discovery read located before the\ninvocation's effect connection opened, which are its own records and, for a located reservation, the\nnative custody keys of that one reservation. Only an approval's scope holds the reservation's UID\nkey; a revoke's never does. A step that needs a key outside the scope holds as `scope-mismatch`\nbefore anything is issued, including before native custody of a reservation the scope does not name.\nA replay of the same request discovers the stored binding and assignment and scopes them.\nEach invocation's effect connection is a fresh self-minted data-account identity named\n`cotal:service-host-effect:<space>`. Its credential publishes exactly the scope's keys as `$KV`\nsubjects, and one more token under each auth family, beside the leader reads both stores need;\ndiscovery's credential publishes no `$KV` subject at all. That grant confines publish subjects only;\nit does not restrict what a publish on a granted subject does, and the engine's own writes are only\ncreates and exact-revision CASes on those keys. Reads are not confined: the leader reads\nare stream-wide on both stores. The effect credential never renews or reconnects. Its one expiry is\nthe invocation's original deadline, at most 60 s ahead, rounded up to the whole second. The broker\nchecks expiry in whole seconds against its own clock: it admits no connect once its current second\nis past that expiry, and it closes a live connection with one whole-second timer armed at connect.\nWith a broker clock that agrees with the host's and timely broker and client scheduling, that close\ncomes within the second after the expiry, up to about 1999 ms after the deadline. This is timer\ngranularity, not a guaranteed close time: a skewed clock or a paused or late broker or client moves\nthe close either way. Neither the expiry nor the close is proof that an earlier write cannot still\nsettle. Losing the effect connection fences the invocation: a later write holds, and a write\nin flight across the loss reports held. An effect connection that does not open holds as\n`unavailable` at `effect-open` with nothing written.\nRegister reads admission, capacity, the selector's assignment and the name binding first. An initial\nrefusal writes nothing and binds nothing. Otherwise the binding is created before the capacity CAS\nand the zero-history proposal create, whose times are fixed once in the binding. A refusal found\nafter the binding exists is recorded on it. Capacity counts entries whose `expiresAtMs` is still in\nthe future: at most 256 per space, 32 per owner and one per selector. Clock skew between writers\ncan under-count that bound; it never extends authority. Past a register's own bound an absent\nproposal key is fenced with a terminal `expired` tombstone, so a delayed create loses. Every close\nwrites the proposal's terminal record before it releases capacity. An unobserved release stays as\nrecorded debt until a later read observes it.\n\nAn approval binds before its first effect, then moves the proposal to `approving` at the admitted\nrevision, creates the assignment, runs native custody bootstrap and writes the endpoint-gate approval\nCAS. No authority-increasing step starts at or after the operation's original deadline, which is at\nmost ten minutes after admission and never past the proposal's expiry. An endpoint gate carrying\nthe approval's digest, approved or later revoked, proves that approval landed; a landing observed\nafter the deadline is recorded as a historical result, not current readiness. An expired approval\nthat holds an assignment binds its own cancel identity in that assignment, or adopts the one\nalready bound, and cancels natively.\nThe assignment record carries the complete native cancel identity `{operationId, requestDigest,\ncause}`. Any authorized revoker can cancel from that record alone, and the first binding wins.\nDeny-new has landed exactly when the endpoint gate reads `revoked` for this assignment. After that, an\n`approving` proposal of the assignment closes as `approved` when the gate carries an approval digest\nand as refused otherwise. A gate row at the key that belongs to another assignment is no evidence\neither way: every revoke path that reads the gate reports deny-new `unknown` for it, as for a failed\nread; an already fenced assignment is its own evidence and reports `landed`. Revocation stays\nnonterminal. Owner-scoped reads authorize against the subject owner fixed at binding, and terminal views carry no commands or cluster digests. None of these\nrecords proves a human decision, broker writer exclusion, restore readiness or terminal retirement.\n\nAn authority plane opened with `serviceEndpoints` hosts these operations; without it, the default,\nthe plane opens no service host, no discovery connection and no `svchost.admission` write. The host\nuses the plane's own claim hold, data account and actor ledger directory. Its startup MUST be named\n`normal`: a restore or a missing startup refuses the whole plane open, which unwinds what it opened\nand releases the claim. If that unwind cannot close an effect connection, for instance the startup\nadmission write's, it stops there. The open still refuses, but with the close failure; the claim stays\nheld; the cleanup timer, discovery, both scanners and every client opened so far stay live; and no\nhandle exists to retry. Until the process exits, a successor cannot reclaim the claim while those\nscanners live; after exit, the existing crash reclaim applies. Discovery is one standing connection named\n`cotal:service-host-discovery:<space>` on the ordinary renewing profile with the read-only grant. A\nbroker loss makes its reads fail until the stock client reconnects; a read that fails answers as\n`unavailable` within its invocation's own limit, with nothing written. A renewal failure closes it\nfor good, and every later read through it fails until the plane is opened again; nothing reopens it.\nBoth plane fatal paths, a scanner death and a failed native-issuance cleanup, trip the host's fatal\nlatch, and a fence that lands while the host is opening latches it once it exists. A scanner death\nor a failed cleanup while the plane closes still trips the host, so a call close is draining stops at its next step, but\nit does not make the plane fatal. From the moment\nplane close is called it refuses every host call, before it waits for anything. It then waits until\nevery call that entered before it has returned, including one still reading discovery or opening its\neffect connection. An effect connection whose close failed stays owned by the plane after its call\nhas settled, and that call rejects with the failure. Close closes every such connection again and,\nwhile one remains open, rejects with the claim still held, so a later close retries it; a request\nthat was only rejected does not hold close. A close rejected that way has already stopped the\ncleanup and sweep timers, but discovery, the administrative rail, both scanners and the remaining\nclients stay live, so no successor can reclaim the claim until a later close succeeds or the process\nexits. Only then does close close discovery, and only after that does it release the claim. Close\nitself trips no call it waits for: each ends under its own discovery-read bound and invocation\ndeadline, each at most 60 s. Its own scanner teardown, after that wait, does trip the host, which by\nthen has no call in flight, and does not make the plane fatal.\n\nThe plane and a hosted context expose `decide`, `revoke`, `name-bind`, `operation-read` and\n`proposal-read` as one in-process function; a hosted context refuses it as `unavailable` while it is\nnot ready. The host checks an owner granter's current interactive row but authenticates no caller:\nthe embedder MUST authenticate the granter it passes, operator or owner. The stock auth service\nserves that function on `POST /service-endpoint-host` when started with `--service-endpoints`, or\nas a lane of `auth-service --spaces` whose manifest entry sets `serviceEndpoints`: the\nbody is `{ idpToken, request }` with no granter, the route verifies the IdP token and derives the\ngranter itself. `decide`, a revoke whose cause is `owner-request`, the four caller-policy operations\n(`caller-grant`, `caller-revoke`, `caller-policy-read`, `caller-policy-list`) and the reads\n(`proposal-read`, `operation-read` and `name-read`, each scoped to the owner's own records; a\nproposal read names its endpoint's binding only when that binding is the owner's) run as the proved\nowner on either face; `name-bind`, any other revoke and the admission operations are the operator's\nand are served on the loopback face under the exchange capability only, with the proved subject as\nthe audit id. The admission operations have no engine handler in this cut and answer `unsupported`.\nThe engine's answer, replay included, is returned as is. Host requestIds share one space-wide\nnamespace, so a client MUST mint them unpredictably (16 random bytes); a guessable id can be bound\nfirst by another owner.\n\n`name-bind` is create-only and needs an operator granter. Its `expectedRevision` MUST be 0; any other\nvalue answers `unsupported`, and a native control endpoint name is refused. It issues one\nzero-history create of `servicename.<endpointToken>` through its invocation's custody host, whose\nscope and effect credential hold only that key. The row binds account, space, endpoint, owner, the\noperator's `claimReference`, requestId and the canonical request digest. Only the identical request\nrecovers an existing row; the same requestId with another body is a `conflict`, and any other request\nfor a bound name is `name-bound`. Nothing updates, transfers or releases a binding. The host verifies\nno domain control: the claim reference is the operator's assertion, and an unused name is no proof.\nA `held` name binding names its requestId's deterministic operation coordinate, which no operation\nrecord carries; it recovers only by replaying the same request.\n\nThe public route `/service-endpoint-authority` exists only with `serviceEndpoints`, on both faces;\nwithout it the route answers 404. `GET` returns `{v:1, kind:\"service-endpoint-authority-info\", space,\naccountPublicKey, issuer, keys}` for the receiver's own account with `cache-control: no-store`:\n`issuer` is the exact `iss` its service access bearers carry and `keys` the Ed25519 verification\nkeys it publishes at `GET /jwks`, public coordinates only (`kty`, `crv`, `kid`, `x`, at most 16),\neach a canonical encoding of a full-order point; a key of small order is refused on both sides. A\nguest verifies its access bearer under them before it brands its serve grant (§13.6). A door that\npredates the identity answers the four account fields alone, and a guest that needs it refuses to\nserve rather than brand unverified. `POST` takes one\nenvelope of at most 2 MiB. The proof is the credential on either face; the loopback capability is\nnever read. A request naming another account or space is refused before its proof is used. The proof\nkinds each operation admits are fixed: register needs IdP; activate needs IdP or a renewal proof;\nrenew needs a renewal proof; ready needs an access proof; status admits all three. Any other pairing\nis bad shape (400). An IdP proof verifies under the pinned issuer and exact audience, and its subject\nderives the owner, who also needs a current interactive cli or web row. A renewal or access proof\nverifies against this context's own issuer keys and yields its signed witness, never an owner's\nauthority: its owner is the witness's, and a request that carries a witness must carry the proof's.\nStatus carries none, so a renewal proof's own witness is the expected one. A refused proof counts\nagainst the face's refusal budget and answers 401, or 429 once that budget is spent; a valid proof\nnever consumes it. Protocol answers are 200 for `registered`, `credential`, `ready` and `status`, 202\nfor `approval-required` and `pending`, and for `denied` 409 on a conflict, a closed proposal or a\nmoved registration, 422 on refused input, 429 on a bound and 403 otherwise. An answer that cannot be\ncompleted after the proof, an unread, unknown or inconsistent record, or a `held` engine answer is a\n503 with no protocol echo, because the request may already be bound.\n\nRegister compiles the submitted closures in memory. Each cluster digest names a submitted manifest\nwhose root names a submitted cluster document, each verified against its content digest. The schema\nclosures the commands reference (each `inputDigest` and `outputDigest`) MAY be submitted with them;\na submitted one is admitted only whole: its manifest at that digest, its root and every member\npresent, and the bundle recompiling to that closure digest. Every artifact must belong to a declared\ncluster closure or to a referenced schema closure. A schema closure that is not submitted is not\nrefused: the host publishes the canonical void closure itself when it opens service endpoints, and\nany other schema closure is the registrant's to publish. The proposal's commands are exactly those\ndocuments' declarations; a journal-class command, or one declaring a governed trait (`ai.cotal.guarded`,\n`ai.cotal.priced`), is refused as `unsupported-runtime`, in the proposal phase and the registration\nphase alike. A native control endpoint name (`auth`, `delivery`, `manager`) is refused as\n`permission-denied` before any effect and binds nothing. The engine requestId is the first 32 lowercase hex\ncharacters of SHA-256 over the canonical JSON `[\"cotal-service-endpoint-authority\", 1, account,\nspace, owner, endpoint, instanceId, operation, requestId]`, with the derived owner, so the full public\nidempotency key selects the binding. That binding's request digest covers the public request's\ncanonical digest, which excludes the proof: a changed public body under the same key is a\n`conflict`.\n\nRegister has two phases, chosen by the derived owner's assignment at the selector. Until that\nassignment's endpoint gate carries an approval (no assignment, or one whose approval is still\nsettling), register is in its proposal phase, which takes only `expected:{state:\"unregistered\"}` and\nanswers `conflict` for any other. A first admission answers `approval-required` with the proposal id\nand digest. A replay answers from the proposal as it is now: `approval-required` while it is live and\nunexpired, also while its approval is in progress; `pending` at phase `approved-unregistered` if its\napproval landed after the phase was read; and `denied` once the proposal is refused or expired or its\napproval revoked. An undecided proposal reads as expired once the whole second of its expiry has\npassed, before any tombstone closes it. The door never answers expired before the host would refuse\nits approval, but its other answers can trail the expiry: an undecided proposal can still read\n`approval-required` or `proposed` for up to one second after it; a proposal whose approval is in\nprogress answers `approval-required` to a replay and `proposed` to status, with no expiry mapping on\neither, until that decision settles; and a first admission's `approval-required` is computed when the\nproposal is created, so an admission that was held and settles on a later replay can produce it after\nthe expiry, not only deliver it late.\n\nOnce the gate carries an approval, register is in its registration phase, and so are activate, renew\nand ready. Each of these requests, in order: proves its caller as above; resolves the caller's own\nassignment at the selector before any read by request key, so another owner or a selector with no\nassignment answers `permission-denied` (a revoked one `approval-revoked`) and any witness the request\ncarries must name that assignment's selector, owner, serving actor and lifecycle UID; reads its\nintent `svcint.<id>`, where `id` is the engine's operation id of the request's engine requestId; and,\nonly when no intent exists, checks the state the request needs. A register key keeps the binding its\nproposal phase gave it: the operation record of the same id, when one exists, must be a register\nadmitted with this body, else `conflict`, and must name the approved proposal; a key whose proposal\nwas refused or has expired answers `proposal-refused` or `proposal-expired`, as its proposal-phase\nreplay does, and any other proposal is `conflict`. Both are decided before the state check and before\nanything is written. A registration needs a bound\nassignment with no cancel identity, an approved gate without `activationIssued`, a recompiled surface\nwhose proposal digest equals the approved proposal's, and an `expected` that matches the current\nregistration stamp exactly (no stamp for `unregistered`); refusals are `approval-revoked`,\n`registration-active`, `approval-mismatch` and `conflict`. Activate, renew and ready need their\nwitness to be the current stamp's, else `stale-witness`. A new admission then lists its id in the\ninstance's index `svcintx.<endpointToken>.<instanceId>`, which is created with the assignment's owner\nand checked against it on every read; an id already listed takes no slot, and a 65th id is\n`resource-exhausted` (429) before any effect. It then creates its intent with zero history. The\nintent records the operation, account, owner, selector, the public requestId and digest, the\nregistration the request names (register's expected one, or the request witness's) with that\nwitness's digest, and its admission time. No proof, token or reply is ever stored. An existing intent\nwith another digest is a `conflict` before any state check, and a create that loses to an equal\nintent is a replay. Intents and the index are never updated, pruned or deleted in this cut: they\nstay for the assignment's lifetime, and an id listed without an intent (a stop between the two\nwrites) stays listed.\n\nEvery effect is then evaluated against current native state. A registration answers\n`approval-revoked` first if the assignment is revoked. Otherwise, when the current stamp names this\nrequest (requestId and digest), it answers the top-level `registered` with that witness and snapshot,\nbefore or after activation and readiness: no barrier, no epoch advance and no artifact publish.\nOtherwise it answers `registration-active` once activation has been issued. A gate frozen by this\nsame request's operation resumes with no further check here; any other request requires the gate\nopen (else `registration-pending`), `expected` to match the stamp (else `conflict`), and a live\napproval (else `expired`). It then publishes each submitted artifact\ncreate-only to the contract store and runs the native registration barrier and spec registration\nunder the request's operation id, with no repair cursor (a service's credential family is empty\nbefore activation). The barrier freezes the gate revision it observes after those publishes\nwhenever the gate is not frozen by this request's operation, which includes a request that read it\nfrozen and finds it reopened, and the request checks again on exactly that revision before anything\nis frozen or written: a stamp that already names this request answers as a replay does, and a gate\nthat moved answers `conflict`, or `approval-revoked` once revoked; those answers are definite. A\ngate the recheck finds frozen by this request's own operation with no stamp yet is another\ninvocation of the request still running, so this one is held and answers 503, and its replay resumes\nor recovers it. A request whose barrier observes the gate already frozen by its own operation\nresumes with no recheck. A refusal the native barrier makes itself, such as a gate it observes\nfrozen by another operation or a freeze it loses after the recheck held, is a held step that answers\n503. It answers `registered` only once the stamp names this request. A first\nregistration keeps process epoch 0; a pre-activation re-registration advances it. Activate requires\nthe gate open with a live approval and native root, the request witness to be the current stamp's,\nand then lands the monotonic `activationIssued` CAS unless it already holds. Renew requires the same\nand an activated gate, and writes nothing. Both answer `credential` with a fresh access bearer and\nrenewal proof whose expiries are fixed when the door admits the request: at most 60 s and 24 h, and\nnever past the native root's or the approval's expiry. Material that cannot be minted is `expired`\nonly once its fixed access expiry has passed; any other failure answers 503, and the replay mints.\nA replay of either mints replacement material for the same current registration; earlier material\nkeeps its own expiry. Ready requires the same as\nrenew, plus the native name binding at the witness's revision, and writes the service-reported status\n`ready` at the witness's process epoch and spec revision, with `reportedAt` in Unix seconds, fenced on\nthe gate's epoch. It answers `ready`. Every write of a serving request goes through its own\ninvocation, whose effect credential publishes exactly its intent and index keys and that operation's\neffect keys (the endpoint gate for register and activate, the spec and governance head for register,\nthe status for ready), and publishes and reads back exactly the submitted artifacts. The\ncredential also grants an exact Direct Get on each records key the operation reads, but the\nregistry's KV handles are bound without Direct Get: every auth and records read of a serving\neffect is a leader message get (`STREAM.MSG.GET` last by subject) under the base read grant. The\nnative registration and the ready status write through their own\nclient on that connection, and a fatal latch closes the connection, so none of their requests is\nissued after the fence; a request already issued stays unknown.\n\nA serving client keeps one requestId per (operation, witness), persisted with the witness and its\nrenewal material in its single-owner store before dispatch, and reuses it, with an unchanged body,\nafter a restart. Only a pre-activation re-registration produces a new witness and so new keys. An\nactivated instance therefore needs a handful of keys for its life, and the 64-intent bound is\nreached only by a client that draws fresh keys.\n\nStatus takes `target:{kind:\"instance\"}` or `target:{kind:\"operation\", operation, requestId}`, where\n`operation` is one of `register`, `activate`, `renew`, `ready` and `revoke`; this selector replaced\n`{kind:\"operation\", requestId}`, which no longer parses. An owner's IdP proof reads that owner's own\nrequests and assignment, and only while the owner holds an interactive row, as for every owner\nrequest: without one it is `denied` `permission-denied` (403) before any read. A renewal or access\nproof reads only intents whose witness digest is its own, and the instance only as its own\nincarnation; a register with no intent is not readable by it. A witness naming another selector\nreads `not-found` before any read, and on a bound assignment a witness that does not name the\nbinding reads `not-found` before the precedence below, so another instance's revocation is never\nvisible to it.\nAnother owner's request reads `not-found`. `revoke` answers `denied` `unsupported`. Every required\nrecord that is unreadable, missing where it must exist, or inconsistent with another answers 503,\nnever `not-found` and never a `superseded` whose ids were not read from records. An operation status\nfollows this precedence:\n- an id listed in the index without its intent answers 503; it stays 503 if a later replay is\n refused, because no effect ran or can run and status never guesses absence;\n- with neither record, a register is in its proposal phase (below) and anything else is `not-found`;\n- a bound cancel identity or a fenced assignment answers `revoking` first, with phase\n `deny-new-landed` once the gate reads revoked and `deny-new-pending` before;\n- a register intent answers, first match wins: `registered` or `ready` when the stamp is this\n request; `superseded` with this request's id and the stamp's when the stamp names neither this\n request nor its expected registration, or names the expected one after activation; `registering`\n at phase `barrier` when the gate's pending registration is this request; `registering` at phase\n `admitted` when there is no stamp and nothing was expected, or the stamp is the expected one before\n activation, with the gate open or frozen by another request; otherwise 503;\n- an activate, renew or ready intent answers `superseded` with its registration's id and the stamp's\n when the stamp moved on, `registering` at phase `barrier` with the other operation's id while the\n gate is frozen, and `registered` or `ready` when the current witness is the intent's; otherwise 503.\n\nA register with no intent answers from its proposal-phase operation record: `registering` while that\nregister is in flight, `refused` for a refused register or a closed proposal, which stays refused and\nnever reads another proposal's assignment, `proposed` while its proposal is live and unexpired or its\napproval is in progress, `revoking` once the assignment it approved has a cancel identity, and, once\napproved, `approved-unregistered` with the gate's approval digest while no registration exists, or\n`superseded` with the current stamp's request id once another request registered: this request can\nnever register, because its replay would expect no registration. Instance status answers the\ncaller's assignment as it is: `revoking`, `registering` at phase `approving` while its approval\nsettles, `approved-unregistered`, `registering` at phase `barrier` while the gate is frozen,\n`registered` or `ready`, and for a service proof whose registration was replaced, `superseded`.\n`registered` and `ready` say only that the request's registration is current; neither says whether a\nreply was delivered or whether an activation landed, and the recovery is always to replay the same\nrequest.\n\nAn authority plane opened with `serviceEndpoints` also composes the native service callout. A\nconnection presenting a service access bearer is minted only for the current bound assignment its\nwitness names, which the service host reads, on its own writer connection\n`cotal:service-callout:<space>`. That writer adds the endpoint gate and endpoint credential families\nto the base writer grant; a broker grant cannot confine those families to service assignments, and\nthe native mint writes only the bearer's own rows. A fenced plane or a latched host refuses the\nmint. Registered closures are read back from the contract store on the issuer connection's\nexact-subject Direct Get. Revocation, the Describe view, caller policy, terminal retirement and\nrestore remain unsupported: a revoked assignment's bearer is refused at its next connect, but a\nconnection already open keeps its original expiry of at most 60 s.\n\nA local scoped Describe callback may receive immutable request context alongside the caller.\nIts subject comes from actual dispatch, and its fingerprint is the canonical digest of\n`{subject,envelope}`, using the complete original decoded JSON envelope after native Describe\nvalidation. A picked parser projection cannot substitute for that envelope. Local receive time\nis monotonic and captured before validation; deadlineMs remains the original relative budget.\nThis is receiver-relative context, not a publisher-start timestamp. The context exposes no raw\nproof bytes. Neither a context value nor its digest establishes actual receipt or authority to\nanother process; a trusted observer must establish that independently.\n\nThe service authority's read-only `describe-view` request adds the complete current `witness` and\n`observation:{subject,fingerprint}` to its common coordinates. Only service-access proof is admitted.\nThe subject must be an untargeted native Describe for this space and endpoint; an instance route\nmust name this instance. Parsing does not prove that the request was observed. The host must verify\ncurrent native service authority and an independent live observation before evaluating caller policy.\n\nIts successful result has `state:\"view\"`, the matching witness and observation,\n`basis:\"principal-policy-v1\"`, unique declared command names and positive integer `validForMs` no\ngreater than 2000. That basis denotes current principal-policy visibility, not the connected\ncredential's exact permission ceiling. The serving client verifies commands against its registered\nsurface. It requires request and response no-store, original receive-relative budget and the host's\nremaining duration after subtracting the full local query roundtrip. Proof, preparation, HTTP body\nand validation work cannot restart the deadline. Missing access proof never triggers IdP login.\nTransport failure on this read is not an unknown mutation outcome. The host's current-root,\nobservation, source/provenance and freshness checks remain mandatory beyond this wire shape.\n\nA service access bearer uses the user-token shape with `act.view: \"service-endpoint\"`.\nIts closed payload has `iss`, scalar `aud`, `sub`, `iat`, `nbf`, `exp`, `ver`, `scope` and `act`.\nIts protected header has only `alg: \"EdDSA\"` and `kid`. The closed actor has `owner`, `actor`,\n`scope`, `lifecycleUid`, `credentialId`, `view` and `service`. Both scopes are empty lists.\nThe closed service claim is `{duty: \"serve\", witness}`. The complete witness binds the same\nspace, owner, actor, native lifecycle UID and root credential as the outer bearer. Parent, manager,\nsession and transfer claims are forbidden. Times are integer Unix seconds, `nbf` equals `iat`,\nand the fixed expiry is at most 60 seconds after issuance. Validation refuses at the original\nexpiry, without extending it through clock tolerance. Ordinary exchange and profile construction\nMUST refuse this view. Only a dedicated service authority path may issue and authorize it after\ncurrent native root, approval and registration checks. Signature validation alone does not\nestablish that authority.\n\nThe dedicated callout authenticates the sealed broker request before using its user key, server\nkey or client id. It captures admission time before authority reads and fixes native expiry no\nlater than the access expiry or admission plus 60 seconds. It derives serving permissions from\nthe current native registration, preserves principal-name attribution and uses the separate\nclient inbox nonce. Native issuance and receipt checks and final root authorization precede the\nencrypted response. An expiry reached while encoding or sealing that response refuses release.\nAn unconfigured or non-native service authority cannot fall through to ordinary actor hooks.\n\nA service renewal proof is a separate EdDSA JWT class with protected `typ:\n\"cotal-service-renewal+jwt\"`, `alg` and `kid` headers. Its closed claims are `ver: 1`,\n`kind: \"service-renewal\"`, the complete registration `witness`, its canonical `witnessDigest`,\nand `iss`, `aud`, `sub`, `iat`, `nbf`, `exp`. Issuer and key resolution are pinned by the host;\naudience is the one space and subject is the witness owner. `nbf` equals `iat`; expiry is a fixed\nUnix-second deadline no more than 24 hours after issuance. Validation rejects the proof at its\noriginal expiry and binds every witness coordinate, not just the service name. User/connect token\nvalidation rejects this JWT class even if it carries actor-like claims. A normal user bearer is\nnot a service renewal proof.\n\nThe signature primitive does not establish current authority. Before issuing or accepting service\nauthority, the host checks the current native root, approval, registration and operation eligibility.\nIt bounds expiry by root and approval expiry. Signing cannot extend a supplied fixed deadline;\nmaterial that expires while signing is not released. Renewal proofs contain no ordinary capability\nscope and are never native DATA-account credentials.\n\n**`holderPrincipal` is ALWAYS a CONNZ-attributable `<owner>.<actor>` in\nBOTH families** (the barrier KICKs it; an endpoint NAME is not attributable and never sits\nthere): in `cred.` it is the caller principal; in `epcred.` it is the serving instance's own\nconnection principal, copied from the endpoint gate's `principal`, while the endpoint NAME that\nforms the `epcred.` KEY is a SEPARATE row field, so the key identity and the eviction target\nstay disjoint (an `epcred` row that put the endpoint name in `holderPrincipal` could never be\nKICKed). The `cred.`/`epcred.` families hold ONLY conformant ledger rows:\nimplementation staging, half-minted state, and tombstone fences live in a distinct\n`stage.` family, never under a ledger prefix a barrier enumerates.\n\nService-callout `epcred` rows also carry the closed `serviceConnection` object\n`{userNkey, serverId, clientId}`. The user and server keys are checksum-valid NKeys of their\nrespective kinds; clientId is a positive safe integer from the authenticated broker request.\nThese fields are forbidden in the `cred` root family. Service issuance requires this binding,\npreserves it during staging and leader-reads the row and unchanged gate authority after its CAS.\nAn ordinary serving issuance cannot carry service connection evidence. These rows prove issuance,\nnot broker acceptance or response delivery. Native root authorization remains separate.\n\nService-callout natkey evidence additionally carries\n`service:{witness,credentialId,connection}`. The outer credentialId is the native root; the nested\ncredentialId identifies the issued service JWT in epcred. The connection is the same authenticated\nbroker triple, and its user key must match the natkey key. Recording checks the active epcred\nbinding before and after the create-only write, verifies its receipt, reauthorizes and checks the\noriginal expiry before release. Existing receipt history cannot be reused. Expired service evidence\nis retained until topology-qualified retirement authorizes removal; the ordinary expiry pruner\nreports it separately and cannot remove it. That terminal pruning path is not implemented yet.\n\n**Native-key issuance evidence.** Every callout success first writes one create-only\n`natkey.<userNkey>` row in the same auth bucket, where `userNkey` is the broker-generated\nper-connection user public key the minted JWT is issued to (never the client's inbox nonce or a\ndisplay name). The row is the closed v1 record `{v, space, owner, actor, lifecycleUid,\ncredentialId, view, connId, iat, exp}`, taken from the validated bearer's own signed claims\n(already equality-checked against the current row) and from the minted JWT's own `iat`/`exp` (a\nsession-caller's is its grant's). An existing row for the key, under any lifecycle, refuses. After\nthe write the responder re-reads the lifecycle and credential authority in the same stream; only\nthen may the JWT leave. Any failure is a signed deny. A row is evidence of an issuance, not proof\nthat a client received the JWT or that the broker accepted the connection: a write that landed\nbefore a refusal stays. `natkey.` is not a ledger family and authorizes nothing. The issuing\nservice removes a row only after its `exp` plus the clock tolerance, at boot and then on its own\ntimer, walking the family with the leader-served `STREAM.MSG.GET` `next_by_subj` read (never a\nconsumer) and purging each row pinned to the sequence it read, with the bucket's marker TTL on the\npurge marker so it expires too. A row\nthat does not parse fails the boot open or fences the running service. Connections admitted\nbefore this row existed, responders that do not write it, and static (non-callout) JWTs have no\nrow. This evidence names keys; it does not by itself stop a still-authorized bearer from\nconnecting again under a fresh key.\n\n**Remote manager-service authority (user-auth only).** `manager-service` is one CLOSED,\nserver-authored authority view, not a profile name, arbitrary bearer profile, or client-supplied\npermission set. The human exchange serves only a signed-in human whose current actor-ledger row\ncontains the dedicated `supervise` scope. A trusted host composition may separately issue the\nowner-bound platform supervisor registration material defined in §13.15, without a human exchange.\n`spawn` and `admin` never imply `supervise`, and `supervise` never\nimplies either. Only the loopback/operator exchange MAY issue this view; the public exchange and\nevery managed-agent secret exchange MUST refuse it. The callout re-reads the ledger row at exchange\nand connect, so a missing, narrowed, or revoked `supervise` scope denies the next view exchange and\nnew connection with the full re-grant requirement. A plain user bearer remains `agent`-scoped.\n\nThe view names exactly one ordinary derived owner, a fixed server-selected manager actor, that\nactor's lifecycle UID, and one opaque locally selected `instanceId`. The actor and instance id are\nnot client-selectable, and the view grants no second manager instance, other endpoint, or other owner.\nIt may reach only the manager instance's own `svc.manager.<instanceId>` registration/status,\npre-authorized immutable contract publication, endpoint rails, and the disjoint\n`epgate.manager.<instanceId>` / `epcred.manager.<instanceId>.<credentialId>` family. It does not\nconfer the space signer, callout signer, owner secret, static provisioner credential, generic\nstream/KV authority, or authority over another instance's gate, records, contracts, or\ncredentials. A manager-service credential is ledgered and gated exactly as this section requires;\nits `holderPrincipal` is the derived-owner/fixed-actor principal, never the endpoint name.\n\nThe typed protocol includes two host-owned registration-maintenance operations. An\n`evict-family-principal` request names `principals`, 1 to 256 distinct holders, so a restart's\nfamily eviction costs one request and one family scan per 256 holders. The host MUST enumerate the\nauthenticated caller instance's `epcred.manager.<instanceId>.*` family once per request and refuse\nunless every named principal is one of its holders. The host, using its signer, then mints the\nbounded delivery-admin caller, requests `evictPrincipals` for the set, and returns `evictions`, one\nclosed `EvictionResult` per principal in request order; a garbled, foreign, misordered, or\ncontradictory result MUST NOT authorize. The participant never receives that credential. A\n`reconcile-registration` request MAY name another manager instance in the same space only to clear\nan abandoned governance-slot holder. The host MUST observe that target's frozen registration gate,\nprove the freeze-holder `gone` under a complete liveness sweep, run the normal registration repair\nwith verified eviction, and refuse live, unknown, incomplete, unestablishable, or non-registration\nstates. There is no force path. A participant credential still gains no direct authority over the\ntarget gate, records, family, or delivery-admin rail.\n\nThe bounded executor returned by `prepare` is renewable through `renew` for the same public nkey and\ncurrent open registration. A remote manager MUST obtain a fresh executor before maintenance or clean\nderegistration when its retained credential is not healthy. A restart MUST drive family eviction\nthrough the host operation before advancing its epoch. A registration blocked by a foreign frozen\nmanager governance slot MAY request guarded host reconciliation and retry exactly once.\n\nThe typed protocol also carries two host-owned MANAGED-AGENT operations,\n`manager-managed-agent-enrollment` and `manager-managed-agent-prepare-retirement`. Both name the\nauthenticated owner's own managed agent and both require the caller's current `supervise` scope;\n`spawn` and `admin` never imply it. Both MUST be authorized against the caller instance's CURRENT\nopen manager gate: the gate's principal MUST equal the server-derived serve principal, its process\nepoch MUST equal the request's `serveEpoch`, and the request's registration proof MUST match the\nproof the host issued for that registration revision and epoch. An enrollment request MUST carry the\nSHA-256 digest of the agent's standing actor token and never the token itself, and MUST NOT carry a\nlifecycle UID: the HOST selects it, because only the host can observe the retirement tombstones that\nmake a UID permanently unusable. A prepare-retirement request MUST name a target owner equal to the\nauthenticated owner, and its `opId` MUST equal `managedRetirementOpId(target.lifecycleUid)`,\nrecomputed by the host rather than trusted, so one lifecycle never carries two terminal operations.\n\nThese two operations mutate host-owned storage, so an implementation that owns no such storage MUST\nrefuse them with `unimplemented` rather than answering a manager-lifecycle phase for them. An auth\nservice that owns the actor ledger and the space's provisioning authority answers both itself, after\nthe same decision. Its enrollment writes the managed grant at a fresh host-minted lifecycle UID with\nthe request's supervising actor as the grant's parent, so the ledger's delegation envelope bounds it,\nand then provisions that UID's durables; a provisioning failure revokes the grant and releases the\nfootprint before the refusal. An enrollment whose token digest matches the agent's standing grant is\na retry of that enrollment: it walks the held grant through the supervising actor's current\ndelegation envelope and refuses as a fresh enrollment would when the grant falls outside it;\notherwise it answers the held UID and provisions it again, and its failure leaves that grant in\nplace. While the agent holds a grant with another digest, enrollment MUST be refused\nwith `conflict` until that lifecycle's retirement is prepared, so a successor never takes a running\nagent's grant. Its prepare-retirement releases the target UID's broker footprint and then revokes the\ngrant, only while the grant still names that UID, so a repeated request is harmless. The service runs\nenrollment and prepare-retirement of one agent one at a time, and every revoke it performs names the\nUID it releases. The enrolled agent's bearer exchanges at the public exchange face, so an auth\nservice without that face MUST refuse enrollment with `failed-precondition`. A host\nplatform that owns the writers MAY intercept them on its own authenticated route and obtain the\ndecision alone from the auth service's loopback door\n`POST /manager-service-authority/verify-enrollment`, which carries the same loopback guards as the\nmanaged-retire door (POST only, no `Origin`, JSON, the per-start capability, a closed\n`{ owner, request }` body). That door MUST derive the caller's capability scope from its own ledger\nand MUST NOT accept a scope from the caller. It decides only: it mints nothing, writes nothing, and\nreturns no secret.\n\nTwo further host-owned kinds address the hosted runtime of an already-enrolled managed agent:\n`manager-managed-agent-runtime-create` and `manager-managed-agent-runtime-status`. Each carries the\nmanaged-agent envelope plus exactly `target: { owner, actor, lifecycleUid }`. Both schemas are closed:\nan unknown top-level or target field, including `providerRef`, `handle`, or `name`, MUST be refused as\n`bad-request` with no effect. There are no participant stop, adopt, or probe kinds. Both MUST be\nauthorized with the same gate, epoch, and proof checks as enrollment, with a target owner equal to the\nauthenticated owner, and with `supervise` read from the host's own ledger row for the manager actor.\nThe decision yields only the verified owner, instance id, manager actor, and target. A status decision\nauthorizes no effect. An implementation without host intent storage MUST refuse both with\n`unimplemented`. The answer carries `state` (`reserved`, `creating`, `bound`, `create-unknown`,\n`closing`, or `closed`), `readiness` (`ready`, `bound-not-ready`, or `none`), and an optional\n`retirementPhase`. An enrollment result MAY carry `runtimeIntent: { state: \"reserved\" }`, which is\ndisplay-only and MUST NOT be treated as authority.\n\nThe host, not the participant, issues every data-account credential requiring the account signing\nkey. The only remote path is the lifecycle- and instance-bound typed protocol of §13.6; a broader\nbearer or a generic credential-mint endpoint is non-conformant. Its gate is frozen before staged\nmaterial becomes usable; every release is preceded by the ledger write and gate CAS; and all\nreplay/idempotency coordinates bind the owner, fixed actor, lifecycle UID, instanceId, operation,\nand public nkey. A remote manager may provision a managed descendant only after the host validates\nthat its current owner equals the manager-service owner and the current manager grant; that is a\nsame-owner validation seam, not delegated signer authority. Revocation freezes the one family,\nrejects fresh material and new connections, and proceeds through the bounded renewal/verified\nrevocation policy below. It MUST NOT silently substitute static or local authority.\n\n**Platform control authority (service view).** `platform-control` is a second CLOSED,\nserver-authored manager authority view, beside and separate from `manager-service`. It lets a host\nplatform run one control manager per assigned data account without any human's session. It is not a\nprofile name, not an exchange view, and not a generic host profile: the public exchange, the\nloopback exchange, and every managed-agent secret exchange MUST refuse it as a view. Its holder is a\nplatform principal. The holder's owner is a platform owner token, `p_` followed by 26 base32-lower\ncharacters, which the host derives from the space's owner secret, the space, and the assigned\ndata-account public key. This extends the §2 owner-token format for this view's principals and\ntheir same-owner descendants only; everywhere else §2 stands. A platform owner token is disjoint\nfrom every `u_` derived owner, from `local`, from nkeys, and from the §13.2 mode words. The host\nMUST NOT derive it from, or bind it to, an IdP subject, and MUST NOT name a `u_` owner on this path.\nNo human is authenticated, and no ledger `supervise` scope is read or synthesized.\n\nThe view exists only while the host's current platform-control assignment names it. An assignment\nis one row `{ space, accountPublicKey, instanceId, lifecycleUid, predecessorInstanceId?,\nassignmentRevision, state }` that the platform backend alone writes. An account has at most one\ncurrent row, so it has at most one platform control instance. The host MUST read it fresh for every\nrequest under this view\nand MUST refuse, writing nothing, when it is absent or `revoked`, or when it disagrees with the\nrequest's account, instance id, lifecycle UID, or assignment revision. A failed read MUST refuse\nrather than reuse an earlier answer. The instance id and lifecycle UID are the assignment's, not\nthe caller's choice. They stay the same across the instance's restarts: a restart re-registers\nthrough the same-principal registration barrier at an advanced process epoch and is never a second\ninstance. The actors are the same fixed functions of the instance id. When the assignment names a\n`predecessorInstanceId`, the host MUST refuse `prepare` and `activate` with `failed-precondition`,\nwriting nothing, while that instance has a current `svc.manager` registration or a `frozen`\nissuance gate. The host only reads that instance's rows. It MUST NOT probe, freeze, evict, revoke,\nreopen, or deregister them. Apart from the\nholder's owner and this authorization source, the view is the `manager-service` family: the same\n`svc.manager.<instanceId>`, `epgate.manager.<instanceId>`, and\n`epcred.manager.<instanceId>.<credentialId>` rows, ledgered and gated as this section requires, with\n`holderPrincipal` the platform owner plus the fixed actor.\n\nThe view MUST NOT reach an instance whose issuance gate names another principal, including an\ninstance a signed-in human registered under `manager-service` and a manager registered under the\n`local` owner. There is no force or takeover path between the two views. Such an instance retires\nthrough its own owner's path before a platform instance may register. A re-registration never\nchanges an instance's owner, so the view never binds to an existing instance registered under\nanother owner. It registers its own assigned instance once that instance's predecessor has left\nthrough the predecessor's own path. Both registration proofs bind the owner, so a `manager-service` proof never\nvalidates under this view and a `platform-control` proof never validates under `manager-service`.\n\nA manager holding this view MUST run with no local signing trust and no local or custodial runtime\n(pooled control). The view confers no space signer, callout signer, owner secret, provisioner\ncredential, or launch authority. It provisions, enrolls, retires, validates, and authorizes only\nsame-owner descendants, whose owner is its own platform owner token, and grants nothing over a\nhuman owner's agents.\n\n**Environment manager authority.** `environment-manager` is a third CLOSED, host-authored\nmanager authority family. It admits one signerless manager and at most one managed child\nlifecycle in one provider environment. It is not an exchange view or caller-selectable\nprofile. Every human, public and managed-agent exchange MUST refuse it. Its owner is the\nordinary derived owner recorded by the hosting authority, not a synthetic human ledger\nrow or the `platform-control` owner. Neither this family nor its bootstrap authenticates\nan owner's IdP session.\n\nBefore issuance, the external authority MUST durably bind the environment record ID,\nowner, space, data-account public key, manager instance ID, manager lifecycle UID,\nbootstrap caller triple, admission revision and finite expiry. These coordinates come\nfrom host admission, never guest claims. The bootstrap caller uses that manager lifecycle\nUID and the sixth fixed actor `manager_bootstrap_<instanceId>`. This temporary actor is\nseparate from the five standing identities. Admission reserves the UID, creates\n`epgate.manager.<instanceId>` open, then freezes it `open → frozen` under one host-selected\nregistration operation intent in the same admitted operation, all before bootstrap mint.\nA gate is never born frozen under registration. The closed endpoint gate row gains the\noptional immutable discriminator `authorityFamily: \"environment-manager\"`, written only\nby this admission and retained by every subsequent CAS at open, frozen and retired states.\nIt cannot be cleared or reassigned. This extends §13.1's endpoint gate row grammar by\nthat single optional field and one literal value; any other value or new field remains\nrefused. This gate-level marker, not an op on an open gate, keeps symmetric family checks\neffective after activation; existing open/op rules remain unchanged. Only the trusted host\nmay write this family's gate, repair cursor or credential ledger. The environment supervisor\nand executor MUST NOT reuse the shipped `remote-manager` profile, whose direct writes\ncould remove this marker. Fixed mediated profiles below keep those writes host-only;\nfield-level immutability is not claimed for a credential that can publish the whole row. Staged environment, revision and operation coordinates use `stage.<opId>.…`\nand the operation's normal retention. No new permanent `stage.` key is introduced.\nThe retained retired gate remains the permanent terminal family marker. The bootstrap mint writes `cred.<managerUid>.<credentialId>` with the native\n`sourceChain: [root]` lineage (§13.1) and admission expiry, then CAS-pins that staged gate before returning\nmaterial. Only the fixed bootstrap profile is usable in this pre-preparation phase.\n`prepare` continues that same registration operation, never a second intent.\n\nEvery issuance pins the admission revision through its native issuance-gate CAS.\nTermination MUST fence that gate and revoke the bootstrap credential before marking the\nprivate admission ended. Before activation it aborts registration `frozen → open`, then\nruns retirement `open → frozen → retired` under its own intent. After activation it runs\nretirement alone. No bootstrap mint or preparation is admitted without the admission's\nsame live registration intent, regardless of revision, so the abort's reopened interval\nmints nothing. Gate advancement and verified revocation precede private admission ended. Issuance records the revision it observed in its gate intent and CAS; a termination\nadvance makes the stale CAS fail without returning material. A crash between those steps\nleaves closing/retirement-pending state and resumes the same intent. Auth unavailability\ncannot prevent bounded provider termination, but MUST NOT be reported as completed authority\nretirement. The auth gate is the issuance fence; the private admission store records its\noutcome. A fresh admission read alone MUST NOT permit material to escape a concurrent\ntermination. The admission also records the only permitted\nchild actor and its delegation ceiling. Its first enrollment binds one host-selected\nchild UID permanently; retirement does not permit a second child lifecycle. This is a\nsingle-shot environment: a crashed child cannot be relaunched under its handed-off UID\n(§13.17) or replaced by another UID. Lang reports that failure; a replacement requires a\nnew admitted environment. Missing\nmanager registration, child enrollment, run admission or terminal retirement policy MUST\nrefuse admission before bootstrap issuance.\n\nThe authority MUST re-read that binding for every request, bootstrap and renewal included.\nAn absent, expired, ended, destroyed or mismatched binding authorizes nothing. A failed\nread refuses rather than reusing a previous decision. The registration, five manager\nidentities, process epochs, credential ledger and issuance-gate barriers remain those of\nthis section and §13.6. This family MUST NOT construct a human `supervise` holder or use a\nplatform-control holder to reach issuance. Credentials MUST expire no later than admission\nexpiry. A registration proof alone is not bearer authority: later requests require the\nbroker-authenticated, instance-bound caller issued for the corresponding manager identity,\nthe current registration proof and the current process fence. The host-issued proof MUST\nalso bind this authority family, environment ID and admission revision. A human or platform\nregistration proof MUST NOT validate here, nor an environment proof under either other\nfamily. This requires a distinct, family-discriminated environment registration-proof\nderivation binding the existing coordinates and artifacts plus environment ID and admission\nrevision; the current human/platform derivation cannot be reused unchanged. Admission MUST\nrefuse an instance already bound to another family, including the same owner's human\nmanager; it provides no takeover or force path.\n\nSymmetrically, human `manager-service` and `platform-control` prepare, activate, renew,\nmaintenance and retirement MUST refuse `permission-denied` before effect for an instance or\nlifecycle whose gate or stage names `environment-manager`, under any owner. They gain no\ntakeover or repair path through this insertion. The family check precedes any freeze, epoch\nadvance, liveness probe, eviction, deregistration or credential issue. An unreadable family\nbinding refuses. Environment-bound cleanup remains the external host's admitted path.\n\nThe manager and child MUST have separate effective OS users and private material stores.\nChild launch material crosses into the child's store by value, never as paths into the\nmanager's store. The child MUST NOT receive the provider credential, hosting or model\nsponsor key, account signing seed, owner IdP token, manager credentials or manager proof.\nA runtime unable to enforce this boundary MUST refuse launch. Provider RUNNING alone\nestablishes neither manager nor child readiness. Their presence binds the opaque\nenvironment record ID through the existing `environment` field.\n\n**A read is never a fence; only a CAS write is.** JetStream `DIRECT.GET` may be served by a\nfollower or mirror and gives NO read-your-writes guarantee (a mint that *reads* the gate can\nobserve a stale `open` after a barrier froze it on the leader), so the auth bucket sets\n`allow_direct=false` (§13.12) and every fence here is a leader-served, revision-pinned CAS\nwrite. The mint protocol is **observe gate → write rows → CAS the gate → release**: the auth\npath reads the gate (recording `state`, `generation`, and KV `revision`), writes the\n`cred.`/`bysrc.` rows, then performs a **revision-pinned CAS update of `gate.<lifecycleUid>`\nitself at the observed revision**; a leader write that fails if the gate changed at all,\nand releases the credential only on CAS success with the gate still `open` at the same\ngeneration. On CAS failure, `frozen`/`retired`, or any generation advance it aborts and marks\nits own row revoked, never releasing. A barrier CASes the gate to `frozen` FIRST and only then\nenumerates the family. The race is closed by **serialization on one key**, not by timing or\nread freshness: freeze and mint-finalize are both CAS writes to the SAME gate key, so one\nloses; a mint that wins wrote its rows before its winning CAS, so the barrier's later\nenumeration sees them; a mint that loses never released. The ledger is written only by the\ntrusted auth path (§13.9 matrix; NATS binding: the auth KV, §13.12).\n\n**Every lifecycle operation is a cross-bucket saga, never an implied transaction.** The\nrecords head and the auth gate/ledger live in different buckets with no shared order, so\neach operation persists its durable intent (the gate `op`, above) before touching the\nsecond bucket, every crash boundary resumes the SAME operation from that intent, and the\nsafe orders are normative. **Initial activation, in order**: reserve the UID (create-only\n`uid.<lifecycleUid>`, above) → create the issuance gate `frozen` carrying the activation\n`op` (unmintable from birth; no credential is ever released under a frozen gate, per the\nunledgered-mint rule) → CAS the alias head to the new mapping (`active`) → reopen the gate\nat its first mintable generation as the operation's LAST step. A head-CAS loser\nterminalizes its own orphan gate and burns its reserved UID (never deleting either); a\ncrash after the head CAS leaves the lifecycle active-but-unreachable, and recovery resumes\nthe same activation `opId`, never minting a second UID for one activation. **Takeover**\nkeeps the barrier order above (freeze → revoke + verified-evict → epoch head CAS LAST →\nreopen). **Terminal retirement** keeps the barrier order below. No other head transition\nexists: the head advances only inside these operations, and no epoch-advance or retire\nseam is exposed outside the operation that completes its barrier.\n\nBinding rule (normative): **durable** authority and state; sturdy handles, accepted goals,\ncheckpoint tokens and resumes, durable consumers and delivery state, ledger rows, bind\n`(principal, lifecycleUid)` and survive supervised restart. **Live** authority, session\ngrants, reply attribution, serve/commit ownership, additionally binds the process epoch and\ndies on restart. The alias alone authorizes nothing: a delayed or redelivered request, handle,\nor teardown that names a recycled alias fails against the replacement because the lifecycle\nUID differs. Endpoint daemons carry the same triple, with the **stable logical instance id**\n(`instanceId`, `[a-z0-9]{26,32}`, ≥128 bits of CSPRNG entropy, persisted for the endpoint\nlifetime) as their routable identity component. `instanceId` is **minted by the provisioner,\nnever reused, and unique within `(space, endpoint)`**, the allocator records it in the\ninstance's service record by create-only CAS and rejects collisions durably. Reply\nattribution, scatter deduplication, queue ownership, and the event/timer planes all key on\nit, so its uniqueness and entropy are load-bearing, not cosmetic. `instanceId` is to an\nendpoint what `lifecycleUid` is to a managed agent, and both follow the same\nrestart-preserve / terminal-retire / epoch-fence rules.\n\n**Cross-plane scoping.** Chat/DM/presence *subjects* keep the §3 grammar (the alias), but\ntheir backing state is lifecycle-scoped: presence carries the current `lifecycleUid` (§6);\nper-instance durable consumers, pending delivery cursors, durable memberships, history\ncutoffs, and ACL/ledger rows key on `(principal, lifecycleUid)` (§8, §9). The DM subjects\n(`inst.>`) DELIBERATELY stay alias-keyed; a second implementer MUST NOT uid-scope them; the\nsuccessor cut for DMs is the ACTIVATION FRONTIER (the DM stream sequence captured at the\nlifecycle's provisioning, delivery starting at frontier+1, §8), and that frontier capture is\na leader-served read (the §13.9 read-service class), never a follower get. Explicit same-name\nrecreation inherits **no** predecessor authority or content: terminal retirement records\nper-stream sequence cutoffs before the alias is freed, messages published while no lifecycle\nis active do not flow to a later replacement, and retirement across streams is ordered and\nreconciled (never assumed atomic). **Destructive cleanup is broker-enforced where the resource is broker-addressable**: durable\nconsumer names, ACL rows, KV record keys, and membership rows are lifecycle-keyed, the UID\nis part of the resource NAME, and the teardown credential (the deprovisioner) is minted\ntarget-pinned to `(principal, lifecycleUid)` by exact name, so a credential minted for\nlifecycle A cannot even NAME lifecycle B's resources; the broker denies the stale delete\noutright. Only resources the broker cannot see (the manager's local credential/token/health\nfiles) fall back to a handler-side **delete-if-current** check carrying the retiring UID +\nexpected ownership revision. In both regimes the alias stays reserved until retirement and\ncleanup have durably completed, so a stale detached teardown can never destroy a same-name\nsuccessor. **Terminal retirement is additionally a credential barrier, in order**: CAS the issuance\ngate `open → frozen` carrying the durable retirement `op` FIRST (the bar: a staged mint\nloses the gate CAS, exactly the mint-protocol race above; the gate revision moves, so a\nmint that observed `open` cannot finalize) → CAS the head `active → retiring` bound to the\nsame `op.opId` (from this point every currency seam yields no current mapping and no\ncurrent epoch, and the alias is NOT replaceable) → revoke every\nactive credential-ledger row under the lifecycle prefix (all roots and all descendants,\ncredential ledger above), verifying revocation enforcement on every server as in the\ntakeover barrier → cluster-verified eviction of every revoked credential's live connections\n(`evictPrincipal`, as in the takeover barrier above) → **drain the target's acceptance\nobligations to quiescence** (§13.8: enumerate `oblig.<targetUid>.>`, settle every\nunresolved row through its decision coordinate, and re-enumerate until an enumeration\nfinds none unsettled; every writer that observed the pre-`retiring` mapping is settled\nHERE, before the cleaner below runs and before any frontier closes) → **fence the drain's\nper-op repair principals** (the commit applier, pool-route reconciler, and effects canceller\nminted inside the drain, `local.{epapl|eprec|epcan}_<opId-hash>`): cluster-verify eviction of\nany live connection under each BEFORE the cleaner and BEFORE any frontier — the applier\nespecially, whose records-KV last-value write is returned to a normal reader regardless of the\nper-stream frontier cutoff. These are self-minted data-account bearers with NO credential-ledger\nrow, so there is no connect-time deny-new: the guarantee here is **kill-live** (verified eviction\nof currently-connected principals), NOT reconnect prevention; a fresh connect within the\nbearer's TTL is the accepted residual NAMED per drain-repair profile in the §13.9 matrix (each\n\"RETIREMENT-FENCE residual\" row), of the same kill-live-not-deny-new class §13.13 fences for the\nplane connections (repair connections MUST be minted non-reconnecting so a verified eviction is\ndurable) → the trusted terminal **pool\ncleaner** settles the lifecycle's expired and orphaned pool work under a DISTINCT,\nseparately minted, exact-pool scoped profile whose pool set is this operation's **effective\ninventory**: the target's accepted `oblig.<lifecycleUid>.>` pool routes enumerated from the\nSAME drained, now-`retiring` obligation set (so no new row can appear and the enumeration is\ndeterministic across resumes). The inventory is DISCOVERY-ONLY: the barrier takes no\ncaller-supplied pool hint, so every inventory entry is an obligation-discovered pool this target\nholds accepted work on, and no pool ever enters the cleaner/executor grant without a backing\nobligation. Confinement is the EXACT per-pool effective-inventory grant plus the\nexecutor's per-item decision/horizon/retire-target checks (which bind HONEST execution, not a\ncompromised bearer): (§13.9\nmatrix row: bind-only on the pool's\npre-created durable, terminal-only ACK after the item's durable terminal fact, no consumer\ncreate/update/delete, no raw stream DELETE; it never holds, reuses, or impersonates the\nrevoked owner's authority, which this barrier just killed) → **retire the cleaner\ncredential itself, verified, BEFORE any frontier closes**: once the cleaner has settled the\npool and proven it quiescent (every pre-existing owner ACK drained through `AckWait`, and a\nfresh consumer read shows zero `num_pending` and zero `ack_pending`; a fire-and-forget ACK\nis confirmed with `AckSync` or re-proven, never assumed), the barrier REVOKES the cleaner's\nown bounded-lived credential and cluster-verifies eviction of its principal (`evictPrincipal`,\nexactly as for the owner above), so no in-flight cleaner can ACK a redelivery or write a\nterminal after the alias is reused; the cleaner's authority MUST be dead before the frontier\nrecords → record the\nper-stream retirement frontiers (the create-only, never-deleted `frontier.<lifecycleUid>`\nrecord, §13.7: one key per retired lifecycle, recorded once under this operation's `opId`) →\nCAS the gate `frozen → retired` (terminal; unlike\ntakeover, retirement never reopens it) → CAS the head `retiring → retired` → only then\nfree the alias, and a successor activates only with a freshly reserved UID. `retired` on\nthe head therefore ASSERTS completed cleanup: replacing a retired predecessor needs no\nfurther proof, because nothing reaches `retired` without the barrier. Every boundary of\nthis sequence is crash-resumable through the durable `op` intent, and only the same\noperation resumes it. A **managed** lifecycle's terminal retirement has exactly one operation\nidentity, `managedRetirementOpId(uid)`, whichever entry point requests it: the participant\nmanager's `retire-lifecycle` rail request (§13.2) or the host's loopback managed-retire door, which\nfinishes the retirement when that manager is gone and requires the managed grant to be revoked at\nthat UID first. Both entry points create or resume the same durable operation, and one process\nnever executes it twice concurrently. Chat/DM/presence subjects stay\nalias-keyed, so without the revoke-and-verified-evict step a still-connected stale process\ncould keep speaking as the recycled alias. Where the deployment cannot revoke the credential\nor cannot verify eviction, alias reuse is **forbidden**: a same-name respawn fails loud.\nSupervised restart of the same UID retains all of it.\nIntentional role-mailbox continuity across lifecycles is only available as an explicit,\nseparately authorized transfer operation, never an accidental consequence of string reuse.\n\n### 13.2 Grammar\n\n**Endpoint names.** An endpoint name is one or more DNS-shaped labels, each matching\n`[a-z0-9]([a-z0-9-]*[a-z0-9])?` (no leading/trailing dash, no bare dashes; `_` MUST NOT\nappear in a label). Single-label names (`manager`, `delivery`) are reserved for\nendpoints shipped by this contract's reference implementation and require the space operator's\nprovisioning authority to serve; a third-party endpoint name MUST be reverse-DNS (two or more\nlabels under a domain its author controls, e.g. `com.acme.deploy`) and is mintable only under\nthe owner that registered that domain claim. In a wire subject the name is one token with `.`\nreplaced by `_` (`com_acme_deploy`); because `_` cannot appear in a label the mapping is\nbijective. Name authority is the credential, never the registry (§13.9). Endpoint-name\ntokens may contain `-` inside labels; they are never used to derive principal dash-form\nnames; control-surface consumer names are the §13.9 pinned grammars, each carrying a\nstated collision-freedom argument, and none is ever parsed back into its components, so\nthe §2 dash-form separator stays unambiguous.\n\n**Command tokens.** A command name is one token `[a-z0-9-]{1,32}`. The command is a validated\nsubject token so the broker enforces per-command authority (§13.9). `describe` and `cancel`\nare reserved command names (§13.7, §13.6).\n\n**Request subjects.** Three **addressing modes** under one kind `ep`, the mode token says\nwhere a request routes, never which verb it is (the verb rides the envelope, §13.3/§13.5):\n`one` (queue-group anycast: exactly one class member), `all` (scatter: every instance),\n`inst` (one instance by its stable triple). The `one` rail's queue group is canonically\nnamed by the endpoint-name token, and serve subscriptions to it are **queue-qualified\nonly** (§13.9): no credential can plain-subscribe the class rail, which is what keeps\nper-request nonces visible only to the queue-selected instance. Every request carries the caller as **three**\nforge-locked tokens `<owner>.<actor>.<uid>` (principal + lifecycle UID, §13.1) followed by a\ncaller-chosen unguessable **nonce** token (`[A-Za-z0-9_-]{22,64}`, ≥128 bits of CSPRNG\nentropy; one outstanding call per nonce; reuse before the prior call resolves is a caller\nerror and the reply rail MUST treat the earlier subscription as dead); always, on calls and\ncasts alike, so one grant row covers both verbs and no shape is distinguished by counting. A\ncommand whose contract declares it **targeted** carries an **authorization-mode token** and,\nper mode, zero to three pinned target tokens between the command and the caller:\n\n| Form | Subject | Tokens |\n| --- | --- | --- |\n| Class, untargeted | `cotal.<space>.ep.one.<endpoint>.<command>.<owner>.<actor>.<uid>.<nonce>` | 10 |\n| Class, `self` | `cotal.<space>.ep.one.<endpoint>.<command>.self.<owner>.<actor>.<uid>.<nonce>` | 11 |\n| Class, `owner`/`any` | `cotal.<space>.ep.one.<endpoint>.<command>.<authz>.<tOwner>.<owner>.<actor>.<uid>.<nonce>` | 12 |\n| Class, `child`/`ledger` | `cotal.<space>.ep.one.<endpoint>.<command>.<authz>.<tOwner>.<owner>.<actor>.<uid>.<nonce>` | 12 |\n| Class, `handle` | `cotal.<space>.ep.one.<endpoint>.<command>.handle.<tOwner>.<tActor>.<tUid>.<owner>.<actor>.<uid>.<nonce>` | 14 |\n| Class, `exact` | `cotal.<space>.ep.one.<endpoint>.<command>.exact.<tOwner>.<tActor>.<tUid>.<owner>.<actor>.<uid>.<nonce>` | 14 |\n| Scatter | as class forms with mode token `all` | 10-14 |\n| Instance | `cotal.<space>.ep.inst.<endpoint>.<instanceId>.<command>[.<authz>[.<target tokens per mode>]].<owner>.<actor>.<uid>.<nonce>` | 11-15 |\n| Reply | `cotal.<space>.ep.reply.<endpoint>.<instanceId>.<epoch>.<owner>.<actor>.<uid>.<nonce>` | 11 |\n| Versioned rail (§13.15) | every form above with `ep.v1` in place of `ep` and `<generation>` inserted between `<uid>` and `<nonce>` | 12-17 |\n\n**The versioned rail.** An **issued** caller (§13.15) rides `cotal.<space>.ep.v1.…`: the same\nforms, one more token, the caller's issued `<generation>` (32 lowercase hex characters), placed\nbetween `<uid>` and `<nonce>` on every request and reply form. The legacy `ep.` rail and the\n`ep.v1.` rail are disjoint subject spaces at the broker: an issued credential holds rows on the\nversioned rail only, a legacy credential holds rows on the legacy rail only, and an endpoint\nserves both. A responder derives the reply subject from the authenticated request subject on\nwhichever rail it arrived, generation included. `v1` versions the rail encoding, not the\nprotocol.\n\n**Single-owner endpoint names (normative).** An endpoint name binds to exactly ONE owner\n(§13.9: operator-provisioned core names, domain-owner-bound reverse-DNS names), so the name\ntoken alone determines the serving owner and instance-addressed subjects carry **no owner\ntokens**: `(endpoint, instanceId)` is the complete routable instance address. Two parties\nwanting the \"same\" name use their own reverse-DNS names; an owner-qualified shared-name form,\nif ever wanted, would be a later additive subject form, not a change to these. This trades an\nalready-forbidden expressiveness for structurally smaller subjects and credentials.\n\n**Remote manager service.** The core `manager` name remains operator-governed: a\n`manager-service` bearer (§13.1) does not transfer its name authority or create a generic\nuser-owned endpoint. It is the one closed user-auth exception to the single-owner endpoint rule:\nthe host may authorize one `manager` service instance whose service-record owner and serving\nprincipal are the bearer's derived owner plus fixed server-selected manager actor. The exception is\nscoped by the server-authorized lifecycle UID and opaque globally unique instance id, so the\n`(manager, instanceId)` route stays unambiguous and no registration can be mistaken for another\nowner's. The standard `ep` grammar is unchanged: the bearer reaches only that exact manager\ninstance, while the manager's own agent-control requests use the existing owner and same-owner\ndescendant checks. No endpoint name, target form, or wildcard is added for this view.\n\nThe target's **lifecycle UID is body-carried, not a subject token** (`target.lifecycleUid`,\n§13.3): a grant could only ever wildcard it (targets are dynamic; the UID is unknowable at\nmint time), so a token there would add zero broker enforcement while costing every targeted\ngrant row a token, the trusted validator, not the broker, compares the expected UID against\nthe current mapping (§13.1). The one exception is `handle` mode: at handle redemption the\ntarget's UID IS known and current, so the redemption-minted form pins the full target triple\nas subject tokens (below); pin what is knowable at mint time; body-carry only what is not.\nEvery form stays within the NATS 16-token recommendation.\n\n**Explicit discrimination (never arity counting).** The forms are distinguished by the token\nafter `<command>`: it is either one of the six reserved authorization-mode tokens (`self`,\n`owner`, `any`, `child`, `ledger`, `handle`) or the caller's owner token, and the two sets\nare disjoint by construction, because an owner token is `local` or `u_`+base32 (§2), never a\nbare mode word. The target-block arity then follows the mode (`self`: none;\n`owner`/`any`/`child`/`ledger`: one `<tOwner>` token; `handle`: three,\n`<tOwner>.<tActor>.<tUid>`); a closed set at a fixed position, exactly the property that\nmakes per-mode arity safe. A parser dispatches on that set; a subject matching no defined shape\nhas no sender and MUST NOT be handled.\n\n**Token bounds (normative).** On the endpoint rails every identity token is bounded:\n`owner` ≤ 64, `actor` ≤ 64, `command` ≤ 32, `endpoint` ≤ 64, nonce and ids ≤ 64 characters;\n`lifecycleUid` and `instanceId` are bounded by their single defining grammar\n`[a-z0-9]{26,32}` (§13.1); deliberately not restated here, so the bound cannot drift from\nthe definition. A total request or reply subject MUST NOT\nexceed 1024 bytes; implementations validate fail-loud at build time. (Transport headroom:\nthe reference deployment raises `max_control_line` to 64 KiB; the PUB line is never the\nbinding constraint; minted-credential size is, §13.9.)\n\n**The authorization-mode token** (`<authz>`) makes the authority gradient explicit and\nbroker-enforced where it is statically expressible, and honestly validator-primary where it is\nnot. Seven modes:\n\n- `self`, the target IS the caller: the form carries **no target tokens and no body\n `target`** (a supplied one is `target-mismatch`, never ignored); the endpoint derives the\n target from the broker-authenticated caller triple in the same subject. Fully\n broker-confined, including the lifecycle UID, because the caller's own `<uid>` token is\n the target's UID, forge-locked by the mint: a stale lifecycle's credential cannot even\n publish the successor's subject.\n- `owner`, owner-domain: the target block is `<authz>.<tOwner>` (ONE target token); grants\n pin `<tOwner>` to the caller's own owner (standing mints; a handle redemption instead pins\n the issuer-signed target owner, §13.6). The target actor and expected lifecycle UID are\n body-carried (`target`) and validator-checked against the current mapping, the broker\n cannot express \"any actor under my owner, currently mapped to this UID\". An `owner`-mode\n grant is NEVER minted with a wildcard target owner. Broker-confined on the owner; validator\n on the rest.\n- `any`, unrestricted target owner (`<authz>.<tOwner>` with `*`): a distinct mode mintable\n only for operator/admin capabilities, so no widening of an `owner` grant can ever reach\n it. Validator-checked target as for `owner`.\n- `handle`, **redemption-minted only** (§13.6): the target block is\n `handle.<tOwner>.<tActor>.<tUid>` (THREE target tokens), each a literal pinned at\n redemption from the issuer-signed grant against the then-current mapping. Never a standing\n capability, never wildcarded. Broker-confined on the full target triple; the validator\n re-checks only currency; a subject `<tUid>` that no longer matches the current mapping is\n `expired`.\n- `exact`, **privileged exact incarnation, minted only through its owning profile** (Cotal\n #399): the target block is `exact.<tOwner>.<tActor>.<tUid>` (THREE target tokens), the same\n literal-triple shape `handle` carries, minus the redemption promise. There is no issuer-signed\n artifact, no redemption step, and no `sourceChain`; the row is built directly by the profile\n that owns this command under root authority for one target it names, never a standing\n capability, never wildcarded. Broker-confined on the full target triple, exactly as `handle`;\n the validator re-checks only currency, and a subject `<tUid>` that no longer matches the\n current mapping is `expired`. A generic reader of this mode infers precisely a privileged,\n grant-pinned exact triple with a current-mapping check, and nothing more.\n- `child`, static-mesh own-child (`spawner == caller`): a **distinct trusted-validator form**.\n The grant means \"may ask this validator\", not \"already authorized\"; the handler MUST\n fresh-check the immutable spawner relation against durable state and fail closed. Its\n `<tOwner>` ceiling is the caller's own owner, as for `owner` mode (a static-mesh child\n shares its spawner's owner).\n- `ledger`, fresh-ledger escalation: a distinct trusted-validator form; the handler MUST\n fresh-read the authorization ledger and fail closed on lookup failure, timeout, or absence.\n Its grants pin literal `<tOwner>` values named at mint; a wildcard target owner in `ledger`\n mode is mintable only for operator/admin profiles.\n\n`any`, `child`, `ledger`, `handle`, and `exact` are never wildcard-reachable from a `self`/`owner`\ngrant (distinct token ⇒ distinct subject ⇒ distinct grant row). A handler MUST resolve the target (the\nrevision-pinned `(alias, lifecycleUid)` mapping, §13.1) immediately before effect and reject\nany request whose body target disagrees with the subject target tokens (`target-mismatch`) or\nwhose expected target lifecycle UID does not match the current mapping (`expired`). The\nsubject, never the body, is the authorization boundary; handler policy only narrows.\n\nA responder that finds no current mapping for the target refuses `expired` with `outcome:\nnot-executed` and `details[].kind = ai.cotal.ep.target-unmapped`, which says the instance that\nanswered holds no mapping for it. A responder whose mappings are instance-local, as a manager's\nare for the agents it hosts, cannot tell a target another instance hosts from one retired\neverywhere. A caller that reached it on the class rail MAY therefore re-resolve and re-issue, as\nafter a bind refusal; on the `inst` rail the refusal is that instance's answer.\n\n**Replies.** Every reply rides the dedicated reply rail above, **deterministically derived\nfrom the authenticated request subject**: the responder copies the caller triple and nonce\nfrom the request subject and prefixes its own endpoint/instance/epoch tokens (the owner is\ndetermined by the endpoint name; no owner tokens appear). A responder\nMUST ignore any transport- or payload-supplied reply target (the confused-deputy boundary).\nThe grants are exact-arity, no `>` tail admits subjects outside the grammar: the caller's\nread grant is its own rail (`ep.reply.*.*.*.<owner>.<actor>.<uid>.*`), so it reads only\nreplies addressed to it; the responder's publish grant pins its own instance triple and\nepoch (`ep.reply.<endpoint>.<iId>.<epoch>.*.*.*.*`), so the answering instance and\nepoch are read off the broker-authenticated reply subject, never trusted from the payload.\nTwo properties, enforced differently, stated precisely: **attribution** (who answered) is\nbroker-enforced by the responder's pinned prefix; **addressing** (whom a responder may\nanswer) is capability-by-secret, the responder's grant spans all caller suffixes, and what\nconfines it to the requester is possession of the unguessable per-request nonce, which only\nthe request's recipients hold. A stale process (superseded epoch) publishes attributably\nstale replies that callers reject; scatter gathers additionally reject replies from\ninstances outside the frozen expected set (§13.5).\n\n**Incarnation admission (the bound-incarnation fence).** Rejecting a reply is a REPORT, not a\nguard: it happens after the responder has already handled the request. On the class rail the\nqueue picks the responder, so a caller that resolved incarnation B can have its command executed\nby A and then be told the call failed — with no way to say whether any effect landed. A caller\nthat will accept an effect only from the incarnation it resolved therefore declares it in the\nrequest (`bind`, §13.3), and a responder that is not that incarnation **MUST refuse it at the\npre-effect seam** — before args validation, before target resolution, and before the §13.6/§13.10\ngoverned gate, which may consume a one-use payment proof. The refusal carries\n`ai.cotal.ep.bind-refused` and means the command did not run, so re-resolving and re-issuing\ncannot duplicate an effect; that is the distinction `ai.cotal.ep.unbound-responder` (raised by the\ncaller, on the reply) cannot make. `bind` is a caller declaration and never authority: it can only\nnarrow a request the subject already routed, and attribution still comes from the reply subject —\na refusal attributed to the very incarnation the caller bound is incoherent and MUST be rejected\n(`internal`) rather than honored. A responder that does not implement the fence ignores the field\n(§5) and executes; the caller-side check remains the only protection in that skewed pair.\n\nThe **caller's** process epoch is\ndeliberately NOT encoded in the rails: reply consumption binds to the requesting process\nbecause a caller MUST subscribe the exact concrete nonce subject before publishing a call\nand MUST NOT persist nonces; a restarted successor never holds the predecessor's nonce\nsubscriptions, so in-flight calls die with the process (they are ephemeral by definition)\nand a late reply is unreadable rather than misdelivered.\n\n**Event and journal subjects.** Endpoint-published planes, captured by per-space streams\n(§13.12); the publishing instance's identity is forge-locked into the subject:\n\n| Plane | Subject |\n| --- | --- |\n| Events | `cotal.<space>.epe.<endpoint>.<instanceId>.<epoch>.<topic...>` |\n| Canonical facts | `cotal.<space>.epf.<endpoint>.<topic...>` |\n| Submissions | `cotal.<space>.epj.<endpoint>.<command>[.<authz>[.<target tokens per mode>]].<owner>.<actor>.<uid>` |\n| Timers | `cotal.<space>.ept.<endpoint>.<instanceId>.<epoch>.<timerId>.<schedule\\|armed\\|fire>` |\n| Record writes | `cotal.<space>.epr.<endpoint>.<instanceId>.<epoch>.<kind>.<qualifier...>` (mediated record-writer ingress; the instance's epoch-pinned rail for `svc`/`goal`/`cp` status writes; consumed ONLY by the record writer, which reads the writing epoch from the broker-authenticated subject, never from payload, §13.9) |\n| Contract artifacts | `cotal.<space>.epc.<digest-hex>` (one immutable artifact per subject; `<digest-hex>` is the artifact's SHA-256 hex, 64 chars; the `sha256:` prefix is not a subject token; §13.7) |\n| Work pools | `cotal.<space>.epw.<endpoint>.<pool>.<cOwner>.<cActor>.<cUid>.<id>` (one item per subject; the trailing four tokens are the item's **acceptance identity**; the accepted submission's caller triple + request id, §13.6) |\n| Sessions | `cotal.<space>.eps.<endpoint>.<sessionId>.<epoch>.<in\\|out>` |\n\nEvents carry the publishing instance's **epoch as a subject token**, pinned by the serve\ngrant, so a superseded process cannot emit progress indistinguishable from the current\nincarnation's; readers match the current (or goal-accepted) epoch and treat stale-epoch\nevents as attributably stale. A **targeted** journal command carries the same authz/target\nblock in its submission subject as its request forms, so the broker confines targeted\njournal work exactly as it confines calls; the canonicalizer additionally requires exact\nbody/subject agreement before acceptance. Timers use three forms: `.schedule` is the\ninstance-published **schedule request**, captured by a stream with message schedules\nDISABLED, so any client-set scheduling header is inert bytes, and the mediated timer writer\nrejects a request carrying one; `.armed` holds the **authoritative schedule message**,\npublished only by the mediated timer writer (§13.9), which derives the ADR-51\n`Nats-Schedule-Target`, the sibling `.fire` subject, from the broker-authenticated\nREQUEST subject's own tokens, never from any payload or header (a schedule's target MUST\ndiffer from its publish subject per ADR-51; replacement is the writer's same-subject\npublish on `.armed`); `.fire` is where fires appear. An instance's serve grant covers\n**only `.schedule`** (epoch-pinned); no client credential holds `.armed` or `.fire`\npublish; fired messages are written by the broker's scheduler alone, and the handler\nvalidates the carried `(timerId, generation)` against current status AND\n`now ≥ the authoritative deadline` AND that the broker-authored scheduler-origin header\nnames its own exact sibling `.armed` subject (§13.12) before acting.\n\nReserved event topics: `ev.<cluster>.<event>` (cluster events), `goal.<cOwner>.<cActor>.\n<cUid>.<goalId>.<t>` (per-goal action progress; the caller identity in the subject gives\nmint-time read containment), `cp.<token>.<t>` (checkpoint transitions). Reserved fact topics:\n`dec.<cOwner>.<cActor>.<cUid>.<id>` (canonical decisions (accepted/rejected) caller-scoped, §13.4), `quar.<sourceSeq>` (poison quarantine, §13.4; its own family,\ndisjoint from the caller-id `dec` namespace by construction), `goal.<cOwner>.<cActor>.<cUid>.<goalId>.result` (terminal\nresults), `wrk.<pool>.<cOwner>.<cActor>.<cUid>.<id>` (per-work-item terminal results,\nkeyed by the item's acceptance identity, §13.5/§13.6), `eff.<cOwner>.<cActor>.<cUid>.<id>`\n(per-request effect-complete facts for non-action effects commands, §13.9), `cp.<token>` (one-use checkpoint\nresume, journaled by create-only CAS, §13.6),\n`receipt.<cOwner>.<cActor>.<cUid>.<id>.<sourceSeq>`\n(caller-scoped; request ids are caller-chosen, so an endpoint-wide `receipt.<id>` would\nlet two callers collide and read each other's receipts, and **execution-scoped**: the\naccepted submission's `sourceSeq` is unique per execution, so a request id lawfully reused\nafter its decision retention expires (§13.4) mints a NEW receipt subject instead of\nappending to the old one, where a last-by-subject read would have hidden the earlier\nreceipt for the rest of its 90-day retention). Submissions are publishable directly by capability holders\nand are **explicitly untrusted** (§13.4); canonical fact subjects are publishable only by\ntheir mediated writer (§13.9). `<id>`, `<goalId>`, `<timerId>`, `<token>`, `<sessionId>` are\nsingle tokens `[A-Za-z0-9_-]{1,64}`.\n\nThe v0 subjects `cotal.<space>.ctl.>` and `cotal.<space>.control.>` are retired: nothing\nserves them and no post-cut credential carries a grant on them. `trace.<instance>` remains reserved,\nunchanged. `<pool>` is a single token `[a-z0-9-]{1,32}` (command-token grammar).\n\n### 13.3 Envelope\n\nRequests, replies, submissions, events, facts, and progress payloads are UTF-8 JSON. The\nenvelope is versioned and typed; `ControlRequest`/`ControlReply` are deleted.\n\n`EndpointRequest`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `v` | `1` | MUST | envelope schema version (independent of the wire `protocolVersion`; the envelope starts at its own v1 inside the v0.4 revision); other values rejected (`unsupported-version`) |\n| `id` | string | MUST | caller-chosen request id, `[A-Za-z0-9_-]{1,64}`; the idempotency key at the declared scope (§13.8), realized on journaled planes by the caller-scoped decision CAS (§13.4), never by a transport header |\n| `op` | object | MUST | `{ endpoint, command, inputDigest, outputDigest }`; MUST agree with the subject (`op-mismatch`). The digests bind the invocation to the described contract and are **both REQUIRED on every command except `describe`** (the discovery bootstrap), unconditional, because every command declares both schemas: a side with no payload declares the canonical void schema (§13.7), whose digest exists like any other. A serving member rejects a missing digest (`contract-mismatch`) before any effect, and one that cannot honor a pinned digest replies `contract-mismatch`, never coerces |\n| `class` | `ephemeral` \\| `journal` | MUST | the submission's declared delivery contract; MUST equal the command's contract class (`class-mismatch`); immutable per submission. (`record` is a state contract, never a request class; the action composite is a command marker, not a class; an action command's submissions are `journal`) |\n| `replyExpected` | boolean | MUST | the verb: `true` = call (a reply is expected on the reply rail; `deadlineMs` required; the caller subscribes its exact nonce before publishing), `false` = cast (fire-and-forget; a responder MUST NOT reply). The subject shape is identical for both; the verb never changes the grammar |\n| `goalId` | string | action commands | MUST for a command whose contract declares the action composite: the client-generated goal id (§13.6); absent otherwise. `id` remains the per-request idempotency key |\n| `target` | object | per mode | `{ owner, actor, lifecycleUid, mappingRevision? }`. **Absent for `self`** (and for untargeted ops): a supplied one is `target-mismatch`, never ignored. **Required for `owner`/`any`/`child`/`ledger`/`handle`**: `owner` MUST equal the subject `<tOwner>` token (`target-mismatch`); `actor` and `lifecycleUid` are validator-compared against the current mapping (`expired` on mismatch), and in `handle` mode MUST additionally equal the subject `<tActor>`/`<tUid>` tokens (`target-mismatch`); `mappingRevision`, when present, additionally pins the exact mapping revision the caller observed |\n| `bind` | object | MAY | `{ instanceId, epoch }` — the incarnation the caller's `describe` resolved against. A responder whose own `(instanceId, epoch)` differs **MUST refuse before any effect**, at the pre-effect seam and ahead of the governed gate: `failed-precondition` when a different instance received it, `expired` when the same instance is at another epoch, both carrying `details[].kind = ai.cotal.ep.bind-refused`, which asserts the command **did not run**. **Absent on `describe`** (the bootstrap that produces the bind; a supplied one is `bad-request`) and **absent on the scatter rail** (which addresses every incarnation; `bad-request`). On the `inst` rail it MUST name the subject's instance (`bad-request` otherwise) and adds the epoch the subject grammar has no token for. It confers nothing and can only make a responder the subject already reached refuse, so it satisfies monotonic attenuation |\n| `args` | object | MAY | validated against the input schema before any effect (`bad-request`) |\n| `from` | `EndpointRef` | MUST | as §5; `from.id` MUST equal the subject sender principal, and the sender UID token MUST match the caller's minted lifecycle UID (broker-enforced by the grant) |\n| `deadlineMs` | number | MUST for call/scatter and journal submissions | caller deadline budget; bounded, never unbounded. On a journal-class submission it is the **decision deadline**: the bound within which the caller expects its durable decision fact (§13.4) |\n| `correlation` | object | MAY | `{ traceparent?, tracestate?, baggage? }` per W3C Trace Context; propagated to downstream calls, events, facts, receipts |\n| `auth` | string | MAY | opaque signed authorization-context slot (capability handle, obligations, payment proof). Opaque to the transport, never to identity: its **`authDigest`** (§13.4 fingerprint) is `sha256:<hex>` over the UTF-8 bytes of this string **exactly as carried**; the slot is already a canonical signed artifact, so it is digested as bytes, never re-canonicalized, and is absent from the fingerprint iff `auth` is absent |\n\n`EndpointReply`:\n\n| Field | Type | Req | Notes |\n| --- | --- | --- | --- |\n| `v` | `1` | MUST | |\n| `id` | string | MUST | echoes the request `id` |\n| `ok` | boolean | MUST | |\n| `data` | any JSON | MAY | present iff `ok`; validated against the output schema |\n| `error` | object | iff `!ok` | `{ code, message, details?[], outcome? }`; codes below; `details[]` entries carry reverse-DNS `kind`; `outcome` per **Effect outcome** below |\n| `receipt` | string | MAY | opaque signed receipt slot (§13.10) |\n\n**Effect outcome.** An error reply MAY carry `error.outcome`, one of `executed`, `not-executed`,\nor `unknown`, stating whether the command's effect occurred. It is emitted by the **responder**,\nwhich is the only party that knows: a responder that refuses BEFORE dispatching to the handler\nMUST carry `not-executed`, and one that refuses AFTER the handler has run MUST carry `executed`.\nA responder that cannot distinguish the two MUST carry `unknown` rather than guess. An error\nreply that omits `outcome` MUST be read as `unknown`. A handler that refuses before its command's\nfirst effect has started SHOULD carry `not-executed`, because nothing occurred. A handler that\nrefuses after an effect may have started MUST NOT carry `not-executed`.\n\n`outcome` describes a reply, and only a reply. A refusal a CALLER raises locally is not an\n`EndpointReply` and carries no `outcome` field. It does not follow that the caller knows nothing:\nit MUST classify the refusal from what it observed, and only one of the four cases below is\ngenuinely `unknown`.\n\n- **Refused before publication** — the request was never put on the wire. The caller knows the\n effect did not occur and MUST classify it `not-executed`. Treating this as `unknown` suppresses\n a retry that is provably safe, including for a `write`.\n- **Refused while holding a reply** — the caller parsed a reply and then rejected it for a reason\n of its own, the §13.2 post-reply currency check being the case in this document. What the caller\n knows comes from the reply it holds: an `ok:true` reply means the handler ran to completion, so\n the refusal is `executed`; an `ok:false` reply carries the responder's own `outcome`, which the\n caller MUST adopt rather than overwrite. Discarding a held reply's outcome because the caller\n went on to reject the reply loses the one fact the responder was in a position to state.\n- **Answered by the broker with no responders** — the request subject had zero subscribers, and\n the broker says so on the reserved no-responders sentinel. That is a positive, broker-attested\n fact that nothing received the request, so it is `not-executed`, not merely unanswered. A caller\n MUST trust it ONLY on that reserved sentinel, which carries no responder publish grant: the same\n status on an ordinary reply subject is a responder's own claim and proves nothing about\n delivery.\n- **No reply observed** — a deadline that expires with no answer at all, a transport failure after\n publication, any path where the caller cannot tell whether the request was handled. This is\n `unknown`, and it is the only local case that is.\n\nThe reference connector reports an unanswered submitted persona definition as an unknown write\noutcome and directs the caller to read the catalog on the same manager before acting.\n\nA caller **MUST NOT infer execution from the mere arrival of a reply**: a reply proves the request\nwas HANDLED, never that it executed. The two differ on every path where a responder refuses before\nthe handler — the version, class, target, sender, authz, contract, and guard checks all publish\n`ok:false` having executed nothing, and each of those replies says so in its own `outcome`.\n\n`outcome` exists because a refusal code alone cannot carry this fact: the same code and the same\nmessage are correct for a request that ran and for one that never left, and a caller that cannot\ntell them apart and retries duplicates the effect. `effect` (§13.7) tells a client whether a\nrepeat is safe; `outcome` tells the caller what already happened. Neither substitutes for the\nother, and a `write` command refused with `unknown` is precisely the case where no automatic\nrecovery is available and the decision belongs to the caller.\n\n`outcome` is NOT a goal's terminal state. An action accepted under §13.6 reports its result as a\ngoal fact; an accepted action whose caller then loses its follow has an `outcome` of `executed`\nfor the SUBMISSION and no terminal state at all, which are different facts about different\nthings. `outcome` MUST NOT be used to report, replace, or summarize a goal outcome.\n\nThe answering instance, its epoch, and the addressee are read from the **reply subject**\n(§13.2), not from payload fields; a payload claim of either is advisory display data only.\n\nEvery other plane is typed too: a journaled **submission** is an `EndpointRequest` (same\nenvelope, published to `epj`); an **event** (incl. per-goal progress) is\n`{ v: 1, topic, ts, data, correlation? }`; an **acceptance fact** is the `AcceptanceFact` of\n§13.4; a **terminal result fact** carries the goal's terminal state (one of the five\nterminal values of §13.6), outcome digest, and\nresult payload (or its digest-pinned reference). All are runtime-validated at their\nconsuming boundary.\n\n**Monotonic attenuation (invariant).** Envelope content, the `auth` slot, a handle,\nobligations; may only narrow what the presenting credential already permits, never widen it.\nA handler that honors envelope content as authority beyond the broker grant is non-conformant.\nAuthority *conferral* exists only as trusted redemption (§13.6 capability handle).\n\n**Error catalog.** `code` is one token: `bad-request`, `unsupported-version`, `op-mismatch`,\n`class-mismatch`, `target-mismatch`, `sender-mismatch`, `unauthenticated`,\n`permission-denied`, `not-found`, `already-exists`, `conflict` (CAS/fencing loss,\nfingerprint conflict, duplicate resume), `contract-mismatch`, `contract-invalid` (schema\noutside the profile / over budget at registration), `failed-precondition`,\n`deadline-exceeded`, `cancelled`, `expired` (lease, handle, lifecycle UID, epoch, token),\n`unavailable` (no responder), `unimplemented`, `resource-exhausted`, `internal`. Extensions\nadd codes only under reverse-DNS. A `code` (catalog or extension) is one token of at\nmost **64 bytes**, so every fact shape that embeds one (`RejectionFact`, `QuarantineFact`)\nstays bounded by construction and the §13.12 fact fixture is a true worst case.\n\n### 13.4 Delivery contracts\n\nThree delivery contracts, chosen per command class, declared in the contract, immutable per\nsubmission. Decision rule: crash means \"just re-ask\" → **ephemeral**; long-lived state\nsomething converges on → **record**; must survive restart, be audited, metered, or\ncompensated → **journal**. Wrong-class submission fails loud.\n\n**Ephemeral**, request/reply on the `ep` rails; no broker persistence; at-most-once effect\nunless the command is idempotent by `id`. No-responder is a loud `unavailable`.\n\n**Record**, a `{kind, schema, spec, status, meta}` resource in the per-space records bucket,\nstored as **two keys with independent revisions**: `<key>.spec` and `<key>.status`. The split\nis the broker-enforced writer boundary: the spec-writer and status-writer roles hold publish\ngrants on their own key only (per-kind writer table, §13.9). Writes use per-key CAS; a lost\nrace is a loud `conflict`. The merged logical read returns both\nrevisions and carries `status.observedSpecRevision`; a reader treats\n`observedSpecRevision < spec.revision` as a stale-but-valid level-triggered projection, not\nan error, and `observedSpecRevision > spec.revision` (a lagging spec read, possible across\nreplica freshness points) as its own signal to re-read the spec key, bounded retries until\ncaught up or the caller's deadline, never trusting the mismatched pair. Watch delivers\ncurrent values then deltas per key; a watcher that falls behind MUST re-read both keys and\nresume, never patch forward across a gap. Records are\nbounded (§13.8).\n\n**Journal**, an explicitly **untrusted at-least-once submission log** feeding **canonical\naccepted-fact subjects** with a mediated writer; effects consume only canonical facts, never\nraw submissions.\n\n1. A journaled submission is published to the submission plane (`epj`) as a **plain append**:\n submitters MUST NOT set `Nats-Msg-Id`, and native dedupe is **not relied upon**, the\n server does not accept a zero duplicate window (§13.12), so the reference config sets the\n server minimum and the guarantee rests on the header rule, not the window: a conformant\n submission carries no dedupe header and cannot be suppressed by one. Native broker dedupe\n keys on a caller-set header value compared\n **stream-wide**, so on a shared submissions stream any writer could pre-seed a predicted\n header value from its own allowed subject and silently suppress another caller's first\n submission for a full dedupe window, a cross-caller denial that no \"advisory\" framing\n makes safe; with the MUST NOT in force, a hostile header-bearing publish can suppress only\n another non-conformant header-bearing write. Transport retries therefore simply append\n again; the caller-scoped decision\n CAS below resolves every copy to one decision. Submission subjects and fact subjects are\n disjoint by construction (§13.2), so a submission credential cannot write a fact.\n2. The **semantic fingerprint** covers every effect-defining dimension, the fingerprint\n object is `{endpoint, command,\n class, authz?, target?: {owner, actor, lifecycleUid, mappingRevision?}, inputDigest,\n outputDigest, args, authDigest?, caller: {id, lifecycleUid}, goalId?, id}`, and the\n fingerprint VALUE is that object's `sha256:<hex>` content digest per §13.7 (strict\n RFC 8785 over I-JSON, the SAME canonicalization every contract artifact uses; one\n canonicalizer, never a second): absent optional fields are OMITTED from the object, never\n written `null`, so two implementations digest identical bytes, which also makes the\n fingerprint **computable for EVERY parseable submission**, however incomplete: a\n parseable envelope missing `class` or digests fingerprints the subset it carries and is\n rejected with that fingerprint. **\"Parseable\" here means canonicalizable I-JSON**, not\n merely syntactically valid JSON: bytes that parse but cannot be canonicalized, duplicate\n object names, a lone surrogate, a non-finite or out-of-I-JSON-range number; have no\n interoperable RFC 8785 form and therefore no fingerprint, so they take the quarantine\n path exactly as unparseable bytes and an invalid `id` do (§13.4 item 3: raw-byte digest,\n no fingerprint). Every submission thus has exactly one terminal path. Same id +\n same fingerprint is the same request (idempotent, first-wins); same id + different\n fingerprint (including the same args retargeted at a different lifecycle) is a loud\n `conflict`, never accepted or effected.\n3. The **canonicalizer**, the narrowly scoped mediated writer for this endpoint's facts\n (§13.9); consumes the submission plane through a **normative durable `AckExplicit`\n consumer** and acks a submission ONLY after a durable decision fact exists, and, for a\n pool-admitted acceptance, ONLY after the §13.6 EPW enqueue create has additionally\n succeeded (or lost its CAS to an already-present entry): a crash anywhere between\n acceptance and enqueue therefore redelivers the submission, and the reconciliation\n predicate resolves the redelivered copy; recovery never has to DISCOVER orphaned\n acceptances, because an acceptance without its enqueue is by construction an unacked\n submission that comes back. A crash before\n the fact redelivers the submission; a crash after it observes the CAS winner on\n redelivery. It validates each submission (schema, body/subject agreement incl. the target\n block, authorization per §13.6, and (for work-pool commands) pool admission/capacity\n BEFORE acceptance) and then decides each request exactly once by publishing a\n **decision fact** to the caller-scoped subject\n `epf.<endpoint>.dec.<cOwner>.<cActor>.<cUid>.<id>` with create-only CAS (expected last\n sequence on the subject = 0), so distinct callers can never squat each other's ids. **For\n an action command the canonicalizer additionally binds the goal before accepting**: it\n create-only-CASes a **goal-bind fact** `epf.<endpoint>.goal.<cOwner>.<cActor>.<cUid>.<goalId>.bind`\n carrying the accepted fingerprint, and rejects (`conflict`) any later submission whose\n `goalId` matches but whose fingerprint differs, so two distinct `id`s naming one `goalId`\n cannot both be accepted-and-effected (the decision CAS keys on `id`, which alone would let\n both through; the goal-bind CAS keys on `goalId`, which stops the second BEFORE acceptance\n and effect, not at the terminal-result stage where the effect has already happened).\n The decision is `accepted` or `rejected` (with the catalog error); **rejection is as\n durable, caller-readable, and idempotent as acceptance**, so a permanently invalid\n submission is distinguishable from a lost one. First decision wins atomically; a later\n attempt fails its CAS and reads the existing fact. There is no append-then-memo pair to\n crash between. The canonicalizer is a **singleton per endpoint** (one active principal,\n epoch-fenced like any serve identity, recovered through the §13.1 takeover barrier):\n admission checks (pool capacity for work-pool commands) are thereby serialized with the\n decisions they gate, so two canonicalizers cannot both admit the last slot; capacity is\n consumed by the acceptance itself, never checked apart from it. A submission that cannot\n yield a decision key; bytes that are not canonicalizable I-JSON (unparseable, duplicate\n object names, lone surrogate, out-of-range number), or no `id` within the token\n grammar; **or bytes that breach the command's declared `admissionCeiling`** (§13.7): raw\n size over `maxBytes`, nesting over `maxDepth`, or member count over `maxItems`; is\n **quarantined, never redelivered forever**: the canonicalizer publishes a\n **`QuarantineFact`** to the disjoint quarantine family\n `epf.<endpoint>.quar.<sourceSeq>` (§13.2); keyed by the source sequence, which exists\n for every stored copy by construction, in a family that shares no namespace with\n caller-chosen `dec` ids, so no legal request id can collide with a quarantine key, with\n create-only CAS, and terminally acks\n (`AckTerm`) the submission ONLY after that fact durably exists (or its CAS loss shows it\n already does), so a poison message cannot pin `MaxAckPending` and the\n fact-before-terminal-ack rule holds on the poison path exactly as on the decision path.\n `QuarantineFact` = `{ v: 1, decision: \"quarantined\", sourceSeq, submissionDigest (the\n `sha256:<hex>` digest of the raw stored bytes, §13.7), error: { code (catalog token),\n detail? (≤ 256 bytes) }, caller?: { id, lifecycleUid } (from the broker-authenticated\n submission subject, when it parses), ts }`, every field bounded or fixed-size, so the\n fact fits by construction; it never carries the poison bytes themselves.\n4. Journal submissions set `replyExpected: false`; the caller **observes its decision** by\n watching/reading its own decision subtree (`epf.<endpoint>.dec.<its triple>.>`, a\n caller-scoped read grant minted with every journal capability). An action command's\n accept/reject is exactly its decision fact, expected within the submission deadline.\n5. The **acceptance fact is self-sufficient for effect and replay** (`AcceptanceFact`, the\n `accepted` decision): `{ v: 1, id, decision: \"accepted\", fingerprint, request: <the\n canonical EndpointRequest, args INLINE, bounded by the broker's max_payload; a submission\n too large is refused loudly with resource-exhausted, never spilled into storage>, caller:\n {id, lifecycleUid}, target?: {owner, actor, lifecycleUid, mappingRevision},\n contractDigests: {input, output}, authzDecision: {revision, epoch},\n route: \"effects\" | `pool.<pool>` (the acceptance's SINGLE execution route, decided by\n the canonicalizer at admission: a pool-routed acceptance is executed by the pool's\n worker path (§13.5) and the effects consumers MUST ack it without effect; an\n effects-routed acceptance is executed by exactly one instance off the shared effects\n durable (§13.9). No acceptance is ever executed twice, because the fact names its route),\n readinessDeadlineMs?: <the acceptance-relative readiness bound, present iff the command\n declares bounded readiness, §13.6; persisted HERE because it is goal state, not the\n request's decision deadline>,\n workExpiry?: <absolute expiry of a pool-routed item, present iff `route` is a pool, §13.8;\n survives reconciliation re-enqueue unchanged>, sourceSeq, ts }`. A `target`-bearing\n acceptance (work bound to a lifecycle) publishes ONLY after its target-indexed\n obligation row exists AND only under an unexpired admission proof the mediator issued\n for that row (§13.8: proof issuance is the post-create currency recheck, so a row whose\n target or policy moved between create and recheck never admits; the fact's durable\n address is caller-scoped, so the obligation row, keyed target-first, is the ONLY\n target-enumerable record a retirement barrier can drain;\n `target.mappingRevision` is provenance, never a fence). The\n canonicalizer preflights the **serialized decision fact**, not merely the inline args,\n against `max_payload`: a submission whose acceptance fact would not fit is rejected\n `resource-exhausted`, and the rejection fact always fits by construction: every field\n is bounded or fixed-size (the operator floor assertion covers the maximum serialized\n rejection/quarantine fact, §13.12):\n `RejectionFact` = `{ v: 1, id, decision: \"rejected\", fingerprint, error: { code (catalog\n token), detail? (≤ 256 bytes) }, caller: {id, lifecycleUid}, authzDecision?: {revision,\n epoch}, sourceSeq,\n ts }`; the fingerprint and the catalog error, never the args (a parseable submission\n always yields the fingerprint; the unparseable/no-id case is the QuarantineFact above,\n which requires neither `id` nor `fingerprint`). Digest-pinned\n references inside a fact may name **only already-published public contract artifacts**,\n never per-request payloads: the contract store is public, immutable, and permanent,\n the opposite lifecycle of private, horizon-bounded request content (a large-payload\n facility, if ever needed, is its own future primitive with its own store, retention, and\n §13.9 rows). Effects and replay read the fact, never the raw submission (a TOCTOU re-read\n of the untrusted log is non-conformant).\n6. Decision facts/tombstones are retained at least the declared **idempotency horizon**\n (default 24h, space-configurable) AND longer than the maximum submission-log retention\n plus recovery/redelivery lag; otherwise a rebuilt canonicalizer could re-accept an old\n submission still sitting in the log as new work. The horizon is **realized by decision\n retention, not by a clock**: the create-only CAS returns the recorded decision for exactly\n as long as the fact exists, and a reused id becomes new work only once retention has\n evicted the old fact and freed its subject; there is no separate time rule for the CAS\n to disagree with. The §13.12 retention floor states the horizon by OUTCOME: no removal\n cause may drop a decision fact or tombstone before it. The canonical subjects are the authority (D12) for anything\n auditable, metered, compensated, effected, or replayed. Ordering is per-subject;\n consumers never assume cross-subject order.\n\n**Events are not facts.** Cluster events and per-goal progress (`epe`) are direct,\nepoch-fenced, instance-published notifications on a durable, ordered, replayable stream;\nthat is the sense in which they ride the journal contract. They do NOT pass through the\ncanonicalizer, carry no acceptance semantics, and MUST NOT drive effects that require\ncanonical acceptance; anything auditable/metered/compensated goes through submissions and\nfacts.\n\n### 13.5 Verbs\n\n- **call**, bounded request/reply (`replyExpected: true`, `deadlineMs` mandatory). On the\n `one` rail it is queue-group anycast; on `inst` it addresses one stable instance. No\n responder → `unavailable`.\n- **cast**, the same subjects and grants (`replyExpected: false`): fire-and-forget,\n at-most-once, the responder MUST NOT reply and the caller never reads the rail (the nonce\n is present but unused). A cast to a journaled command is `class-mismatch`; journaled work\n goes through submissions. In the NATS binding a publish violation is asynchronous — the\n publish call returns normally while the broker refuses — so a caller-side cast\n implementation MUST watch the connection status for a violation on the cast's own subject\n and raise `permission-denied` naming that subject, exactly as a call does; a cast\n implementation MUST NOT resolve as though a refused publish had been cast.\n- **watch**; observe a record (KV watch; fell-behind ⇒ re-read, §13.4) or an event topic\n (live subscription within the read grant plus filtered replay from the event stream).\n Per-key and per-goal subjects carry read containment; a watch grant names the exact subtree.\n- **claim**, competitive at-most-one-winner acquisition from a durable work pool (`epw`),\n **owner-mediated**: the pool's owning endpoint holds the pool's single `AckExplicit` pull\n consumer (§13.12); workers hold **no** JetStream grant on the pool and acquire, renew, and\n settle work exclusively through the owning endpoint's reserved **`lease`** and **`commit`**\n commands on the ordinary `ep` rails. This is the only shape that satisfies both claim\n invariants at once: the delivery's ack token never leaves the party allowed to use it, and\n the attempt binding is **owner-recorded at assignment** rather than asserted by the worker\n (a worker-carried \"sequence + attempt\" proves nothing about delivery; an owner assignment\n does). The stored pool message is **work identity and input only, never the authoritative\n lease**: broker redelivery re-delivers the same stored bytes, so a token in the payload\n cannot fence, and the consumer's `ack_wait` is the broker's redelivery-to-owner timer only,\n never the lease. `lease` (call): the owner fetches the next stored item and records the\n lease `{item, sourceSeq, attempt: the delivery count, worker: the broker-authenticated\n caller (principal + lifecycle UID, plus epoch for endpoint workers), fencingToken,\n leaseDeadline}` in its `lease` record (key grammar §13.7, writer table §13.9) by\n **first-wins idempotent CAS per (item, attempt)**, a duplicate or\n delayed `lease` call for a still-current attempt returns the SAME lease; an attempt is\n superseded once redelivery advances the delivery count; `fencingToken` is CAS-incremented\n per attempt and `leaseDeadline` comes from the owner's own clock. Expiry revokes the claim\n at that deadline even before reassignment. Every Cotal-owned commit from claimed work is\n submitted through the reserved **`commit` command** carrying the exact lease tuple; the\n handler validates token currency AND unexpired lease against its own clock AND that the\n caller is the lease's bound worker, then performs an **atomic, idempotent per-item CAS to\n a cached terminal result**, the per-item terminal fact\n `epf.<endpoint>.wrk.<pool>.<acceptance identity>` (§13.2), create-only CAS per item,\n under its mediated writer credential (§13.9): a committed item\n can never be leased again, a duplicate commit returns the cached terminal outcome, and a\n raced commit loses loudly. Only after observing the committed terminal state does the\n owner ack the WorkQueue message; it holds the delivery natively, so the deletion\n capability is never transferred, and no worker-side ack can destroy an item whose commit\n was rejected. A lost owner ack merely redelivers the item to the owner, which observes the\n committed terminal state and acks again: **settled work is never re-enqueued as new** (the\n durable bridge is the acceptance fact plus the per-item terminal CAS; an accepted item\n with no terminal result and no live pool entry is the only re-enqueueable state, §13.6). A\n stale token, expired lease, or superseded worker is `expired`/`conflict`; workers hold no\n bypass write.\n- **scatter**, a request on the `all` rail. The caller freezes a **request-scoped expected\n set**, the live instances of the class from the service registry, each as\n `(instanceId, registrationRevision, epoch)`, where `registrationRevision` is the store\n revision of the instance's `svc….spec` record key (§13.7: it advances only on mediated\n registration writes, and the record read/watch grant that freezes it is a §13.9 matrix\n row), at send time. Gather accepts at most one\n terminal reply per expected `instanceId`, attributed from the reply subject **including its\n epoch** (§13.2): a second reply from the same `(instanceId, epoch)` is classified\n `duplicate` and **reported, never silently dropped** (first reply wins); a reply from a\n frozen `instanceId` at a different epoch, or an observed registration-revision advance;\n is classified `churn` (the instance restarted mid-scatter and may never have seen the\n request) and does not count toward completion; replies from outside the frozen set are\n classified `unexpected` and never count toward completion. Completion is\n all-expected-replied or deadline, in which case the result is explicitly partial with\n `missing` / `churn` / `unexpected` / `duplicate` / `late` classifications (a churned slot\n reports as `churn`, not `missing`). An empty or unreadable registry is\n `failed-precondition`, not an empty success. Deadline mandatory. A per-instance liveness\n probe that asks the broker about an instance's own rail is such a cast, and a refused\n probe publish MUST surface as that same `permission-denied` refusal naming the refused\n subject, never as a liveness verdict: only the broker's no-responders answer is a\n liveness fact, and a refusal licenses nothing (a caller that swallowed it into `unknown`\n would read a permission problem as \"no verdict\" and pay the full budget for it).\n\n### 13.6 Composites\n\nPatterns over the verbs and contracts; zero new transport.\n\n**Action**, a long-running command. `action` is a command **marker**, never a class: an\naction command's submissions are `class: journal` (§13.3).\n\n1. The caller submits with a client-generated `goalId` and the request fingerprint (§13.4).\n Accept/reject is the durable decision fact (§13.4), expected within the submission's\n decision deadline; there is no reply-rail answer to recover.\n **Authorization linearizes at acceptance**: the acceptance fact persists the caller and\n target lifecycle tuples, command + contract digests, and the authorization decision\n revision/epoch it was made under. A scope narrowing before acceptance rejects the goal;\n after acceptance it blocks *new* goals but an accepted goal continues, unless the\n command's contract declares **continuous reauthorization**, in which case each declared\n checkpoint re-validates and deterministically transitions to `cancelling`/`failed`\n (`permission-denied`) on narrowing. Handle expiry/revocation mid-goal follows the same\n declared policy.\n2. States: `accepted → running ⇄ waiting → succeeded | failed | cancelled | expired |\n uncertain`, with\n `cancelling` between a cancel and its terminal state. This is the **single status\n vocabulary** for every long-running surface. All five of `succeeded`, `failed`,\n `cancelled`, `expired`, and `uncertain` (item 6) are **terminal**, and first-terminal-fact-wins\n applies uniformly: `uncertain` is not an absence of an outcome, it is the outcome\n \"this action's success signal did not arrive within its readiness deadline\".\n3. Progress rides per-goal events (`epe…goal.<caller triple>.<goalId>.progress`), read-scoped\n to the caller at mint time. The goal's current state is a status-only record projection;\n the journal owns the facts.\n4. Cancel is the reserved `cancel` command: `graceful` (compensations, default) or\n `terminate`. Cancel of an unknown/terminal goal is `failed-precondition` with the cached\n outcome attached. Cancel races completion at the mediated commit point: first terminal\n fact wins; the loser observes it.\n5. The terminal result is a journal fact and is cached. The full payload is retained at least\n the declared result retention (default 24h); a **terminal tombstone**\n `{goalId, fingerprint, state, outcomeDigest}` at least the idempotency horizon (≥ result\n retention; outcome-stated by the §13.12 retention floor). Same goalId + fingerprint returns the cached outcome (after payload eviction:\n the tombstone summary, `data.evicted: true`); same goalId + different fingerprint is\n `conflict`; beyond the horizon a reused goalId is explicitly new work.\n6. **Bounded readiness (`uncertain`).** An action whose success signal may lawfully not\n arrive within its readiness bound declares a **readiness deadline**, a distinct,\n acceptance-relative bound persisted in the acceptance fact/goal state, NOT the\n submission's `deadlineMs` (which bounds only the decision, §13.3). Spawn readiness is\n the reference case: its readiness deadline is **30 s**, the migrated presence-or-exit\n backstop, D29; every legacy spawn-timeout consumer converges on this single bound. A\n spawn whose agent application waits for the operator before its session joins, as its\n connector declares for the launch's options (a session picker, for one), has its running\n process as the success signal: the owner records `succeeded` once that process has run\n briefly without exiting, and the result's `waitingFor` names the screen. When\n the deadline passes without the signal, the owner records the goal's terminal **result\n fact** (`goal….result`, §13.2) with the outcome\n `uncertain`, and the goal IS terminal: `uncertain` is a terminal outcome like\n `succeeded`/`failed`, immutable, first-terminal-fact-wins as for any goal (there is no\n call and no reply rail here: an action is a journal submission, and the result fact IS\n the caller-visible outcome, item 5). The underlying ENTITY's later convergence\n (ready/exited) is observable on that entity's own status record (`svc….status`, the\n lifecycle mapping); a caller that needs the eventual answer watches the entity, never\n the goal; the goal is not rewritten and its status does not linger non-terminal. An owner\n that observed the entity still running when the deadline passed MAY add a detail of kind\n `ai.cotal.goal.entity-running` to the `uncertain` result's `details`, and a caller then\n reports the action as still starting.\n7. Goals bind the target's `(principal, lifecycleUid)` (§13.1): a goal accepted against a\n lifecycle is not redeemable, cancellable, or effectful against a same-name successor. A\n restarted instance (same `instanceId`/UID, advanced epoch) recovers its goals from journal\n + records; a superseded epoch cannot commit transitions.\n\n**Awaitable checkpoint**; one durable pause primitive (approvals, guard holds, payment\nauthorization). A waiting action mints a checkpoint: a durable token persisted with the goal,\na `waiting` status carrying the checkpoint id and its **deadline generation**, and a durable\ntimer (§13.12). Deadlines are mandatory. Heartbeat/extension CAS-advances the generation in\nstatus, then replaces the timer (a new `.schedule` request; the mediated timer writer's\nsame-subject `.armed` publish is the server rollup, §13.2/§13.12, the 2.14 atomic\nstop-plus-publish is NOT assumed at the 2.12 floor). A firing timer carries\n`(timerId, generation)`; the endpoint validates the generation against current status before\nacting, stale fires **no-op**. Because status and timer are two resources with no atomic\nbridge, a **durable reconciler** on the owning endpoint repairs the pair after crash or\nleadership change WITHOUT any status↔schedule read the no-read timer plane cannot serve: the\nreconciler **re-emits a `.schedule` request at the current generation for every `waiting`\nstatus it owns**, and a same-`(timerId, generation)` arm is **idempotent at the timer writer**\n(it re-derives the same `.armed` message; a duplicate is a no-op replacement), so\nover-emission is harmless and a missing schedule is repaired without the reconciler ever\nhaving to observe whether one exists. Stale-generation fires still no-op at the handler. Cancellation of a timer is cleanup, never the correctness boundary.\nTimer retention MUST exceed the maximum deadline plus a recovery margin. Resume: a `resume`\ncommand presenting the checkpoint token; resume authorization is **one-use** (journaled by\ncreate-only CAS on the checkpoint token; duplicate resume is `conflict`) and holder-bound\n(§13.10). Expiry fails the checkpoint closed.\n\nA settlement MAY name the answer it accepted. The one-use settle fact carries an OPTIONAL\n`answerId`, and the status carries the matching OPTIONAL `settledAnswerId`; both are id tokens,\nboth are permitted ONLY on a `resumed` settlement, and an implementation MUST reject either on an\nexpiry. Their key sets are closed: an endpoint that does not know these keys MUST hard-error on a\nfact that carries one. The answer's payload MUST NOT ride either field.\n\n**Guard checkpoint**, the pre-effect authorization hook. A command carrying the governed\n`ai.cotal.guarded` trait MUST NOT effect until the guard endpoint named by the trait value\nanswered **allow** (class call). Answers: `allow | deny | hold` plus optional signed\nobligations (attenuations the endpoint MUST apply; monotonic). `hold` converts the action to\n`waiting` on a checkpoint owned by the guard decision. Timeout or unreachable guard is\n**deny** (fail closed). Ordering is guard-then-effect. Side-effecting guards own their own\nreconciliation.\n\n**Capability handle**, the one passable reference type: a signed JSON grant, RFC 8785\ncanonical, Ed25519-signed by a key in the trust-anchor registry (§13.10):\n\n`{ v: 1, id, space, issuer: { keyId }, holder: { id, lifecycleUid }, grants: [{ endpoint,\ninstanceId?, commands: [{ name, authz?, targetOwner?, targetActor?, targetLifecycleUid? }],\nreads?: [<record-key or event-topic subtree>] }], iat, nbf?, exp, parentDigest?, sturdy,\nepoch?, sig }`\n\nA grant entry carries **every subject-level dimension** a capability has (§13.9): a targeted\ncommand names its authorization mode and target components; read scopes name exact\nrecord-key / event-topic subtrees. The per-command target tuple is a **closed set of three\nlegal shapes**, no target components; `targetOwner` alone; or the full triple\n`{targetOwner, targetActor, targetLifecycleUid}`, and **every other combination is\nschema-invalid** (`contract-invalid`): in particular `targetActor` without\n`targetLifecycleUid` (a handle that pins a recyclable alias component MUST pin the lifecycle\nit means) and `targetLifecycleUid` without `targetActor` (a lifecycle restriction with no\ncompile target would otherwise be silently DROPPED into an owner-wide grant, a partial\ntuple never weakens into a broader one). The normative compiler maps a grant entry to\nexactly the subjects the equivalent minted capability would receive (never wider) it MUST\nconsume every present signed component (a component the compile target cannot express is\nschema-invalid, never ignored), and every legal entry HAS a compile target:\n\n- a **no-target** entry compiles to the untargeted or `self` form per the command's\n contract; an `authz` field on it is schema-invalid.\n- an **owner-domain** entry (`targetOwner` alone) compiles to the mode its `authz` field\n names, `owner` (the default), `child`, or `ledger`, and NOTHING else: each pins the\n signed `targetOwner` in that mode's own subject form (§13.2), **never collapsing `child`\n or `ledger` to `owner`** (the modes are distinct validator-primary rails and rewriting\n one into another widens authority), and **`authz: \"any\"` is schema-invalid in a handle\n grant entry** (`contract-invalid`): the `any` rail is operator-ceiling authority, minted\n only as a standing capability under an operator-scoped anchor (§13.10), never conferred\n or attenuated through a handle; a compiler therefore has no `any` case, and no\n implementation choice exists between rejecting, literalizing, or widening it.\n- an **actor-pinned** entry (the full triple) compiles to the `handle`-mode form pinning the\n full signed triple `<targetOwner>.<targetActor>.<targetLifecycleUid>` (§13.2); an `authz`\n field on it is schema-invalid (the triple IS the mode).\n- an **instance** entry compiles to\n the exact `ep.inst` rails; complete, because `(endpoint, instanceId)` is the whole instance\n address and instance ids are never reused (§13.1).\n\nA capability that cannot be represented in this shape MUST\nNOT be carried by a handle.\n\n- **Two uses, both fail-closed.** *Attenuation:* presented in the `auth` slot, a handle only\n narrows; the handler enforces `effective = presenter-cred ∩ handle.grants ∩\n issuer-authority`, and additionally requires any signed target triple to match the\n request's target and the current mapping (`expired` on mismatch); it never confers broker\n reach. *Conferral:* a handle grants reach only by **redemption through the trusted auth\n path** (the exchange/callout of §9/§10), which verifies the signed target triple against\n the current mapping **at redemption time** (`expired` on mismatch) and mints a short-lived\n credential whose grants are the intersection of issuer authority, handle grants, and the\n redeeming holder's current lifecycle + credential; actor-pinned grants compile to\n `handle`-mode subjects carrying the verified triple (§13.2), so a target lifecycle that\n rotates after mint is caught by the endpoint's currency check; no handler-side widening\n exists. The minted credential is **ledgered before release** in the credential ledger\n (§13.1), keyed under the redeeming holder's lifecycle with the FULL presented handle\n chain as its `sourceChain` (plus the per-ancestor `bysrc.` index keys), so\n takeover/retirement barriers revoke it with the family and revoking ANY handle in its\n lineage (parent or leaf) cascades to it. Chain verification itself checks the\n revocation status of EVERY sturdy link in the chain, not only the presented leaf,\n failing closed on any revoked ancestor.\n- **Holder-bound:** `holder` names the one `(principal, lifecycleUid)` that may present or\n redeem it; bearer transfer exists only as an explicit issuer-signed re-issue. `space` binds\n it to one space. A recycled alias cannot present its predecessor's handles (UID mismatch).\n- **Attenuation chain:** `parentDigest` references the parent handle; a child MUST be ⊆ its\n parent under the **normative containment order**, per grant entry: endpoint within the\n parent's endpoint/domain pattern; `instanceId` equal or newly pinned (never widened to\n absent); commands a name-subset with per-command mode never higher in `self < owner < any`\n (`child`/`ledger`/`handle` are grantable only where the parent names the same mode); target\n components equal or newly pinned; read subtrees subject-prefix-contained, and per\n envelope: same `space`, validity window within the parent's, `sturdy` only if the parent is\n sturdy. The issuer of a child is the parent's holder, anchor-registered with a `handles`\n role whose scope covers the child (§13.10); the same containment order defines issuer-scope\n coverage. Presentation carries the full chain inline (`parentDigest`-linked artifacts\n presented together, no ambient fetch); verification walks every link to a registered\n anchor, failing closed on widening, unknown/revoked keys, or expiry.\n- **Sturdy vs live:** live handles (`sturdy: false`) bind the current process `epoch`, are\n never persisted, `exp ≤ 24h`, and die on restart. Sturdy handles bind the lifecycle UID\n (surviving supervised restart), persist as issuer-namespaced `handle.<issuerKeyId>.<id>`\n records (spec create-only; status = revocation state, monotonic; §13.9 writer table), and\n verifiers MUST check revocation (fail closed if unreadable). Max sturdy TTL is\n space-configured (default 30d).\n- Handles are reusable within TTL unless a composite declares one-use (checkpoint resume);\n the replay matrix of §13.10 governs every signed artifact.\n\n**Session (bidirectional stream)**, the generic composite for interactive byte/frame\nstreams (terminal attach is its first consumer; nothing terminal-specific is normative). It\nis exactly D26's cast-ingress + watch-egress composed over dedicated per-session subjects,\nno new verb and no new transport: the `in` subject is a cast-only rail (caller publishes,\nendpoint subscribes) and the `out` subject is a watch rail (endpoint publishes, caller\nsubscribes). A session is established by an ordinary command whose answer is a **session\ngrant**: a one-use,\nholder-bound handle (live: bound to the caller's lifecycle AND current process epoch,\nlive authority dies on restart, §13.1, so redemption fresh-checks the holder epoch and an\nunredeemed grant does not survive the caller's restart, plus the serving instance epoch) naming a fresh\nunguessable `sessionId` and the epoch-pinned session subjects\n`eps.<endpoint>.<sessionId>.<epoch>.in` (caller → endpoint) and `….out` (endpoint → caller).\nSession subjects are **core-only**, never stream-captured; the bounded flow window lives in\nmemory and a dropped frame is the composite's problem, not retention's. Redemption mints\nexact asymmetric per-session credentials: the caller publishes `in` and subscribes `out`;\nthe serving instance the reverse; no third party holds either, and no standing wildcard EPS\ngrant exists. Frames are opaque; flow control is bounded (window declared in the grant;\noverflow is `resource-exhausted`, never unbounded buffering). Close is explicit, and\nrevocation has a **durable** named authority that survives the\nserving endpoint: the trusted auth path (the exchange/callout of §9/§10) persists a **session\nledger row** at redemption, key `session.<sessionId>` in the auth store (§13.12), value\n`{sessionId, endpoint, serving instance + epoch, holder (principal + lifecycleUid), both\nminted credential ids, per-credential revocation marks, state, exp}` (the endpoint is in the\nrow because an `instanceId` is unique only within its endpoint, so every serving-party\noperation authenticates against the full serving identity the row pins), create-only CAS per\n`sessionId` (this CAS IS the one-use\nredemption), state monotonic\n(`active → closed | expired | superseded | retired`, all terminal), and each per-session\ncredential is simultaneously a credential-ledger row under its holder's lifecycle (§13.1),\nwhich is the index the §13.1 barriers enumerate, and a barrier that revokes a\nsession-sourced credential MUST resolve its `session.<sessionId>` row, transition it\nterminal, and revoke BOTH per-session credentials, so either side's takeover or retirement\ntears down the whole pair, not its own half. Redemption's writes are ordered by a **finalize CAS**, so no half-issued session is ever\nusable: the create-CAS writes the session row in state `issuing` (this create IS the\none-use), then both per-session credential rows are written gate-checked (§13.1), then the\nredemption **CAS-finalizes the session row `issuing → active`**, fresh-checking BOTH the\nholder and serving process epochs and both lifecycle gates at that CAS, and releases the two\ncredentials only on finalize success. A credential is authority ONLY once its session row is\n`active`; an `issuing` row confers nothing. Close/expiry/either barrier CAS the row to a\nterminal state (`closed`/`expired`/`superseded`/`retired`) and revoke both credential ids by\nname (the ids are known from the row, whether or not both credentials were released) so a\ncrash mid-issue leaves an `issuing` row that the expiry sweep collects (revoking both ids and\ntombstoning), never a live half-pair, and a redemption racing a close loses its finalize CAS\nand releases nothing. A revocation mark is set only by a revoke that SUCCEEDED; a terminal\nrow with an unmarked credential is retried by every later sweep pass, exactly the unconfirmed\nids, until both marks confirm, so a transient revocation failure can never quietly leave half\na pair alive. The auth path revokes BOTH per-session\ncredentials with eviction (bounded\npropagation) on any of: an **authenticated close input** on the trusted auth path itself,\na defined operation of the SAME exchange/callout surface that redemption already uses\n(§9/§10, off-broker, so no broker grant row applies): the caller authenticates as one of\nthe session's two parties (its lifecycle or per-session credential) or as the operator and\nnames the `sessionId`; the auth path verifies party membership against the ledger row\nbefore transitioning it. The in-band close frame\nis an advisory peer signal, never the revocation authority, because EPS subjects are\ncore-only and captured by nothing; expiry per the handle rules (`exp` is enforced by the\nauth path's own timer, not by the endpoint), or the serving\nepoch's supersession / lifecycle retirement via the §13.1 barriers (either side's lifecycle:\nholder and serving rows both index the family). Neither side can keep a\nhalf-closed session alive, and a crashed serving endpoint cannot orphan one, the ledger, not\nthe endpoint, remembers what to revoke. Ledger rows are retained at least the maximum\nsession `exp` plus a recovery margin. The session dies with the serving instance's epoch\n(the epoch is in the subject, so a restarted instance cannot resume it; a durable session is\na new establishment). Routing is authenticated broker routing end to end; there is no loopback URL\nor out-of-band transport in the contract, and cross-machine reachability is exactly broker\nreachability.\n\n**Remote manager service registration.** A remote registered user becomes a manager only through\none host-operated, typed `prepare → activate → renew` exchange. It is not a generic credential\nmint surface and is available only on the loopback/operator face to a signed-in human holding the\nclosed `manager-service` view (§13.1); the public exchange and managed-agent secret exchange\nrefuse every stage. All inputs and stored stage records are closed schemas. An operation is keyed\nby `{ owner, managerActor, lifecycleUid, instanceId, operationId }`, where `managerActor` and the\nlifecycle UID come from the server-authorized view, `instanceId` is opaque and collision-resistant,\nand `operationId` is caller-generated for replay convergence. A repeated operation with the same\nfingerprint returns its recorded result; a different fingerprint at the same coordinate is\n`conflict`; a retired lifecycle or instance is never revived.\n\n`prepare` fresh-checks the ledger scope and lifecycle, freezes only\n`epgate.manager.<instanceId>`, and durably stages the exact service registration, contract closure,\nstatus coordinate, requested public nkey, and credential lifetime. It releases no usable material.\n`activate` re-checks that same live ledger row and gate, creates the exact `svc.manager.<instanceId>`\nregistration, publishes only the staged immutable contract artifacts, and asks the host to sign\nNATS JWT material for that public nkey. The host writes the matching\n`epcred.manager.<instanceId>.<credentialId>` row before the gate-finalize CAS and returns the JWT\nonly after that CAS; it never returns a signing seed. `renew` is the only way to obtain successor\npublic-nkey JWT material. It re-checks the live `supervise` grant, owner, actor, lifecycle,\ninstance, current gate, and bounded renewal window, then records and releases a replacement under\nthe same family. It cannot create another instance or broaden a staged contract, record, endpoint,\nor credential grant. A crashed operation resumes only from its durable stage and operation id.\n\nRenewal is bounded and denial is fail-closed. When a manager cannot renew because its login,\nledger scope, or host service is unavailable, it reports degraded state, retains already-live\nagents only while their independently valid authority remains usable, and refuses new starts,\nrestarts, replacement credentials, and unsafe recovery. It MUST NOT turn a transient failure into\nstatic authority or kill a live agent merely to make the state look healthy. When the current\nfamily expires or is revoked, the host's verified revocation path closes it; a later restart still\nrequires a new successful prepare/activate operation. Same-owner descendant provisioning is\nhost-validated at every request, and loss of that validation also refuses a new start or restart.\n\n**Platform control registration.** A platform-run control manager registers, activates, renews,\nand retires through the same typed `prepare → activate → renew` protocol and operations as the\nremote manager service above: `session`, `retire`, `transferReader`, `renewStandingBundle`, `renewRunDriver`, the\nhost-owned maintenance operations, retained-agent validation, the goal-index scan, admin\nauthorization, and run admission and attempt. Each request rides inside one closed\n`platform-control-authority` envelope that adds only the space, the assigned account, and the\nassignment revision. The envelope and every inner request are closed schemas. The envelope carries\nno profile name, permission set, subject, lifetime, claim, or identity assertion. An inner request\nkeeps its existing operation-specific coordinates, such as the `session` operation's requested\n`exp`, which the host caps at its own bound, and the run admission's served `run.subject`, which\nthe host re-parses and checks against the caller's issued ceiling. The host validates each one as it\ndoes under `manager-service`. No field of either selects a signing subject, permission set,\nprofile, claim, or a credential lifetime past the host's bound, and an unknown kind or field MUST\nbe refused as `bad-request` with no effect. The managed-agent enrollment, retirement-preparation, and\nruntime kinds are not carried; a host without its own storage for them MUST refuse them as\n`unimplemented`. The door is a typed in-process operation of the host's authority context. It\nexists only where the host supplies its assignment source, and no listener serves it. It needs no\nexchange capability: the host MUST NOT hand its loopback capability or account signer to a control\nmanager, and a host that runs the control manager in another process carries the closed envelope\nover its own caller-bound channel. A request carrying a human IdP token MUST be refused. It is not a\ngeneric credential-mint surface and adds no daemon, listener, or protocol.\n\nHost-owned maintenance is narrower under this view than under `manager-service`. Under\n`platform-control`, a maintenance request's `targetInstanceId` MUST equal the assigned instance id\nfor both `evict-family-principal` and `reconcile-registration`, and the host MUST observe that the\ntarget gate's principal is the platform owner plus that instance's fixed serve actor. Both checks\nrun after the assignment check and before any liveness probe, revocation, eviction, or reopen. A\nfailure is `permission-denied` with no effect. A foreign slot holder therefore blocks platform\nregistration with the existing registration refusal, and it is repaired only through its own\nowner's `manager-service` maintenance or the host operator's guarded gate repair, neither of which\nthis view reaches. `manager-service` maintenance, including its reconciliation of a foreign slot\nholder, is unchanged.\n\nRenewal and fencing are the remote manager service's, unchanged. `renewStandingBundle` returns the\nclosed five-credential family for the same caller-held nkeys and the assigned account only when the\ncurrent gate is open, its principal is the platform owner plus the fixed serve actor, its process\nepoch equals the request's, and the host-keyed current registration proof matches. A stale epoch\nis `conflict`. A revoked or advanced assignment refuses the next request, renewal included, so\nrevocation never waits on a person and renewal never authenticates one. The remote manager\nservice's degraded-state and fail-closed renewal rules apply with the assignment in place of the\nlogin and ledger scope. A start after revocation or expiry requires a fresh `prepare` and\n`activate` under a current assignment.\n\n**Environment manager bootstrap and registration.** A hosting authority MAY serve this\nfamily as an ordinary registered, instance-addressed endpoint. `bootstrap` declares the\nephemeral class only. Its responder realizes §13.4's at-most-once effect through the\nauthenticated reservation and canonical fingerprint; this adds no idempotency-basis field\nto §13.7's contract. It is not a journal action. Wrong-class invocation MUST refuse before\neffect. Its bootstrap principal has the fixed `environment-bootstrap` grant of §13.9,\nnot manager supervisor or executor authority. The host admits first, waits for observed\nprovider RUNNING, then mints and delivers the file through a native post-boot secret/file\nchannel. It caps lifetime at the lesser of five minutes and remaining admission lifetime;\nno channel or insufficient remaining lifetime refuses delivery rather than using an\nexpired create-time file. No provider create or guest boot acknowledgement is registration.\n\nThe bootstrap file carries version one, the environment record ID, preselected manager\ninstance and lifecycle, credential and private connection nkey, finite expiry, pinned WSS\nbroker hostname, authority endpoint and instance, and the two bootstrap commands' contract\ndigests. It carries no owner session, account signing seed, profile selector or grants.\nThe verified immutable image's system trust store anchors TLS; deployments using a private\nCA MUST separately supply explicit digest-bound mesh trust. Certificate and hostname\nverification MUST remain enabled. Bootstrap admits no trust-on-first-use path. The host\nMUST NOT retain the private bootstrap seed after writing the private file; its durable\nrecord holds only digest, recipient lifecycle, expiry and consumed state. The guest MUST\nrefuse any file version other than one before connecting.\n\nThe post-boot channel first delivers the private file, then starts or signals the stock\nentry point. An entry started without the file refuses and exits; it never polls for one\nor opens a plane without it. The manager takes and unlinks the manager-only file before\nordinary command handling or connecting a plane. It generates the five manager nkeys locally and atomically persists\nthem with the bootstrap recovery material in its private store before sending a request.\nA crash after taking the file but before that first persistence is terminal: the external\nhost closes the environment and retires its reserved UID. It MUST NOT mint another\nbootstrap for that admission.\n\n`bootstrap` takes only `{ environmentId, identities }`, where `identities` has the five\npublic-nkey coordinates of the existing registration request. It returns the existing\n`RemoteManagerAuthorityMaterial` for preparation. The broker-authenticated subject selects\nthe admitted bootstrap caller; payload fields cannot choose its owner, account, manager\ninstance, lifecycle, permission ceiling or private signing material. Before preparation,\na first-wins CAS MUST pin the canonical request fingerprint and the preselected manager\ncoordinates. A different fingerprint at that reservation refuses `conflict`. An unknown\nissuance outcome stays held and MUST NOT start another preparation.\n\n`bootstrap-status` takes only `{ environmentId }` and reads that caller's reservation.\nDuring the bootstrap lifetime it returns the same recorded, public-nkey-bound preparation\nresult, or an explicit pending state. It issues nothing and selects no new keys or\nlifecycle. Same-input lost-reply recovery uses this command, not a second prepare. A\ncompleted registration or terminal admission refuses both commands; expiry does not delete\nthe reservation or permit reuse. Stored preparation material may contain signed JWTs under\nthe host-private credential-custody contract, never a guest private seed.\n\nThe subsequent `authority` command takes one closed `{ v: 1,\nkind: \"environment-manager-authority\", environmentId, admissionRevision, request }`\nenvelope. `request` is one of the existing closed manager registration, standing renewal,\nmaintenance, managed-child enrollment, child retirement, retained-child validation,\ntransfer, goal-index read, serve-time admin-authorization decision, run-admission or\nrun-attempt requests, plus the closed `environment-manager-deregister` request below.\nPer-session attach and shared MCP sessions are unsupported in this first family: their\nentry points MUST refuse `unimplemented` before issuing, staging or redeeming any session\nmaterial. The authority MUST refuse `session` and `session-revoke` requests rather than\nminting a JWT whose guest-side stage would need the forbidden auth-store write. The stock\nmanager does not construct the session plane for this family. Its attach/shared-MCP entry\nrefuses before `mintSessionServing`; the host's session refusal is a second fence.\nThere is no generic signing, mint, profile, permission, administrative control or\ncross-environment operation. An unknown field or\nkind refuses `bad-request` before any effect. Missing host policy refuses `unimplemented`;\nan adapter MUST NOT substitute a human or platform holder.\n\nPreparation, activation and restart use the existing registration barrier, performed by\nthe trusted host through this closed authority command. The guest MUST NOT execute\n`registerRemoteManagerAuthority` over the shipped executor's direct store profile. This\nrequires an additive stock host-mediated registration path; a private adapter cannot replace\nit by widening guest grants. The authority binds the authenticated caller to the recorded\nmanager identity for that phase and checks\nthe current host-issued proof, admission revision and process epoch. Activation rechecks\nthe same preparation's frozen gate; later operations require the current open registration.\nThe host uses its embedded canonical manager contract closure for the admitted stock\nrelease, pinned by the immutable workload profile digest. A host with no closure for that\nrelease MUST refuse admission `unimplemented` before bootstrap issuance. A guest whose\nembedded closure differs from the returned serving snapshot MUST refuse to serve.\nThe guest cannot select another closure or submit an unbounded artifact set. The existing two-document activation envelope\nand 64-artifact cap are unchanged; the full schema closure is available to the host without\na guest contract-store grant.\n\nRegistration returns the host-authorized serving snapshot: epoch, registration and\nname-authority revisions, complete command surface, closure digest and descriptor. Before\nserving, the guest verifies that snapshot against its embedded manager closure and the\nhost-signed serve credential's account, owner, instance and epoch. An additive stock\nreconstitution seam explicitly validates this authenticated host-to-guest direction and\nproduces the process-local branded serve grant. A JSON copy, self-asserted snapshot or\ncalling the trusted-host-only reconstruction seam as a guest shortcut MUST refuse.\nAll issued material stays inside the admission's five-key family and expiry. The guest\natomically persists prepared and activated material in its manager-only store. A restart\nuses that identity and proof at a newly admitted process epoch, never bootstrap redemption.\nRenewal rides a still-valid executor credential and MUST be scheduled before its JWT\nexpiry. Per-operation reconnects and the existing all-duty preflight dials remain allowed\nunder the fixed profiles; they open no store and require no new authority. A manager stopped beyond executor validity cannot renew or redeem bootstrap again;\nthat admission becomes terminal and external cleanup must close it. There is no owner\nlogin, static credential or fresh-key fallback.\nMaintenance targets only the admitted instance; a foreign governance-slot holder blocks\nregistration and requires its own authorized repair path.\n\nGraceful stop uses `environment-manager-deregister`, a closed inner request carrying only\n`{ v: 1, kind: \"environment-manager-deregister\", registrationRevision,\nregistrationProof, processEpoch }` inside the admission-bound authority envelope. The host\nderives the instance, owner and expected proof/epoch from the bound executor and current\nadmission; it compares the supplied proof and epoch and checks the revision against the\nregistration receipt it committed. It performs native revision-pinned `deregisterServiceInstance` and its own gate\ngeneration read. Absent or already superseded registration is an idempotent observation;\nno caller-selected endpoint, key or foreign instance is accepted. The stock stop path uses\nthis mediated result instead of opening stores or printing a signer-only repair command.\nDeregistration alone issues no replacement lifecycle and does not retire the admission;\na still-current manager restart uses the existing fenced registration ceremony.\n\nChild enrollment preserves the existing host-selected UID and delegation checks. The\nhost commits its sole-child binding before releasing child material; changed input,\na second actor or a second lifecycle refuses before launch. Child retirement addresses\nonly that recorded UID and retains the existing terminal-operation and custody fences.\nRun admission and attempts preserve the starting caller's issued ceiling, owner and process\nfences. Provisioning adds no scheduler or Lang syntax. Delegated launch still refuses\nsupervise restart policy, caller cwd, resume, exact continuity and shared MCP servers.\nRepository/ref checkout is admitted workload configuration; Lang worktree identity is a\nlogical exclusion key rather than a workstation path.\n\nA bootstrap never presented before expiry, or a preparation not activated before expiry,\nbecomes terminal durably. Activation MUST revoke the bootstrap credential and evict\n`manager_bootstrap_<instanceId>` connections through the ordinary ledger eviction before\nreleasing activated material. `activate` is requested and answered on the executor\nconnection from prepare material, not the bootstrap connection, so eviction cannot cut\nthat reply. The external\nhost revokes prepared credentials and burns or retires the reserved UID; an unavailable\nrevocation service leaves a persisted cleanup obligation, never reusable admission.\nEnvironment expiry or forced close proceeds independently of the guest manager. Observed\nprovider termination, result retention and retirement of the bound manager/child UIDs are\nseparate facts; host-side retirement failure remains pending and does not erase termination.\n\n| Refused input or state | Required refusal and boundary |\n|---|---|\n| Unknown field, kind, profile or permission selector | `bad-request`, before policy or issuance (§13.6) |\n| Wrong authenticated bootstrap/manager caller or foreign environment, owner, account, instance or UID | `permission-denied`, no issuance or lifecycle effect (§13.1, §13.9) |\n| Changed request at an existing bootstrap reservation | `conflict`, original reservation retained (§13.1, §13.6) |\n| Expired bootstrap, ended admission or completed registration used as bootstrap | `permission-denied`, no new preparation (§13.1, §13.6) |\n| Bootstrap mint without an admission-pinned frozen registration gate and the same live operation intent | Refuse with no material (§13.1, §13.6) |\n| Human or platform operation naming an environment-family gate or stage | `permission-denied`, no takeover, repair, issuance or retirement (§13.1, §13.6) |\n| Guest direct gate/repair/credential write or auth-store read/scan | Broker-denied by every credential in this family; no field-parser substitute (§13.1, §13.9) |\n| Attach or shared MCP session, including session mint/stage/revoke | `unimplemented` before session material or ledger effects (§13.6) |\n| Deregistration revision not from the host's receipt or a foreign instance/key selector | `conflict` or `bad-request` before any delete; no stale delete of a successor (§13.6) |\n| Missing or unreadable current admission, ledger or gate | Refuse before effect; no cached authorization (§13.1) |\n| Stale admission revision, proof or process epoch | `conflict`, no replacement material (§13.1, §13.6) |\n| Missing child/run/retirement policy or unsupported UID/material delivery | `unimplemented`, admission or launch remains refused (§13.1, §14) |\n| Second child actor or lifecycle, including after terminal retirement | `permission-denied`, first binding retained (§13.1, §13.6) |\n| Child scope, channels or capabilities exceeding the admission ceiling | `permission-denied`, first binding retained (§13.1, §13.6) |\n| Run not admitted by the recorded owner, or placement naming another instance | `permission-denied`, no admission, attempt or launch (§13.6, §14) |\n| Foreign maintenance target or foreign slot-holder repair | `permission-denied`, no probe, eviction or repair (§13.1, §13.6) |\n| Ambiguous preparation, result retention or retirement | Preserve the held operation or cleanup obligation; never infer success (§13.1, §13.6) |\n\n**Virtual endpoints.** An endpoint MAY be virtual: registered (`spec.activation = on-demand`)\nwith no live instance. A virtual endpoint's commands MUST be journal-class: the buffered\ningress path is the ordinary submission plane (`epj` is durable and needs no live\nsubscriber), and the canonicalizer, which for a virtual endpoint runs wherever its\nactivator/owning authority runs, checks pool admission BEFORE deciding (an over-capacity\nsubmission is rejected `resource-exhausted` as its durable decision fact, never accepted and\nstranded), then accepts and enqueues the work into the endpoint's `epw` pool. Admission\noccupancy is the pool consumer's `num_pending + num_ack_pending`, read fresh from the exact\nper-pool consumer INFO after reconciling the canonicalizer's own outstanding acceptances\nagainst the predicate below (a repaired item is inside the count new work competes under);\nthe read fails closed (an unreadable consumer is `unavailable`, never an empty pool), and the\nsum is honest only while the pool consumer's delivery ceiling is unlimited\n(`max_deliver = -1`) AND its filter is exactly the pool's own subtree; BOTH are editable after\ncreation, so both are pinned at creation AND re-proved at every read (a message that exhausts\na finite ceiling stays stored but leaves both counters; a narrowed or foreign filter reads\nempty while stored work remains). The admission capacity comes from the endpoint's REGISTERED\nactivation policy (declared as the registration's `spec.activation` block, a closed schema\nwhose `capacity` is required; the registration path publishes each version as an immutable\n`policy` record, §13.7, and the govern head's selector below names the enforced one), READ\nleader-served at each decision (the read is FENCING by use, so a\nfollower Direct Get is never used; a scoped canonicalizer executes it only through the\nconfined policy reader of §13.8, whose request subject binds the authenticated endpoint)\nand its enforced revision RE-PROVEN after the decision's\nlater reads and carried into the acceptance commit, never a free-standing argument; the\ncarried revision is provenance, and the FENCE against the policy or lifecycle moving while\nthe acceptance is in flight is the §13.8 obligation row, not the carried value. The\n**endpoint-wide policy coordinate** is not a new head: it is the governance head\n`govern.<endpoint>` (§13.7, the endpoint's registration linearization point). To make the\nenforced policy MACHINE-SELECTABLE by any second implementer (not inferable from prose), the\ngovern head value carries a normative **policy selector**: `{ enforcedPolicyKey (the exact\nrecords key of the immutable `policy` record currently governing, §13.7), enforcedPolicyRevision\n(that record's STORE revision), pendingPolicyKey?, pendingPolicyRevision? }`. A canonicalizer reads\ngovern leader-served, follows `enforcedPolicyKey`, and re-proves it is still at\n`enforcedPolicyRevision`, with no per-instance guesswork; `policyRevision` throughout this\nsection IS `enforcedPolicyRevision`. **`enforcedPolicyKey` MUST name an IMMUTABLE,\nREVISION-ADDRESSED policy record, not a mutable per-instance slot** (a bare\n`svc.<endpoint>.<instanceId>.spec` overwritten on every re-registration is disqualified: the\nrecords bucket keeps history 1, so once a mutation overwrites it the OLD `enforcedPolicyRevision`\ncan no longer be read, and the drain window's claim that \"the old policy keeps governing\" would\nbe unbacked). The normative immutable form is the **`policy` record kind** (§13.7):\n`policy.<endpoint>.<digest-hex>`, one unsplit, create-only, NEVER-DELETED key per policy\nversion, where `<digest-hex>` is the SHA-256 hex of the record's canonical value bytes: the\nkey is self-certifying (a reader re-digests the value and refuses a mismatch), so a\ndifferent-byte overwrite is caught on read, and BOTH the enforced and the pending revisions\nstay readable throughout the drain. Immutability is upheld by the sole writer's create-only\nCAS plus that read-time self-certification, not a broker-level subtraction (§13.9). A\ndeployment that cannot provide an immutable policy key MUST pause admission during the\nmutation rather than claim the old value remains readable.\nA policy mutation is a re-registration under the frozen registration gate that lands in TWO\nfenced govern-head CAS steps (§13.9): (1) **stage** records the new registration as\n`pendingPolicy{Key,Revision}` (a NEW immutable policy key) while `enforcedPolicy...` still\npoints at the OLD immutable record, so\nthe old policy keeps governing and stays readable; (2) **promote**, only after the mutation has **drained the\nendpoint's unresolved obligations to quiescence** (§13.8: enumerate `oblig.*.<endpoint>.>`,\nsettle every unresolved row pinning an older `enforcedPolicyRevision` through its decision\ncoordinate, re-enumerate until none remain), moves `pendingPolicy...` into `enforcedPolicy...`\nand clears the pending slot. Admission always pins the CURRENT `enforcedPolicyRevision`,\nand **while a `pendingPolicy…` is staged, proof issuance for policy-admitted decisions\nREFUSES** (`failed-precondition`: the endpoint is inside its drain window; target-bound-only\nadmissions are unaffected). The pause is what makes the drain CONVERGE under load and makes\n§13.8's rule (a row created after the drain's final enumeration can never admit) hold for\npolicy movement exactly as it holds for retirement; rows admitted BEFORE the stage keep their\npinned old revision readable through the immutable key, so no admission is ever judged\nagainst a policy it did not pin. The stage/drain/promote order is a durable, resumable\ngovern-head sequence, never an implied transaction. The **restart-status commit is the same two-coordinate\nclass**: before its status CAS the supervisor obtains a `self`-class obligation (§13.8)\nthrough the same mediator, pinning the `enforcedPolicyRevision` its thresholds were read\nunder AND the complete commit intent `{ commitKey, commitBaseRevision, commitValue, commitDigest }`\nof the\nstatus record it will write; the status CAS is authorized only while that obligation is\n`accepted`, so a policy or lifecycle movement settles the obligation and the delayed commit\nloses a CAS, and a crash after `accepted` is finished deterministically from the pinned\nintent (§13.8 recovery), never a\ncarried-revision comparison. The\nrestart-intensity thresholds are read leader-served from the SAME registered policy, so neither\na caller nor a follower-stale read can loosen the window to suppress an escalation. A command\nname is declared ONCE across the whole closure; a cross-cluster duplicate is an ambiguous\nsurface and registration refuses it, and a command declared non-journal-class in ANY cluster is\nnon-journal for the on-demand registration check. The supervisor-owned status fields (the\nrestart history and the retirement mark) and the `escalated` state can be ORIGINATED only\nunder the supervisor's DISTINCT WRITE AUTHORITY (a package-private branded capability held by\nthe restart-note and the escalation reconciler, never an ambiently-mintable factory or the mere\npresence of a revision pin): an instance-side status write, whether it creates the first status\nor updates a later one, has them stripped and cannot originate `escalated`. The restart history\nand retirement mark are validated at every read boundary (a unique-epoch history, an integer\nmark present only on an escalated row), and a DEL/PURGE status marker fails closed on the\nretirement path (a deletion is never clean absence). Every status write operates on a validated DETACHED snapshot\ntaken before its first read, so a caller mutating a shared status object mid-write cannot split\nthe authenticated coordinate from the stored bytes. The activator's reply authority is its\nown CONNECTION-SCOPED inbox (`_INBOX_<connId>.>`), never the account-wide default, and its\noccupancy read re-proves the pool consumer's ack policy and pull mode alongside its editable\ndelivery ceiling and filter (a delete/recreate must not substitute a semantically different\nconsumer). A supervision clock behind the newest recorded restart is refused before the\nduplicate-note short-circuit, so a rolled-back clock never returns a stale count. The virtual endpoint's canonicalizer durable serializes admission\n(`max_ack_pending = 1`): one submission is in the count-decide-enqueue path at a time, so two\nsubmissions cannot both observe the same free slot; because MaxAckPending is also editable\nafter creation, every admission re-proves the live pin and refuses on drift rather than\ndeciding under a serialization it no longer has; pool-worker execution concurrency is an\nindependent knob, already inside the count via `num_ack_pending`. A virtual endpoint's\nregistration REFUSES if any declared command is not journal-class (an ephemeral surface\ncannot exist with no live instance). Acceptance and\nenqueue span two streams with no atomic bridge, so the enqueue is **idempotent, keyed by the\nacceptance identity, and reconciled against a decidable predicate**: the pool subject carries\nthe acceptance identity and the enqueue is a create (expected-last-sequence-for-subject 0),\nso a duplicate enqueue loses its CAS harmlessly; because the pool owner acks only after the\ncommitted terminal state (§13.5), an acceptance fact **with** a terminal result is settled\nand never re-enqueued, and an acceptance fact with **no** terminal result and **no** live\npool entry (a FENCING absence: the probe is the leader-served `STREAM.MSG.GET` last-by-subject\nread of the §13.9 work-pool reconciliation row, never a follower-servable Direct Get, because a stale\nfollower miss would re-arm settled work) is unambiguously never-enqueued-or-lost, the\nonly re-enqueueable state. A crash after the acceptance CAS but before the enqueue is\nrepaired by exactly that predicate; an enqueue without an acceptance fact cannot occur\nbecause only the canonicalizer holds the pool-write grant and it enqueues only from its own\naccepted decisions. The stored item bytes are the CANONICAL derivation of the acceptance —\nthe RFC-8785 canonical JSON of exactly `{ v: 1, id, fingerprint, sourceSeq, workExpiry,\ncaller, request }` (work identity + input only; never a lease, token, or decision metadata) —\nso any two conforming writers (a first enqueue and a crash repair) produce BYTE-IDENTICAL\nitems, and the create's same-subject-same-bytes idempotency holds across them; a differing\nbody under the same acceptance identity is a mixup and refuses loud. An ephemeral\ncall to a virtual endpoint with no live instance is an honest `unavailable`; nothing\nsilently buffers it. An **activator** (holder of its activation capability) watches the pool\nand starts an instance; single-writer per identity is fenced by instance-record CAS +\nepoch. The exact consumer INFO the activator watches is a request/reply snapshot with no\nbroker wakeup, so watching is bounded polling with backoff to a finite maximum interval, and\nan INFO failure is loud, never a silent skipped poll; the activator's broker authority is\nexactly that INFO read plus its mediated, target-bound start seam (no pool consume/ack, no\nstream read, no consumer create/update/delete). Passivation drains, updates status, exits;\ndurable reminders ride the timer plane.\nSupervision is restart-intensity escalation: more than `maxRestarts` (default 3) within\n`restartWindow` (default 60s) escalates; the instance stops restarting, status records\n`escalated`, the lifecycle retires terminally (§13.1), and the failure is loud. The restart\nhistory is DURABLE on the instance's own status record, SUPERVISOR-OWNED (the status writer\ncarries it forward through every ordinary instance-side write, so a successor's `ready`\nconvergence can neither reset nor forge it), and each note is a revision-pinned CAS: a\nsupervisor restart cannot amnesty the count and two concurrent notes cannot merge-lose a\nrestart. Each history entry is bound to the DYING PROCESS EPOCH (a real restart advances the\nepoch), so a replayed or duplicated notification of one restart is an idempotent no-op, never\na double count; and a supervision clock behind the newest recorded restart REFUSES rather\nthan silently truncating history. `escalated` is IRREVERSIBLE at the status writer (no later\nwrite, any epoch, replaces it), refuses further notes, and is excluded from every liveness\nderivation (a frozen scatter expected set never contains an escalated instance). The\nescalation commits before the lifecycle retirement runs; the retire seam MUST be idempotent,\na retirement failure leaves the escalation standing, and a reconciler retries retirement on\nalready-escalated rows until it completes, recording completion durably (nothing\nun-escalates).\n\n**Interactive session**, a one-use, holder-bound, bidirectional byte stream to a managed target\n(the `attach` reference case). Establishment is a two-step, collapsible exchange: the serving endpoint\nmints a signed **session grant** bound to `(holder triple, target (owner, actor, lifecycleUid),\nserving instanceId + epoch, expiry)` and returns it as the establishment answer, **never a transport\nURL and never logged**; the holder **redeems** it by opening the session, which consumes it (create-only\nCAS on the durable `session.<sessionId>` ledger row, §13.12; a second redeem is `conflict`). The grant\nis non-bearer: redemption is **presenter-equality** bound to `holder` (§13.10), so a leaked grant confers\nnothing. Authorization is the target command's own (`owner`/`any` + name authority, §13.9); a session is\nnever a path around the despawn/attach authorization.\n\nThe byte stream rides two CORE-ONLY rails, `eps.<endpoint>.<sessionId>.<epoch>.<in|out>` (§13.9), never\nstream-captured: the holder publishes `in` and subscribes `out`, the serving endpoint the reverse; the\nholder's grant covers exactly its own session's two subjects. **Framing** (the terminal-session profile):\napplication bytes are `{ k: \"data\", b: <standard base64> }`; control is structured JSON, `{ k: \"ready\" }`,\n`{ k: \"resize\", cols, rows }` (both positive integers), `{ k: \"end\", reason }`, `{ k: \"drop\", bytes }`.\nOrdering is per direction by publisher sequence. Flow is a bounded in-flight window per direction; output\nthe window cannot take is **dropped, counted, and surfaced** as a `drop` frame before the resumed stream,\nnever silently lost. On the holder's `ready` the serving side replays a byte-exact reconstruction of the\ntarget's current screen, then streams live output in order. A degenerate or unparseable caller frame is\ndropped, never a session teardown.\n\n**Termination is honest and distinct**: every teardown surfaces an `end` frame naming a bounded reason,\n`process-exit` (the target exited), `closed` (a party closed), `expired` (the session TTL elapsed),\n`target-despawn` (the target lifecycle retired), `manager-restart` (the serving incarnation advanced its\nepoch). The session binds the target's `(principal, lifecycleUid)` and the serving epoch (§13.1): a\nsuccessor incarnation (advanced epoch) refuses old-epoch grants, and a same-name successor is a distinct\nsession.\n\n### 13.7 Contracts and discovery\n\n**Clusters.** An endpoint's surface is a set of composable **capability clusters**, each\n`{ urn, revision, attributes[], commands[], events[] }`:\n\n- `urn`, reverse-DNS cluster type URN (`ai.cotal.lifecycle`, `com.acme.deploy`).\n- `attributes`, readable/watchable state; each declares a name, value schema, and record\n derivation (which record key carries it). Attribute reads/subscribes ride the record\n contract, never ephemeral replies.\n- `commands`, each declares name, input/output schemas, `class`, `targeted` (and if so which\n authz modes it admits), its **capability requirement** (the named capability minting maps to\n subjects, §13.9), its `effect` (below), and optional traits.\n Each `journal`-class command **MUST** declare **`admissionCeiling`** =\n `{ maxBytes, maxDepth, maxItems }`, the bounds its canonicalizer refuses beyond (§13.4\n item 3). The ceiling is **declared, never compiled in**, because it decides what a\n submission durably *becomes*: two implementations that agree on the wire and disagree on a\n constant would write different permanent decisions for identical bytes.\n- `events`, name + payload schema; events ride the journal contract on the event plane\n (`epe….ev.<cluster>.<event>`), read-contained by event-topic grants.\n\n**Manager presence reads.** The reference manager's `ps` and `inspect` rows may carry\n`presenceIdentityVerified` and `presenceObservedAt`. A true identity flag means the\nname-matched roster card also matched the managed seat's principal and lifecycle UID.\nThe timestamp is the manager's snapshot time and appears only when its presence view\nis current and identity is verified; it is not a heartbeat from the seat. A client\nrequires both a current `meshView` and a true identity flag before presenting the\nrow's roster status or `activeAt` as this lifecycle's observation. A false or absent\nflag is not proof that the seat is absent, and older managers may omit both fields.\n\n**Effect.** A command declaration carries `effect`, one of `read` or `write`.\n\n**Reachability.** `effect` is reachable only under `protocol.v: 2` (*Version*, below). A responder\nwhose descriptor is pinned to `v: 1` cannot declare the field on the command surface a caller\nresolves against, and nothing in such a deployment consumes it, so the `v: 1` rule below is the\nwhole of what governs.\n\nNote what the pin does NOT do. A descriptor MAY inline the registered cluster artifact verbatim\n(*Descriptor and describe*, §13.7), and an artifact is not filtered against the parsed command\nsurface, so a key named `effect` inside one can appear on the wire under a `v: 1` descriptor. Its\npresence there is not a declaration and MUST NOT be read as one. Repeat-safety information exists\nonly at `protocol.v: 2`, and a caller that recovers it from raw artifact bytes under a `v: 1`\ndescriptor has reinstated exactly the retry this section exists to stop, while believing it read a\ndeclaration. A reference implementation that has not moved to\n`2` therefore carries its repeat-safety knowledge somewhere off the wire, as a static allowlist of\nthe commands it knows to be safe to repeat. Such an allowlist stands in for this field for exactly\nas long as no `v: 2` descriptor can exist, and it is superseded by the declaration the moment one\ncan: allowlist-says-safe and author-declares-`write` are answers to the same question, and two\nanswers to one question is one answer too many.\n\n`read` asserts that executing the command again **changes nothing the command is trying to\nchange**: the state after two executions is the state after one, and any difference between their\nresults is only the freshness a caller would see by asking twice. The state in question is not\nonly the endpoint's own — a command whose intended effect lands somewhere else is still a `write`.\n`evictPrincipal` on the delivery endpoint is the case that fixes the boundary: it drops live\nbroker connections and leaves the endpoint's own records untouched, and it is a `write`, because\ndropping those connections is the point of calling it.\n\nExactly one class of difference is excluded, and it is narrow: the incidental trace of having been\ncalled. Request ids, spans, access logs, metrics, counters, and timing are observable and are not\nwhat the command was for, so a command is not `write` merely because it can be seen to have been\ncalled. The test is not \"did anything change\" — something always does — but **would a caller who\nrepeated this command be surprised by what the repeat did**. If the answer is no, it is `read`.\n\n`write` asserts nothing and MUST be assumed unsafe to repeat.\n\nA client MUST NOT automatically re-issue a command declared `write` after any outcome that does\nnot prove non-execution (§13.3), **whatever `id` the re-issue carries**. The exemption is not the\ntoken but the CONVERGENCE: a re-issue is a resubmission, governed by §13.8 rather than by this\nrule, only while the responder will converge it onto the recorded prior decision. A re-issue the\nresponder accepts as NEW WORK is a repeat, and this prohibition binds it however the `id` was\nchosen.\n\nThat distinction is load-bearing because the two are not distinguishable by inspection. Same-`id`\nconvergence lasts only while the prior decision is retained (§13.8), and a caller cannot observe\nretention from outside — so a client that reuses an `id` after the horizon has issued a repeat\nwhile believing it issued a resubmission. Reusing the token is therefore not a substitute for the\nproof this rule demands: absent an outcome that proves non-execution, a client that cannot\nestablish convergence MUST treat its re-issue as a repeat and MUST NOT make it automatically.\n\n`effect` is a property of the command, not of its delivery class: `class` says how a request is\ncarried, `effect` says whether carrying it twice is safe, and the two are independent — an\n`ephemeral` command may be either.\n\n`effect` is declarative, and a declaration is a claim the endpoint author makes. It binds\nclients, not the responder: nothing in this section relieves a handler of its own correctness,\nand a `read` declaration over a mutating handler is a defect in the endpoint, not a licence.\n\n**Version.** `effect` cannot be introduced additively. A client that does not implement it\nignores it and retries exactly as it did before, and no default value repairs that direction,\nbecause the field's entire purpose is to STOP a retry an older client already performs. So it\nrides the discovery protocol's version marker rather than the unknown-field rule (§7).\n\nThat marker is the one that already exists: `protocol.v` on the **service record spec and the\ndescribe descriptor** (*Descriptor and describe*, below). It is deliberately not a new field on\nthe cluster document, which has no `protocol` of its own — adding one there would be subject to §7\nand dropped unread by exactly the clients this cut has to stop, which is the failure it is meant\nto prevent. An instance whose registered clusters declare `effect` MUST register and describe with\n`protocol.v` of `2`, and every command in every cluster it serves MUST then carry `effect`. `v:1`\ndescriptors remain valid, carry no `effect`, and give a resolving caller no repeat-safety\ninformation — it MUST treat every command served under one as `write`. There is therefore no\n\"omitted `effect`\" case under a `v:2` descriptor, and no surface in which the field is present but\noptional.\n\nA client that does not implement this section MUST refuse to resolve a descriptor whose\n`protocol.v` it does not implement, rather than ignore what it cannot honor. **That refusal is a\nrequirement this section CREATES, not one already met.** What protects an unamended client today\nis a fence on the other side of the wire: `describe`'s pinned output schema fixes\n`descriptor.protocol.v` to the constant `1`, so an unamended responder cannot publish a `v:2`\ndescriptor at all — its own reply fails output validation and surfaces as a responder bug. The\nregistry read path fails closed the same way, refusing a service record whose `protocol.v` is not\n`1`. The resolving caller does neither: it reads the describe answer without validating it, and\nthe shape it reads does not carry `protocol`. So the version marker is enforced today by the\nRESPONDER's contract and by the REGISTRY reader, and by nothing in the caller — which is safe only\nfor as long as no `v:2` descriptor can exist.\n\n**Emission.** Moving to `protocol.v: 2` **is** a non-additive discovery change, so §11's\nchange-process rule for one governs it and is the authority on how it is rolled out; this section\nadds only what is specific to `2` and states no cutover rule of its own.\n\nSpecific to `2`: a caller that resolves a descriptor whose `protocol.v` it does not implement MUST\nfail the resolve (`unsupported-version`) and MUST NOT invoke against it — a descriptor it cannot\nread is not a weaker descriptor, it is no descriptor, and treating it as `v:1` reinstates exactly\nthe repeat this section exists to stop. Implementing that refusal is what makes a caller count as\nhaving adopted this section for the purposes of §11's rule, which is the condition a responder's\ndeployment must satisfy before any responder in it registers or describes at `2`.\n\nWhy the rule lives there and not here: the condition is a property of the whole deployment, and a\nresponder cannot evaluate it from where it stands — per §11 there is no in-band capability\nnegotiation and no request carries a caller version, so a responder cannot tell an amended caller\nfrom an unamended one. A rule stated here would bind the one party unable to check it. §11 assigns\nit instead to the deployment, which can.\n\nAn **endpoint type** is a conformance set of cluster URNs. `manager` and `delivery` are\nordinary conformance sets defined by the reference implementation; core knows only\n\"endpoint\".\n\n**Schemas.** Contract schemas are JSON Schema **2020-12**, validated by a real 2020-12\nvalidator (the reference implementation pins `ajv`), under this normative resource profile: a\nschema is a **closed resource bundle**, either fully self-contained (local `$defs`/`#/…`\nrefs) or referencing other contract-store artifacts **by digest** only. `$id`/`$anchor`/\n`$dynamicRef` resolve deterministically within the bundle; ambient HTTP/file/URI resolution\nMUST NOT occur. Contract identity is the **closure digest** (above): the digest of the\nmanifest naming the complete resolved closure, not of the root document alone. Registration-time bounds (loud `contract-invalid`, distinct from\ninvocation-time `bad-request`): document ≤ 256 KiB, closure ≤ 1 MiB, nesting ≤ 32, ref chain\n≤ 32, bounded pattern complexity, compile/validation time budgets, and a bounded compiled-schema cache (reference: 256-entry LRU) (§13.8). Runtime\nvalidation at the serving boundary is mandatory: args before any effect, replies against the\noutput schema. Authoring tooling is free (the reference implementation authors in Zod); the\nwire artifact and validation semantics are the JSON Schema documents themselves.\n**Every command declares BOTH an input and an output schema**: a side with no payload\ndeclares the **canonical void schema**, the artifact `{\"type\":\"null\"}`, whose RFC 8785\ndigest is therefore one fixed value, so both `op` digests exist for every command (§13.3)\nand no shape in this section is conditional on a missing side. Validation against the void\nschema means the side's payload is absent or `null`.\n\n**Content addressing.** A contract artifact (cluster document, schema bundle member, trait\ndefinition or attachment) is identified by the SHA-256 digest of its RFC 8785 canonical JSON\n(strict RFC 8785 over I-JSON; the reference implementation pins `json-canonicalize`'s strict\npath and gates on the RFC's published test vectors, including number-serialization and\nsurrogate edges). **Two digests, never conflated.** An **artifact digest** identifies ONE\ndocument's bytes and is the value that keys its subject and every by-digest reference. A\n**closure digest** identifies a whole resolved bundle, a cluster document or a schema\nclosure, and is the artifact digest of that bundle's **manifest**: the artifact\n`{ v: 1, root: <artifact digest>, members: [<artifact digest>, …] }`, `members` being every\nartifact transitively reachable through by-digest references from `root`, sorted\nlexicographically and deduplicated. The manifest is itself an ordinary artifact on its own\ndigest subject, so a closure digest is an artifact digest, nothing dispatches on which kind\na digest is. Contract identity (§13.7 `contractDigest`, `clusterDigests[]`, and the\n`op.inputDigest`/`outputDigest` a caller pins) is always a CLOSURE digest; a `$ref`-by-digest\ninside a schema is always an ARTIFACT digest.\n\n**Every `*Digest` field in this section is one scalar shape**, `sha256:<hex>`, lowercase\nhex, and each names exactly one input, so no field's digest is implementation-defined:\n`inputDigest`/`outputDigest`, `contractDigest`, `clusterDigests[]` = the CLOSURE digest of\nthe named bundle (above); a schema's by-digest `$ref` = an ARTIFACT digest;\n`argsDigest`/`outcomeDigest`/`resultDigest` = over the strict RFC 8785 canonical JSON of\nthat value (absent iff the value is absent); `authDigest` = over the raw UTF-8 bytes of the\n`auth` slot as carried (§13.3); `submissionDigest` = over the raw stored submission bytes\n(§13.4). Integer fields on the wire (`sourceSeq`, `revision`, `epoch`, `ts`,\n`deadlineMs`, `readinessDeadlineMs`) are non-negative integers ≤ 2^53 − 1, the I-JSON\ninteroperable range, so at most 16 decimal digits, which is what makes the §13.12\nmaximum-fact fixture a computable worst case rather than an estimate.\n\nArtifacts live in the per-space **contract stream**: one artifact per\ndigest-keyed subject `cotal.<space>.epc.<digest-hex>` (§13.2), published as a single\nmessage; possible because a document is bounded at 256 KiB (below) and the operator floor\nasserts `max_payload` covers it (§13.12); a closure is fetched artifact-by-artifact through\nits digest references, never as one blob. Reads are the subject-scoped last-by-subject\nDirect Get on the exact digest subject, no consumer, no replay machinery, and nothing\nbody-selected (§13.9). Readers MUST verify fetched bytes against the digest and fail loud\non mismatch. Publication is mediated and create-only (§13.9): artifacts are immutable once\npublished. A single-message digest subject is readable subject-confined; a chunked object\nstore is not, because chunk replay needs a consumer whose delivery target is body-selected\n(§13.9).\n\n**Record kinds and key grammar.** Every record kind is registered: core kinds are defined\nby this section (writer table, §13.9), and each kind's registry entry pins its **key\ngrammar** (the qualifier tokens between the kind token and the `.spec`/`.status` suffix),\nits writer roles, and its mediation class; grants and merged watches are derived from that\ngrammar, so two implementations always agree on which key carries what. The core kinds'\nkey grammars, pinned here (each key then splits `.spec`/`.status` per §13.4, EXCEPT the\nunsplit atomic keys the table marks: the `lifecycle` head, `govern`, `uid`, `oblig`,\n`goalidx`, `goaleff`, `epname`, `epmig`, and `answer`):\n\n| Kind | Key grammar |\n| --- | --- |\n| `svc` | `svc.<endpoint>.<instanceId>` |\n| `signer` | `signer.<keyId>` |\n| `handle` | `handle.<issuerKeyId>.<id>` |\n| `contracts` | `contracts.<endpoint>` |\n| `goal` | `goal.<endpoint>.<cOwner>.<cActor>.<cUid>.<goalId>` |\n| `goalidx` | `goalidx.<endpoint>.<cOwner>.<cActor>.<cUid>.<goalId>` (atomic; an in-flight action's reconcile index, written create-only before the goal binds and deleted at its terminal, enumerated by a bounded boot-sweep authority so a superseded executor's orphaned goals settle; never caller-addressed). A deleted entry is not recorded again: a later record of the same goal is refused `failed-precondition`, since that goal settled or its acceptance was withdrawn. The reference local signer composition uses its ephemeral provisioner. The signerless remote-manager composition uses an authenticated host operation backed by a sealed, owner-filtered `goalidx.manager.<cOwner>.>` scan; no participant credential carries records consumer create or delete. Writer: the **goal-writer** principal (§13.9), which composes the commit principal with three additions, this index subtree among them, and NOT the bare commit principal, whose enumeration does not reach this kind. The two are separated because the index is created BEFORE the bind, so the principal that writes it is the one that also binds; a deployment that grants the index on the bare commit row has widened every commit principal to reach a key only the goal writer needs |\n| `goaleff` | `goaleff.<endpoint>.<cOwner>.<cActor>.<cUid>.<goalId>.<gen>` (atomic; the at-most-one-launch election for one accepted action, written create-only by the effects executor that wins it and advanced by revision-CAS through its phases). `<gen>` is the accepted submission's **EPJ `sourceSeq`**, the sequence it was delivered at, carried verbatim into the acceptance fact; the only discriminator that exists at the EARLIEST coordinate, since `goalidx` is created before the bind and therefore before any decision fact exists, so a decision sequence cannot key it. The generation token is what keeps this kind out of the one-use-forever trap: a lawful later acceptance under the same `goalId` gets a different `<gen>` and a fresh key, never a permanent tombstone. Writer: the owning endpoint's **commit path** ONLY (§13.9), inherited by the goal-writer principal that composes it; the generic per-kind spec/status writer row does not reach it, because this kind is unsplit and has no `.spec`/`.status` to write. The value machine, including which actor may settle a row, is *The two coordination machines* below |\n| `epname` | `epname.<endpoint>.<nameToken>` (atomic; the durable claim on one name, keyed by the NAME rather than by a caller triple, because the thing being made exclusive is the name and two callers must contend on one key). Writer: the owning endpoint's **commit path** ONLY (§13.9); unsplit, so create-only for the claim and revision-CAS for every state change. The state machine, its actor roles, and the claimant union are *The two coordination machines* below |\n| `epmig` | `epmig.<endpoint>` (atomic; the endpoint's cutover manifest: the inventory a migration is performed against, and the durable record of the cutover runs performed against it, so a run generation is never reused by a later run). That run generation is **scoped to cutover and is key material nowhere else**: the `<gen>` token in the `goaleff` grammar is the accepted submission's EPJ `sourceSeq` and only that, the `goal`, `goalidx`, and `goal….result` grammars carry no generation token at all, and an implementation that keys any of them from this manifest has built an election two conforming peers can never meet inside. Writer: the owning endpoint's **commit path** ONLY (§13.9); unsplit, and its qualifier profile is `[qEndpoint]` alone, one manifest per endpoint, never one per caller or per run |\n| `cp` | `cp.<endpoint>.<token>` |\n| `lease` | `lease.<endpoint>.<pool>.<cOwner>.<cActor>.<cUid>.<id>` (the item's acceptance identity, §13.2) |\n| `lifecycle` | `lifecycle.<owner>.<actor>.<lifecycleUid>` (the §13.1 mapping detail) |\n| `lifecycle` head | `lifecycle.<owner>.<actor>`; the alias's **authoritative current mapping**, and the ONLY key `mappingRevision` (§13.3) counts: a **single unsplit key** (NOT `.spec`/`.status`-split; the mapping is one atomic record, and a handler's \"fresh current mapping\" read is one leader-consistent read of this key returning `{ mapping, revision }`, the revision being the STORE revision, never a value field), CAS-updated, NEVER-DELETED (the head discipline: no grant permits DEL/PURGE, true absence alone is virgin, a deletion marker refuses loudly as corruption). States `active \\| retiring \\| retired` (§13.1): the mapping is current ONLY at `active`; `retiring` is the op-bound containment phase, non-current and not replaceable; `retired` asserts the completed §13.1 barrier. Activation CASes it from none (create-only) or from a `retired` predecessor to a freshly reserved UID's mapping; two concurrent mints for one alias cannot both win the CAS; the terminal barrier CASes `active → retiring` at its bar and `retiring → retired` as its final head step. The per-UID `lifecycle.<owner>.<actor>.<lifecycleUid>` detail below is optional append-only audit, never the authority |\n| `uid` | `uid.<lifecycleUid>`; the §13.1 **space-global UID reservation**: a **single unsplit key**, create-only, NEVER-DELETED, value = `{ owner, actor, mintedBy }` (the reserving authority and intended alias, audit only; the KEY is the reservation). A key exists for every UID ever reserved, including burned candidates; a DEL/PURGE marker is corruption |\n| `policy` | `policy.<endpoint>.<digest-hex>`; the §13.6 **immutable admission-policy version**: a **single unsplit key** per policy version, create-only, NEVER-DELETED. `<digest-hex>` is the SHA-256 hex (64 chars) of the record's canonical value bytes, so the key is SELF-CERTIFYING: a reader re-digests the value it read and refuses a mismatch. Immutability is a TRUSTED-WRITER invariant (create-only CAS by the sole writer) BACKED by that read-time self-certification, not a broker subtraction (KV create/update/delete share the one subject, §13.9): a different-byte overwrite is refused on read, and the residual (a DEL or same-byte overwrite by a buggy/compromised writer destroying availability under history 1) fails admission closed rather than admitting a lost policy. `enforcedPolicyKey`/`pendingPolicyKey` on the govern head (§13.6) name keys of exactly this kind, which is what keeps BOTH the enforced and the pending policy readable through a mutation's whole drain window. Writer: the provisioner registration path ONLY (§13.9); a DEL/PURGE marker is corruption |\n| `oblig` | `oblig.<targetUid>.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>`; the §13.8 **target-indexed acceptance obligation**: a **single unsplit key** whose grammar IS the deterministic acceptance identity (target lifecycle UID first, so a retirement barrier enumerates `oblig.<targetUid>.>`), create-only winner, monotonic value states, NEVER-DELETED. An admission under policy with NO target lifecycle keys the row with the fixed sentinel target token `ep` (which the §13.1 UID token grammar can never produce, so no collision exists): `oblig.ep.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>`: excluded from retirement drains (it binds no lifecycle) and included, like every targeted row, in the endpoint's policy drain via the endpoint-position filter `oblig.*.<endpoint>.>` (§13.6/§13.8) |\n| `frontier` | `frontier.<lifecycleUid>`; the §13.1 **per-stream retirement frontiers**: a **single unsplit key** per retired lifecycle, create-only, NEVER-DELETED, value = `{ lifecycleUid, opId, streams }` where `streams` maps each lifecycle-bounded stream to its last sequence at retirement. Written by the terminal barrier AFTER the obligation drain, the drain's repair-principal fence, the pool cleaner, and the cleaner-credential revoke+evict, and BEFORE the gate/head terminals (§13.1 order), so a `retired` head implies its frontier exists. The cutoffs bound the predecessor's half-open interval `(activationFrontier, retirementFrontier]` (§8); they are never a successor's start (a successor captures its OWN activation frontier). Writer: the minting authority's retirement barrier ONLY; it records once, under its own operation (a foreign-op record refuses the barrier closed); a DEL/PURGE marker is corruption |\n| `govern` | `govern.<endpoint>`; the endpoint's **governance head**: a **single unsplit key** (NOT `.spec`/`.status`-split), value = the endpoint's MONOTONIC binding map, command to governed URN set, the NORMATIVE **admission-policy selector** `{ enforcedPolicyKey, enforcedPolicyRevision, pendingPolicyKey?, pendingPolicyRevision? }` (§13.6: `enforcedPolicyKey` is the exact records key of the immutable `policy` record currently governing admission and `enforcedPolicyRevision` its store revision, so any implementer selects the endpoint-wide enforced policy WITHOUT per-instance guesswork; a mutation stages `pendingPolicy…` and promotes it into `enforcedPolicy…` only after the endpoint's obligation drain, so the selector alone decides which revision governs during the drain window), plus whatever internal serialization state the provisioner's registration CAS needs (that state is non-normative: a second implementer may linearize registration with a different slot shape and conform, provided every registration contends on this head under its frozen gate through spec publication, the policy selector fields carry the meaning above, and the external guarantees hold). One of those external guarantees is LIVENESS of the linearization itself, and it is normative however the slot is shaped: an in-flight registration that stops before its spec publication MUST NOT block the endpoint's registrations permanently. Whatever state a registration holds on this head, an implementation MUST be able to decide that state ABANDONED from durable facts rather than from a liveness probe, and a later registration MUST then be able to take it. The reference implementation decides it by comparing the held state's recorded gate generation against the holder's live issuance gate: a gate that has reopened past it proves the hold can never complete, since completion requires that same generation still frozen. An implementation that cannot make that determination MUST refuse rather than take the hold, because an in-flight registration and an abandoned one are otherwise indistinguishable, and taking a live one would put two registrations through the linearization point at once. Enforcing the governed-attachment no-strip/no-downgrade mandate (Traits, below) is a HISTORY-bearing, ENDPOINT-WIDE property: a fresh instance, a remove-then-re-add, or a concurrent registration must not launder a governed binding away, so this head is also the endpoint's **registration linearization point**. Writer: the provisioner registration path ONLY (§13.9); NEVER-DELETED, per the `lifecycle`-head discipline |\n\n| `run` | `run.<endpoint>.<runId>`; a **workflow run's** last-value-wins state beside its append-only step journal (§14). `.spec`/`.status`-split, and the split is load-bearing: the spec is what the run IS, decided once at start and never rewritten (`{ v: 1, run, pins, createdAt }`, the resolved PIN SET of §14.3), the status is what it is DOING (`{ v: 1, observedSpecRevision, state, holder, epoch, fencingToken, journalHigh, at, failure? }`), so a lease renewal can never rewrite the pins. A `failed` status MAY carry `failure: { code?, message }`, the error the program failed with: its `L` code when it has one, and its message, at most 4000 characters. No other state carries it, and a reader MUST NOT require it, because a status written before it existed has none. `<runId>` is an id token minted by the DRIVER, never caller-supplied and **never reused**: a run is never re-run under its own id (that is a fork, and a fork takes a new id), so a deleted `run` key staying closed is correct and no generation token is owed. A fork's child is a new run under a new id and this revision records no lineage on it (§14.3); a later revision that adds a parent field puts it on the SPEC half and never the status half, because parentage is decided at creation and a status-half lineage could name a different parent after a takeover. Writer: the run driver's commit path ONLY (§13.9) |\n| `answer` | `answer.<endpoint>.<token>.<answerId>`; a checkpoint's ANSWER payload beside its one-use settle fact (§13.6, `answerId`/`settledAnswerId`): a **single unsplit key**, create-only, never updated and never deleted, value `{ v: 1, token, answerId, value?, artifact?, by, at, supersedes? }` (`supersedes` only on an amendment, §14.5). **Keyed per answer rather than per presenter because a workflow checkpoint's holder is the run driver and every resolver reaches the checkpoint through it, so every presenter is the same principal**: a presenter-keyed slot collapses to one, two racing resolvers overwrite it, and the settlement then selects whichever answer was written last rather than the one that won. `<answerId>` is derived from the answer's own content (§14.5), so a retry after a crash lands on its own record with its own bytes; an amendment's is minted fresh per filing (§14.5). Writer: the run driver's commit path ONLY (§13.9) |\n| `notice` | `notice.<endpoint>.<runId>.<addresseeId>.<noticeId>`; one bounded decision a workflow told one agent (`notify`, [`spec/cotal-lang.md`](spec/cotal-lang.md) §6.8), filed onto the run and rendered ahead of that agent's next turn, never a channel message. `.spec`/`.status`-split: the spec is the notice (`{ v: 1, run, step, addressee, fact, at }`) and is create-only, the status is its consumption (`{ v: 1, consumedAt, by, observedSpecRevision }`). **`<addresseeId>` is a digest of the agent's name and never the name, because an agent name is dotted and a dot is the key separator**: a raw name re-tokenizes the key into a key of another shape, and mangling it destroys the identity being keyed on; a reader holding the handle re-derives the same token (§14.5), so per-addressee enumeration stays one prefix scan. `<noticeId>` is derived from the step's request id and the addressee, so a `notify` re-run after a crash lands on the same records. Writer: the run driver's commit path ONLY (§13.9) |\n| `migration` | `migration.<endpoint>.<runId>.<migrationId>`; one run's move onto edited source ([`spec/cotal-lang.md`](spec/cotal-lang.md) §11.2): what the divergence-and-orphan check found, which refusals a person overrode, and who they were. `.spec`/`.status`-split: the spec is the REPORT (`{ v: 1, run, fromHash?, toHash, at, consumedThrough, orphans[], overrides[], actor }`) and is create-only, the status is the APPLICATION (`{ v: 1, appliedAt, by, observedSpecRevision }`) and names the driver that advanced the run. Its own kind because it is neither half of the run record: a migration is append-only history with an actor on it, and a run can migrate more than once, so the status half would let the second erase the first and the spec half cannot be written twice. **`<migrationId>` is a digest of the report's own content and never a counter**, because a migration is decided by a dry walk a crash can force to be re-run, so the same decision must land on the same record rather than filing a second one, and a counter would need a second arbiter for a fact the content already determines (§14.5). **The application is create-only for the same reason the notice's consumption is**: two drivers racing to advance one run both find no status and both write, and the store decides which one moved it. Writer: the run driver's commit path ONLY (§13.9) |\n\nThird-party kinds\nregister under reverse-DNS kind names.\n\n**The two coordination machines.** `goaleff` and `epname` carry closed value machines. A row's\nlegal field set is fixed per phase or per state, and a writer that presents a field the phase does\nnot define, or omits one it does, is refused rather than accommodated: a single broad object with\neverything optional cannot express that a field is present exactly when a launch is in flight, and\npresent-exactly-when is the only form in which those fields decide anything.\n\n`goaleff` has four phases: `claimed`, `launching`, `launched`, `settled`. Every row carries `v: 1`,\nthe electing `executor` as an incarnation `{ instanceId, processEpoch }`, the `attemptId` nonce of\nthe attempt that won the election, and `ts`. `launching` and `launched` additionally carry `addr`,\nthe allocated address `{ nameToken, lifecycleUid }`; `settled` MAY carry it; `claimed` MUST NOT.\nThe legal edges are `claimed → launching`, `claimed → settled`, `launching → launched`,\n`launching → settled`, and `launched → settled`. `settled` is terminal because no edge leaves it,\nwhich is the terminality rule itself rather than a separate check that could come to disagree with\nthe table. The `executor` and `attemptId` do not move across an edge, and an allocated `addr` is\nnever rewritten to a different one.\n\nTwo actor roles take those edges. An **executor** may take any of them and MUST be the row's own\nexecutor at the row's own `attemptId`: a re-read that finds a foreign incarnation or a foreign\nnonce is a loss, never a licence to proceed. A **sweeper** acts for an executor it believes is gone\nand MAY take only the edges into `settled`, because advancing a launch phase on a dead executor's\nbehalf is the split brain the election exists to prevent, and the resulting row is\nindistinguishable from the executor having advanced it. An actor presenting neither role is\nrefused; an unrecognized role that falls through both checks is the most permissive possible answer\nto the question of who is acting.\n\nEvery settle is gated on the goal's terminal fact **already existing**. Settling without one\npublishes a row asserting that a goal finished when nothing durable records that it did, so the\nterminal-first order is normative and the reverse order is never legal. A crash between the two is\na row left un-settled with its terminal present, which is recoverable; the reverse would not be.\n\n`epname` has seven states: `claimed`, `launching`, `live`, `preserved`, `relaunching`, `draining`,\n`released`. Every row carries `v: 1`, `ts`, `state`, and `claimant`, which is either `null` or one\nof three kinds: an **action** claim `{ goalId, gen }`, a **direct** claim\n`{ instanceId, processEpoch, opId }`, or an **incumbent** claim `{ backfillId }` recorded by a\ncutover backfill. A launch in flight (`launching`, `relaunching`) additionally carries\n`lifecycleUid`, `launchAttemptId`, and the `executor` incarnation; a name that is up (`live`,\n`preserved`) carries `lifecycleUid` and `runtimeOwner`; `draining` carries `lifecycleUid`,\n`runtimeOwner`, and `enteredAt`; `claimed` and `released` carry the base fields alone.\n\n`runtimeOwner` is the incarnation that owns the handle table for the name, and it is **moved, never\nderived**. It MOVES on the four launch-resolving edges, `launching → live`, `relaunching → live`,\n`launching → draining`, and `relaunching → draining`: the row's full `executor` incarnation becomes\nits `runtimeOwner` and `launchAttemptId` is cleared, recorded at the moment it becomes true. Both\nfields of the incarnation move together, because an `instanceId` without its `processEpoch` names a\nprocess rather than the run of it that holds the handle table. On the three edges that neither\ncreate the row nor resolve a launch, `live → preserved`, `live → draining`, and\n`preserved → draining`, it is CARRIED unchanged. The one creation edge that produces a `live` row,\nthe cutover backfill, INSTALLS it instead, read from the incumbent's own live gate row: a cutover\nthat cannot read one MUST record a casualty rather than backfill, because a `live` row whose owner\nis unknown puts an unevaluable value into the durable record that every later release reads. Except\non that edge it is never reconstructed from any other row, because a supported deployment mode has no such row to read and a\npredicate that cannot be evaluated on a supported path either refuses forever or falls back to\nabsence. An `instanceId` alone will not stand in: an identity is not an incarnation, and a\nrestarted process under the same identity holds an empty handle table, which is the absence of\nknowledge rather than knowledge of absence.\n\nSix actor roles take the `epname` edges. An **allocator** creates a claim (`→ claimed`, and\n`released → claimed`, so a released name is claimable again and the row is never deleted). A\n**claimant** drives its own launch (`claimed → launching → live`) and may abandon an unlaunched\nclaim (`claimed → released`). A **holder**, identified by the row's `lifecycleUid`, drives the\npreserve cycle (`live → preserved → relaunching → live`). A **sweeper** may release an unlaunched\nclaim and may move `launching`, `live`, `preserved`, or `relaunching` into `draining`. A\n**cutover** may establish a `live` incumbent directly, which is the backfill path. An **operator**\nhas exactly one edge, `draining → released`.\n\nThat last edge is operator-only by design rather than by omission. An ordinary release would\nrequire an actor attesting that a runtime is gone, and no such actor can exist: an owner still\nalive has no per-attempt handle to attest about, and a restarted one is a different incarnation.\nThe edge is therefore removed rather than weakened, and `draining` is a state an operator clears by\nhand until a durable runtime-attempt token exists. Two consequences follow and are normative. A\ngoal reaching a `succeeded` terminal does **not** release the name it holds; and release is a\ntransition to `released`, never a delete, so the row survives to answer who held the name last.\n\n**The actor roles above are entitlements inside the value machines, not wire principals, and which\nprincipal may present each of them is unspecified: RAISED, NOT SETTLED.** The write grants on both\nkinds are the commit path and the goal-writer principal that composes it (§13.9). No sweeper,\noperator, allocator, or cutover principal is granted anywhere in this document, so this section\ndoes not say whether a conforming sweep runs under the commit principal or under a principal a\ndeployment would have to add. An implementation MUST NOT read a role in these machines as\nconferring a grant, and a deployment that needs a distinct sweep identity is outside what this\nversion specifies.\n\n**Descriptor and describe.** Each instance registers a **service record** (kind `svc`, key\n`svc.<endpoint>.<instanceId>`; the owner is determined by the name and recorded in the\nvalue): spec = `{ endpoint, owner, endpointType?,\nclusterDigests[], protocol: { v: 1 | 2 }, activation? }`, status = `{ epoch, state,\nobservedSpecRevision, … }` (writer table §13.9). The spec key's **store revision is the\ninstance's `registrationRevision`**, the value scatter freezes (§13.5): it advances only\nwhen the mediated registration path writes the spec key, so an advance during a scatter is\nexactly a re-registration. The `processEpoch` of the instance's issuance gate (§13.1) is 0 after\nthe first registration of its `instanceId`, and each later registration of it commits the previous\nepoch plus one. A registration is the first when the gate's `registrationRevision` is still 0; a\nderegistration leaves the gate unchanged, so the registration after it is a later one. Epoch 0 is\nopen and serving like any later epoch, and a consumer or sweeper MUST NOT treat it as absent or not\nready. `describe` is a reserved untargeted\nephemeral command every endpoint MUST serve, returning the descriptor with clusters inline or\nby digest. **Authorization-scoped answers use a trusted authorization source only**: the\nanswer is intersected against a fresh view of the caller's authority obtained from the\ndeployment's authorization ledger/callout (§9/§10), keyed by the broker-authenticated caller\nidentity, never against payload- or slot-asserted scope, which is ignored. If the trusted\nview is unavailable or stale beyond its declared freshness bound, describe fails closed\n(`unavailable`) rather than answering from a weaker source; deployments MAY declare an\nendpoint's descriptor public, in which case no view is consulted and the answer says so.\nDescriptor visibility is never inferred from reachability of `describe` alone. A KV browse\nindex (record kind `contracts`) is an advisory convenience copy; `describe` is authoritative.\n\n**Manager-service records.** A remote manager registration is one closed, opaque-instance family:\nits `svc.manager.<instanceId>` spec/status pair, its instance-bound contract closure, and its\n`epgate.manager.<instanceId>` / `epcred.manager.<instanceId>.<credentialId>` rows all name the\nsame server-authorized `{ owner, managerActor, lifecycleUid, instanceId }` tuple. The registration\nmediator MUST reject any tuple mismatch, instance collision, contract substitution, or status/gate\noperation from another principal or lifecycle. It may publish only the contract artifacts staged by\n`prepare`; it may not use manager-service authority to publish a contract for any other endpoint.\nRetiring the family retires the instance record and gate together; no stale stage, registration,\ncontract, status, or credential can activate a new lifecycle or another instance. `describe` and\nstatus report the manager instance's serving/degraded state without treating discovery as\nauthorization (§13.9).\n\n**Invocation binding.** The digests are not caller courtesy but a two-sided requirement\n(§13.3): a caller MUST pin `op.inputDigest`/`op.outputDigest` on every command except\n`describe` (the discovery bootstrap), and a serving member MUST reject their absence\n(`contract-mismatch`) before any effect; an unpinned invocation cannot silently bypass the\ndescribe→invoke binding, and MUST honor pinned digests or reject `contract-mismatch`. Rolling updates keep classes contract-homogeneous: an incompatible\ngeneration registers a distinct routable identity (new endpoint name or explicit version\nlabel) until homogeneous.\n\n**Traits.** A trait attaches governed metadata to a cluster, command, attribute, or event.\nA **trait definition** `{ urn, valueSchema (digest), selector, breakingChanges, authority }`\nis content-addressed and signed: `ai.cotal.*` definitions by the space-operator authority;\nthird-party definitions by their defining owner's registered key. **Attachment authority is\ndistinct from definition authority**: every *required/governed* attachment (this revision governs\nexactly `ai.cotal.guarded` and `ai.cotal.priced`) is separately signed by the definition's\nnamed authority over `{ endpoint, command, contractDigest (the cluster document's complete\nclosure digest), traitUrn, value }`, so a self-published descriptor cannot strip, forge, or downgrade a governed\nannotation; removal or downgrade is an authorized contract revision. Enforcement is\nfail-closed at the pre-effect seam: missing, unverifiable, or stale governed attachments\nrefuse before effect. Non-governed traits are unsigned vocabulary.\n\n**Compatibility.** Cluster evolution is BACKWARD by default: within a revision line, changes\nMUST be additive and added fields MUST carry defaults; removal, rename, or semantic change\nmints a new cluster URN version. A push-time JSON-native compatibility differ + review gate\nenforce this in the reference workflow (repository tooling under `scripts/`, not shipped\nclient code). The discovery protocol itself is versioned under `protocol.v`, additively by\ndefault: a bump is reserved for a change a client cannot safely ignore, and `effect` (§13.7) is\nthe one such change so far — a client that ignored it would keep performing exactly the retry the\nfield exists to stop, so it refuses the document instead.\n\n### 13.8 Distributed guarantees\n\n- **Idempotency scope.** Ephemeral idempotent commands by `id` (handler-local, within result\n retention); journaled submissions and actions by `id`/`goalId` + fingerprint within the\n declared horizon. Exactly-once is bounded honestly: delivery is at-least-once; Cotal\n guarantees idempotent submission/fact recording and fenced commits of Cotal-owned state; an\n external side effect is exactly-once only when the external API honors the propagated\n idempotency key or fencing token, else the contract documents at-least-once effects. A\n workflow step inside a `once` scope (`spec/cotal-lang.md` §7.8) is dispatched at most once per\n step key whatever the far side honors, a dispatch being one call of its handler under its request\n id that the handler does not refuse (the handler may retry inside that call): a resume that finds\n it begun and unsettled opens a hold under a token derived from its recorded request id instead of\n dispatching it again, trading the run's liveness for the bound.\n- **Repeat versus resubmission.** **A command that is idempotent by `id` is NOT thereby `read`:\n safe to resubmit is not safe to repeat.** That is the rule neither mechanism states alone, and\n declaring such a command `read` licenses a fresh-`id` retry that duplicates the effect. The two\n properties are independent; a command may hold either, both, or neither.\n\n A **resubmission** is a re-send the responder CONVERGES onto the decision it already recorded; a\n **repeat** is a re-send it accepts as new work. Reusing the `id` is how a caller ASKS for\n convergence, and within the horizon below it is how convergence is keyed — but the `id` is the\n request, not the answer, and a re-send under a reused token that the responder accepts as new\n work is a repeat by this definition. `effect` (§13.7) governs repeats, whatever token they\n carry. `id` governs resubmissions — and what `id` alone is worth differs by rail:\n - **Ephemeral** — `id` is the whole key. A same-`id` resubmission within result retention is\n the same call; an idempotent command may dedup on it and consult nothing else.\n - **Journal** — `id` is necessary but NOT sufficient. It is one of the fields the fingerprint\n binds, so a same-`id` resubmission converges to the first outcome only if the rest of the\n fingerprint matches too. Same `id` with different args is neither a resubmission nor a fresh\n call: it is a loud `conflict` (§13.4), because the decision subject is already occupied by a\n fact with a different fingerprint. A caller that mutates arguments and reuses an `id`\n therefore gets an error rather than either behaviour it might have expected from the\n ephemeral rail.\n\n **Both rails are bounded by a horizon, and outside it neither rule applies.** A resubmission is\n a resubmission only while the prior decision is still retained — the idempotency horizon is\n realized by decision-fact retention on the journal rail and by result retention on the ephemeral\n rail, never by a clock (§13.4). Once the retained decision is gone, the `id` carries no history:\n a re-send under it is a fresh call that WILL execute, and the same `id` with different args is\n no longer a `conflict` but simply a new submission. The finite horizon is what makes the decision\n store finite, so this is a fact callers MUST hold rather than a hole to be closed — but the hole\n it WOULD open if `repeat` were defined by the token is closed at the definition above: a re-send\n the responder accepts as new work is a **repeat**, so a post-horizon same-`id` re-send of a\n `write` is exactly what §13.7 prohibits a client from making automatically. Reusing the token\n buys nothing outside the horizon, and a caller that cannot establish it is still inside one has\n not established that its re-send is safe.\n\n Neither word is \"retry\": callers retry under a reused `id` and under a fresh one and mean the\n same English word both times, which is the confusion this paragraph exists to remove. And the\n dangerous reading is a REASONABLE one, not a careless one — an operator who has correctly\n learned that a command is idempotent by `id` will retry it after a timeout, mint a fresh `id`\n because the old request is gone, and get a second effect. Nothing in this document told them\n those were different acts until now.\n- **Fencing and mediated commits.** Every Cotal-owned authoritative transition flows through\n its mediated writer (§13.9) carrying `(fencingToken | lifecycleUid | epoch)` as applicable;\n the writer validates token currency, unexpired lease against its own clock, lifecycle\n currency, and epoch currency. Value-carried tokens + CAS stop conforming-but-stale writers;\n scoped credentials + mediation stop everything else. The threat boundary of any\n direct-owner write is explicitly downgraded (§13.9).\n- **CAS conflict.** Any lost CAS is a loud `conflict`; the loser re-reads and re-decides.\n- **Authority-head reservation/drain.** An authority head (the §13.1 lifecycle head; the\n §13.6 registered admission policy) and a durable acceptance/start fact live in different\n streams; no cross-stream CAS exists, and a revision carried inside a fact is provenance,\n never a fence. Any durable acceptance or start that creates work bound to a lifecycle,\n or admits work under a policy read, therefore contends with the head's movement on ONE\n durable serialization coordinate: the **target-indexed obligation row** (kind `oblig`,\n §13.7). In order: (1) BEFORE the EPF decision publish, the writer obtains the obligation\n through the **admission mediator**. The mediator owns the `oblig.` prefix (the\n canonicalizer holds no raw write on it), derives the coordinate from the\n broker-authenticated request subject (never from a body field), and IMMEDIATELY before\n the create performs the FENCING currency reads it will pin: for a target-bound\n admission a leader-served read of the target's lifecycle head, REFUSING unless the state\n is `active` (a `retiring` or `retired` target admits nothing); for a policy-admitted\n decision a leader-served read of the governance head (§13.6) that FIRST refuses if a\n `pendingPolicyKey` is present (the endpoint is inside its drain window; the drain-window\n admission pause is a normative step of THIS algorithm, not only a §13.6 property, so any\n conforming mediator refuses without needing to infer it) and only then follows\n `enforcedPolicyKey`, self-certifies it (§13.7), and pins its `enforcedPolicyRevision` as\n `policyRevision`. Refusing at the create-fence (not only at the post-create recheck) is\n also what bounds the row set: a request that could not create its row leaves no\n never-deleted `oblig` debt behind, so a long or crashed drain cannot accumulate an\n unbounded set of rejected rows. An admission with no target lifecycle keys the\n row under the fixed sentinel target token `ep` (§13.7). It then creates the row\n create-only at the deterministic acceptance-identity\n key `oblig.<targetUid>.<endpoint>.<cOwner>.<cActor>.<cUid>.<id>`. The KEY never contains\n `sourceSeq`, delivery attempt, mapping revision, or writer op id (a redelivery of the\n same logical acceptance MUST land on the SAME key); where a digest stands in for the\n tuple it is a versioned, collision-resistant digest of exactly that tuple, never\n delimiter-ambiguous concatenation. The VALUE pins the first winner under a CLOSED\n per-class schema: every row carries `{ state: provisional | accepted | rejected |\n terminal, decision: epf | self, opId }` plus the currency pins taken above\n (`mappingRevision` iff target-bound, `policyRevision` iff policy-admitted; at least one\n present); an `epf`-class row (a canonical acceptance) adds `{ fingerprint, sourceSeq,\n route }`; a `self`-class row (a guarded record commit, e.g. the restart-status CAS,\n §13.6) adds the COMPLETE commit intent `{ commitKey, commitBaseRevision, commitValue,\n commitDigest }`: the exact record key its accepted state authorizes, the store revision of\n that record the commit CASes FROM, the value it commits, and that value's digest.\n `commitValue` is a CLOSED discriminated union, so two implementations resolve and replay the\n SAME value: `{ enc: \"b64u\", bytes }` carries a JSON encoding of the committed value,\n base64url-encoded (RFC 4648 §5, no padding), or `{ enc: \"ref\", key }` names an\n IMMUTABLE, create-only records key (the §13.7 `policy` kind or another never-overwritten\n key) whose stored value IS the commit value; a mutable or absent `ref` target\n refuses at recovery, fail-closed. Never only a digest (a digest cannot reconstruct the\n value a crash recovery must re-write). `commitDigest` is the RFC-8785 CANONICAL content\n digest of the committed value, `sha256:<hex>` (the same `*Digest` scalar shape §13.7 uses\n everywhere; over the CANONICAL value, never a non-canonical storage stringify, so the\n landed/not-landed comparison is insensitive to how the store serializes the record). A\n crashed writer's commit is thus deterministically finishable from the row alone (below). The\n `decision` class is fixed by the TRUSTED operation kind, never caller-selectable. A\n create loser leader-reads the winner: the FULL pinned identity must match to join (an\n `epf`-class row on coordinate + fingerprint + route; a `self`-class row on the ENTIRE commit\n intent `commitKey` + `commitBaseRevision` + `commitDigest`, so two different desired values\n or base revisions never join under one `commitKey`); any\n mismatch is `conflict`, never a second obligation. (2) **Proof issuance is a post-create\n currency recheck, and admission is proof-gated**: after winning or joining the create,\n the mediator leader-reads the SAME coordinates AGAIN, and only if the target head is\n still `active` at the pinned `mappingRevision` AND (for a policy-admitted decision) the\n governance head STILL stages no `pendingPolicyKey` and the enforced policy is still at\n the pinned `policyRevision` does it return the opaque admission proof; otherwise it\n IMMEDIATELY settles its own provisional through the row's decision coordinate (below) and\n refuses. The recheck reads the SAME govern head the create-fence read, so a\n `pendingPolicy` staged in the window between the create and the recheck also fails\n proof issuance, not merely a moved `enforcedPolicyRevision`.\n No target-bound or policy-admitted EPF acceptance may publish, and no `self`-class\n guarded commit may run, without an unexpired proof issued under this rule. This is the\n structural half of the head fence: an obligation created in the window between a fresh\n `active` read and a head or policy movement exists durably, but its proof can never\n issue, so it can never admit; it is inert cleanup debt any later drain settles. (3) The\n EPF decision CAS runs as\n specified (§13.4), publishing with the WINNER's pinned acceptance identity and\n `sourceSeq`, whichever delivery is processing; a `self`-class writer instead advances\n its own row `provisional → accepted` (revision-pinned) and performs its guarded commit\n only while the row is `accepted`. (4) On acceptance the SAME key advances\n `provisional → accepted` and is retained until the accepted route is\n terminal and cleaned: the only enumerable record of accepted work is never\n erased at the moment it wins. States are monotonic (`provisional → accepted →\n terminal`, or `provisional → rejected`), the row is NEVER-DELETED, and a DEL/PURGE\n marker is corruption. The stored `opId` is not a bearer capability: a resuming writer\n re-authenticates as the same endpoint-scoped principal through the mediator and joins\n by acceptance identity + fingerprint; any opaque reservation token the mediator issues\n is target/endpoint/connection-bound, bounded-lived, and checked against the CURRENT\n obligation state; the durable obligation is the authority, never possession of its\n identifier. **The decision coordinate is per-class** and is where every unresolved row\n settles: an `epf`-class row settles through the EPF decision subject's create-only CAS\n (read the winner; if absent, create-only publish the terminal rejection so a delayed\n acceptance CAS loses; the mediator holds that rejection-publish authority and executes\n it for its own recheck refusals and on behalf of the drains, §13.9); a `self`-class row\n settles on ITSELF: while still `provisional`, the drain CASes `provisional → rejected`\n (the writer's `provisional → accepted` CAS and the drain's rejection contend on the ONE\n row, exactly one wins, and a delayed guarded commit finds its authority gone). An\n `accepted` `self`-class row is NOT stuck and does NOT block quiescence: because the row\n pins the complete commit intent `{ commitKey, commitBaseRevision, commitValue, commitDigest }`,\n either\n the writer's own resume OR a drain reconciler drives it `accepted → terminal`\n deterministically. Read the record at `commitKey`: if its value canonically digests to\n `commitDigest` the commit landed, CAS the row `accepted → terminal`; if it is still at\n `commitBaseRevision` the commit did not run, re-apply it by CASing the resolved\n `commitValue` (decode `b64u`, or leader-read the immutable `ref` key's value, verifying its\n canonical digest against `commitDigest` BEFORE writing) at\n `commitBaseRevision` then CAS the row terminal; if the\n record has moved PAST\n `commitBaseRevision` to a foreign value the intended commit can never land (the guarded\n CAS would lose), so CAS the row straight to `terminal` as superseded. Quiescence therefore\n means NO `provisional` and NO un-driven `accepted` `self`-class rows remain: an accepted\n commit is always completable from the row alone, never an unrecoverable orphan. **Reclamation is never\n clock-only**, and because the EPF writer need not be the retiring lifecycle (a\n cross-endpoint canonicalizer publishes decisions bound to a foreign target, and revoking\n the TARGET's credential family disarms nothing that writer holds), target-side\n revocation alone is NEVER the reclamation condition. An unresolved `provisional` is\n reclaimed only by: settling it through its decision coordinate; or revoking +\n verified-evicting the WRITER's own commit authority; or the target head being\n non-current AND the drain below having completed to quiescence under the create fence +\n proof gate. A timeout alone never frees a slot\n while the writer retains publish authority. **Drain to quiescence**: after the head\n CASes to `retiring` (§13.1), and equally when a policy mutation must enforce a new\n revision (§13.6, enumerating `oblig.*.<endpoint>.>`), the drain enumerates the prefix\n (`oblig.<targetUid>.>` for retirement), settles every\n unresolved row through its decision coordinate, completes accept-side reconciliation\n (enqueue/goal/terminal, §13.6) for accepted rows, then RE-ENUMERATES, and records its\n cleaner and frontier completion (or treats the new policy as enforced) only when an\n enumeration finds no unsettled row. A provisional whose pinned `mappingRevision` or\n `policyRevision` is no longer the live coordinate is settled as REJECTION, never treated\n as still open for acceptance. A row created after the final enumeration cannot admit\n (its proof can never issue, step 2) and is settled by any later enumeration;\n an acceptance published after the recorded cleanup frontier from a\n stale `active` read is non-conformant even if later effect resolution would reject it.\n Whether the obligation is released once the route is settled under ordinary policy\n movement (`release-after-accept`) or survives as cleanup debt the terminal barrier must\n observe (`promote-to-lifecycle-obligation`) is fixed by the TRUSTED operation kind,\n never caller-selectable. The admission-policy specialization additionally binds\n identity at the read: the confined policy reader's request subject pins the\n authenticated canonicalizer endpoint AND the requested policy endpoint, requires their\n equality, derives the reply rail from that authenticated subject, and returns\n `{ policy, revision }` with an opaque proof binding `{ space, endpoint, policy\n revision, obligation/op id }`; endpoint A can never obtain, or replay, endpoint B's\n admission proof.\n- **Retry/backoff.** Only idempotent-at-scope operations are retried: exponential backoff,\n base 250 ms, factor 2, cap 15 s, full jitter, bounded by the caller deadline.\n- **Deadlines.** Mandatory on call, scatter, claims, checkpoints, timers, sessions. Reference\n default call deadline 15 s; defaults are overridable, never removable.\n- **Cancellation ordering.** First terminal fact at the mediated commit point wins.\n- **Watch recovery.** Fell-behind ⇒ snapshot re-read then resume; bounded relist; no silent\n gap-skipping.\n- **Ordering/partitioning.** Per-subject only; the subject is the partition key.\n- **Retention floors.** Submissions ≥ recovery/redelivery lag (§13.12; native dedupe is not\n relied upon, §13.4); facts/tombstones ≥ idempotency horizon;\n results ≥ result retention; receipts ≥ receipt retention; timers ≥ max deadline + recovery\n margin. **Pool coupling:** every accepted pool item carries an **absolute work expiry**\n (`workExpiry`, set at acceptance in the AcceptanceFact, NOT a per-message age a\n reconciliation re-publish would reset; a re-enqueue re-publishes with the SAME `workExpiry`,\n and the item is dead once it passes, leased or not). The EPW stream's max age is ≥ the\n maximum `workExpiry` + recovery margin, and a pool item's decision and `wrk` terminal facts\n are retained ≥ that same bound, so a live (or crash-recovering) item can never outlive the\n facts that identify it as accepted or settled: a decision that expired under a still-live\n item would let a reused id collide with the old enqueue, and an expired `wrk` under a\n lost owner ack would make settled work unrecognizable on redelivery. A reused `id` becomes\n new work only after the old item's `workExpiry` AND its facts' retention have both passed.\n An endpoint MUST refuse to start against a store below its declared floors.\n- **Backpressure and budgets.** Bounded consumer pending (default 1024), bounded\n virtual-endpoint pools and session windows, flow control on watches; overload is\n `resource-exhausted`. Schema compile/validate budgets (reference: 100 ms / 10 ms) and\n bounded regex; over budget is `contract-invalid`/`bad-request`.\n- **Timers.** Broker message schedules at the 2.12 floor; same-subject replacement only (at\n the mediated `.armed` subject, §13.12); generation- and scheduler-origin-validated firing\n (stale or foreign-origin ⇒ no-op); durable reconciliation repairs\n status↔schedule divergence; replication and offline-assets downgrade fail loud at the\n broker floor gate.\n\n### 13.9 Authority boundary\n\nThe credential is the coarse boundary; every subject in §13.2 is default-deny. Every\n**statically expressible** authorization dimension is broker-enforced through the subject\ngrammar: caller identity + lifecycle, endpoint,\ncommand, the target components each mode pins statically (§13.2: the full triple for `self`,\nthe caller's own, and for `handle`, redemption-pinned; the owner for\n`owner`/`any`/`child`/`ledger`), serve identity, reply\n**attribution**, and plane writer ownership.\nReply **addressing** is the one deliberate exception: it is capability-by-secret (the\nper-request nonce, §13.2), not a broker grant, and it is sound precisely because serve\ncredentials cannot plain-subscribe the class rail (queue-qualified grants, §13.2), so nonces\nare visible only to the instance the queue selected (plus every instance on a scatter, which\nis scatter's definition). Target enforcement is stated per mode, never as a blanket claim:\n`self` is broker-confined end to end including the lifecycle UID; `handle` is broker-confined\non the full redemption-pinned target triple, with the validator re-checking only mapping\ncurrency; `owner`/`any` are broker-confined on the target owner and validator-primary on the\nactor and UID currency; `child`/`ledger` are validator-primary within their distinct broker\nrails. The **named dynamic relations** (static-mesh\nown-child, fresh-ledger escalation, target-mapping currency, authorization epochs after\nacceptance) are trusted-validator-primary by design, fail-closed, and operate only within\nthe broker ceiling. Handlers only narrow. **The process epoch fences only the five planes\nwhose subjects carry it** (reply, `epe`, `ept`, `eps`, `epr`). Request-ingress subjects and durable record\nkeys cannot carry it; the caller cannot know it, and a restart-stable key must not change,\nso those two classes are fenced by the mechanism each admits: records by mediation (writer\ntable below), ingress by credential revocation with verified eviction (§13.1), never by\nsubject.\n\n**Caller grants.** Minting maps each named capability to exact endpoint+command subjects:\npublish on the request forms (class + instance) with the authz-mode/target pattern the\ncapability specifies, subscribe on the caller's own reply rail, publish on matching `epj`\nsubmission subjects for journaled commands, and the exact record-key / event-topic subtrees\nfor attribute/event read capabilities (per-goal containment rides the caller triple in the\ntopic). The caller's lifecycle UID token is pinned in every granted subject, so a credential\nis dead against its principal's next lifecycle by construction. Wildcards are bounded: `*` in\nthe command position only when the capability covers every command of the endpoint; `*` in\nthe endpoint position never, outside operator/admin profiles; `child`/`ledger` mode subjects\nare never covered by an `owner`-mode wildcard. `describe` is granted by default for all\nendpoints; a space MAY narrow it. Because the subject shape is verb-invariant (§13.2), one\npublish row covers call and cast of a command. Minted credentials MUST stay within the\ndeployment's JWT size envelope, and the envelope is validated against a **normative\nmaximum-capability fixture**, not an adjective: the reference fixture is an agent holding\nevery baseline grant plus capabilities on 3 endpoints x 12 commands each, each targeted\ncommand in both `self` and `owner` modes, plus journaled submissions and per-goal read\nscopes for all of them. Minting MUST fail loud before emitting a credential that exceeds the\npolicy gate (reference: 16 KiB); the transport bound is the CONNECT control line\n(`max_control_line`, §13.12) and the policy gate MUST be the tighter of the two. The mint\nMUST also refuse, before any issuance record is written, a user JWT whose byte size exceeds the\ncontrol line minus the CONNECT envelope (`MAX_MINTED_JWT_BYTES`), so a composition of individually\nvalid grants can never produce a credential the broker drops silently. The fixture\nset additionally includes a **maximum-command serve credential** (a 12-command endpoint's\nper-command rows, below); the §13.12 operator assertion uses the largest encoded CONNECT\nline in the set.\n\nThe agent baseline includes the self-targeted manager command `run-answer`. Its grant is only the\n`self` request form. The manager MUST authorize a baseline managed seat only when an open `ask` or\nescalated checkpoint is named by a pending relay addressed to that exact caller incarnation, and\nMUST refuse every other run or pause. A caller holding the explicit `run` capability may use the\nsame self-targeted form for ordinary run answers. The request never carries the answerer's name.\nThe amend form of `run-answer` (§14.5) addresses a settled pause instead, and the manager MUST\nauthorize it for a baseline managed seat only when the accepted answer it supersedes was recorded\nunder that seat's own name.\n\n**Serve grants.** Serving is granted authority, dual to calling. On the **subscribe side**\nan instance's credential binds its registered service name, stable instance id, and\n**registered command set**, one queue-qualified subscribe row per registered command\n(matrix below), never a bare `>` tail spanning commands the instance did not register. The\nper-command enumeration is affordable precisely where the caller-side equivalent is not:\nserve credentials are one per instance, a handful per space, with no capability-count\nscaling pressure. The subscribe side deliberately does NOT bind the epoch; a caller cannot\nname the serving epoch, so no request subject carries it and **ingress cannot be\nepoch-fenced by subject**; the fence for a superseded subscriber is the §13.1 takeover\nbarrier (revoke + cluster-verified eviction), not a grant shape. On the **publish side** the\ncredential binds the epoch everywhere it is real: the epoch-pinned reply prefix, the\nepoch-pinned `epe` event plane, its `ept` timer schedule requests, and its `epr`\nrecord-write ingress. Session subjects are\ndeliberately absent from the standing serve grant: both sides of a session hold only\nredemption-minted per-session credentials (§13.6); no standing EPS grant exists on either\nside. The credential also carries the record keys the writer table assigns it and, where\nthe endpoint owns a work pool, the pool's consumer + ack grants (§13.5; matrix below).\nNothing else. Every \"binds X\" in this paragraph has a matrix row below that actually binds\nX. Serve\ncredentials are re-minted on takeover (new epoch, §13.1 barrier); a superseded credential's\nreplies and commits are rejectable by epoch. Core names require operator provisioning\nauthority; reverse-DNS names bind to their registered owner. The registry is discovery; the\nserve grant is the authority: a foreign credential cannot subscribe a class rail, answer as\nan instance, or enter a frozen scatter set.\n\n**Remote manager-service grant.** The server-authored `manager-service` view is an\ninstance-scoped authority family, not a reusable host profile. Its generated grant is the exact\nunion of the one manager instance's serve rows, its one service registration/status mediator,\nits staged contract-publication row, `epgate.manager.<instanceId>`, and\n`epcred.manager.<instanceId>.<credentialId>`; no wildcard may span an instance, manager actor,\nowner, endpoint, record kind, contract digest, or credential id. The trusted auth path alone owns\ngate/ledger writes and all host signing. The manager service's descendant-provision request is\nmediated by that host path and MUST re-derive the requested agent's owner from the authenticated\ncaller, require it to equal the manager-service owner, and fresh-validate the active grant before\nminting any child material. It is never a raw provisioner, stream, KV, consumer, signer, or\ncross-owner control grant. The registration and renewal operations are typed/idempotent as §13.6\nrequires, and their stage records remain inaccessible to every ordinary agent, observer, admin,\nor managed-agent exchange.\n\n**Platform control grant.** The `platform-control` view's generated grant is the remote\nmanager-service grant above with the platform owner token as owner: the union of the one assigned\ninstance's serve rows, its one service registration/status mediator, its staged\ncontract-publication row, `epgate.manager.<instanceId>`, and\n`epcred.manager.<instanceId>.<credentialId>`, with no wildcard spanning an instance, manager actor,\nowner, account, endpoint, record kind, contract digest, or credential id. Descendant provisioning\nMUST re-derive the requested agent's owner from the authenticated caller and require it to equal\nthe platform owner token. Serve-time admin authorization answers `authorized: true` only for a\ncaller whose owner equals that token; a human `admin` scope never authorizes against it. It is\nnever a raw provisioner, stream, KV, consumer, signer, launch, or cross-owner control grant.\n\n**Environment manager grants.** `environment-bootstrap` is a fixed, ephemeral caller\nprofile for the host-admitted bootstrap triple. It publishes only the literal instance\ncommand rows `ep.inst.<authorityEndpoint>.<authorityInstanceId>.<command>.<cO>.<cA>.<cUid>.*`\nfor the closed set `describe`, `bootstrap` and `bootstrap-status`. `describe` is read-only\nand supplies the current authority epoch; it issues no workload material. It subscribes\nonly to its native caller rail `ep.reply.*.*.*.<cO>.<cA>.<cUid>.*` and its own\nconnection-scoped inbox. The native reply filter includes the broker's reserved\nno-responders sentinel and matches the standard client's subscription. It exposes no\nother caller's replies; every accepted response still binds the request nonce, endpoint,\ninstance and current epoch. Endpoint and instance tokens use §13.2's native encoding. The\ncommands are ephemeral and untargeted; the nonce is the only wildcard request token.\nThe released stock bootstrap client embeds both complete command contract artifacts and\nverifies their digests against the admitted file before sending. The stock path uses\nnative instance-pinned `describeEndpoint` to observe the authority epoch, verifies its\ncommand declarations against the embedded contracts, then invokes native `epCall` with\nthat instance/epoch and the pre-effect bind. It neither fabricates `ResolvedService` nor\nrequests arbitrary contract artifacts. An authority restart permits a fresh read-only\ndescribe followed by the same held bootstrap-status or bounded operation, never a new\ncreation or lifecycle. A changed contract pin refuses. No artifact-store, class or scatter\ngrant is needed. This profile grants no messaging, presence, JetStream API,\nconsumer, KV, manager, signer or other authority-endpoint access.\n\nThe admitted manager keeps five locally generated identities but uses fixed\n`environment-manager-supervisor` and `environment-manager-executor` profiles in place of\n`remote-manager` for those two duties. Neither holds publish, read, scan, consumer-create,\nupdate, delete or purge authority on `cotal_auth_<space>`, nor direct service registration,\ncontract publication, governance or repair writes. The trusted host performs those bounded\neffects through native barriers under the authenticated authority command. The existing serve and session-ledger profiles keep their own duties and MUST NOT gain\nan authority-family write or auth-store scan through this addition. The goal-writer\nidentity uses fixed `environment-manager-goal-writer`: native goal/coordination rows for\nthis manager, but no auth-store `STREAM.MSG.GET` or consumer access. Its optional own-gate\nfast-fail read is omitted; the native barrier revoke and verified connection eviction\nremain the durable supersession fence. The stock manager skips installing the optional\ngoal-writer gate belt for this family; it MUST NOT open the auth bucket and tolerate a\ndenial. The accepted residual is a deposed incarnation's ability to initiate terminal\npublishes from barrier start until its eviction is verified, the existing §13.1 class for\nother endpoints on an auth mesh. Removing the belt MUST NOT add a fallback or permit\nwrites after verified barrier revocation/eviction.\n\nThe environment supervisor holds its exact\n`$KV.cotal_manager_<space>.lease.<instanceId>` create/CAS row, manager-bucket\n`STREAM.INFO` and leader `STREAM.MSG.GET` rows for lease binding/read, `$JS.API.INFO`,\nits own presence write, existing presence-roster watch and flow control, manager-plane\nliveness serve/reply rows and its own inbox. Those manager/presence bucket reads confer\nno auth-store access. It holds no broad manager/profile grant. The environment executor holds only the fixed instance caller rows for `describe` and\n`authority`, under `<cO>.<executorActor>.<managerUid>`, its native own-caller reply filter\nand its own connection inbox. No command, endpoint, instance or caller wildcard is added. Any required\nregistration, gate, goal-index or credential-currency read is host-mediated, not a broad\nstream read granted to the guest. This row is authority-request access, not an issuance or\nledger-write grant. The host binds it to the admitted account, environment, manager instance,\nexecutor nkey, UID and expiry; it accepts no user-selected profile or command wildcard.\nLike bootstrap, the stock executor binds the current epoch with instance-pinned native\ndescribe and uses the embedded `authority` contract through `epCall`, never a fabricated\n`ResolvedService` or a contract-store read. Standard reply attribution and pre-effect bind\nchecks remain mandatory.\nThe family still holds no account signer, provider API key or foreign instance authority.\n\nThe trusted host alone writes admission/reservation and credential-custody records and\nperforms issuance and external retirement through their existing native barriers. No guest\ncredential receives that private store's reads, writes, deletes, scans or consumer access.\nGrant generation MUST use the ownership rows below. This amendment adds two fixed mediated\nregistration profiles and the narrowed goal-writer profile, rather than adding caller\nrows to the shipped direct `remote-manager` grant.\nNeither these profiles nor their authority caller rows may be issued through ordinary\nhuman or platform-control registration. Tests MUST attempt raw broker writes and auth-store\nscans with every guest credential, not merely pass them through trusted-path parsers.\n\n**Manager status metadata.** The Manager `status` contract permits optional string fields\n`host` and `version`. The stock Manager emits its answering process's host name and its own\nrunning `@cotal-ai/manager` package version, captured at module load. These fields are advisory\nonly and MUST NOT grant authority, select a route or determine placement. Callers MUST use\nverified responder attribution for instance identity and accept payloads that omit either field\nwithout inferring a value from the broker, browser, presence or service registry.\n\n**Platform readiness read.** A platform composition learns whether its assigned control manager\ninstance is serving through the auth context's readiness read. The trusted auth process answers over\nits own self-minted reader connection and hands out neither that connection nor its credential. The\nreader's grant is the `describe` and `status` request rows on `ep.inst.manager.<instanceId>` for the\none assigned instance under the reader's own caller triple, the subject-scoped contract-store Direct\nGet, its own reply rail, and its own `_INBOX_<connId>.>`. It holds no other command, instance, class\nor scatter route, no other store read, no KV write, and no signer. The read observes the current\nassignment on every call, refuses any other instance, and refuses an instance whose gate names\nanother principal. The reader renews as the other self-minted authority connections do: a\nshort-lived user JWT re-minted in process at a random point between 50% and 80% of its lifetime,\nafter which the connection reconnects onto it.\n\n**The ownership matrix (normative).** Every profile × resource × transition is classified\n**mediated** or **direct**, in an independently reviewed matrix from which grants are\ngenerated (never the reverse). Each row names the writer PROFILE, the exact subject/API\nnamespace (including the queue qualifier where one applies; the grant grammar has a queue\ndimension, §13.2), the operation, and the enforcement class; **read, consume, ack, and\ndelete authority are rows in the same table**, never prose that \"follows\" it. Every\ncredential and every audit probe is generated from these rows.\n\n**Consumer-name grammar (normative).** Every consumer a row names has a pinned name grammar\n(dash-form, §2; `<e>` is the endpoint-name token, `<uid>` the holder's lifecycleUid or\ninstanceId): `canonD = canon_<e>` (the canonicalizer durable), `poolD = pool_<e>_<pool>`\n(the pool durable, **pre-created by the provisioner** with exact filter\n`cotal.<space>.epw.<e>.<pool>.>`, the §8 item-3 pattern: the bare create form is\nbody-filter-selectable and is granted to NO ONE on control-surface streams), `timerD =\ntimerw_<space>` (the timer writer durable), `recwD-k = recw_<space>-<kind>` (one record\nwriter durable PER RECORD KIND, §13.9), `effD = eff_<e>` (the endpoint's ONE shared\neffects durable; below), `goalD = goal_<uid>-<e>` (the caller's own goal-result durable).\nEvery composite name is **collision-free by construction**, and\neach derivation states why: `pool_<e>_<pool>` parses uniquely from its LAST `_` because a\npool token contains no `_` (`[a-z0-9-]`) while `<e>` may (a dash separator would be\nambiguous, both tokens admit `-`); `dec_<uid>-<e>` parses from its FIRST `-` because\n`<uid>` is `[a-z0-9]` and contains none, and `goal_<uid>-<e>` likewise; `eve_<uid>-<e>-<gid>-<n>`\ncarries TWO `-`-adjacent soft components (`<e>` and `<gid>`), so `<gid>` is constrained\nSEPARATOR-FREE (`[a-z0-9]`, no `-` or `_`): then `<uid>` (leading, `-`-free), `<n>` (trailing\ndigits) and `<gid>` (separator-free) are each a single token off their edges, leaving `<e>` as\nthe only `-`-bearing component with an unambiguous extent (`eve_<uid>-a-b-c-0` can ONLY be\nendpoint `a-b`/gid `c`, never endpoint `a`/gid `b-c`). `rec_<uid>-<gid>-<n>` has one soft\ncomponent `<gid>` bounded by `-`-free `<uid>` and digit `<n>`. Without the separator-free `<gid>`\nthe two grants above would collide on one durable name. A derivation that cannot state its\ncollision-freedom argument is non-conformant. Reader consumers use **mint-time-enumerated LITERAL names**, and every one\nis **pre-created by the provisioner at capability mint as a PULL durable with its exact\nfilter; the holder receives BIND-ONLY grants** (INFO/MSG.NEXT/ACK, never CREATE or\nDELETE): `decD = dec_<uid>-<e>` (one per journal capability), `goalD = goal_<uid>-<e>`\n(one per action capability),\n`eveD = eve_<uid>-<e>-<gid>-<n>` and `recD = rec_<uid>-<gid>-<n>` (one per granted subtree;\n`<gid>` is the **grant id**, a short stable SEPARATOR-FREE (`[a-z0-9]`) id the provisioner\nassigns per minted capability grant, so two independent capability mints for one lifecycle UID\nnever collide AND the `<e>`/`<gid>` boundary stays unambiguous, and `<n>` is\nthe subtree's zero-based index within THAT grant, sorted lexicographically at mint; the\ndeprovision key is `<uid>-<gid>`, so revoking one capability deletes exactly its own reader\ndurables and cannot reach a sibling capability's). Two reasons, both\nload-bearing. A NATS wildcard replaces a\nWHOLE dot-separated token and never matches inside one, so an embedded `*` in a name token\n(e.g. `dec_<uid>-*`) is a literal character, not a glob; every name token in a grant is\nfully literal.\n\n**Mediated reads (normative).** No untrusted capability holder is granted **any** raw\nJetStream read of a control-surface stream, not a consumer create, not a bind-only pull,\nnot a `DIRECT.GET`. Every JetStream read is request/reply where the server delivers stored\nbytes to a **caller-chosen destination the broker does not confine to the caller's\n`pub.allow`**: a push consumer's `deliver_subject`, a pull `MSG.NEXT` request's reply\nsubject, and a `DIRECT.GET` request's reply subject are all set in the request body, and the\nserver's internal client publishes there regardless of the requester's publish permissions.\nA holder with only `MSG.NEXT` or\n`DIRECT.GET` on its own filtered reader can therefore route stored bytes onto a victim's DM,\nreply, or record subject, a confused deputy no filter tail, literal name, or pull-vs-push\nchoice prevents, because the destination is the vulnerable field, not the filter. Untrusted\ncallers instead read exactly as the §8 durable backstop already does, through a **trusted\nread path**, never a self-bound consumer: a caller receives its decisions, goal results,\nevent catch-up, and record reads over its OWN confined rails, a live core subscription to a\nsubject inside its `sub.allow` (bytes land only on the caller's own subscription), or a\nmediator that owns the reader consumer, re-authorizes each read against the caller's current\ngrants, and returns bytes over the caller's own attribution-pinned reply rail\n(`ep.reply.…<caller triple>.<nonce>`: the mediator holds the publish grant, the caller the\nread grant, and the nonce confines addressing, §13.2). The mediator IS a trusted\nsingle-purpose principal (the delivery/read daemon, §8/Appendix B) that delivers only to the\nre-authorized caller and never proxies to an arbitrary subject; raw\nconsumer/`DIRECT.GET`/`STREAM.MSG.GET`\nauthority stays with trusted single-purpose infra principals (canonicalizer, commit\nprincipal, record writer, timer writer, the read mediator, the auth path) that deliver to\nthemselves. A registered endpoint MAY also mediate its own callers' goal-result reads through\nits separate trusted commit/read connection. Each request MUST be authorized by the requesting\nconnection's broker-enforced command grant on its authenticated caller triple. User-auth revocation\nhas the same bearer-lifetime bound as other live endpoint commands; renewal requires a fresh\nexchange and connect that re-authorize the caller. This read does not claim a per-request ledger\ncheck. The endpoint and full caller triple MUST come from the broker-authenticated request\nsubject; caller input supplies only the goal id. The response MUST\nuse the derived attribution-pinned caller reply rail, never a caller-supplied destination. This\nhosting choice grants no raw read to the endpoint's serve credential or to its callers. The\nexisting trusted reader's body-selected, space-wide leader-read residual MUST remain documented.\nThis contract fixes the boundary; untrusted callers never hold raw reads; reads are mediated onto\nconfined caller rails, and leaves the read-command wire shape (batching, cursors, flow control) to\nthe reference implementation.\n**Subject convention:**\napplication subjects in rows are written relative and are prefixed `cotal.<space>.` on the\nwire; **JetStream API tails (extended-create filter tails and `DIRECT.GET` subject\ntails) are always spelled in FULL** (`cotal.<space>.…`/`$KV.…`/`$O.…`), because the API\nsubject embeds the stored subject verbatim and a relative tail matches nothing (the\nstreams capture `cotal.<space>.ep*.>`, §13.12).\nThe grep tests the matrix MUST pass: the only `CONSUMER.CREATE` grants below belong to\ntrusted provisioning/infra profiles and each carries a full literal filter tail; every\nconsumer-name token in a grant is a LITERAL (no embedded `*`); every filter or Direct-Get\ntail is fully qualified; **no UNTRUSTED profile (agent/observer/admin) holds any\n`CONSUMER.CREATE`/`MSG.NEXT`/`DIRECT.GET`/`STREAM.MSG.GET` on a control-surface resource** (an\naudit MUST run this over Appendix B too, not only this matrix; the profile tables are\ngenerated from these rows, so a generated grant that contradicts the matrix fails the build);\nand the ONLY `STREAM.MSG.GET` (body-selected) grants that exist at all are the leader-served\nreads of named TRUSTED single-purpose profiles, each granted to no other profile - every one\na FENCING read (read service, below) except where its row names it a CAS-PINNING read, a\nleader-served currency read whose FENCE is the pinned CAS write it feeds (§13.1: a read is\nnever a fence): the auth path and the host-private tool-result snapshot reader on\n`KV_cotal_auth_<space>`, the lifecycle mapping-reader and\nthe provisioner-registration principal on the `cotal_records_<space>` heads, the endpoint's\ncanonicalizer on `EPF_<space>`/`EPW_<space>`, the endpoint's commit principal on its own\n`EPF_<space>` fact families AND on `KV_cotal_records_<space>` (its goal/checkpoint FENCING\nspec-and-currency reads: the terminal-commit's spec read and the epoch/deadline reads the\nread-service clause names), each record kind's spec/status writer principal on\n`KV_cotal_records_<space>` (its fresh lifecycle-mapping `processEpoch` currency read, the\nwriter-table stale-writer fence; per §13.1 a mapping yields a current epoch ONLY at\n`state: \"active\"`, and `retiring`/`retired` alike refuse the write), and the space's timer writer on\n`KV_cotal_records_<space>` (its fresh generation/deadline check before arming, a FENCING\nread) and on `EPT_<space>` (`$JS.API.STREAM.MSG.GET.EPT_<space>`, the armed-subject's own\nlast-by-subject sequence read: CAS-PINNING, the leader-served input to the arm's\n`Nats-Expected-Last-Subject-Sequence` publish, whose broker CAS - not the read - is the\nfence, the same §13.1 complementarity class as the FIRE handler's status CAS). The timer\nFIRE handler holds no records `STREAM.MSG.GET`: its settlement is a revision-pinned status\nCAS, so a stale read loses the CAS loudly (§13.1 complementarity), never mis-fires (the\nmatrix rows below). The body-selected form is not\nsubject-confinable by the broker, so each of these grants trades broker confinement for\nprofile trust; the trade is acceptable exactly because every holder IS a trusted\nsingle-purpose principal for whom read-your-writes is a correctness requirement, not a\nhazard (on the `allow_direct=false` buckets a leader-consistent get is precisely a\n`STREAM.MSG.GET`). Every OTHER subject-scoped read is NON-fencing and uses the\nlast-by-subject `DIRECT.GET.<stream>.<subject>` form, which the broker confines by subject\ntokens. (The pre-v0.4 messaging-surface CHKV/DLVKV reads in Appendix B are the v0.3 binding,\noutside this matrix; their confused-deputy exposure is the §9 in-scope-for-v0.4 remediation.)\n\n**Read service (fencing reads are leader-served).** A read is FENCING when its result, a\nvalue, a revision, OR an authoritative ABSENCE, gates a subsequent CAS or authorizes an\neffect; fencing is defined by USE, never by subject family. A CAS loser reading the winner,\na terminal-commit's spec read, and the work-pool re-enqueue predicate (accepted, with the\nauthoritative absence of BOTH a committed terminal and a live `EPW` entry, §13.6) are all\nfencing: a stale follower read that misses a committed terminal while the `EPW` entry is\nlegitimately absent re-arms settled work. A fencing read MUST be leader-served, meaning one\nof `STREAM.MSG.GET`, a get against a bucket with `allow_direct=false`, or delivery\nserialized by the authoritative primary stream/consumer (an authoritative `MSG.NEXT`, e.g.\nthe accepted-fact effects row and the auth path's snapshot enumeration below), and it MUST\nbe served against the AUTHORITATIVE stream or bucket for its key, never a mirror, a sourced\nstream, or a cross-space replica (\"leader-served\" means that authoritative primary; a\nmirror's own leader can lag its source). `allow_direct=true` and Direct Get exist for\nNON-fencing, subject-confined reads only; a client MUST NOT let a fencing read silently\nride Direct Get because the bucket allows it. This does not weaken §13.1's rule that a read\nis never a fence: the fence itself stays a CAS or create-only write; leader service is what\nkeeps the read's result from silently falsifying the CAS or effect it feeds.\n\n| Transition | Writer profile | Exact namespace (per space/endpoint) | Class |\n| --- | --- | --- | --- |\n| Native current-connection identity | one-shot `provisioner` | publish only `$SYS.REQ.USER.INFO`, subscribe its existing connection-scoped inbox. The configured NATS system account imports/maps this service to the requesting connection's own account and user; no arbitrary-account/user variant or system credential is granted. Clients compare the response's user/account and serving server with their pinned connection. Response permissions, expiry and metadata are not an issued ceiling, lifecycle or apply authority | native NATS read; own connection only |\n| Request publish | capability holder (agent, per capability) | per §13.2 form: `ep.{one,all}.<endpoint>.<command>[.<mode>[.<target tokens per mode>]].<cO>.<cA>.<cUid>.*` and `ep.inst.<endpoint>.<instanceId>.<command>[.<mode>[.<target tokens per mode>]].<cO>.<cA>.<cUid>.*`, mode/target tokens literal per the minted capability (`handle`: the full redemption-pinned triple) | direct, untrusted input, broker-confined |\n| Reply subscribe (caller) | capability holder | `ep.reply.*.*.*.<cO>.<cA>.<cUid>.*` (exact arity) | direct read; own rail only |\n| Serve subscribe | the endpoint's serve credential | per registered command: `\"ep.one.<endpoint>.<command>.> <endpoint>\"` (queue-qualified ONLY), `ep.all.<endpoint>.<command>.>` plain, `ep.inst.<endpoint>.<instanceId>.<command>.>` exact (never a cross-command `>` | direct) name/instance/command-pinned; epoch deliberately absent (§13.1 barrier is the fence) |\n| Reply publish | the endpoint's serve credential | `ep.reply.<endpoint>.<instanceId>.<epoch>.*.*.*.*` | direct; attribution-pinned; addressing by nonce |\n| Versioned-rail request, reply, serve (§13.15) | as the four rows above | the same rows with `ep.v1` for `ep` and one more pinned token: the caller's `<generation>` literal in its request-publish and reply-subscribe rows (`ep.v1.reply.*.*.*.<cO>.<cA>.<cUid>.<generation>.*`), a spanned token in the serve credential's reply-publish row (`ep.v1.reply.<endpoint>.<instanceId>.<epoch>.*.*.*.*.*`) and its three serve-subscribe shapes per command | direct; broker-confined on the generation exactly as on the caller triple |\n| Issuance (§13.15) | the `issuer` principal, minted by the party holding the space signer: one auth-service session per account, space and authority plane for its callout's user-auth issuance, renewed before expiry; one-shot per issuance window or lifecycle terminal otherwise | `$KV.cotal_issued_<space>.>` and `$KV.cotal_accepted_<space>.>` publish, `STREAM.INFO`/`STREAM.MSG.GET` on `KV_cotal_issued_<space>`, `STREAM.INFO` on `KV_cotal_accepted_<space>` (the bind-time shape check of both stores), its own ordered consumers on that store, and ONE leader-served `STREAM.MSG.GET` on `KV_cotal_auth_<space>` for source liveness; NO auth-store write, no rail row | mediated; create-only CAS on evidence, revision-CAS on the attempt row |\n| Run admission (§14.8) | the `run-admitter` principal (one-shot, 60 s, minted per run by the hosting endpoint or the local operator) | exactly `$KV.cotal_admission_<space>.admission.v1.<endpoint>.<runId>` and `….revoked.v1.<endpoint>.<runId>` publish plus `STREAM.MSG.GET` on that store; nothing else | mediated; create-only |\n| Resume transfer write (§8) | the `transfer-writer` principal (one-shot, 5 min, per `cotal spawn --resume --detach --on` call after the CLI hashes the transcript: minted by the operator holding the space signer, or on a user-auth space exchanged as the `transfer-writer` view, §10) | publish exactly `$O.cotal_xfer_<space>_<instanceId>.C.<hex>` and `$O.cotal_xfer_<space>_<instanceId>.M.<name>` (one object of one instance's bucket), plus `$JS.API.DIRECT.GET.OBJ_cotal_xfer_<space>_<instanceId>.` followed by each of those two subjects; no consumer, no stream API, no other object | direct; object-pinned |\n| Resume transfer read (§8) | the `transfer-reader` principal (one-shot, 5 min, minted per `transcript-receive` or sweep by the receiving manager from the space signer, or issued to a remote manager by the host's `transferReader` authority operation for that manager's own instance) | `STREAM.CREATE`, `STREAM.INFO`, `STREAM.MSG.GET`, `STREAM.PURGE` and `CONSUMER.CREATE` on its own `OBJ_cotal_xfer_<space>_<instanceId>` only, publish `$O.cotal_xfer_<space>_<instanceId>.M.>` (the stock delete marker), `$JS.API.INFO`, and that stream's `$JS.FC.OBJ_cotal_xfer_<space>_<instanceId>.>` flow control; every other credential, seats, the spawn capability, the supervisor, the provisioner and other instances' readers included, holds nothing that names `OBJ_cotal_xfer_` or `$O.cotal_xfer_` | mediated; instance-pinned |\n| Run admission read (§14.8) | the `run-mediator` and `run-operator` principals | `STREAM.MSG.GET` on `KV_cotal_admission_<space>` (leader-served; body-selected, stream-wide, the same residual as every records reader); the `run-driver` holds NO row on this store | mediated read; fail-closed |\n| Journal submission append | capability holder | `epj.<endpoint>.<command>[.<mode>[.<target tokens per mode>]].<cO>.<cA>.<cUid>` | direct, explicitly untrusted input |\n| Canonicalizer consume | the endpoint's canonicalizer principal (singleton, §13.4) | its durable on `EPJ_<space>`: `$JS.API.CONSUMER.CREATE.EPJ_<space>.<canonD>.cotal.<space>.epj.<endpoint>.>` (full-tail single filter), `$JS.API.CONSUMER.INFO.EPJ_<space>.<canonD>`, `$JS.API.CONSUMER.MSG.NEXT.EPJ_<space>.<canonD>`, plus `$JS.ACK.EPJ_<space>.<canonD>.>` (ack/term after durable decision only, and, for pool-admitted acceptances, after the enqueue, §13.4) | mediated |\n| Canonical decisions + quarantine + goal-bind | the endpoint's canonicalizer principal | publish `epf.<endpoint>.dec.>`, `epf.<endpoint>.quar.>`, and `epf.<endpoint>.goal.*.*.*.*.bind` (the per-goal first-wins bind, §13.4, create-only CAS per subject; the `.bind` leaf is disjoint from the commit principal's `goal….result`/status writes, so no writer overlap) | mediated |\n| Canonicalizer CAS-winner + terminal read | the endpoint's canonicalizer principal | leader-served `$JS.API.STREAM.MSG.GET.EPF_<space>` (body-selected `last_by_subj`; these reads are FENCING, read service above, so the follower-served `$JS.API.DIRECT.GET.EPF_<space>.…` form is NOT granted; the body-selected form is the broker-confinement-for-profile-trust trade above) over exactly its families: `epf.<endpoint>.dec.>` + `epf.<endpoint>.quar.>` (observes the winning fact on redelivery, §13.4) + `epf.<endpoint>.wrk.>` (READ-ONLY: the reconciliation predicate's terminal probe, §13.6; `wrk` writes stay with the commit principal, row below) + `epf.<endpoint>.goal.*.*.*.*.bind` (the goal-bind CAS winner: on a lost `.bind` create the canonicalizer reads the existing bind to decide same-fingerprint retry vs. `conflict`, §13.4) | mediated |\n| Caller durable reads (decisions, goal results, receipts, event catch-up, record reads/watches) | the **read mediator** owns the reader consumers; a registered endpoint MAY mediate its own callers' goal results through its separate trusted commit/read connection; the **caller** holds only its own reply rail | **Mediated (normative above).** The caller holds NO consumer/`DIRECT.GET` grant on EPF/EPE/EPC/records. It issues a read command and receives its own caller-scoped facts (`dec`/`goal…result`/`receipt` under its triple, §13.2), event catch-up, and record snapshots over its attribution-pinned reply rail `ep.reply.…<cO>.<cA>.<cUid>.<nonce>`; the read mediator re-authorizes each read against the caller's current grants before delivering; registered-endpoint goal reads use the connection-grant authorization and bearer-lifetime bounds specified above. Live progress is the caller's own core subscription to granted `epe` subtrees within `sub.allow` (bytes land only on its own sub). Reader consumers (`decD`/`goalD`/`eveD`/`recD`) are owned and bound by the mediator, never the caller | mediated read; confined to the caller's own rails |\n| Accepted-fact consume (effects) | every instance's serve credential, on the endpoint's ONE shared durable | **bind-only** on the provisioner-pre-created pull durable `effD = eff_<e>` (exact filter `cotal.<space>.epf.<endpoint>.dec.>`, `AckExplicit`): `$JS.API.CONSUMER.INFO.EPF_<space>.<effD>`, `$JS.API.CONSUMER.MSG.NEXT.EPF_<space>.<effD>`, `$JS.ACK.EPF_<space>.<effD>.>`; instances **pull-compete on the shared durable** so each accepted decision is delivered to exactly one live instance (at-least-once): a per-instance consumer over the class-wide decision subtree would be broadcast, and every instance would duplicate the external effect. Effects consume canonical facts, never raw submissions (§13.4); a rejected/quarantined decision is ack-skipped, and so is any acceptance whose `route` is a pool (§13.4, the pool's worker path executes it; effects MUST NOT). **Ack barrier:** an effecting instance MUST ack a `dec` message ONLY after its effect is durably recorded, for an action command the terminal `goal….result` fact; for a **non-action `route:\"effects\"` journal command** a generic per-request **effect fact** `epf.<endpoint>.eff.<cO>.<cA>.<cUid>.<id>` (create-only CAS, written by the effecting instance's commit path before ack; every `route:\"effects\"` acceptance has exactly this durable effect-complete marker), never before; an ack-before-effect would let a crash drop journal work the at-least-once contract promised. A crash before the ack redelivers the decision to another competing instance, which observes the existing terminal fact (idempotent) or effects it | direct read, endpoint-scoped, work-shared |\n| Result/receipt/terminal/resume facts | the endpoint's commit principal | enumerated fact families, no subtraction and **never `dec.>`/`quar.>`** (canonicalizer-only): publish `epf.<endpoint>.goal.*.*.*.*.result` (the goal terminal result; the `.bind` leaf under `goal.>` is the canonicalizer's, row above), `epf.<endpoint>.eff.>` (per-request effect-complete fact for non-action `route:\"effects\"` commands, create-only CAS, §13.9 ack barrier), `epf.<endpoint>.receipt.>` (caller-scoped subjects, §13.2), `epf.<endpoint>.wrk.>` (per-item terminal, create-only CAS), `epf.<endpoint>.cp.>` (one-use resume CAS); read-back is FENCING (read service above: it gates create-only CAS emission and idempotent re-commit decisions), leader-served `$JS.API.STREAM.MSG.GET.EPF_<space>` (body-selected `last_by_subj` over exactly these five families; the follower-served per-family `DIRECT.GET` form is NOT granted) | mediated |\n| Live event progress (caller) | capability holder (per read capability) | a caller-owned **core subscription** to the granted `epe` subtrees (fully-qualified `cotal.<space>.epe.…` in `sub.allow`, Appendix B), incl. per-goal `epe.<endpoint>.*.*.goal.<cO>.<cA>.<cUid>.>`; safe because a core sub delivers only to the caller's own subscription, never a caller-chosen subject; durable catch-up/replay is the mediated read above, not a self-bound consumer. A follower settles a goal from live progress only on a terminal whose subject names the instance and epoch that accepted it and the same goal as its body; any other terminal is at most a prompt to read the goal's recorded result | direct read; own subscription only |\n| Claim / action / checkpoint commits | the owning endpoint's commit path | its own record keys (`goal`/`cp`/`lease`/`goaleff`/`epname`/`epmig` grammars, §13.7, per the writer table; the three coordination kinds are enumerated HERE because a shared registry profile does not confer a grant; a kind absent from this enumeration is default-denied however it is registered, and that default-deny binds every principal in this table, including the composed profile in the row below) + the enumerated commit fact families of the Result row above, never `dec.>`/`quar.>`; its goal/checkpoint FENCING reads (the terminal-commit's spec read, epoch/deadline currency) are leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` (read service above; the records bucket's Direct Get is NON-fencing only) | mediated (validates fencing, lease clock, lifecycle, epoch) |\n| Goal-writer commits (journal-class actions) | the **goal-writer** principal: the commit principal of the row above, composed with three additions and nothing else | the composed profile is exactly (i) everything the commit row grants, inherited rather than restated, (ii) the per-goal first-wins bind leaf `epf.<endpoint>.goal.*.*.*.*.bind`, (iii) the reconcile index subtree `goalidx.<endpoint>.>` in the records bucket, key-pinned to this endpoint, and (iv) a currency read of its OWN issuance gate `epgate.<endpoint>.<instanceId>` before the first terminal-fact CAS, so a superseded writer declines to commit. That read carries the NAMED RESIDUAL this section requires of every bucket-blind read: the auth store is not Direct-Get enabled, so the read is a leader-served body-selected `STREAM.MSG.GET` that cannot be key-pinned to the single gate key, and the profile can therefore read any row of that bucket's gate and ledger METADATA, never bearer bytes. It is the same residual class the one-shot serve-executor profile carries, here on a standing connection, and it is a fast-fail belt rather than the fence; the durable fence is barrier revocation. `goalidx` is enumerated HERE and NOT on the commit row, because the index is written create-only BEFORE the goal binds, so the principal that writes it is the one that also binds; granting it on the bare commit row would widen every commit principal to a key only this profile needs. This profile holds NO records consumer create: the sweep that enumerates the index runs over the provisioner (row below), never over this standing connection, which is why an index write grant is not an index enumeration grant | mediated (as the commit row, plus the bind's create-only CAS per subject) |\n| Contract-artifact publication | the contract publisher principal | publish `epc.<digest-hex>` (`epc.*`), create-only per subject (`Nats-Expected-Last-Subject-Sequence: 0`; a digest subject is written at most once); read-back via the reader row below | mediated, immutable once published |\n| Contract-artifact read | trusted infra directly (`DIRECT.GET.EPC_<space>.cotal.<space>.epc.>`); untrusted callers via the read mediator | contract artifacts are content-addressed and public (verify-on-read is the tamper boundary, §13.7), so exposure is not the risk; the confused-deputy INJECTION is, so an untrusted caller's artifact fetch is mediated onto its own reply rail exactly like any other read; trusted infra fetches directly | mediated for callers / direct for infra |\n| Record write ingress (`epr`) | the owning instance | publish `epr.<endpoint>.<instanceId>.<epoch>.<kind>.<qualifier...>`; the instance's ONLY path to `svc`/`goal`/`cp` status writes; the epoch token is pinned by the serve credential, so the record writer reads the writing epoch from the broker-authenticated subject, never from payload | direct; epoch-pinned ingress to the mediated writer |\n| Record writer consume + `spec`/`status` writes | the kind's separately scoped spec/status writer principal (writer table); **one principal and one consumer PER KIND**, never a single writer draining every kind | consume: `$JS.API.CONSUMER.CREATE.EPR_<space>.<recwD-k>.cotal.<space>.epr.*.*.*.<kind>.>` (full-tail single filter on the `<kind>` token of §13.2's `epr` grammar; `recwD-k = recw_<space>-<kind>`) + `$JS.API.CONSUMER.INFO.EPR_<space>.<recwD-k>` + `$JS.API.CONSUMER.MSG.NEXT.EPR_<space>.<recwD-k>` + `$JS.ACK.EPR_<space>.<recwD-k>.>`; write: `$KV.cotal_records_<space>.<that kind's §13.7 key grammar>.{spec,status}`; its writer-table stale-writer fence (the FRESH lifecycle-mapping `processEpoch` currency read; current ONLY at `state: \"active\"`, §13.1, so a `retiring` or `retired` mapping refuses the write) is leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` (a FENCING read, read service above); the kind token in the ingress subject is what keeps the writer separation the writer table declares | mediated per kind below, no row left open |\n| Reader/pool/effects consumer provisioning (one-shot, at capability mint / endpoint setup) | the provisioner | exact full-tail extended creates for every pre-created durable this matrix names: `$JS.API.CONSUMER.CREATE.EPW_<space>.<poolD>.cotal.<space>.epw.<e>.<pool>.>`, `$JS.API.CONSUMER.CREATE.EPF_<space>.<effD>.cotal.<space>.epf.<e>.dec.>`, `$JS.API.CONSUMER.CREATE.EPF_<space>.<decD>.cotal.<space>.epf.<e>.dec.<cO>.<cA>.<cUid>.>`, `$JS.API.CONSUMER.CREATE.EPF_<space>.<goalD>.cotal.<space>.epf.<e>.goal.<cO>.<cA>.<cUid>.>` (per action capability), `$JS.API.CONSUMER.CREATE.EPE_<space>.<eveD-n>.<granted full-tail subtree>`, `$JS.API.CONSUMER.CREATE.KV_cotal_records_<space>.<recD-n>.$KV.cotal_records_<space>.<granted subtree>` (the reader-config seam is an ALLOWLIST: the `<granted subtree>` kind token MUST be a registered caller-readable record kind, so it REFUSES every authority-control kind (`oblig` above all, plus `govern`/`policy`/`uid`/`frontier`) and every unregistered kind, and for a dual-token kind whose atomic head is authority (`lifecycle`, head `lifecycle.<owner>.<actor>`) it admits only a filter strictly deeper than the head, never one that can match the head key itself; so no reader durable is ever pre-created over the `oblig.` subtree the sealed records scanner owns nor over an authority head, nats-server#8274), every create PULL, every filter a full literal tail; plus matching `CONSUMER.DELETE` for deprovisioning (lifecycle-keyed names, §13.1) | mediated, trusted provisioning only |\n| Events | the owning instance | `epe.<endpoint>.<instanceId>.<epoch>.>` | direct; subject-confined, epoch-pinned |\n| Timer schedule request | the owning instance | publish `ept.<endpoint>.<instanceId>.<epoch>.*.schedule` (never `.armed`/`.fire`); a request carrying any scheduling header is rejected by the timer writer (§13.2) | direct; epoch-pinned; captured by the schedules-DISABLED request stream |\n| Timer request consume + arm | the space's timer writer principal (singleton infra, like the delivery daemon) | consume: `$JS.API.CONSUMER.CREATE.EPT_REQ_<space>.<timerD>.cotal.<space>.ept.*.*.*.*.schedule` (full-tail single filter) + `$JS.API.CONSUMER.INFO.EPT_REQ_<space>.<timerD>` + `$JS.API.CONSUMER.MSG.NEXT.EPT_REQ_<space>.<timerD>` + `$JS.ACK.EPT_REQ_<space>.<timerD>.>`; arm: publish `ept.*.*.*.*.armed`, deriving `Nats-Schedule-Target` = the sibling `.fire` from the authenticated request subject tokens ONLY, stripping/rejecting every client scheduling header, and **fresh-checking the authoritative timer generation/deadline before arming** (a FENCING read: leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` on the checkpoint record, read service above); the arm also reads the armed-subject's own last sequence via `$JS.API.STREAM.MSG.GET.EPT_<space>` and publishes with `Nats-Expected-Last-Subject-Sequence` pinned to it - that read is CAS-PINNING, not fencing: the broker CAS is the fence and a delayed writer's stale read loses it loudly (§13.1 complementarity, the FIRE handler's class); a redelivered or delayed stale-generation request is discarded, never armed, so it cannot overwrite the current schedule and silently lose the live deadline (§13.2, §13.6, §13.12) | mediated |\n| Timer fire consume | the owning instance | its own `ept.<endpoint>.<instanceId>.<epoch>.*.fire` (fired messages validated against its authoritative schedule state AND the broker-authored scheduler-origin header = its exact sibling `.armed`, §13.12); no client credential holds `.armed` or `.fire` publish | direct read |\n| Session `.in` publish | the session's caller (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.in` exact | direct |\n| Session `.in` subscribe | the serving instance (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.in` exact | direct read |\n| Session `.out` publish | the serving instance (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.out` exact | direct |\n| Session `.out` subscribe | the session's caller (per-session credential) | `eps.<endpoint>.<sessionId>.<epoch>.out` exact | direct read |\n| Chat-session admission index, owner quota and sweep cursor (§10) | the trusted auth path (§9/§10), admission and its sweep only | `$KV.cotal_auth_<space>.chatholder.<owner>.<holderHash>` (create-only, then revision-pinned CAS, never deleted), `….chatowner.<owner>` (create-only when absent, then revision-pinned CAS), `….chatsweep.cursor` (revision-pinned CAS); exact arity on each, never a `chat…>` wildcard. The chat principal's own leaf holds none of them | mediated |\n| Session ledger (one-use redemption, credential ids, revocation state, authenticated close) | the trusted auth path (§9/§10) | `$KV.cotal_auth_<space>.session.<sessionId>`, create-only CAS per `sessionId`, monotonic state (§13.6) | mediated |\n| Credential ledger (issuance gate, descendant enumeration, lineage index, revocation) | the trusted auth path (§9/§10) | writes: `$KV.cotal_auth_<space>.cred.<lifecycleUid>.<credentialId>` + `….gate.<lifecycleUid>` (the issuance gate, revision-pinned CAS is the mint fence, §13.1) + `….epgate.<endpoint>.<instanceId>` + `….epcred.<endpoint>.<instanceId>.<credentialId>` + the exact `….eprepair.<endpoint>.<instanceId>` interrupted-repair cursor (the disjoint endpoint families, §13.1: same protocol, explicit prefixes, never arity; the repair executor is pinned to one exact cursor key) + `….stage.>` (implementation staging/tombstone fences; NEVER under `cred.`/`epcred.`, §13.1) + `….natkey.<userNkey>` (create-only native-key issuance evidence, §13.1) + `….srcgate.<issuerKeyId>.<id>` (per-handle source gate, §13.1) + `….bysrc.<issuerKeyId>.<id>.<lifecycleUid>.<credentialId>` (the per-ancestor lineage index) + `….session.<sessionId>` (create-CAS `issuing`, finalize-CAS `active`, §13.6) + `….plane` (the ONE plane-ownership claim row, §13.13: create/revision-CAS by the barrier profile only, exact arity, never `plane.>`); reads: **leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_auth_<space>`** (with `allow_direct=false` a KV get is exactly this body-selected `last_by_subj` call against the stream LEADER; read-your-writes, not a follower-served `DIRECT.GET`; the body-selection trades broker confinement for trusted profile custody; the separate tool-result snapshot reader below holds the same leader-read verb without ledger write authority) for gate/session/row state, which is why the mint and session fences are revision-pinned CAS *writes* rather than reads (a read is never a fence, §13.1); and **fence-free prefix enumeration through the SEALED auth-ledger scanner, never a runtime consumer create**: no standing or runtime-reachable auth credential (the takeover/retirement/handle-revocation barrier, the session sweep, any replayable executor) holds `$JS.API.CONSUMER.CREATE` on `cotal_auth_<space>`, because a consumer-create request BODY is not subject-ACL confinable: an extended `CONSUMER.CREATE.<stream>.<name>.<filter>` grant still admits a body with `durable_name` (equal to the subject name token) and a push `deliver_subject`, a DURABLE exporter of every current and future row that SURVIVES the credential's connection close and revocation; a subject ACL cannot constrain that body, so the only safe runtime grant is none. The dynamic-enumeration `CONSUMER.CREATE` lives in exactly ONE profile, a SEALED scanner the trusted auth process opens for itself and NEVER hands out: its credential, connection, and identity seed reach no caller, child, log, or persistence (a process-memory compromise reaches it, the SAME residual class as the account signing seed the process already holds; never broker confinement, never a network-reachable JWT). The scanner is pinned to ONE literal consumer name under a FORCED config: pull (no `deliver_subject`), ephemeral (no `durable_name`), `AckPolicy.None`, `DeliverPolicy.LastPerSubject`, memory storage, bounded inactivity; re-read and bind-verified before use and unconditionally deleted after, with every scan over the stream serialized on that one name, and the injected scanner bonded to its exact space so a hand-assembled or foreign-space scanner never enumerates. The scan is FENCE-FREE by construction: under the history=1 store a same-subject `active→revoked` overwrite EVICTS the pre-scan revision, so a sequence/`STREAM.INFO` cutoff would DROP that subject and leave its holder un-revoked; a LastPerSubject read carries no upper cutoff and, draining to a freshly re-observed zero pending (never a stale local count), returns each subject's CURRENT last, so a concurrent overwrite is SEEN, never dropped. It enumerates exactly `cred.<lifecycleUid>.>`, `bysrc.<issuerKeyId>.<id>.>`, `stage.>` (operation-intent discovery), or `session.>`. The barrier's family enumeration and the expiry sweep are executable reads, not prose. The tool-result profiles below add only their listed auth-store verbs and families; no untrusted profile gains an auth-store grant | mediated |\n| Tool-result consent record (§13.19) | the trusted auth mint writer, never its derived host writers | `$KV.cotal_auth_<space>.consent.*` publish; retained auth leader-read authority checks the recorded consent. The revocation writer has no consent write grant | mediated; consent schema, authenticated holder/target and expiry checks |\n| Tool-result fresh-store creation (§13.19) | a short-lived host-private create-only provisioner | `$JS.API.INFO` and `$JS.API.STREAM.CREATE.KV_cotal_auth_<space>` publish; own `_INBOX_<connId>.>` subscribe; no update/delete/purge, data write, consumer or stream read grant | mediated; only fresh controlled creation after durable private intent, closes after creation |\n| Tool-result revocation append (§13.19) | host-private revocation writer, never handed out | `$KV.cotal_auth_<space>.revocation.*.*` publish and own `_INBOX_<connId>.>` subscribe only. Canonical key is `revocation.<targetDigest>.<consentId>`; raw grants do not constrain operation headers, TTL, target or CAS | mediated; exact recorded-consent binding and expected-last-subject-sequence zero, no operation/TTL inputs, durable receipt, unknown persistence is not a safe retry |\n| Tool-result fixed-cut snapshot (§13.19) | host-private snapshot reader, never handed out | `$JS.API.INFO`, `$JS.API.STREAM.INFO.KV_cotal_auth_<space>` and `$JS.API.STREAM.MSG.GET.KV_cotal_auth_<space>` publish; own `_INBOX_<connId>.>` subscribe only; no data write, Direct Get, consumer or administration grant | mediated leader-served fencing read; finite committed-W cut, creation-owned uninterrupted custody and independent receipt cross-check, not the credential-ledger moving-tail enumeration. Raw body-selected MSG.GET retains stream-wide read and caller-selected foreign-subject reply-injection authority despite own-inbox subscription |\n| Remote manager-service registration and renewal (§13.1/§13.6) | the trusted auth path is the sole gate/ledger writer and host JWT issuer; a user manager presents only the server-authored closed view | exactly one staged `{ owner, managerActor, lifecycleUid, instanceId }` family: `svc.manager.<instanceId>`, the stage-pinned contract artifacts, `epgate.manager.<instanceId>`, and `epcred.manager.<instanceId>.<credentialId>`. `prepare` freezes/stages; `activate` creates the matching service record and releases host-signed material only after ledger + gate finalization; `renew` is bounded, rechecks the live ledger scope, and can replace material only inside that family. Descendant provisioning is a mediated same-owner request revalidated by the host. No row grants signer material, generic stream/KV/consumer authority, another instance, or a public/managed-agent exchange path | mediated, closed family; revocation/renewal failure denies new authority and unsafe restarts while retaining live agents only within their independently valid lifetimes |\n| Environment bootstrap request and recovery (§13.1/§13.6) | the ephemeral `environment-bootstrap` caller, issued only by the external hosting authority | the literal instance describe/bootstrap/bootstrap-status rows and native own-caller reply/inbox rows above; read-only describe binds the current authority epoch, `bootstrap` durably pins the one admitted caller and five public keys before preparation, `bootstrap-status` reads only that reservation; no other endpoint, command, caller, store or manager profile | direct request, mediated preparation/recovery; expiry and terminal state never permit reuse |\n| Environment manager supervision (§13.1/§13.6) | the admitted supervisor identity under fixed `environment-manager-supervisor` | exact own instance lease create/CAS, manager-bucket STREAM.INFO/leader MSG.GET and API.INFO for binding/read, own presence/roster watch and flow control, existing manager liveness serve/reply, own inbox; no auth-store or registration/repair/contract/governance writes, reads or scans | direct liveness/lease duties, host-mediated registration; no reuse of `remote-manager` grants |\n| Environment manager goal writes (§13.1/§13.6) | the admitted goal-writer identity under fixed `environment-manager-goal-writer` | native goal/coordination grant rows for the manager with the auth-store own-gate MSG.GET belt removed; no auth-store read/scan/write or consumer access | direct goal duties under native barrier revoke and verified eviction; no new authority-family writes |\n| Environment manager graceful deregistration (§13.6) | the admitted executor asks; trusted host alone executes | closed deregistration request through the authority command, current proof/epoch and host-committed registration revision, native own-instance gate-generation read and revision-pinned delete; no guest store credential or foreign selector | host-mediated, idempotent observation; cannot delete a successor or substitute signer-only repair |\n| Environment manager authority request (§13.1/§13.6) | the admitted manager's recorded executor identity under fixed `environment-manager-executor` | literal instance describe/authority command rows and native own-caller reply/inbox rows above; the authenticated caller, proof, epoch, admission revision and finite expiry bind every closed inner operation to this environment and manager family, with at most the one admitted child lifecycle | direct request, host-mediated effects; no guest signing, ledger write or foreign family reach |\n| Environment admission, preparation and terminal cleanup (§13.1/§13.6) | the external hosting authority alone | auth-owned `epgate.manager.<instanceId>` carries its immutable `authorityFamily` marker at every state and is the issuance fence before bootstrap mint; operation-retained staging stays under `stage.<opId>.…`; the bootstrap `cred.<managerUid>.<credentialId>` row, root source chain and activation revocation/eviction; the existing manager `svc`/`epcred` and lifecycle retirement families bind the recorded owner, instance and manager/child UIDs; termination aborts an unactivated registration then retires, retaining the gate's family marker, before recording private admission ended; private admission/reservation and credential-custody records retain CAS outcomes and terminal state, with no guest store credential or caller-selected target | mediated; cleanup survives host restart and guest loss; retention, observed provider termination and authority retirement remain separate facts |\n| Auth-ledger enumeration (the SEALED scanner profile, the credential-ledger row's enumeration seam) | the trusted auth process's DEDICATED self-minted scanner principal; opened for the process itself, NEVER handed out (full rationale in the credential-ledger row above) | exactly `$JS.API.INFO` + `$JS.API.STREAM.INFO.KV_cotal_auth_<space>` + `$JS.API.CONSUMER.CREATE.KV_cotal_auth_<space>.cotal-ledger-scan.$KV.cotal_auth_<space>.>` + `$JS.API.CONSUMER.INFO.KV_cotal_auth_<space>.cotal-ledger-scan` + `$JS.API.CONSUMER.MSG.NEXT.KV_cotal_auth_<space>.cotal-ledger-scan` + `$JS.API.CONSUMER.DELETE.KV_cotal_auth_<space>.cotal-ledger-scan` + its connection-scoped `_INBOX_<connId>.>` subscribe, and NOTHING else (no records-stream grant, no KV write, no `DIRECT.GET`, no `$JS.ACK`: an `AckPolicy.None` scan acks nothing); `cotal-ledger-scan` is the ONE pinned literal consumer name every auth-stream scan serializes on, and this profile plus the records scanner below are the ONLY DYNAMIC-ENUMERATION `CONSUMER.CREATE` holders on the two authority streams (the provisioning row's pre-created full-tail reader durables, CREATE+DELETE by the provisioner and INFO/MSG.NEXT/ACK bind by the read mediator, are the one other records-stream consumer authority, and the reader-config seam REFUSES an authority-control record kind so no reader durable can target the `oblig.` subtree the records scanner owns), re-audited mechanically per this section's closing clause | mediated |\n| Obligation enumeration (the SEALED records scanner profile, the acceptance-obligation row's enumeration seam, ONE instance per space) | the trusted process's DEDICATED self-minted records-scanner principal; opened for the process itself, NEVER handed out (full rationale in the acceptance-obligation row below; every scan over the literal name serializes process-wide per space, so a second instance can never interleave with a live scan and hand back a partial result, and the scanner handle is immutable once branded) | exactly `$JS.API.INFO` + `$JS.API.STREAM.INFO.KV_cotal_records_<space>` + `$JS.API.CONSUMER.CREATE.KV_cotal_records_<space>.cotal-records-scan.$KV.cotal_records_<space>.oblig.>` (the CREATE filter is confined to the `oblig.` subtree) + `$JS.API.CONSUMER.INFO.KV_cotal_records_<space>.cotal-records-scan` + `$JS.API.CONSUMER.MSG.NEXT.KV_cotal_records_<space>.cotal-records-scan` + `$JS.API.CONSUMER.DELETE.KV_cotal_records_<space>.cotal-records-scan` + its connection-scoped `_INBOX_<connId>.>` subscribe, and NOTHING else; `cotal-records-scan` is the ONE pinned literal consumer name, disjoint from the auth scanner's (one scanner instance, lock, and literal name PER STREAM) | mediated |\n| Work-pool enqueue | the endpoint's canonicalizer (from accepted decisions only) | `epw.<endpoint>.>` publish, create-per-subject (`Nats-Expected-Last-Subject-Sequence: 0`; the acceptance identity is the subject, §13.2) | mediated |\n| Work-pool reconciliation probe | the endpoint's canonicalizer | leader-served `$JS.API.STREAM.MSG.GET.EPW_<space>` (body-selected `last_by_subj` on the exact item subject; the probe is FENCING, read service above: a follower-served `DIRECT.GET` that misses the live entry re-arms settled work, so that form is NOT granted) + the CAS-winner read row above (`dec` + `wrk` last-by-subject), together they decide the §13.6 predicate: accepted, **`now < workExpiry`** (an expired item is never re-enqueued; it is terminally settled `expired` with its `wrk` fact and acked without effect), no terminal, no live entry ⇒ re-enqueue for the item's REMAINING TTL; a worker likewise MUST check `now < workExpiry` before lease/effect and refuse expired work | mediated |\n| Virtual-endpoint activation watch | the endpoint's activator principal (holder of its activation capability, §13.6) | exactly `$JS.API.CONSUMER.INFO.EPW_<space>.<poolD>` (the per-pool occupancy snapshot; request/reply, so watching is bounded polling) PLUS its own connection-scoped reply inbox `_INBOX_<connId>.>` (never the account-wide default); the instance START is a mediated, target-bound seam resolved by the supervisor's own authority, never a broker grant; NOTHING else: no `CONSUMER.MSG.NEXT`/`$JS.ACK` (watching is never draining), no `STREAM.MSG.GET.EPW_<space>` (no reconciliation authority), no consumer create/update/delete, no `epw.>` publish | mediated |\n| Work-pool consume + ack | the pool's owning endpoint ONLY (workers hold NO pool grant, §13.5) | **bind-only** on the provisioner-pre-created exact-filter `poolD` (grammar above): `$JS.API.CONSUMER.INFO.EPW_<space>.<poolD>`, `$JS.API.CONSUMER.MSG.NEXT.EPW_<space>.<poolD>`, `$JS.ACK.EPW_<space>.<poolD>.>` (ack only after committed terminal state); NO consumer create, NO stream-wide read | mediated |\n| Lease issue / fencing advance | the pool's owning endpoint (`lease` command) | its `lease` record keys (§13.7 grammar), via the record-writer seam | mediated |\n| Lifecycle mapping / teardown | minting manager's commit path; lifecycle-pinned deprovisioner | the **unsplit** alias CAS head `$KV.cotal_records_<space>.lifecycle.<owner>.<actor>` (one atomic key, NOT `.spec`/`.status`-split; the authoritative current mapping and the only `mappingRevision` source, activation/retirement serialize here by CAS, §13.7; NEVER-DELETED, three states `active \\| retiring \\| retired`, transitions only inside the §13.1 operations) + the create-only space-global UID reservation `$KV.cotal_records_<space>.uid.<lifecycleUid>` (§13.1: won BEFORE any gate or head write; NEVER-DELETED); leader-consistent current-mapping read `$JS.API.DIRECT.GET` is NOT used for authority reads of this key (the records bucket may follower-serve; a fresh mapping read is a leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` last-by-subject get on the head key; leader-served for read-your-writes, granted to the trusted mapping-reader/mediator profile, not a follower-served `DIRECT.GET`; that reader profile ALSO holds exactly `$JS.API.STREAM.INFO.KV_cotal_records_<space>` so it can shape-prove at bind time that the stream it leader-reads is the primary, un-mirrored, non-evicting records store (§13.12); a reader that cannot prove its store's shape MUST refuse to serve authority reads); optional append-only per-UID audit `$KV.cotal_records_<space>.lifecycle.<owner>.<actor>.<lifecycleUid>`; teardown: exact lifecycle-keyed names only | mediated / broker-pinned delete |\n| Acceptance obligation (reservation/drain, §13.8) | the admission mediator (per endpoint; the canonicalizer holds NO raw `oblig.` grant) | create-only winner + monotonic revision-pinned CAS on `$KV.cotal_records_<space>.oblig.<targetUid>.<endpoint>.<cO>.<cA>.<cUid>.<id>` (§13.7; the key derives from the broker-authenticated request subject plus the create-fence currency reads of §13.8, never from a body field; proof issuance only after the post-create recheck); its winner/settle reads are FENCING, leader-served `$JS.API.STREAM.MSG.GET` on the obligation key and on the EPF decision subject; its currency reads are FENCING, leader-served `$JS.API.STREAM.MSG.GET` on the target's `lifecycle` head AND on the endpoint's `govern` head (§13.6: the govern head read is what surfaces both a staged `pendingPolicyKey` (which pauses policy-admitted proof issuance) and the enforced policy selector the mediator follows to the immutable `policy.<endpoint>.<digest-hex>` version; the mediator reads govern and policy for its OWN endpoint only, the confined-reader identity bind) PLUS the immutable `policy.<endpoint>.>` version it names; PLUS create-only publish on the endpoint's EPF decision subjects for the TERMINAL REJECTION settle only (§13.8: its own recheck refusals and the retirement/policy drains, which settle through it); the broker cannot distinguish a rejection payload from an acceptance, and rejection-only is NOT subject-expressible (both decisions MUST share the create-only decision subject for first-wins settlement), so this grant's residual is explicit per D32: a compromised mediator can forge a decision for ITS endpoint INCLUDING AN ACCEPTANCE, an escalation to injecting executed work, never merely reject/stall (the same class of trust already placed in that endpoint's canonicalizer), and never beyond its endpoint (the decision-publish row is endpoint-literal); obligation enumeration (the §13.1 retirement barrier's `oblig.<targetUid>.>` discovery + quiescence recheck, and the mediator's own `oblig.*.<endpoint>.>` policy-movement drain, §13.6) runs through a SEALED records scanner, the same seal as the auth-ledger scanner above: this profile holds NO `$JS.API.CONSUMER.CREATE` (nor INFO/MSG.NEXT/DELETE) on `cotal_records_<space>`, because a consumer-create request BODY is not subject-ACL confinable: an extended `CONSUMER.CREATE.<records>.<name>.<oblig filter>` grant still admits a body with `durable_name` and a push `deliver_subject`, a DURABLE exporter of the whole `oblig.` subtree that SURVIVES the credential's connection close and revocation (nats-server#8274; reproduced live against the prior grant). The fence-free `LastPerSubject` enumeration `CONSUMER.CREATE` lives in exactly ONE profile: a sealed records scanner the trusted process opens for itself and NEVER hands out (its credential, connection, and seed reach no caller; the same process-memory residual class as the auth-ledger scanner), pinned to ONE literal consumer name under a FORCED pull/ephemeral/`AckPolicy.None`/`DeliverPolicy.LastPerSubject`/memory config, bind-verified before use and unconditionally deleted after, its CREATE filter confined to the `oblig.` subtree, and the injected scanner bonded to its exact space so a hand-assembled or foreign-space scanner never enumerates; its fencing `STREAM.MSG.GET` rows are stream-level grants whose read exposure is space-wide, explicit per D32 (the terminal-cleanup row's same read residual); its reply inbox is connection-scoped (`_INBOX_<connId>.>`, never the account-wide default); the rows are NEVER-DELETED, a WRITER discipline the broker cannot fully enforce: the raw KV publish grant is operation/header-blind, so a compromised mediator can overwrite its own endpoint's row to a valid `terminal` value (hiding cleanup debt) or emit DEL/PURGE markers, where every reader refuses a deletion marker loud as corruption (§13.12 retention floor) and the records stream denies stream-API message-delete/purge, leaving the valid-row overwrite as a second explicit D32 residual, exactly parallel to the decision-forge residual and confined the same way (its own endpoint's rows only) | mediated |\n| Terminal pool cleanup (§13.1 barrier) | the retirement cleaner profile: minted per (retirement `op` × endpoint), its grant listing the EXACT pools of this operation's EFFECTIVE INVENTORY, DISCOVERY-ONLY: the target's accepted `oblig.<lifecycleUid>.>` pool routes (the barrier takes no caller-supplied hint, so every listed pool is one the target holds accepted work on), never a pool wildcard, never space-wide EPW rights, DISTINCT from every owner/agent/endpoint profile (never the revoked owner's credential), bounded-lived and, once the pool is proven quiescent (every prior owner ACK drained through `AckWait`, and a fresh consumer read shows zero `num_pending`/`ack_pending`; a fire-and-forget ACK confirmed with `AckSync`, never assumed), REVOKED and cluster-verified-EVICTED (its own principal) BEFORE any frontier records (§13.1 order), so no in-flight cleaner can ACK a redelivery after the alias is reused | runs only AFTER the target's obligation drain reached quiescence (§13.1 order) and BEFORE the frontiers; bind-only on each named pool's provisioner-pre-created durable: `$JS.API.CONSUMER.INFO.EPW_<space>.<poolD>`, `$JS.API.CONSUMER.MSG.NEXT.EPW_<space>.<poolD>`, `$JS.ACK.EPW_<space>.<poolD>.>` (re-proving at bind, per the work-pool row, that the durable's filter is exactly the named pool's subtree, pull mode, unlimited delivery ceiling), plus its own connection-scoped reply inbox `_INBOX_<connId>.>` (never the account-wide default) and leader-served terminal-observe reads `$JS.API.STREAM.MSG.GET.EPF_<space>` on `wrk.>`/`dec.>` item subjects, a STREAM-level grant whose read exposure is space-wide, explicit per D32; the cleaner holds NO lease or records authority, NO `wrk` (or any EPF/EPW) publish, NO consumer create/update/delete, NO raw stream DELETE: for each delivered message it hands the item's coordinates and requested disposition to the retirement settlement executor (next row; cleaner-supplied coordinates never authorize, the executor re-derives them from the durable acceptance), then re-reads and codec-validates the executor's lease-derived terminal, and ACKs ONLY a message whose item is durably terminal (a live, unexpired, foreign-target item is NEVER settled or ACKed, and the barrier refuses to close frontiers while one remains unsettled); this profile's explicit D32 residuals are terminal-free ACK suppression across its WHOLE EFFECTIVE INVENTORY (every discovered pool: a raw `$JS.ACK` cannot be broker-conditioned on a prior terminal, so compromise can silently drop effective-inventory-pool deliveries without settlement) and the space-wide `STREAM.MSG.GET` read exposure; it can forge NO terminal and mutate NO lease (it holds no write grant at all) | mediated |\n| Retirement settlement (§13.1 barrier executor) | the retirement barrier's op-bounded executor: a DISTINCT per-operation principal (`local.epexe_<opId-hash>`, CONNZ principal-tagged) minted per (op × endpoint) over this operation's EFFECTIVE INVENTORY bound to the durable intent (`opId`, target lifecycle; the pools are the target's accepted `oblig.<uid>.>` routes, DISCOVERY-ONLY (no caller-supplied hint)), its settlement code running on ITS OWN connection, live only for that operation and revoked + cluster-verified-evicted by the barrier at the same fence as the cleaner, BEFORE any frontier records; never the cleaner profile, never the barrier's standing connection, never a standing grant | the settlement seam is EFFECTIVE-INVENTORY-CLOSED: for every item the cleaner hands it, the executor re-derives the authority coordinates from the item's durable acceptance decision (a FENCING leader-served read; cleaner-supplied coordinates never authorize) and refuses a ref whose endpoint or pool is outside its EFFECTIVE-INVENTORY spec (the discovered pools), a decision that is not an accepted pool admission, an `expired` request before the item's OWN `workExpiry`, and a `retired` request for an accepted target that is not the intent's lifecycle (the confused-deputy closure: a cleaner chooses refs but can never borrow this authority beyond that effective inventory or the retirement lifecycle); it settles by CASing the item's `lease.<endpoint>.<pool>.<acceptance>.spec` record to a settled state, where the ONLY settlements it may INITIATE are `expired` (bound to the item's own horizon) and `retired` (re-bound to ITS operation's retiring target through the acceptance) and an ALREADY-settled lease DOMINATES (a crashed owner's `committed` lease is derived and its terminal published verbatim, never overwritten, never contradicted), then publishes/observes the exact lease-derived `wrk` terminal create-only (first terminal wins, §13.8 cancellation ordering) for the cleaner to validate; its authority is lease-record CAS plus `epf.<endpoint>.wrk.<pool>.>` publish on its effective-inventory pools plus the leader-served fencing reads its own code path performs (`STREAM.MSG.GET` on the facts stream and on the records store, plus the records store's bind-probe `STREAM.INFO` and `$JS.API.INFO`; NO work-stream read: the settlement path always settles or expires through the lease key before any EPW live-entry probe, so that read is unreachable and ungranted) and its connection-scoped reply inbox, and NOTHING else (no consumer authority anywhere, no work-enqueue publish, no auth-store access), and it carries the write residual the bounded cleaner does NOT: KV subject permissions cannot distinguish CAS from overwrite or DEL/PURGE markers, and the `wrk` publish is payload-blind, so a compromised executor can forge a lease settlement or work terminal within its WHOLE EFFECTIVE INVENTORY (every discovered pool; the per-item checks above bind honest execution, not a compromised bearer), explicit per D32, op-bounded and effective-inventory-confined, never standing, never beyond that inventory | mediated |\n| Drain commit applier (§13.8 accepted-self recovery) | a per-op, per-repair principal (`local.epapl_<opId-hash>`, CONNZ principal-tagged) the retirement drain mints ONLY after the commit key passes the CLOSED self-commit class: the key's kind must resolve in the canonical frozen kind registry to a NON-authority definition whose targeted `spec`/`status` half is registered to the §13.8 commit-path writer, at exact arity (which structurally excludes every authority HEAD, including the 3-token lifecycle head) with every qualifier token validated; a key outside the class refuses BEFORE any credential exists (the confused-deputy closure: a forged accepted-self row cannot turn `oblig.`/`govern.`/`policy.`/`uid.`/`frontier.`/a lifecycle head/an unregistered kind into a granted coordinate) | exactly ONE `$KV.cotal_records_<space>.<commitKey>` publish row plus its connection-scoped reply inbox; NO reads, NO wildcards. It executes the mediator-validated command verbatim: the resolved, canonically digest-verified intent bytes at the pinned base revision, written by guarded CAS; a CAS loss reports the another-writer conflict and the drain's re-enumeration re-classifies (landed / superseded), never a blind retry. NAMED residual: KV subject permissions cannot distinguish CAS from overwrite or DEL/PURGE, so within its one granted key a compromised applier can overwrite or delete for the credential's short life — the confinement is the exact key, the closed class, and the op-bounded lifetime, never write semantics. RETIREMENT-FENCE residual (§13.1/§13.13): no credential-ledger row backs this bearer, so the retirement fence guarantees KILL-LIVE (cluster-verified eviction of any live connection before the frontier), never deny-new — the connection is minted non-reconnecting so a KICK is durable in one round, and a fresh connect with a still-unexpired held bearer+seed after that point-in-time scan is the accepted residual, dominated by data-account signing-seed compromise (signing-key rotation is the only true deny-new) | mediated |\n| Drain route reconciler (§13.8 accepted-pool repair) | a per-op, per-repair principal (`local.eprec_<opId-hash>`, CONNZ principal-tagged) the retirement drain mints only to execute a MEDIATOR-DERIVED closed repair command: the mediator reads the item's durable acceptance decision itself (a leader-served fencing read), binds it to the obligation row (fingerprint/sourceSeq/route/horizon), and derives the exact EPW item subject plus the canonical acceptance item bytes (§13.6); the executor re-validates the exact six-token item shape for its own space and holds NO derivation authority (row-supplied coordinates or bytes never reach a grant) | exactly ONE `cotal.<space>.epw.<endpoint>.<pool>.<cOwner>.<cActor>.<cUid>.<id>` create-only publish row plus its connection-scoped reply inbox; a lost create is benign (a concurrent enqueue won; the drain re-reads establishment either way, so a no-op executor still fails closed); the payload-blind enqueue residual is confined to the one item subject for the credential's short life. RETIREMENT-FENCE residual (§13.1/§13.13): no credential-ledger row backs this bearer, so the retirement fence guarantees KILL-LIVE (cluster-verified eviction of any live connection before the frontier), never deny-new — the connection is minted non-reconnecting so a KICK is durable in one round, and a fresh connect with a still-unexpired held bearer+seed after that point-in-time scan is the accepted residual, dominated by data-account signing-seed compromise (signing-key rotation is the only true deny-new) | mediated |\n| Drain effects canceller (§13.8 option-(i) retirement cancel) | a per-op, per-repair principal (`local.epcan_<opId-hash>`, CONNZ principal-tagged) the retirement drain mints only to execute a MEDIATOR-DERIVED effects-cancel repair: the mediator reads and row-binds the acceptance decision itself and derives the exact completion subject (the `eff` marker or the goal `result` coordinate; the executor re-validates that exact shape for its own space); the cancelled terminal is built by the CORE validated builders, which refuse a foreign or absent target — a retirement cancels only ITS OWN target's accepted work — and never fabricate success (the effects union's `cancelled` member, or the goal union's first-class `cancelled` state with the digest-bound retirement attribution) | exactly ONE completion-subject create-publish row plus its connection-scoped reply inbox; CREATE-ONLY, so first-terminal-wins is structural (a racing real completion that landed first wins and the cancel loses its create harmlessly; the drain re-reads the winner either way, so a no-op executor still fails closed); the payload-blind single-subject create residual is confined to the one marker for the credential's short life. RETIREMENT-FENCE residual (§13.1/§13.13): no credential-ledger row backs this bearer, so the retirement fence guarantees KILL-LIVE (cluster-verified eviction of any live connection before the frontier), never deny-new — the connection is minted non-reconnecting so a KICK is durable in one round, and a fresh connect with a still-unexpired held bearer+seed after that point-in-time scan is the accepted residual, dominated by data-account signing-seed compromise (signing-key rotation is the only true deny-new) | mediated |\n| Auth endpoint rail (the `auth` listener, §13.2) | the auth service's dedicated LISTENER credential: serve + derived replies on the `ep.one.auth` class rail, standing with the plane. The surface is GENERIC — \"retire a lifecycle (owner, actor, lifecycleUid)\" — never caller-specific; the TARGET rides the subject as the `handle` triple (`ep.one.auth.retire-lifecycle.handle.<tO>.<tA>.<tUid>.<cO>.<cA>.<cUid>.<nonce>`) and caller attribution is the SUBJECT-derived, broker-ACL-enforced caller triple. The reply target is DERIVED from the parsed request (responder instance + caller triple + nonce), so no caller- or payload-supplied reply target can arrive at all — the bound-reply rule became structural rather than a check. Serve-time authz is the RAIL-TIME serve-issuance-gate check, fresh per request: ONE leader-served `STREAM.MSG.GET` of `epgate.<serveEndpoint>.<serveInstanceId>` — coordinates the caller NAMES but which do NOT authorize — requiring (a) the row is present and not `retired`, (b) `row.principal == principalKey(callerOwner, callerActor)` (THE PRINCIPAL CROSS-CHECK: a caller may only be authorized by its OWN serve registration; naming a foreign row buys a refusal, never an authorization), and (c) `row.processEpoch == serveEpoch` (a superseded predecessor after a restart is refused). An absent or TTL-expunged row reads ABSENT and refuses fail-closed. This binding is ALIAS-LEVEL, not incarnation-level: the gate is keyed by the PERSISTED `instanceId` and its row carries no lifecycle uid, so a same-principal predecessor presenting the current epoch still passes — binding the publishing incarnation would require a gate-row schema change. The four-outcome idempotence table answers in operator vocabulary (already-retired = success; the same stable opId resumes; a foreign operation refuses naming it; a stale incarnation refuses naming the current one), and every refusal is a COMPLETE no-op stated as such | subscribe `ep.one.auth.>` QUEUE-QUALIFIED (queue group `auth`; §13.9 forbids a plain subscribe of the class rail) + publish `ep.reply.auth.<instanceId>.<epoch>.*.*.*.*` (REPLY PLANE ONLY: the request and reply planes are disjoint in the grammar, so the listener credential cannot express a request subject at all — the self-forge is closed structurally, not by carving replies out of a shared subtree) (replies ONLY: the handler only ever responds on the DERIVED reply subject, and the reply plane cannot express a request subject at all, so a request is unpublishable by the listener credential, closing the self-forge where a compromised listener publishes a request as an authorized caller and passes its own subject-derived check) + `$JS.API.INFO` + the ONE serve-issuance-gate read row + its connection-scoped inbox; NO store writes, NO consumer authority, NO scanner/plane reach — every executing right stays with the plane's own registry and retirement deps (the drain rides the plane's ONE sealed records scanner) | mediated **NOW A CONFORMING ENDPOINT (Cotal #399, closed): the plane registers `svc.auth.<instanceId>`, publishes contract artifacts, and serves the reserved `describe`, so a generic client discovers and invokes this command the way it would any other registered endpoint (the two rows immediately below). The rail answers the v1 envelope; a legacy `{op,args}`/`{ok,data,error}` body is refused `unsupported-version`.** |\n| Retirement requester (per-despawn, §13.2) | an EPHEMERAL one-shot credential the space manager mints per despawn (`retirement-requester` profile, five-minute window): request + reply ONLY, for exactly ITS OWN caller triple AND exactly ONE grant-pinned TARGET incarnation (the `handle` triple is literal in the grant; the per-request nonce is the only wildcard token), so a leaked requester cannot be re-aimed at another lifecycle. The manager derives a STABLE opId from the retiring lifecycleUid, so a despawn retry, a same-name-spawn nudge, and the auth service's boot resume all drive the SAME operation. The requester holds no executing right — a leaked credential can only ask the rail to retire a lifecycle, and the rail's fresh serve-issuance-gate check (including the principal cross-check) + idempotence table bound what that ask can do | publish exactly `ep.one.auth.retire-lifecycle.handle.<tO>.<tA>.<tUid>.<cO>.<cA>.<cUid>.*` (its minting manager's own caller triple, its one target) + subscribe its own reply-plane filter `ep.reply.*.*.*.<cO>.<cA>.<cUid>.*` and its connection-scoped inbox; nothing else | mediated **`handle`-MODE DEVIATION, stated explicitly (Cotal #399): this row is NOT redemption-minted.** `handle` is normatively redemption-minted only - its triple pinned at redemption from an issuer-signed capability artifact, carrying attenuation, conferral through the trusted auth service, and ledgered `sourceChain` lineage. **This path has NO issuer-signed artifact, NO redemption step and NO `sourceChain`**: the row is built directly from the minting manager's own coordinates under root authority. `handle` is used because it is the ONLY mode with arity 3 (every other mode resolves against the CURRENT mapping, the wrong semantics for retiring a NAMED incarnation), and the reader-facing invariant - the validator re-checks only currency - IS honoured by the serve-time mapping check. What is absent is delegation lineage and artifact revocation; there is no independent issuer/holder boundary on this one-shot path whose revocation would change this requester's authority. Genuine redemption-shaping is tracked at #399. |\n| Registered auth instance (Cotal #399, the M4 conformance closure) | the auth service's own boot registration, over the plane's registration credential (§13.1) | the plane registers `svc.auth.<instanceId>` through the standard `registerServiceInstance` path (the same record shape and registration barrier every other endpoint uses), publishes its `retire-lifecycle` contract artifacts to the content-addressed contract store, and serves the reserved `describe` alongside the command: a generic client's `resolveService` now discovers this endpoint, its closure digests, and its current instance/epoch the way it would any other registered service, closing the round-8 `#399` gap named in the two preceding rows; subscribe `ep.one.auth.>` QUEUE-QUALIFIED (queue group `auth`) + describe reply on the same reply-plane rows as any other registered endpoint + the registration-barrier and contract-artifact publish rows shared by every `registerServiceInstance` caller; no additional store authority beyond that shared registration path | mediated |\n| Retirement requester, describe + registered-endpoint call (Cotal #399, the M4 conformance closure) | the same `retirement-requester` profile above, now calling through the generic client (`resolveService` + `invokeCommand`) instead of a hand-built subject | in addition to the exact-mode `retire-lifecycle` request row already granted above, the profile carries the baseline wildcard-endpoint `describe` row (`epDescribeAllGrantRow`, pinned to this caller's own triple) and a bounded contract-store direct-get row (`$JS.API.DIRECT.GET.<EPC stream>.<space>.epc.>`) so the requester can resolve the endpoint's registered contract digests before it calls; the request itself is still minted in `exact` mode, target-pinned to the one incarnation named at mint time; publish the same exact-mode request row as above + the describe wildcard row + the contract-store direct-get row; subscribe its own reply-plane filter and connection-scoped inbox; nothing else | mediated |\n| Governance head (registration linearization) | the provisioner-registration principal | the **unsplit** governance head `$KV.cotal_records_<space>.govern.<endpoint>` (§13.7): it reads the head FRESH under the frozen registration gate (a FENCING read, read service above: leader-served `$JS.API.STREAM.MSG.GET.KV_cotal_records_<space>` last-by-subject on the head key, never the follower-served `DIRECT.GET` the records bucket would allow) and is the head's ONLY writer (slot-take CAS in phase 1, promote CAS after the spec publish); the SAME principal holds the write on `$KV.cotal_records_<space>.policy.<endpoint>.>` (each immutable policy version is published exactly once, before the stage CAS that names it). The immutability of a policy version is a TRUSTED-WRITER INVARIANT, not a broker-enforced subtraction: KV create/update/delete all publish to the one `$KV.…policy.<endpoint>.<digest>` subject, and NATS subject permissions cannot distinguish the create-CAS header or the `KV-Operation` header, so a subject grant cannot forbid an overwrite or DEL. The invariant is upheld by the writer's create-only CAS plus every reader's SELF-CERTIFICATION (§13.7: the value must digest to the key), so a changed-byte overwrite is REFUSED on read; the residual, confined to this prefix, is that a buggy or compromised provisioner could still DEL or same-byte-overwrite an enforced version and (history 1) destroy its availability, at which point admission pauses fail-closed rather than admitting under a lost policy. No agent, endpoint, observer, admin, or host profile holds any grant. The head is NEVER-DELETED (the `lifecycle`-head discipline): no grant permits DEL/PURGE on `govern.>`; a reader treats only TRUE ABSENCE as a virgin head, and a deletion marker refuses loudly as corruption (§13.12 retention floor), never as absence | mediated |\n\nTerminal pool cleanup settlement is lease-fenced across the two profiles above: the executor\nCASes the item's lease (or observes the winning settled lease), publishes/observes the exact\nlease-derived `wrk` terminal, and only then does the cleaner, after re-reading and\ncodec-validating that terminal, ACK the delivery. A `wrk` create that bypasses the lease CAS is\nnon-conformant: it can contradict a racing commit.\n\nAn `eff` completion fact `epf.<endpoint>.eff.<cO>.<cA>.<cUid>.<id>` is a CLOSED two-member\nunion carrying a REQUIRED `outcome` discriminant on EVERY member (the goal union's `state`\nbar, applied to effects: a member is never structurally assignable to the other, and every\nreader is forced to read the outcome). The RAN member is\n`{ v: 1, id, fingerprint, caller, sourceSeq, ts, outcome: \"ran\" }`; the RETIREMENT-CANCELLED\nmember is `outcome: \"cancelled\"` plus exactly `cancelled: { opId, target }` — the same\nidentity spine, plus the binding to the retiring target's lifecycle and the retirement\noperation that cancelled it. A fact missing the discriminant, or claiming one outcome while\ncarrying the other's fields, refuses. A reader that sees `cancelled` KNOWS the effect did not run; the member is never\na forged success. Both members' caller triple and `id` are bound by the subject, and their\n`fingerprint` and `sourceSeq` MUST equal the accepted decision's. The cancelled member may be\nwritten ONLY for an acceptance whose own `target` names the retiring lifecycle (a retirement\nnever cancels a foreign target's work), publishes CREATE-ONLY on the SAME subject the real\nmarker would use — so first-terminal-wins is structural: a racing real completion that lands\nfirst wins and the cancel loses its create harmlessly, and vice versa — and is produced by\nthe drain's per-op canceller profile (§13.9). An ACTION needs no new member: the `goal….result`\nunion already carries the first-class `cancelled` outcome state, and a retirement-cancelled\ngoal terminalizes through it with the same acceptance-fingerprint binding and the retirement\nattribution in its digest-bound payload (`data.cancelledBy = { opId, target }`). An\neffects-route drain compares the PARSED fact against the acceptance and treats EITHER bound\nmember as established; an action's drain instead requires the parsed `goal….result` fact whose\n`fingerprint` matches the acceptance. Subject presence alone never proves completion: a bare,\nmalformed, or mismatched fact refuses the drain loud (§13.8).\n\nRaw `STREAM.MSG.GET` and `CONSUMER.MSG.NEXT` authority carries a caller-selected reply subject.\nFor every trusted profile holding those APIs, D32 includes confused-deputy response injection:\ncompromise can direct fetched API/message bytes onto a foreign subject even though its\nconnection-scoped inbox prevents subscribing there. This is injection, not foreign read access,\nand requires a future fixed-destination mediation boundary to remove.\n\nDeletes beyond these rows: only the lifecycle-keyed deprovisioner (exact names, §13.1) and\nstream retention.\n\nA **mediated** row means the raw storage grant is held only by a narrowly scoped writer\nprincipal (per endpoint, never a universal writer), with authenticated caller binding,\nidempotent request semantics, and bounded failure/backpressure; CAS headers, fingerprint\nrules, schema validity, and digest-correct bytes are *enforced* there. A **direct** row means\nthe broker guarantees writer/key containment only, and the row **explicitly downgrades**\nCAS/schema/header/byte correctness to a conforming-client guarantee; readers of direct-row\nstate fail loud on invalid content. No profile (agent, observer, admin, host) holds generic\n`$JS.API.>`/`$KV.>`/`$O.>` authority over control-surface state, for the contract store that\nmeans the REAL subjects and APIs: **write** on `cotal.<space>.epc.>` belongs\nto the contract publisher alone (create-only per digest subject); **read** is the\nsubject-scoped last-by-subject Direct Get of the reader row above, never a body-selected\nform and never a consumer, because there is nothing to replay: one message per digest\nsubject IS the store, with verify-on-read as the tamper\nboundary; and the **stream-management surface** of `EPC_<space>`\n(`$JS.API.STREAM.{UPDATE,DELETE,PURGE,MSG.DELETE}.…`) is held by NO profile, publisher\nincluded, stream lifecycle belongs to space setup under operator provisioning authority\nonly, which is what \"immutable once published\" rests on (a `$OBJ.>` deny matches no NATS\nsubject and audits nothing).\nThe matrix is re-audited mechanically (decoded-credential fixture + live positive/negative\nprobes, with predicates over the real `$O.`/`$JS.API` subject forms) at every phase that\nadds a resource or changes ownership.\n\n**Writer table (core kinds, mediation decided, D7: authoritative CAS/schema record writes\nare mediated by separately scoped spec/status writer principals; an endpoint holds no raw\noverwrite grant on its own record keys).** `svc`, spec: the provisioner/registration path,\n**mediated** (CAS + schema enforced at registration); status: the owning instance's commit\npath, **mediated** with **epoch currency enforced at the writer**: the writing epoch is\nread from the broker-authenticated `epr` ingress subject (§13.2, the instance's serve\ncredential pins the epoch token there, so a stale process CANNOT claim the successor's\nepoch: the value is attested by the grant, never by payload), and the writer validates it\nagainst a FRESH read of the authoritative lifecycle mapping's `processEpoch`,\nrejecting a non-current epoch (`expired`), monotonicity against the stored status epoch\nalone is NOT sufficient, because between the takeover CAS (mapping N→N+1) and the completed\nrevoke/evict barrier the superseded N would still equal the stored status epoch and pass a\nbelow-stored check, and additionally rejects a below-stored epoch (`conflict`). The record\nkey is restart-stable and\ncannot carry the epoch (§13.1), so this epoch-pinned-ingress-plus-fresh-equality mediation\nis the record's only stale-writer fence.\n`signer`, spec+status: the space operator's registry tooling as the scoped writer\nprincipal, **mediated**. `handle`; keys are **issuer-namespaced**,\n`handle.<issuerKeyId>.<id>`, so two issuers can never collide or cross-revoke; spec: the\nissuer through the record-writer seam, create-only; status/revocation: issuer or space\noperator, **mediated and monotonic** (revoked never un-revokes; the signature stays the\ncontent authority; mediation enforces key grammar, CAS, and schema). `contracts` index, the instance, **direct** (explicitly advisory and\nnon-authoritative; `describe` is authoritative; readers fail loud on invalid state).\n`goal`/`cp` projections, status: the owning instance's commit path, **mediated**. Lifecycle\nmapping records (§13.1), the minting manager's commit path, **mediated**, CAS-only. The\n`govern` head (§13.7), the provisioner-registration principal, **mediated**, CAS-only (the\nmatrix row above).\nCanonical acceptance, work-pool enqueue, lease state, and contract-artifact publication,\n**mediated** per the matrix above.\n\n**Trait seam.** Core owns the fail-closed pre-effect verification interfaces (guard call,\npriced-proof verification, governed-attachment verification); policy engines, token formats,\nand payment rails remain extensions behind those seams.\n\n### 13.10 Receipts and signing trust anchors\n\n**Receipts.** A receipt binds a request to its outcome, signed and non-repudiable, for\nmetering, disputes, and pipeline causality; payment semantics stay opaque to core.\n\n`Receipt` = `{ v: 1, requestId, sourceSeq (the accepted submission's sequence, the\nexecution identity its subject carries, §13.2), space, endpoint, command, instance: { id, instanceId, epoch },\ncaller: { id, lifecycleUid }, schemaDigests: { input, output }, argsDigest, outcome: { ok,\ncode? }, resultDigest?, ts, signer: { keyId }, sig }`, canonical JSON, Ed25519-signed\n(`space` per the unconditional artifact rule below).\nLifecycle and epoch are recorded as **evidence**, never redemption authority. A command\ncarrying `ai.cotal.priced` MUST verify an independently verifiable payment proof in the\n`auth` slot before effect (never a bare \"settled\" assertion) and emit a receipt fact\n(`epf….receipt.<cOwner>.<cActor>.<cUid>.<id>.<sourceSeq>`, the caller- and\nexecution-scoped subject of §13.2; receipts are create-only per subject). A priced command\nis therefore journal-class: its receipt derives its identity from the accepted submission's\ndecision fact and its outcome from the committed terminal, never from emitter-supplied\nparameters, so a command with no acceptance fact has no receipt to emit; a conforming\nimplementation refuses to serve `ai.cotal.priced` on an ephemeral command (an\nadmission-time refusal at serve construction, never a first-request surprise). Receipt\nretention: default 90 d, ≥ the idempotency horizon (outcome-stated by the §13.12 retention\nfloor).\nVerification: signature against the anchor registry + digest recomputation; forged or\nrequest-mismatched receipts fail loud. Receipts MAY be emitted for unpriced commands.\n\n**Trust anchors.** One per-space registry covers every signed artifact of this section,\nauthorization slots, capability handles, checkpoint resumes, trait definitions and\nattachments, session grants, receipts. Anchors are `signer.<keyId>` records: spec =\n`{ keyId, publicKey (Ed25519), owner (the principal or reverse-DNS domain the key belongs\nto), roles ⊆ [handles, traits, receipts, resume, sessions, authz-slots, obligations,\npayments, consents], scope: per-role structured ceilings, for a `handles`-role key the **full grant\ndimensions**, in the handle-grant shape itself: the endpoints/domains, and per entry the\nmaximal commands, authorization modes, target patterns, instance ids, and read subtrees the\nkey may issue for (a handles- or receipts-role key without a dimension ceiling has that\ndimension closed, not open); for other roles the endpoints/domains it may attest for,\nvalidFrom, validTo }`, status = revocation. `issuer-authority` is defined by exactly this\nrecord: a verifier resolves the artifact's keyId FRESH at verification and enforces the role\nAND its scope under the §13.6 containment order (`handle.grants ⊆ anchor.scope`), a\nhandles-role key scoped to `com.acme.>` cannot issue for `manager`, a receipts-role key\nscoped to one endpoint cannot attest as another, and a handles-role key whose scope names no\n`handle`-mode targets cannot issue actor-pinned grants. Verification (fail closed): resolve the key,\nreject unknown keys, out-of-window use, role mismatch, or revocation (immediate for new\nverifications; effected work is not retroactively unwound). Rotation registers a successor\nand closes the predecessor's window; overlap is permitted for handoff. Third-party trait\nauthorities register under their reverse-DNS domain claim. Trust roots never merge across\nspaces.\n\n**Signature encoding (normative, D28).** For every signed artifact: the signature input is\nthe UTF-8 bytes of the RFC 8785 canonical JSON of the artifact **with its `sig` field\nabsent**; the signature is Ed25519 (nkeys); `sig` carries it base64url-encoded (unpadded).\nVerification recomputes the canonical form, resolves `signer.keyId`/`issuer.keyId` in the\nanchor registry, and fails closed on any mismatch.\n\n**Replay and claims matrix (normative, per artifact type).** Every row below additionally\nand unconditionally requires `space`, the signing `keyId` (`issuer`/`signer` per shape), and\n`sig` (the §13.10 encoding): an artifact missing any of the three is invalid before its\nreplay rule is ever consulted, and each artifact type is a discriminated schema, a verifier\ndispatches on the type, never duck-types the claims.\n\n| Artifact | Required claims | Replay rule |\n| --- | --- | --- |\n| Private tool-result consent (§13.19) | consent id, space, target (owner, actor, lifecycleUid), same-owner interactive holder, window of at most 24 hours, signing keyId and sig (§13.10) | holder-bound; create-only issuance and revocation records; canonical START frontier and current revocation/lifecycle checks per §13.19 |\n| Capability handle | id, space, issuer, holder (principal+UID), structured grants, iat, exp (nbf, parentDigest, epoch as applicable) | reusable within TTL, holder-bound; revocable if sturdy |\n| Checkpoint resume | checkpoint token, goal id, holder (principal+UID), iat, exp, nonce | **one-use** (journaled by create-only CAS); duplicate = `conflict` |\n| Session grant | sessionId, subjects, holder (principal+UID+processEpoch), serving instance+epoch, window, iat, exp, nonce | **one-use** redemption (holder epoch fresh-checked), then live; dies with either side's epoch |\n| Guard obligation | goal/request id, attenuations, iat, exp | bound to its goal/request; reusable within it |\n| Payment proof | per the priced contract's declared policy | default one-use per request id |\n| Trait attachment | endpoint, command, contractDigest, traitUrn, value, signer, ts | revision-bound evidence; replaced only by an authorized contract revision |\n| Receipt | per §13.10 shape (ts, signer; no exp/nonce) | evidence, never authority; replay-irrelevant |\n\nEvery verifier rejects out-of-window use (where `exp` applies), wrong-holder presentation,\nand unknown/revoked keys.\n\n### 13.11 The hard cut\n\nThis section is an intentional hard cut on the pre-1.0 line per §11. The version marker is\nthe grammar itself: the `ep`/`epe`/`epf`/`epj`/`ept`/`epw`/`eps` subject kinds and the\nversioned envelope are disjoint from every v0.3 control subject and shape, and the old rails\nare removed, subjects, envelopes,\nhandlers, credential grants, minting paths. No compatibility adapter, dual serving, or\ntranslation window exists. A credential minted before the cut can publish only into dead v0\nsubjects: nothing subscribes them, no post-cut handler is reachable from them, no trusted\nreply can be elicited (a pre-cut grant matches no endpoint-surface subject by construction,\nverified adversarially with captured pre-cut credentials from every old profile). The one\nstructural exception is the pre-cut `admin` profile, whose space-wide `P.>` subscribe\npredates and therefore MATCHES the new rails: **admin credentials MUST be re-minted at the\ncutover** to the post-cut admin shape (Appendix B: messaging-plane subjects only, no\n`ep*`/`eps`/`epc` subscribe), and the pre-cut admin credential is revoked with the cut;\nthe hard-cut guarantee is not honest without it. The wire\n`protocolVersion` (§6, §11) targets `0.4` at the completion of this revision's migration, per\nthe §11 convention that the advertised version is the migration's normative target, and a\nv0.4-conformant participant MUST advertise it (the optional-field era ends at the marker\nboundary); `1.0` is a separate, later stability declaration (§11).\n\n### 13.12 NATS + JetStream binding\n\n**Broker floor.** The control surface REQUIRES NATS server ≥ 2.12 (message schedules, atomic\ncreate-CAS, counters) AND a `max_control_line` large enough for the deployment's\nmaximum-capability CONNECT line. The two floors are checked at the tier that can see them:\n\n- **Clients** check the server version from the pre-auth INFO and fail loud below 2.12 or\n when schedules are unavailable (including the offline-assets downgrade mode). The\n control-line limit is NOT discoverable pre-auth; an oversized CONNECT is silently dropped\n and looks like a network fault, so a client's obligation is bounded reconnect attempts\n plus the named diagnostic on a repeated pre-auth drop (\"CONNECT may exceed the broker's\n max_control_line; have the operator verify it\"), never an infinite retry loop.\n- **Operator tooling** (doctor/setup) asserts the cause before any credential is minted:\n read `max_control_line` over the system account (`$SYS.REQ.SERVER.PING.VARZ`) from\n **every server of the cluster the credential may connect to**; the ping is fanned out,\n the response set is checked complete against the expected server count, and a partial\n response set is a FAILED assertion, never a pass, and require, on each server,\n `max_control_line ≥ (largest encoded CONNECT line of the §13.9 fixture set) + margin`.\n The fixtures are **byte-reproducible** (concrete maximum-length identities, the full\n grant set at the policy ceiling, the maximum-capability agent credential and the\n maximum-command serve credential, the encoded credentials, the resulting CONNECT\n lengths), so the floor is a measured quantity; the reference deployment's configured value\n is 65536; a derived number, not an assertion. The 16 KiB policy gate remains a distinct\n mint-time cap on credential authority, refused loudly at minting. The same assertion pass\n checks `max_payload ≥` the largest serialized **bounded decision fact** fixture (the\n maximum `RejectionFact`/`QuarantineFact` under the token and detail bounds, §13.4) AND\n `max_payload ≥` the 256 KiB contract-artifact document bound plus envelope margin\n (§13.7; a contract artifact is one message on its digest subject), so\n \"the rejection fact always fits by construction\" and \"an artifact is a single message\"\n are measured floors, not assumptions.\n\nNo sweeper fallback exists. Only 2.12 schedule semantics are assumed (same-subject\nreplacement; NOT the 2.14 stop-plus-publish path).\n\nPer-space resources, created at space setup (`STREAM.CREATE` remains denied to agents):\n\n| Resource | Captures / holds | Retention notes |\n| --- | --- | --- |\n| `EPJ_<space>` stream | `cotal.<space>.epj.>` (submissions, untrusted) | Limits; **native dedupe not relied upon**; submitters never set `Nats-Msg-Id` (§13.4; stream-wide header dedupe is a cross-caller suppression vector on a shared untrusted stream). A zero duplicate window is NOT server-accepted (`0` normalizes to the 120 s default; the minimum is 100 ms), so the config sets the server minimum and the guarantee is the header rule: a hostile header suppresses only another non-conformant header-bearing write; retention ≥ recovery/redelivery lag |\n| `EPF_<space>` stream | `cotal.<space>.epf.>` (canonical facts) | Limits; acceptance via create-only CAS (`Nats-Expected-Last-Subject-Sequence: 0`); `allow_direct=true` (NON-fencing subject-confined reads only: every §13.9 matrix fact read is FENCING and leader-served `STREAM.MSG.GET`, §13.9 read service); retention ≥ horizons, outcome-stated by the retention floor below |\n| `EPE_<space>` stream | `cotal.<space>.epe.>` (events, progress) | Limits; space policy |\n| `EPT_REQ_<space>` stream | `cotal.<space>.ept.*.*.*.*.schedule` (instance schedule REQUESTS, §13.2) | Limits; message schedules **DISABLED**; client-set scheduling headers are inert bytes here; retention ≥ writer recovery lag |\n| `EPR_<space>` stream | `cotal.<space>.epr.>` (record-write ingress, §13.2) | Limits; epoch-pinned publish grants (§13.9); consumed only by the record writer; retention ≥ writer recovery lag |\n| `EPT_<space>` stream | `cotal.<space>.ept.*.*.*.*.armed` + `….fire` (authoritative schedules + fires, §13.2) | `AllowMsgSchedules`; only the timer writer publishes `.armed` (§13.9); each schedule targets its sibling `.fire` subject (ADR-51 forbids target = publish subject); retention ≥ max deadline + margin |\n| `EPW_<space>` stream | `cotal.<space>.epw.>` (work pools; one item per subject, §13.2) | WorkQueue; provisioner-pre-created non-overlapping exact-filter per-pool consumers (§13.9) with **`max_deliver=-1` pinned** (a finite delivery ceiling strands exhausted items outside `num_pending`/`num_ack_pending` and falsifies the §13.6 admission occupancy; the occupancy reader re-checks the pin at every read because MaxDeliver is editable post-create); **`allow_direct=false`**: EPW has NO non-fencing subject-confined reader (pool workers drain the WorkQueue via `CONSUMER.MSG.NEXT`, never a subject read), and its ONLY subject read is the reconciliation probe, which is FENCING and MUST be leader-served `STREAM.MSG.GET` (§13.9 read service; an acked item leaves the WorkQueue, an in-flight one remains readable, which is exactly the §13.6 predicate, and a stale follower miss would re-arm settled work). Disabling Direct Get on EPW makes that leader-served requirement STRUCTURAL: no reader (including virtual-endpoint activation reconciliation, §13.6) can take the follower path even by mistake. This differs from EPF, which keeps `allow_direct=true` because it DOES have non-fencing subject readers (the §13.9 last-by-subject fact reads); EPF's fencing CAS-winner read opts into the leader by caller choice |\n| `WFJ_<space>` stream | `cotal.<space>.wfj.*` (the workflow STEP JOURNAL, §14.4: **one subject per RUN, `cotal.<space>.wfj.<runId>`, not one per entry**) | Limits, file storage, **no `max_age`** and no finite count/byte limit that evicts (an evicted prefix is not a shorter journal, it is a run that re-performs effects it already performed, and a run that sleeps for a month resumes by re-reading it; retirement is by subject purge, deliberately); **`allow_direct=false`** (a resume must read its own predecessor's last appends, and Direct Get is follower-servable, so a stale miss there reads as \"this step never ran\"). Deliberately outside the `ep*` plane letters: the journal is a runtime layer over the control surface, not part of the endpoint contract. Every append is fenced by `Nats-Expected-Last-Subject-Sequence` on the run's own subject (§14.4); a run's driver holds publish on exactly its own run's subject plus a per-takeover replay durable filtered to it, and there is no space-wide `wfj.>` publish grant |\n| (sessions: core-only, no stream) | `cotal.<space>.eps.>` | never captured; bounded in-memory window |\n| `cotal_records_<space>` KV | records: the §13.7 core-kind key grammars (`svc`, `signer`, `handle`, `contracts`, `goal`, `cp`, `lease`, `lifecycle`, `govern`, `uid`, `policy`, `oblig`, and the §14 kinds `run`, `answer`, `notice`, `migration`) | per-key CAS; `.spec`/`.status`-split keys EXCEPT the unsplit atomic keys `lifecycle.<owner>.<actor>`, `govern.<endpoint>`, `uid.<lifecycleUid>`, `policy.<endpoint>.<digest-hex>`, and `oblig.>` (§13.1/§13.7/§13.8/§13.9); `allow_direct=true`, but the heads and every fencing read are leader-served `STREAM.MSG.GET` (§13.9 read service). **No age retention on authority keys:** `lifecycle` heads, `govern`, `uid` reservations, `policy` versions, and `oblig` rows are NEVER-DELETED (no grant permits DEL/PURGE; an age-evicted reservation would reopen UID reuse, an evicted obligation would orphan accepted work); a deletion marker on any of them refuses loudly as corruption, never as absence. **Shape is proved at bind, not assumed:** the stream MUST be primary (never a mirror/sourced copy) and MUST carry no bucket-wide silent-eviction limit (no `max_age`, no finite `max_msgs`/`max_bytes`: under `DiscardOld` a finite global limit evicts a prior authority key's latest row the moment an unrelated key is written); every trusted consumer of this store (the minting authority, the mapping reader, the mediator) verifies exactly this via `STREAM.INFO` when it binds and refuses to serve otherwise |\n| `cotal_auth_<space>` KV | the credential ledger (`cred.<lifecycleUid>.<credentialId>` + issuance gates `gate.<lifecycleUid>` + the disjoint endpoint families `epgate.<endpoint>.<instanceId>` / `epcred.<endpoint>.<instanceId>.<credentialId>` + the staging family `stage.>` + source gates `srcgate.<issuerKeyId>.<id>` + lineage index `bysrc.…` + native-key issuance evidence `natkey.<userNkey>`, §13.1) + session ledger (`session.<sessionId>`, §13.6) | trusted auth path ONLY; no agent, endpoint, observer, admin, or host profile holds any grant (§13.9 matrix); **`allow_direct=false`** (every fence is a leader-served revision-pinned CAS write; Direct Get's follower/mirror reads would defeat read-your-writes, §13.1); CAS + monotonic states. **No bucket-wide age retention:** `gate.`, `epgate.`, `srcgate.`, and `session.` authority keys persist until their lifecycle/handle/session is explicitly terminal (an age-evicted `open` gate would silently reopen minting, or drop a `frozen`/`retired` fence); only `cred.`/`epcred.`/`bysrc.` rows carry a per-key TTL bounded by the credential TTL (NATS per-key message TTL, ≥ 2.12), never a bucket MaxAge; `stage.` rows follow their operation's retention, never a ledger row's. **Shape is proved at bind** (the records-store rule above, plus `allow_direct=false`): primary, un-mirrored, no bucket `max_age`, no finite `max_msgs`/`max_bytes`; the trusted auth path verifies this via `STREAM.INFO` when it binds and refuses to serve otherwise |\n| `cotal_issued_<space>` KV | issued-authority evidence (§13.15): `v1.<owner>.<actor>.<uid>.<generation>` (immutable evidence), `attempt.v1.…` (the one-field attempt row), `bysource.v1.<sha256>.…` (the reverse index from a source gate to the issuances depending on it) | Limits, file storage, no stream-wide age eviction, **`allow_direct=false`** (every read is a fence); create-only evidence, revision-CAS attempt. **Bounded by per-message TTL:** `allow_msg_ttl=true` and no subject delete markers; each row carries its own TTL to its generation's horizon plus the retention margin (§13.15), and nothing else removes it, so no row goes while its generation can authorize anything (a run admitted under it keeps its ceiling in its admission, §14.8). A store without `allow_msg_ttl` predates bounded retention: every provisioner, issuer and resolver checks both stores' shape with `STREAM.INFO` when it binds and refuses it, before it reads or writes either, and it is recreated, never adopted. Immutability is BROKER-ENFORCED the way the EPC store's is: `allow_rollup_hdrs=false, deny_delete=true, deny_purge=true`, set once at creation and verified by every provisioner that binds, so a holder of the issuer's own key row cannot replace evidence or empty the bucket with a `Nats-Rollup` header, a message delete, or a purge |\n| `cotal_accepted_<space>` KV | accepted rows (§13.15): `accepted.v1.<acceptedToken>`, one per issuance, written by the issuer at release | Limits, file storage, `allow_direct=true`: the client's per-key `DIRECT.GET` is the discovery read; create-only, with the same three broker-enforced flags and the same per-message TTL retention as the evidence store: a row lives until the horizon of the generation it names plus the retention margin |\n| `cotal_admission_<space>` KV | run admissions and revocations (§14.8): `admission.v1.<endpoint>.<runId>`, `revoked.v1.<endpoint>.<runId>` | Limits, file storage, no age eviction, `allow_direct=false`; both keys create-only and the marker permanent, BROKER-ENFORCED by `allow_rollup_hdrs=false, deny_delete=true, deny_purge=true` (a run-admitter's own key row admits no `Nats-Rollup` replacement of the admission, and no purge empties another run's row); retained while the run, its program, its journal or its lineage is resumable |\n| `EPC_<space>` stream | `cotal.<space>.epc.>` (content-addressed contract artifacts, one per digest subject, §13.7) | Limits, no age eviction (artifacts are permanent); create-only mediated publication (`Nats-Expected-Last-Subject-Sequence: 0`); `allow_direct=true` (the subject-scoped last-by-subject read IS the fetch path; non-fencing, verify-on-read); permanence is BROKER-ENFORCED: `deny_delete=true, deny_purge=true` (the broker rejects the message-delete and purge APIs even from a stream-API-holding principal). Permanence is the COMBINATION of these flags, the retention floor's no-early-removal rule (below: the flags alone stop delete/purge but not age eviction or a whole-stream teardown), verify-on-read pinning WHAT a subject carries, and the stream-management surface held by no profile (§13.9); no single flag makes deletion structurally impossible |\n\n**Retention floor (one-use-identity facts).** A stream or bucket whose messages carry\none-use identity, that is decision facts realizing the §13.4 idempotency horizon, goal\nterminal facts and tombstones (§13.6), receipt facts (§13.10), and the never-deleted\nauthority heads (`lifecycle`, `govern`, the auth-bucket gates), MUST retain every protected\nmessage until its governing horizon, stated by OUTCOME: NO removal cause may drop a\nprotected fact early. That forbids not only age eviction below the horizon but every\nconforming alternative that erases it while `MaxAge` still passes: a finite\n`MaxMsgs`/`MaxBytes`/`MaxMsgsPerSubject` with `DiscardOld`, a per-message TTL,\nrollup/compaction, or a retention-policy change; for these families finite count/byte\nlimits MUST fail loud or `DiscardNew` rather than evict protected history, and message TTL\nand rollup MUST be disabled on protected subjects (a per-key TTL is permitted only on\nnon-protected keys, e.g. the auth bucket's `cred.`/`bysrc.` index rows above and the\nissued-authority rows, whose TTL ends after their generation's horizon (§13.15), never on a\nprotected fact, head, or gate). NO principal, including operator, setup, and system tooling,\nnot only §13.9 profiles, may `MSG.DELETE`/`PURGE`, `STREAM.DELETE`, or issue a\n`STREAM.UPDATE` that weakens any of these limits; the never-deleted heads and gates carry\nan UNBOUNDED horizon. A KV writer MUST NOT publish a DEL/PURGE marker for a never-deleted\nkey, and a reader that encounters one treats it as corruption, never as absence. (Root can\nalways destroy a broker; such an act is explicitly non-conformant, not outside this\nclause.) `CONSUMER.DELETE` is distinct and permitted: it removes a reader cursor and can\nnever mutate stored facts. Concretely: `EPF_<space>` retention ≥ max(idempotency horizon,\nresult retention, receipt retention), because the acceptance fact is the durable\nreconstruction source for receipts, while the raw submission stream is age-evicted by\ndesign.\n\nClaim pools are pull consumers on `EPW` with `AckExplicit`, held **only by the pool's owning\nendpoint** (§13.5): `ack_wait` is the broker's redelivery-to-owner timer and nothing more;\nthe authoritative lease token and deadline live in the owner's lease record, never in the\nitem value (stored bytes are work identity and input only), and the owner acks only after\nthe committed terminal state. Filtered replay of events/facts uses pinned single-filter\nconsumer creates (the CHAT-history containment mechanism, §8/§9). Timer scheduling is\n**mediated** (§13.2, §13.9): instances publish only `.schedule` REQUESTS into the\nschedules-disabled `EPT_REQ` stream, where a client-set `Nats-Schedule-Target` (or any\nscheduling header) is inert bytes and the timer writer rejects a request carrying one, this\ncloses the ADR-51 confused deputy, in which a direct publisher confined only to \"some\nsubject the schedules stream captures\" could target ANOTHER instance's `.schedule` (installing\nor replacing its schedule state, since schedule headers are copied to the target verbatim) or\nits `.fire`. The timer writer alone publishes the authoritative schedule on `.armed`, with\n`Nats-Schedule-Target` = the sibling `….fire` subject derived from the authenticated request\nsubject's own tokens; and **fire handling is the trusted seam** behind it, a `.fire`\nconsumer acts only on a fired message matching a current authoritative\nschedule it owns (`timerId` + generation + deadline, §13.2) AND whose broker-authored\nscheduler-origin header (`Nats-Scheduler`, the schedule's subject, set by the server on\nfire) equals its own exact sibling `.armed` subject, discarding anything else as\nforged. Replacement is the writer's same-subject publish on `.armed` (server rollup); fired\nmessages appear on `.fire` carrying `(timerId, generation)`.\n\n### 13.13 Plane ownership (the sealed-scanner claim)\n\nAt most ONE authority plane per space may hold the sealed scanners (§13.9's seventh-round\nseal). One process MAY hold the planes of several spaces, each with its own\nclaim row, scanner connections and fence; the exclusion below is per space. The scanners' serialization is process-local, so two same-space auth processes would\ninterleave the literal enumeration consumers' critical sections and return PARTIAL\nenumerations: a drain declares quiescence over undrained obligations and the retirement\nfrontiers close over live work. The exclusion is broker-visible, not host-local:\n\n- **The claim row.** One exact, never-deleted auth-KV key (`plane`, subject\n `$KV.cotal_auth_<space>.plane`) holds `{ v, generation, claimId, state: held | released,\n ledger, records, openedAt }`, where `ledger`/`records` are the two ownership-bearing sealed\n scanner connections' broker identities `(serverId, cid, userNkey)`. The barrier profile is\n the row's SOLE writer, at exact arity (never `plane.>`); reads are leader-served. The\n barrier's own identity is deliberately NOT in the row: barrier liveness is irrelevant to the\n literal consumers and could only falsely block a reclaim.\n- **Open order.** Ensure stores; open BOTH candidate scanner connections NON-RECONNECTING (the\n tuples must be stable and disappearance must be final) and keep them INERT (no scan\n capability exists or escapes); take the claim by broker-atomic create (virgin key) or\n revision-CAS (a `released` row, or a `held` row proven dead as below). Only the WINNER\n constructs the branded scanners; a loser closes both candidates and refuses with\n operator-legible copy. The brief dual connected-credential window before the CAS is inside\n the trusted signing-seed residual; there is no dual SCAN authority because the capability\n does not exist before the win.\n- **Plane credentials.** The two plane-owned scanner connections authenticate with\n NON-EXPIRING user JWTs. The separate host-private tool-result custody profile (§13.19)\n adds two more non-expiring, non-reconnecting connections, one reader and one writer.\n No plane claim is implied by custody. These are three profiles and four standing\n connections in total. For each, an expiring\n credential would have the broker hard-disconnect at expiry, and a renewal cannot be\n presented without the reconnect the non-reconnecting shape forbids — an expiry would fence\n the plane on a timer. The credentials never leave process memory, and the account signing\n seed co-resident in the same memory is strictly stronger authority, so the marginal\n exposure is the existing trusted-process residual class; revocation remains service-stop +\n seed rotation. Service stop closes owned sockets; a copied JWT and user seed remain usable\n until signing-key removal, no longer bounded by the ordinary 900-second credential expiry.\n Every other authority credential, including the short-lived tool-result CREATE provisioner,\n keeps the short-expiry + in-process-renewal boundary. Custody accepts no reconnect or\n re-adoption: any real loss, broker restart or upgrade included, leaves gate 1 permanently\n unavailable for that space until a separately authorized retirement/reprovision protocol exists.\n- **Reclaim is liveness-only.** A `held` row is reclaimed only when BOTH claimed tuples are\n conclusively ABSENT under a COMPLETE connection sweep, adjudicated by the delivery daemon's\n read-only oracle over the privileged delivery-admin rail (the auth process holds no `$SYS`;\n the D5 rail split). The closed oracle verb takes exactly the two claimed tuples and returns\n two bound verdicts (`live | gone | unknown`) plus sweep completeness, echoing the queried\n identities; any live, unknown, incomplete, malformed, or foreign-echo answer REFUSES the\n takeover (at most one plane: dual-refuse is safe, dual-proceed is not). There is NO TTL, NO\n heartbeat, and NO \"did the last sealed scan finish\" bit: a mid-scan crash drops the\n non-reconnecting connections, a complete sweep proves them gone, and the successor's\n fail-closed pre-clean (§13.9) makes its full re-scan safe. A paused-but-live process still\n holds its TCP connections and therefore still holds the plane (no pause hazard).\n- **The single-server proof.** Connection absence alone cannot distinguish a RESTARTED\n claimed server (`server_id` is per-broker-run; genuinely gone, and requiring its reply\n forever would turn every whole-stack crash into a permanent reclaim wedge) from a\n PARTITIONED one (live, unreachable; treating its absence as death authorizes a split-brain\n steal). A `gone` verdict is therefore valid ONLY under the single-nats-server-process\n boundary, proven per observation from the responding server's OWN topology declaration in\n the `$SYS` reply envelope — never inferred from which servers happened to reply: every\n reply must declare NO cluster membership and exactly one distinct server may have replied.\n Any cluster self-report, multi-server observation, or reply without the declaration reads\n `unknown` and refuses. Only a SUCCESSFUL, well-formed page counts toward the sweep: a reply\n carrying an API error, a malformed or empty server envelope, a non-string cluster\n declaration, an envelope/data server-id mismatch, or a structurally incomplete data page\n poisons the whole observation (every verdict `unknown`). Each sweep's reply inbox carries a\n per-call collision-resistant nonce, so concurrent sweeps can never satisfy or falsely\n complete each other's rounds; and the auth plane closed-parses the oracle's result (exact\n keys at every level) before reasoning over it. NAMED residuals: a leafnode- or\n gateway-extended account is outside the cluster self-report, so such topologies are out of\n contract for the space's account; a backup restored onto a fresh broker can present a\n still-running foreign predecessor's `serverId` as dead. A clustered/multi-server deployment\n requires an authoritative server incarnation/roster authority in place of this proof.\n- **Holding invariant.** The winner re-validates the claim (state `held`, its `claimId`, its\n `generation`, AND both pinned scanner tuples — a row rewrite preserving the identifiers but\n swapping a tuple is a lost claim, never \"still ours\") BEFORE every sealed scan (refuse to\n enumerate) and AFTER it (discard the enumeration), inside the serialized critical section.\n An owned scanner disconnect is a FENCING event, and the fence is FATAL to the WHOLE\n authority plane: scan exposure is invalidated immediately, the sibling closes, every\n authority operation (connect authorization, credential mint) refuses from that moment, and\n the service goes DOWN loud rather than serving from a half-dead plane a successor may be\n reclaiming (in a process serving several spaces, that space's service goes down and the\n others' planes are unaffected); a still-live sibling correctly blocks a successor until it is closed or proven\n absent.\n- **Clean close.** Scan-capable clients close FIRST, then the row CASes `held → released`\n (never released while either scanner can still act), then the barrier. A crash leaves\n `held`; the successor reclaims through the oracle. A `released` row is claimed without an\n oracle round. A close whose release did not commit (the row is no longer this plane's, or\n the write failed) still closes the barrier and then reports the failure to its caller.\n- **Operator faces.** The three refusal states carry DISTINCT copy: a live peer (\"stop the\n other auth process\", with the space and connection identities), an inconclusive observation\n (fail-safe wait/retry wording that never says \"stop the other process\"; when the oracle rail\n is down it names the delivery daemon and the restart order), and a mid-life scanner death\n (a deliberate fail-closed stop naming the restart path). An unparseable claim row refuses\n loudly and is never overwritten automatically. Every claim refusal also carries the\n `ai.cotal.auth.plane-claim-refused` detail (§13.3), whose `reason` names the state\n (`corrupt`, `live-peer`, `unknown`, `concurrent`, `fenced`, `released`, `lost`), so a host\n never parses the copy to tell contention from corruption.\n- **Host belt.** Launchers additionally claim an exclusive per-space pidfile, published\n ATOMICALLY and PRE-POPULATED: the claimant writes its pid to a unique temp inode, then\n publishes it as the slot with an atomic no-overwrite `link(2)` — no create-then-write window\n exists for a sibling to misread, and an empty slot is impossible to publish. A live holder\n is yielded to; a provably dead holder's slot — and an empty (pre-protocol crash shape) one —\n is reclaimed exactly once; unattributable content is never stolen. A cheap belt only, never\n the exclusion.\n\n### 13.14 Conformance (control surface)\n\nA conformant endpoint (v0.4) MUST:\n\n1. Serve only under a credential whose serve grants match its registered name, stable\n instance id, and registered command set (publish-side grants pinned to the current\n epoch); register its service record before serving; advance the epoch by CAS on takeover\n and stop serving when superseded; a takeover is complete only after the §13.1 barrier\n (revoke + cluster-verified eviction of the superseded credential).\n2. Answer `describe` authoritatively, intersected only against the trusted authorization view\n (or declared-public), failing closed when that view is unavailable.\n3. Publish contract artifacts content-addressed and immutable; validate args/replies at\n runtime within the schema profile and budgets.\n4. Reply only on the reply rail derived from the authenticated request subject; ignore\n payload/transport reply targets; let attribution ride the reply subject.\n5. Enforce the envelope invariants (version/op/class/target/sender, catalog codes, monotonic\n attenuation); treat the subject, never the body, as the authorization boundary; resolve\n targets by `(alias, lifecycleUid)` against current mappings immediately before effect.\n6. Route effects by delivery class; journaled effects only from canonical accepted facts\n through the mediated writer; fingerprint-bind ids first-wins; hold the declared horizons,\n retentions, and floors.\n7. Validate every Cotal-owned commit through the mediated path (fencing token + unexpired\n lease + lifecycle + epoch as applicable); lose CAS loudly.\n8. Implement advertised composites per §13.6: the single action vocabulary, authorization\n linearized at acceptance, one-use resumes, generation- and scheduler-origin-validated\n timers (a fire counts only against its own sibling `.armed`, §13.12) with durable\n reconciliation, fail-closed governed traits, bounded sessions.\n9. Fail loud below the broker version floor (from the pre-auth INFO), with bounded\n reconnects and the named pre-auth-drop diagnostic (§13.12); the `max_control_line` floor\n is asserted by operator tooling (§13.12), never by the client, which cannot inspect it.\n10. Connect successfully while presenting the normative maximum-capability credential\n fixture for its profile (§13.9), the only test that exercises the control-line bound.\n\nA conformant caller (v0.4) MUST: hold a lifecycle-pinned credential and never present another\nlifecycle's artifacts; choose ids/goalIds/nonces within the token grammar and the 1024-byte\nsubject bound and reuse ids only per the idempotency rules; declare `class` and\n`replyExpected` and honor `contract-mismatch`/`conflict`; freeze scatter expectations from the\nregistry and classify partial results; verify digests of fetched artifacts and signed\nartifacts against the anchor registry, failing closed; refuse to resolve a **describe descriptor**\nwhose `protocol.v` it does not implement (the marker rides the descriptor and the service record,\nnever the cluster document, which carries no `protocol`), and never automatically repeat a `write`\ncommand (§13.7) — whatever `id` the re-issue carries — except on an outcome that proves\nnon-execution (§13.3).\n\n### 13.15 Issued authority\n\nThe caller triple (§13.1) says WHO is calling. It does not say what the credential they are\ncalling with was granted, and a host that performs an effect on a caller's behalf needs that:\nthe ceiling as the issuer accepted it, immutable, and bound to the request by the broker rather\nthan by anything the caller or a mutable ledger says. This section defines that binding.\n\n**The reference.** An issued authority is `{ space, owner, actor, uid, generation }`: the\ncaller triple plus a **generation**, 32 lowercase hex characters. The first 8 are the\ngeneration's **horizon**, the unix second at and after which it authorizes nothing, in big-endian\nhex; the last 24 are issuer-chosen entropy (96 bits). A generation is an identifier, never a\nbearer secret. It is chosen by the issuer, never by the client, and is never reused: a reference\nis created once or refused. The horizon rides the generation, so the broker pins it on the\nrequest subject with the rest of the rail, and nothing written to a store can move it.\n\n**The rail.** An issued credential's request-publish and reply-subscribe rows ride the\nversioned rail (§13.2), with its generation pinned literally beside its triple. A request\narriving on `ep.v1` therefore carries a broker-confined generation, and a request arriving on\nthe legacy rail carries none. A body field, a header, or a policy reference supplied by the\ncaller establishes no binding.\n\n**Issuance.** Before an issued credential's material is returned, the issuer MUST persist its\n**evidence** in `cotal_issued_<space>`: `{ version: 1, ref, sources, permissions, expiresAt? }`,\nwhere `permissions` is the credential's final effective permission ceiling (publish and\nsubscribe, each an explicit `all`, `none` or `patterns` allow plus a deny list, imported from the\nnative permission fragment so an omitted list can never read as a narrow one) and `sources` are\nthe gate coordinates the issuance depends on. `expiresAt`, when present, is no later than the\ngeneration's horizon. Issuance is `prepare → release`: the evidence and\na `prepared` attempt row are written create-only, the issuer performs its own finalization, and\nthe attempt row is CAS-advanced to `active` at the revision the prepare observed. A prepare that\nloses its create is refused; a release whose CAS loses is `aborted`. The evidence store is\nappend-only at the broker (§13.12: unlimited per-key history, no rollup header, no message delete,\nno purge; a row ends only by its own TTL, below), and the evidence and source-index rows are read as the FIRST message on their key, so a\nlater write on the same key by a holder of the issuer's bucket-wide row is inert to every\nresolver; only the attempt row advances, by CAS. The issuer also writes the\n**accepted row** (`cotal_accepted_<space>`, keyed by a token the launching party chose) naming the\nreference, create-only. A client learns which generation it was bound under by reading that one\nrow over a per-key `DIRECT.GET` grant its ceiling carries; it never trusts what it proposed or\nwhat a file says, and it refuses a row naming another owner, actor or lifecycle.\n\n**Retention.** Every row of a generation in either store (its evidence, each attempt state, each\nsource-index row and its accepted row) is written with a per-message TTL (`Nats-TTL`) that keeps\nit until the generation's horizon plus a retention margin of 60 seconds, and no longer. Nothing\nelse removes it. No resolution, renewal or retirement reads or writes a generation's keys at or\nafter its horizon; it refuses the generation as expired first. A key the broker removed, and\nanything later written on it, is therefore never read as that generation's row. The margin\ncovers the clock difference between a writer, the broker and a reader. It need not cover how long\na resolution takes, because the horizon is checked again after the last read. A credential minted\non a generation by a static issuer (a static incarnation's credential, an operator instrument)\nexpires no later than the horizon. A static incarnation's generation has a horizon 30 days after\nits issuance; each renewal of its credential is capped at it, none is minted at or after it, and\nthe incarnation is respawned to continue. A run admitted under a generation keeps its ceiling in\nits admission (§14.8), so removing the generation's rows after the horizon ends no run.\n\n**Renewal.** A renewal of an issued credential keeps its generation only when the ceiling being\nminted is byte-identical (RFC 8785) to the recorded evidence; a changed ceiling is refused as a\nrenewal and is a fresh issuance on a fresh generation, which the client adopts only through a\nnew connection. Refreshing a credential file never switches the generation of an already\nconnected transport. A renewal at or after the generation's horizon is refused before the store is\nread.\n\n**Resolution.** A host that admits an effect under an issued authority resolves it: the\ngeneration is before its horizon, the evidence exists, the attempt row is `active`, the evidence\nis unexpired, every source is live, a second read of the attempt row returns the same revision,\nand the generation is still before its horizon after that read. Any other outcome refuses. A\nretirement of a generation at or past its horizon writes nothing, since every reader already\nrefuses it. The\none source shape this revision issues against is a static incarnation's credential ledger family\n(`cred.<lifecycleUid>` on `cotal_auth_<space>`), whose liveness is its issuance gate not being\n`retired`; a lifecycle terminal retires every issuance indexed to that family\n(`bysource.v1.…`), so a retired incarnation's generations refuse to resolve afterwards.\n\n**User-auth issuance.** On a user-auth space the issuer of an eligible actor's `manager-caller`\nview connection is the auth service, at its callout, and the material is the user JWT the callout\nreturns. Interactive rows retain their issuance path. A managed-agent row is eligible only when its\ncurrent persona-derived scope contains `run` AND a fresh read of its direct parent principal's row\nfinds `run` in that same owner's current grant. An admin parent's containment bypass is not a `run`\ngrant. A missing, malformed, foreign-owner or no-run parent grants no issuance. The existing\n`authorizeManagerCaller` instance gate and `VIEW_REQUIRED_SCOPE` remain unchanged. No request kind,\nview, signer or authority door is added, and ordinary command grants still derive from signed\n`act.scope`, contained against the current child row. The issued view carries the per-key\naccepted-row read beside its instance-pinned rows. It chooses\nthe generation, whose horizon is the bearer's expiry, persists evidence whose permissions are the set it signs and whose one source is\nthat row, `{ space, bucket: \"cotal_actors_<space>\", key: \"actor.<owner>.<actor>.<lifecycleUid>\" }`,\nreleases it, and writes the accepted row, all before it returns the JWT. The accepted token is the\nfirst 32 lowercase hex characters of SHA-256 over `\"cotal.accepted.v1\\0\"` followed by the\nconnection's inbox nonce: the client chose the nonce and derives the token from it, and no token is\nread from a request body. The source is live while the auth service's actor ledger holds a row for\nthat owner and actor carrying that lifecycle UID; a revoked row, or a re-grant under another UID, is\na dead source at the next resolution. Only the auth service attests this shape; every other host\nrefuses it as a coordinate it cannot attest. A reconnect under the same nonce finds the existing\naccepted row. When the row names the same triple, the generation is before its horizon, and the\nceiling being minted is byte-identical to the recorded evidence, the callout renews that generation; otherwise it refuses the connect, and the\nclient adopts a fresh generation only through a new connection under a new nonce. A managed\nissuance's single source is the child's own actor row and lifecycle, not its parent. A managed seat\nmissing either eligibility predicate keeps the legacy manager-caller mint for ordinary commands,\nand `run-start` refuses with `permission-denied`. Without a signed `run` capability the broker\nrefuses the publish. With signed `run` but no eligible parent, the manager returns\n`ai.cotal.ep.unbound-caller-authority`. Failed\nissuance never retries on the legacy rail. The `agent` profile and every other view keep that rail.\n\n**Platform-owned user supervisor.** A trusted host composition MAY issue the closed manager-service\nregistration material for one ordinary derived owner without that owner's IdP proof. This is an\nin-process administrative door, not a user-token exchange. Its recorded assignment MUST name one\nowner, space, account, manager instance, lifecycle UID, revision and finite expiry, and MUST carry\nonly `supervise`. The host MUST authenticate platform-admin authority and re-read the assignment\non every request. The worker's door MUST be bound to that owner and refuse another owner by name.\nIt MUST NOT export an administrative bearer, signer, mint surface, human exchange or cross-owner\nenrollment. The existing fixed manager actors, public nkeys and registration proof remain unchanged.\n\nThe host MUST cap every returned credential at the assignment expiry and refuse issuance after the\nassignment ends. The supervisor and executor registration ceilings MUST be persisted through the\nexisting issued evidence and accepted-row stores before material is returned, with expiry as their\nrecorded lifetime and as their generation's horizon. The recorded permission set MUST be byte-identical to the native permission set\nsigned by the authority plane at issuance and every renewal. Renewal MUST resolve and confirm the\noriginal ceiling and MUST NOT widen it. These JWTs are signed by the authority plane, not the\nuser-token callout. These registration\ncredentials hold no caller rail, so no generation claim is added to their request subjects. The\nother standing duties retain their endpoint gate and credential-family protocol.\n\nWhen the platform ends an assignment, the host MUST record it `ended` and then end its issuance at\nthe authority plane. Ending retires the instance's manager gate (`retired`, op kind `retirement`)\nand retires the issued supervisor and executor generations. Both are terminal rows. From then on,\nevery door that accepts this material MUST refuse it by name, even when the material has not\nexpired. Stock registration refuses on the retired gate. Prepare, activate, `renew` and\n`renewStandingBundle` refuse on the retired generation, read on every call before anything is\nsigned, so a stale host read that still reports the assignment `assigned` reopens nothing. The\ndoor reports `platform supervisor assignment for owner <owner> has ended`. The material's own\nbroker connection lives until its capped expiry: its gate row is writable under its own grant, so\na client that bypasses stock registration can still rewrite that one row. Live eviction remains the\nhost's retirement barrier.\n\n**Compatibility.** A command whose semantics require the binding (this revision: `run-start`\nand `run-cancel`, §14.8, and `run-start-keyed` and `run-submission-status`, §14) MUST refuse a legacy-rail request\nwith `permission-denied` carrying the detail kind\n`ai.cotal.ep.unbound-caller-authority` naming the caller triple, never route it through the\nhost's own authority. The signerless resume and answer restrictions in §14.8 also apply, including\nthe managed-seat legacy answer exception. Commands without these restrictions serve both rails. Origin (that a request on\na generation-pinned subject was published by the grant holder) is a property of the grant set,\nnot of this section: no peer-held profile pairs a write with a raw stream read on one stream, and\nmediated reads remain the remedy.\n\n### 13.16 Delegated user intent\n\nA host platform that runs a `platform-control` service view MAY let that view's manager (the\nholder) execute one launch or one retirement that a signed-in user asked for, while the intent and\nthe resulting agent stay the user's. This subsection adds no exchange view, profile, holder grant or\nstanding delegation, and changes no other clause. A host that does not implement the\n`platform-control` service view, or holds no intent store, MUST refuse both requests below as\n`unimplemented`, and stock dispatch MUST refuse both kinds as `unimplemented`.\n\n**Admission.** A user admits an intent with one closed `delegated-user-intent` request on the host's\nauthenticated human route, the transport the `manager-service` typed requests use. The host MUST\nverify the user's IdP token, derive the owner from the verified subject as it does for a signed-in\nhuman, and read the named actor's ledger row fresh; the row MUST carry `spawn`. The host MUST NOT\nstore, forward or record the token, and MUST NOT read, require, synthesize or write `supervise`. The\nrequest carries the space, the assigned account public key, the user's actor, one platform control\ninstance id, a request id, and one operation: `launch` with one managed-agent enrollment target\nminus its token digest, or `retire` with one `{ owner, actor, lifecycleUid }`. An unknown field,\nincluding an owner, IdP token, scope, serve epoch or token digest, MUST be refused as `bad-request`\nwith no effect. For a launch, the host MUST read the account's platform-control assignment and that\ninstance's manager gate fresh and refuse unless the assignment is `assigned` for this account and\nnames that instance and the gate is open under the platform serve principal, and the requested scope and channel lists MUST lie within\nthe user's actor row under the managed-agent envelope rule. For a retirement, the target owner MUST\nequal the derived owner, and the target lifecycle MUST be one that the host's own record shows a\ndelegated launch on that instance produced and enrolled, for a launch target whose actor equals the\nretirement target's actor; the host MUST compare the launch's target actor, never the user actor\nthat admitted the launch. Any other lifecycle MUST be refused. The host generates\nthe intent id from at least 128 bits of entropy, never from caller input. It binds the account, the\ninstance id, the assignment's lifecycle UID and revision, the gate's process epoch (null for a\nretirement whose launching holder is gone), the one target, the user's principal `<owner>.<actor>`\nas parent, and an expiry at most 300 seconds ahead, and creates the record create-only.\n\n**Execution.** The holder executes an intent with one closed\n`manager-delegated-user-intent-execution` request on the host platform's own route for that holder;\nthe `platform-control` envelope does not carry this kind and refuses it as an unknown kind. The\nrequest names the intent id, the space, the fixed `cli` actor constant that keys the registration\nproof, the account, the assignment revision, the instance id, the manager lifecycle UID, the serve\nepoch, the registration proof, the identities, and one target: the launch target's actor with the\nSHA-256 digest of an actor token the holder generated, or the retirement's `{ owner, actor,\nlifecycleUid }`. The host MUST read the record fresh and refuse as `failed-precondition` an absent\nrecord, an admitted record past its expiry, and a consumed record unless the request is a retry of\nthe execution that consumed it (below). It MUST refuse as `permission-denied` any difference from\nthe record in account, instance id, manager lifecycle UID, assignment revision, operation, serve\nepoch or target. It MUST re-read the assignment and refuse as `permission-denied` one that is\nabsent, revoked, or differs from the record in space, account, instance id, manager lifecycle UID or\nassignment revision. It MUST re-read the gate, refuse a gate whose principal is not the platform\nserve principal, refuse a gate epoch other than the request's as `conflict`, and require the\nhost-keyed current registration proof. Every check completes before any effect. The host then MUST\nCAS the record from `admitted` to `consumed` at the revision it read, and that same write MUST pin\nthe execution: the request id, the serve epoch, the lifecycle UID (host-selected before the CAS for\na launch, the target's for a retirement), the launch's token digest or the retirement's\noperation id, and the host incarnation `{ instanceId, processEpoch }` that executes it. A lost CAS is `conflict` and nothing is enrolled or retired. Because the reads are not\nfences (§13.1), the host MUST repeat the assignment and gate checks for a launch after the CAS and\nbefore any effect, and on a refusal MUST compensate the launch (below) before it ends the record\n`aborted`; a change that lands after that second read is ordered after the execution. An intent\nexecutes at most once and confers nothing after it executes.\n\n**Recovery.** From the CAS on, the host owns the pinned execution, whoever presented it. It MUST\ndrive every consumed record to one outcome, `enrolled`, `retired` or `aborted`, at the pinned\nlifecycle UID, including after a restart or a lost answer. For a launch, the host's first effect\nafter the post-CAS checks MUST be the issuance activation of the alias at the pinned lifecycle UID\n(§13.1), before any ledger row or durable, so that UID has an active head and an open issuance gate\nbefore anything is granted under it. Every launch that ends without `enrolled` after its consuming\nCAS MUST be compensated before it is marked `aborted`, whichever flight observed the refusal,\nbecause a flight that resumes the execution cannot tell whether an earlier flight began the\nactivation: the retirement sequence below at that UID, with that UID's activation completed or\nadopted immediately before the terminal barrier. Before that activation the compensator MUST read\nthe head and the issuance gate at that UID. Once a retirement there has begun, because the head is\nretiring or retired at that UID or the gate is frozen or retired by `managedRetirementOpId` of that\nUID, the compensator MUST NOT run or adopt an activation and MUST go to the terminal barrier, which\nresumes that operation from its durable intent.\nOnly the barrier's answer that the lifecycle is retired at that UID is terminal confirmation; a\nnot-started answer MUST NOT be read as one. When that activation is refused because the alias is\nactive or retiring at another UID, the record MUST keep no outcome and the compensation MUST be\nretried. A request\nwhose request id and serve epoch, and a launch's token digest, equal the pin is a retry of that\nexecution: it passes the same checks except the consumed state, writes no second CAS, and MUST\nreceive that execution's answer. The alias stays held until the record has an outcome, and after a\nsweeper's claim until the release below.\nThe host MUST run each execution in one in-process flight keyed by the intent id, and a retry MUST\njoin that flight or read the record's outcome; a retry MUST NOT run the post-CAS checks, the\nenrollment writer or the retirement sequence itself. Every record write after the consuming CAS\nMUST be a revision-pinned CAS, and a flight MUST answer only from an outcome its own write set or\nfrom the outcome it reads after that write lost, never with material it did not commit. Recovery\nfollows the executor and sweeper roles of §13.7. Only the pinned incarnation is the executor, and\nonly the executor MAY run the enrollment writer for the record. Any other incarnation, including\nthe same instance after a restart advanced its process epoch, is a sweeper. A sweeper MAY act only\non a consumed record with no outcome whose executor it believes gone, because that instance's\nserving issuance gate is absent, not open or at another process epoch. It MUST first claim the\nrecord with a revision-pinned CAS that names its own incarnation and changes nothing else, and\nMAY then take only the terminal edge that removes authority: the compensation above, then\n`aborted`, for a launch, or the retirement sequence below, then `retired`, for a retirement. The\nsequence's terminal barrier freezes the issuance gate at that UID before it retires the lifecycle\n(§13.1), so an executor that a wrong belief left running can mint nothing there and cannot set the\noutcome. A consumed record holds its target alias `(owner, actor)` from the consuming CAS, and an\noutcome its executor writes releases it. After a sweeper's claim the alias MUST stay held after the\noutcome until the executor's own flight, having stopped before any further effect and revoked any\ngrant at the pinned UID, records the release, or until an operator releases it by hand; no door\nreleases it. Before each effect and before its outcome write, the executor MUST re-read the record\nand stop on a claim it did not write. While an alias is held, the host MUST refuse a launch\nadmission for it and MUST refuse, from either enrollment door, any enrollment of it other than the\nholding execution's own, as `failed-precondition` with no write.\n\n**Ownership.** A delegated launch MUST be enrolled under the record's owner with the record's\nparent, through the same writer, managed-agent envelope walk, lifecycle-keyed durables and\nmembership the host uses for that user's own managed-agent enrollment, with the host selecting the\nlifecycle UID. It MUST NOT be enrolled under a platform owner token or any owner other than the\nrecord's, and the manager MUST refuse material naming another owner. The holder is not on the\nagent's delegation chain and gains no ledger row, scope or grant from the launch.\n\n**Retirement.** A delegated retirement runs in order: revoke the managed grant at the target\nlifecycle UID only and complete the resumable release with that UID unchanged; close the provider\nhandle the host's runtime record holds for that UID, holding the alias while that record is\n`create-unknown`; run the auth-owned terminal barrier with `managedRetirementOpId(lifecycleUid)`\nthrough the same operation the host's managed retirement door runs; free the alias only after\nterminal confirmation. The launching holder is gone when its assignment is absent, revoked or at\nanother revision, its gate is not open, or its gate epoch is not the launch's. A retirement admitted\nwhile the launching holder is gone is bound to no live epoch, and the host MUST execute it itself\nthrough the same sequence; a retirement bound to a holder that is gone before it executes expires\nunexecuted. Once a holder's execution has consumed a record, the host MUST finish the sequence\nwhether or not the holder remains. A failed or uncertain step keeps the alias held, and a retry is\nthe same operation.\n\n**What stays.** Under the `platform-control` view itself the holder still enrolls, retires,\nvalidates and authorizes only same-owner descendants, and a `u_` principal's spawn request or admin\nauthorization against a platform manager is refused as before. A spawn the holder starts without a\nconsumed intent is not delegated and gains nothing from this subsection. A delegated agent MUST NOT\nbe restarted or launched again from a consumed intent. A host MAY support rebinding the same child\nafter a holder restart through §13.18. This does not authorize another enrollment or handoff.\n\n### 13.17 Managed lifecycle handoff\n\nThis section is additive. It covers one case: a managed\nagent already enrolled through the §13.1 managed-agent enrollment operation, whose child runs where\nthe enrolling manager's filesystem is not visible (a sandbox, a container, another host).\n\n**One enrollment.** The child MUST NOT request enrollment, agent provisioning, or an enrollment\nredeem, and MUST NOT mint an actor token or a lifecycle UID. It presents the lifecycle UID the host\nselected at enrollment. A launch that needs any other UID or token is a new enrollment, not a\nhandoff.\n\n**Custody.** The raw actor token stays in the custody of the manager that generated it until that\nmanager releases it to the lifecycle's own child, and only to that child. The manager MUST NOT send\nit to the host or to any party other than the runtime transport that delivers it into that child,\nand the host's ledger keeps only its SHA-256 digest. The manager MUST NOT copy, link, or name any\nfile from its own workspace, secret store, launch material, or temporary directory into the child.\n\n**The handoff.** The manager releases one closed handoff document, `kind`\n`cotal-managed-handoff/v1`, carrying by value: `space`, `owner`, `actor`, `lifecycleUid`, `server`,\n`tlsRequired`, `authProvider`, `idp { url, issuer, audience }`, `exchangeUrl` (the enrollment's pinned\nexchange base), `sentinelCreds`, `actorToken`, `subscribe`, `allowSubscribe`, `allowPublish`, and an\noptional `policy { events: \"required\" }`. It MUST NOT carry a signing seed or key, an issuer or\ncallout record, the auth service's loopback capability, the owner-derivation secret, a provisioner,\ndeprovisioner, delivery, membership, supervisor, or other manager credential, a control token, or a\npath on the manager's filesystem. A reader MUST refuse an unknown field. The runtime delivers the\ndocument into the child as one private (0600) file named by `COTAL_MANAGED_HANDOFF_FILE`, never in\nargv or in an inherited environment value, alongside `COTAL_MANAGER_INSTANCE` naming the launching\nmanager. The child's entry point MUST read the file into memory,\nremove it, and drop the variable before it does anything else, including parsing or refusing its\nown arguments, printing help, loading extensions, or refusing an unsupported runtime version, so\nevery outcome leaves no file. It MUST NOT forward the variable or the file into any process it starts.\n\n**Refusal before any plane.** The runtime passes the expected `space`, `owner`, `actor`, and\n`lifecycleUid` beside the file and sets `COTAL_MANAGER_INSTANCE` to the launching manager's\ninstance id. The child MUST refuse, before any broker connection and before any exchange request,\nwhen `COTAL_MANAGER_INSTANCE` is absent (`COTAL_MANAGED_HANDOFF_FILE requires\nCOTAL_MANAGER_INSTANCE`) or malformed, or when the handoff's values differ from them or the\ndocument is malformed. A newer CLI child under an older manager or runtime that omits\n`COTAL_MANAGER_INSTANCE` therefore refuses every delegated launch, so managers and the CLI must be\nupgraded together. A refusal MUST NOT echo the document's contents.\n\n**Launch choices.** The manager MUST refuse, before enrollment, a spawn choice that only its own host\ncan honour, such as resuming a session held on that host, a working directory on its filesystem, or\na tool server it runs. Such a choice is never dropped silently.\n\n**Exchange.** The child obtains bearers only through the existing pinned HTTPS agent-bearer exchange\nat `exchangeUrl`, presenting the raw actor token. The service matches its SHA-256 digest against the\nledger as for any managed agent. Nothing about the exchange changes.\n\n**Readiness.** Readiness is observed from mesh presence of the exact principal and incarnation, as\nfor any managed launch. A runtime create whose acknowledgement is lost or ambiguous MUST leave the\nlaunch held and reported as uncertain. It MUST NOT be reported as exited without an observed exit or\nclose, and MUST NOT be retried into a second create, enrollment, or handoff for that lifecycle. A\nprovider answer that no resource exists is not an observed exit or close. A lifecycle is handed off\nat most once.\n\n**Fenced close.** The child's runtime resource is keyed by lifecycle: `cotal-` followed by the first\n32 lowercase hex characters of the SHA-256 of the UTF-8 bytes of the compact JSON array\n`[\"<space>\",\"<owner>\",\"<actor>\",\"<lifecycleUid>\"]`, with no whitespace. For space `s2420`, owner\n`u_aaaaaaaaaaaaaaaaaaaaaaaaaa`, actor `probe` and lifecycle UID `aaaaaaaaaaaaaaaaaaaaaaaaaa` the key is\n`cotal-ffa44aae523faeee4ab7689a699b392e`. A close by that key completes only when no create for that\nlifecycle can still materialize: the create was answered before the close, or the close fences the\nkey so a later create is refused. Until then the close stays pending and the launch is not exited.\nA runtime MAY issue the create as a durable provider operation keyed by that key and close the\nresource through the identifier the provider returned in its authenticated response to that create,\nkept in a durable record the host can read without the enrolling manager. Only that response binds\nan identifier to the key: an identifier derived from the key, or found by name or by listing\nresources, MUST NOT be closed or adopted as the lifecycle's resource. While the create's response is\nunknown, no identifier is bound, the launch stays held as under Readiness, and a close completes only\nas above.\n\n**Retirement.** A handed-off lifecycle retires only through the existing managed path, in this order:\nthe host-owned prepare-retirement for the UID-exact target with the operation id\n`managedRetirementOpId(lifecycleUid)`; the fenced close of the child's runtime resource through the\nhandle known for that lifecycle; then the auth-owned terminal barrier with the same operation id.\nAfter the enrolling manager is gone, the host runs the same three steps itself, ending at the managed\nretirement door. There is no participant stop kind and no second retirement protocol, and no runtime\nclose or adopt may be keyed on the agent name alone. A runtime MAY host a handed-off child only where\nthe host can perform the fenced close by lifecycle without the enrolling manager. A failed or\nuncertain step keeps the alias held. A manager preservation cut that holds a handed-off lifecycle is\nrefused before any child stops because the local resume path cannot reconstruct it. Optional\nsame-child recovery under §13.18 is separate from that cut. A manager stop after a refused cut\nretires that lifecycle through these steps.\n\n**Owner form.** A handoff serves whatever owner the enrollment returned. It neither requires nor\nexcludes any owner form.\n\n### 13.18 Delegated child recovery\n\nThis optional contract lets the same registered manager instance regain control of an existing\nchild from a §13.16 user intent after its manager process is lost. It does not grant a new launch,\nmove the child, or transfer authority to another instance or assignment. A host or runtime without\nthis support MUST refuse recovery. It MUST NOT ignore recovery fields and execute an ordinary\nlaunch instead. Declaring the types or accepting a document is not runtime support.\n\n**Preparation.** A supporting host MAY accept `recoveryPlan` inside the launch `execute` object of\n`manager-delegated-user-intent-execution`. It contains `runtimeKind`, `launch`,\n`localStoreBindingDigest` and `localStoreIdentityDigest`. `launch` contains `agent`, `events` and\n`sourceDigest`, with optional `model` and `variant`. It carries no prompt, private file path,\ncredential, owner assertion or provider identifier. The ordinary request and target keep their\nexisting validation. The host MUST derive the owner, parent, registration and assignment from its\ncurrent authority, not from the plan.\n\nThe same consuming CAS that pins the original execution MUST retain an immutable descriptor:\n`{ v: 1, intentId, origin, target, runtimeKind, runtimeKey, launchIdentity, authorityDigest,\nlocalStoreBindingDigest, localStoreIdentityDigest }`. `target` is `{ owner, actor, lifecycleUid }`.\n`origin` binds `space`, `accountPublicKey`, `managerInstanceId`, `managerLifecycleUid`,\n`assignmentRevision`, `enrollmentRegistrationRevision`, `enrollmentRegistrationDigest`,\n`enrollmentServeEpoch`, `intentId` and `target`. The runtime key is the §13.17 lifecycle key.\n`launchIdentity` retains the launch fields and optional role, plus `spawner` and `authorityParent`.\nFor this user-intent path, both principals MUST equal the original user's parent, not the platform\nholder. The descriptor cannot be installed after enrollment as an independent write. A consumed\nor enrolled record missing its descriptor or later preparation evidence MUST remain a visible\nhold. The §13.16 executor and sweeper rules still govern incomplete enrollment.\n\n**Custody and identity.** Before provider dispatch, the host MUST confirm the manager persisted its\nlocal token and sentinel in the assigned durable store. Proof fields are digests only:\n`storeBindingDigest`, `storeIdentityDigest`, `actorTokenDigest` and `sentinelDigest`. The original\nsentinel digest is pinned with the enrollment response. A changed store, absent material or\nincompatible authority MUST hold recovery; it cannot trigger initialization, reminting or copying\nanother manager's credentials. Recovery changes none of §13.17's custody rules.\n\nThe runtime MUST retain a protected observation of the child's original execution identity beside\nthe authenticated create response. Rebinding requires a fresh observation of that same execution.\nA resource identifier, roster presence, copied nonce or resource listing alone is insufficient.\nA changed child or guest incarnation MUST be refused. A provider without verifiable same-child\nidentity cannot enable recovery. No rebind may call create, enrollment or handoff again.\n\n**Transport.** Requests use the separate closed `manager-delegated-recovery` family on the host's\nholder route, not an inner `platform-control` request. The envelope contains `v: 1`, `kind`,\n`actor: \"cli\"`, `space`, `accountPublicKey`, `assignmentRevision`, `instanceId`,\n`managerLifecycleUid`, `currentRegistrationRevision`, `serveEpoch`, `registrationProof`,\n`requestId`, the five public `identities`, `operation` and `body`. The existing manager envelope\nvalidator applies, including the `sha256:` registration-proof prefix, nkey and lifecycle grammars.\nThe operation body is closed:\n\n| Operation | Body |\n| --- | --- |\n| `confirm` | `intentId`, `target`, `expectedIntentRevision`, `localProof` |\n| `scan` | Empty, or `scanBinding` and `cursor` together |\n| `claim` | `intentId`, `target`, `expectedRecoveryRevision`, `expectedOrigin`, `attemptId`, `scanBinding` |\n| `settle` | `claimId`, `expectedRecoveryRevision`, `settleId`, and either `observation: \"bound\"` with `executionIdentityDigest`, or `observation: \"held\"` with `reasonCode` |\n| `finish` | `scanBinding`, `finishId`, `expectedScopeRevision` |\n| `watch` | `afterRevision` |\n\nRevisions, epochs and counts are nonnegative safe integers. Scan, claim, attempt, settlement and\nfinish identifiers use the lifecycle-token grammar; `requestId` keeps the manager envelope's\nidempotency-token grammar. Content digests are 64 lowercase hexadecimal characters, distinct from\nthe prefixed registration proof. Unknown fields,\nraw credentials and inconsistent target or scope bindings MUST be refused before effects.\n\nEvery reply echoes the envelope's version, kind, space, account, assignment, instance, manager\nlifecycle, registration revision, epoch and request id, plus the operation and `ok`. A success\ncontains only `result`; a refusal contains only `error { code, reasonCode? }`. Results are closed:\n`confirm` returns the intent, target, new revisions and `prepared: true`; `scan` returns its binding,\nrecords, nullable next cursor and completion flag; `claim` returns its claim id, attempt id, record\nand claim epoch; `settle` returns its claim id, settle id, revision and observation; `finish` returns\nits finish id, scan id, scope revision and `admission: \"open\"`; `watch` returns a revision and\n`scanInvalidated`. Callers MUST validate the echoed coordinates before using a result.\n\nA recovery record contains `intentId`, `intentRevision`, `recoveryRevision`, `target`, `phase`,\n`descriptor`, `descriptorDigest`, `authority`, `localProof`, `startedAt`, `executionIdentityDigest`\nand `reasonCode`. The last seven fields may be null while evidence is incomplete. Phases are\n`incomplete`, `prepared`, `create-unknown`, `eligible`, `bound`, `retiring` and `terminal`. Eligible\nor bound records require the descriptor, its digest, retained authority, local proof, original\nbirth time and child execution identity. Descriptor and authority digests cover canonical JSON.\nAn authority record keeps the existing retained-authority shape and original user parent. A birth\ntime is a canonical ISO instant, not the successor's startup time. A page holds at most 1024 records;\na retained authority list holds at most 64 entries.\n\n**Inventory and fencing.** A scan binding contains `scanId`, `accountPublicKey`,\n`managerInstanceId`, `managerLifecycleUid`, `assignmentRevision`, `currentRegistrationRevision`,\n`currentServeEpoch`, `sourceRevision`, `memberCount` and `membersDigest`. The digest covers the\ncanonical ordered list of `[intentId, recoveryRevision, descriptorDigest]` triples, including null\ndescriptor digests. A scan MUST close a durable same-instance launch-consumption fence and retain\none immutable membership snapshot atomically with that fence. Every page reads that snapshot.\nThe caller MUST verify the full count and digest and reject duplicate members. An incomplete scan\ncannot certify an empty inventory. Concurrent retirement and enrollment compensation MUST advance\nthe scope revision and invalidate affected scans; retirement cannot be blocked by this fence.\n\nClaims and later writes MUST use durable, revision-checked CAS. Every effect MUST also recheck the\ncurrent registration and assignment. Only the same origin instance, manager lifecycle and assignment\nmay continue under its newly registered epoch. A sibling instance, reassignment, mismatched target\nor stale epoch MUST be refused. Claim and settlement retries are content-bound to their attempt\nand settlement ids. Losing a reply does not permit a new create or release an alias. A successor\nmay replace a prior claim only after authoritative registration fencing and a successful new CAS.\n\n`finish` MUST verify current authority, complete membership and each current disposition before it\nopens launch consumption. No missing, held or newly retiring member may be skipped. Watch messages\nare revision hints, not authority or permission to act on a stale snapshot. Failure or loss of the\nwatch requires a new authority check and scan.\n\n**Manager recovery.** The manager MUST reserve every held alias and reconstruct managed rows only\nfrom verified bound handles, original authority and locally derived secret references. It MUST NOT\nfabricate a local working directory, control endpoint, static credential or restart form. Recovery\nruns before goal terminal inference and run-driver takeover. While held, existing goals retain\ntheir identity and observed state, standing credential renewal continues, and new execution remains\nclosed. Actual deadlines and revocations still apply. Failure to recover cannot retire a live\nchild implicitly. User-intent retirement continues through §13.16; old-epoch terminal grants remain\ninvalid, and a fresh terminal session still requires a supported terminal transport.\n\n### 13.19 Private tool results\n\nThis optional, additive contract permits a verified human to consent to one holder reading a\nmanaged agent's future tool results through the endpoint control surface. It adds no public event\npayload: public `events.<owner>.<actor>` MUST continue to withhold `TOOL_CALL_ARGS` and\n`TOOL_CALL_RESULT`. Tool arguments, transcript scraping, a private HTTP result path and provider\ncredentials in a client or sandbox are outside this contract.\n\n**Activation.** Acceptance of this subsection is not implementation or enablement. A deployment\nMUST NOT enable this path until the auth and host, Core and Manager, connector-core, and browser\ncaller owners have each landed and qualified their part, and a stock release carries those parts.\nA product surface additionally MUST qualify its own freshness and viewer checks. The prerequisites\nof §13.19.4 remain mandatory; without either, the serving commands MUST answer `unavailable`.\nNo numeric revocation bound, immediate cutoff, restart guarantee or per-sign-in cutoff may be\nadvertised without those prerequisites. The informative [design rationale](docs/design/private-tool-results.md)\nretains the owner order and activation checklist.\n\n#### 13.19.1 Authority and records\n\nThe endpoint name is `tool-results`. Its three commands, `tool-result`, `tool-result-consent` and\n`tool-result-revoke`, MUST use `handle` authorization mode. Their schemas MUST be closed, with one\nschema per answer state, and frozen at declaration. Malformed requests and unknown fields MUST be\nrefused as `bad-request` before any effect.\n\n**Human proof and consent.** The host MUST parse `auth_time` and `amr` from the verified IdP token.\nConsent requires `auth_time` in integer seconds, not in the future and at most 300 seconds old,\nand `amr` including a password sign-in. Refresh, device and unmarked sessions MUST be refused as\n`permission-denied`. The host MUST hold the consent signing key. The `consents` signing-anchor role\n(§13.10) is scoped to `tool-results`; a verifier MUST enforce that role and scope. A signed consent\nMUST name one target `(owner, actor, lifecycleUid)` and one holder, an interactive actor principal\nof the same owner, with a window of at most 24 hours. The host MUST record each consent id it signs\ncreate-only. A consent does not confer per-sign-in or per-browser-session control.\n\n**Record families.** Consent issuance records and per-consent revocation records are distinct from\nthe connector's bounded result journal. A revocation row MUST be create-only in the space auth\nstore and retained until the consent's expiry plus the store's marker retention. Revocation MUST\ndistinguish known, refused and unknown outcomes. An unknown outcome MUST be read back before any\nretry and MUST NOT be repeated automatically. The journal MUST follow §13.19.2, §13.19.3 and\n§13.19.5; it is not a public event log.\n\n**Serving issuance.** The closed `manager-managed-agent-tool-result-serving` request kind carries\nonly operations `issue` and `renew` on the existing managed-agent manager-authority envelope,\nincluding its serve epoch. The host MUST require scope `supervise`, verify the current Manager\nregistration, and check the ledger to require that the target is a current managed child of that\nManager. A failed authority check MUST be refused as `permission-denied`. Resume is not supported.\nThe host MUST register the serving instance and return its grant, serving credential and the\n§13.19.4 revocation snapshot. The Manager MUST install the material as a 0600 file named by a\ngeneric launch-material field. Connectors MUST use that generic field, without Manager-specific\ncode. Retirement MUST also deregister the instance. Renewal MUST occur before expiry; installation\nor renewal failure MUST remove the serving material rather than continue with failed material.\n\n**Caller view.** Redemption MUST verify the consent, require presenter equality with its holder,\ncheck the current durable revocation record and target lifecycle state, and read the current\nserving registration. The caller credential MUST be limited to the three commands on that one\ninstance, the stock `describe` of that same instance, and the caller's own reply subject. The\nredemption MUST bind one space, account, instance and epoch, and its response MUST name the space,\ninstance and epoch. Consent-bound caller authority MUST be checked against current durable\nrevocation and target lifecycle state at redemption and again at every native callout or\nconnection issuance, including each reconnect. A credential minted before revocation MUST NOT\npermit a new connection after that revocation. Native issuance records alone do not implement\nthis consent view or its current-state check. Invalid consent, wrong presenter, revoked consent or\nan inactive target lifecycle MUST be refused as `permission-denied`; unavailable authority state\nMUST be refused as `unavailable`.\n\n#### 13.19.2 Capture frontier\n\nAfter verifying a consent, the connector MUST sample a durable source position `P` with the\nsource's end operation. Sampling `P` is the linearization point. Every record already in the source\nat that call MUST lie at or before `P`, including unread records, a read in progress, replay after\na restart and ordinary backlog. The reference source operation is `DurableSource.end()`.\n\nThe connector MUST record the holder's consent life generation when the consent arrives and\ncompare it again after every asynchronous step, including verification, the end call and frontier\nplacement, and immediately before committing the consent. Revoke or replacement MUST advance that\ngeneration. An in-flight activation for an old generation MUST refuse and commit nothing. Token\nregistration and pre-capture classification MUST be serialized with that commit. An unresolved\nfrontier MUST grant no eligibility. Expiry and snapshot checks do not replace this lifetime fence.\n\nThe emitter MUST place `P` against each read using source-only position comparison, through a\nfrontier operation equivalent to the reference emitter's `queueTerminal` placement. The reference\naddition is `queueFrontier`, using the existing `boundary` comparison. A START record is eligible\nfor that consent only when its canonical durable position lies after `P`; physical tool execution\ntime MUST NOT determine eligibility. If `P` cannot be placed, the connector MUST drop the frontier\nand refuse the consent as `failed-precondition`. A source whose end operation answers later than\nthe call may only exclude more calls. A RESULT MUST be captured only into an entry its START\ncreated; a RESULT MUST NOT create an entry.\n\n#### 13.19.3 Audience\n\nAt START, each journal entry MUST record the fixed set of consent ids eligible for it. That set\nMUST NOT grow. A lookup MUST NOT return the entry to holder `h` unless an id in its set remains\nactive, unexpired and unrevoked and names `h`. Revoking, expiring or withdrawing consent `c` MUST remove\n`c` from every entry; an entry with an empty set MUST be deleted. Replacing a holder's consent MUST\nrevoke the old consent before applying the new frontier, discarding results visible only through\nthe old consent. A newly consented holder MUST NOT read results captured before its own frontier.\n\n#### 13.19.4 Revocation bound\n\nBoth prerequisites below MUST hold before the serving commands can be available:\n\n1. A sealed, owner-reviewed, bounded read MUST obtain the complete revocation snapshot for the\n target from the stream leader, through a watermark taken after `T0`. Native issuance-row write\n authority MUST NOT be treated as consumer-create or stream-read authority. The snapshot read\n authority MUST be granted and reviewed separately.\n2. A bound `delta` on connector-to-host clock difference MUST be established and enforced. A\n configured token tolerance is not evidence of measured or enforced skew.\n\nThe host MUST take `T0` from its clock, in milliseconds, before the snapshot read starts, read the\ncomplete snapshot under prerequisite 1, and set the serving credential expiry to\n`floor(T0 / 1000) + 600` seconds. Signing, writing and installing MUST NOT extend that expiry. If\nsigning happens more than 30 seconds after `T0` or the expiry has passed, issuance MUST refuse as\n`unavailable` and write nothing.\n\nImmediately before answering a lookup or committing a consent, the connector MUST read the\ninstalled file and require that its own clock is before expiry and the consent id is absent from\nthe snapshot. Otherwise it MUST revoke locally under §13.19.3 and refuse release. An expired file\nMUST be refused as `expired`; a snapshot-revoked consent MUST be refused as `permission-denied`.\n\nLet a revocation be acknowledged at host time `Tr`. If `T0 > Tr`, the snapshot MUST include it and\nevery release MUST refuse it. If `T0 <= Tr`, expiry is at most `Tr + 600` seconds, so with\n`|connectorNow - hostNow| <= delta`, no release may occur at host time `Tr + 600 + delta` or later\n(`Tr` and `delta` expressed in seconds for this bound).\n\nA restarted connector may re-apply a revoked consent inside that window. An already connected\ncaller keeps its transport until eviction or its own credential expiry. Eviction can have an\nunknown outcome and acts on the whole principal. Neither case permits a result past the bound.\nThe host and the Manager installing the file are trusted. This bound is not an immediate cutoff,\na restart non-restoration guarantee or a per-sign-in cutoff.\n\n#### 13.19.5 Receiver answers\n\nBefore invoking, the caller MUST run the stock instance-addressed `describe` on the one redeemed\ninstance and verify its contracts and digests. It MUST refuse an answer from another instance or\nan epoch different from the redemption. This bootstrap requires the narrow, separately reviewed\nsame-instance `describe` grant in §13.19.1. It MUST NOT use class discovery, scatter or a homemade\ncontract. Stock `describe` carries no `bind`, because it produces the binding (§13.3).\n\nEvery subsequent private command MUST carry `bind` naming the redemption's instance and epoch.\nA missing `bind` MUST be refused as `bad-request` before the handler touches the journal. The\n§13.3 pre-effect incarnation check MUST refuse another epoch of the same instance as `expired`\nbefore any handler runs. The caller MUST learn the instance and epoch only from redemption. A\nbrowser caller MUST be Node-free, MUST NOT scatter, guess or silently change the target or epoch,\nand MUST NOT resend after an accepted or unknown effect. It MUST drop its binding on account,\nspace or epoch change.\n\n`tool-result` MUST answer one of these closed states:\n\n| State | Fields beyond the state |\n| --- | --- |\n| `available` | Thread id, tool call id, content, truncated flag, byte count, error flag and capture time |\n| `pending` | Thread id and tool call id |\n| `not-shared`, `missing`, `expired` | None |\n\nThe `expired` answer state belongs to a successful `tool-result` reply. It is distinct from the\n`expired` refusal code for an expired serving file (§13.19.4) or a mismatched epoch (§13.3).\n\nEmpty or falsy content such as `\"\"`, `\"0\"`, `\"false\"` and `\"null\"` MUST be treated as a result.\nContent MUST be inert text bounded to 64 KiB of UTF-8. The journal MUST hold at most 256 entries,\nretain each for at most one hour and MUST NOT store arguments.\n\n---\n\n## 14. Workflow runs (v0.5)\n\n### Keyed submission prerequisite\n\n`run-start-keyed` is a distinct registered command. Its envelope ID is the immutable submission\nidentity. `run-submission-status` accepts only a submission ID and derives its namespace from\nthe authenticated caller owner, actor and lifecycle UID. Both require issued reach, pinned\ncontracts and an exact-instance/epoch bind. Old credentials gain no reach by reconnecting.\nLegacy `run-start` remains unchanged and is never an automatic fallback.\nA keyed request's `deadlineMs` is at most 30000. A host refuses a larger value as `bad-request`\nbefore any read or binding. This maximum is a request budget. It does not show that a publish\nhas settled or that a credential is still valid. The process that receives the request measures\nthe budget on its own monotonic clock from its own receive sample; that reading is never\npersisted, sent or compared with another process's clock. The caller's authority expiry is\nchecked separately on the wall clock. A request that outlives a credential still has an unknown\noutcome.\n\nThe admission authority writes one `submission.v1.<endpointToken>.<callerDigest>.<id>` binding\nin the existing write-once admission store. `callerDigest` is the canonical SHA-256 digest of\n`[owner,actor,lifecycleUid]` without its `sha256:` prefix. The closed value records the caller\ngeneration, semantic fingerprint, accepting instance/epoch, host-minted run ID, frozen\nadmission digest and original callback deadline. That deadline is a wall-clock projection of the\ncallback's window, rounded down. It is a record only: no host enforces or recovers from it. Bindings are permanent, including terminal\nruns. Capacity exhaustion refuses new submissions rather than deleting authority history.\nThe manager takes its stopping and launch-capacity refusals, and reserves the launch, before it\nreads or writes the binding, so such a refusal writes nothing. It says nothing about an earlier\nattempt under the same key, which may already be bound, admitted or activated;\n`run-submission-status` takes no launch reservation and reads it. A launch that still fails after admission\nleaves `admitted` with no run, and nothing in this prerequisite launches or repairs it.\n\nInitial authorization and evidence validation precedes the binding CAS. Before each admission\nattempt, the original binding winner rechecks that same authority. These fallible freshness\nreads may leave permanent binding-only reconciliation debt after the binding exists. They\nnever replace its frozen admission. Only that winner may create its admission, with at most\nthree classified transient attempts in the original callback deadline and authority window.\nThe admission bytes, timestamp, ceiling and\nprovenance remain fixed. A failed create is classified by a leader read of that exact admission\nkey. Matching bytes recover success, authoritative absence permits another same-callback\nattempt, and unreadable or conflicting state holds. The timer bounds waiting and starting\nfurther attempts, not broker acceptance of an already-issued publish. Such a publish may land\nlater with the original frozen bytes. No new admission attempt starts after the request budget\nor authority window ends. After admission, the activation check uses only the manager's remaining\nmonotonic request budget, without rechecking the caller's wall-clock expiry. Earlier admission\nabsence never proves that this pending effect cannot land.\nNo later callback, duplicate, restart,\noperator or read repairs a binding-only submission.\n\nStatus reports `unbound`, `binding-only`, `admitted`, `activated` or `indeterminate`, with the\noriginal bound run and callback deadline when available. Absence is observation-time only.\n`activated` means a run status record was observed, including a completed or failed run. It\ndoes not mean currently running or occupying an active lane. Read native `run-status` for\nlifecycle state. Terminal bindings remain permanent and duplicates never launch them again.\nThe scheduler preserves its original reservation and never allocates a replacement run or\nadopts another instance/epoch from these reads. A later repair protocol requires its own fence\nand review. This prerequisite introduces no second scheduler or generic cancellation.\n\nA **workflow run** is one execution of a program in the Cotal workflow language, hosted by a\n**driver** (an endpoint, in the reference deployment the manager daemon) that performs the\nprogram's effects against the mesh and records every one of them in a per-run **step journal**.\nThis section defines the run's wire footprint: the record it is described by, the stream its\njournal travels on, the records its effects file, and the grants its driver holds. The\nlanguage, the journal entry, and the rules of resume, migration and fork are defined in\n[`spec/cotal-lang.md`](spec/cotal-lang.md), which this section incorporates by reference: an\nimplementation of this section MUST implement that document.\n\n### 14.1 Roles and identity\n\nThe **driver** is the one principal that executes a run: it validates and runs the program, calls\nthe effect handler, appends to the journal, and writes the run's records. It is hosted by an\nendpoint, and every §14 key leads with that `<endpoint>` token so a per-endpoint enumeration and a\nretirement drain (§13.1) both work by prefix. A **run id** (`<runId>`, an id token, §13.2) is minted\nby the driver when the run starts, is never caller-supplied, and is **never reused**: re-running a\nprogram from part of a run's history is a **fork**, and a fork is a new run under a new id whose\nrecord names its parent (§14.3). A run has exactly one **authoritative appender** at a time; §14.4\nis what makes that true.\n\nA user-auth run's durable actions MUST use the owner established by its authenticated admission.\nThe trusted host derives the run-stable actor and lifecycle uid from the run id and retains that\nowner on resume. Grant construction and effect dispatch MUST use the same triple. A supplied\nowner token is not admission evidence. The existing static/local path retains its `local` owner.\nThese identity rules do not authorize exporting host mediator or operator credentials to a driver.\n\nA run that names an explicit placement instance gains instance-rail reach on that one instance\nonly: `describe`, `resolve-cwd` and `spawn`, and owner-mode `turn` pinned to the run's own owner.\nA placed seat is mapped only by the instance hosting it, so the host MUST address that seat's turns\nto its placement instance, never the class rail. Static/local issuance adds no instance row when\nthe program has no placement. Auth-service-issued mediators retain their admitted host-instance\nplacement (§14.8), including for an unplaced program; unplaced seats still use the class rail.\nOn that rail a target-unmapped refusal (§13.3) states only that the members a call reached hold no\nmapping, not that the seat is down.\n\nUnanswered pinned-host discovery before submission, with no accepted goal recorded, reports\nthat host unreachable (L4002). Permission and contract refusals retain their own meaning. A\nreply lost after submission remains governed by goal reconciliation.\nA migration keeps the original seat's recorded host through its new binding and later takeover.\nA receiving placement request cannot move that seat or invent a host missing from older records.\nRefusing that placement leaves the kept hand-over available for a later valid spawn.\n\n### 14.2 The language and its version\n\nPrograms, values, primitives, the step key grammar, the input hash, the request id and the entry\nschema are those of [`spec/cotal-lang.md`](spec/cotal-lang.md). The language carries a\n**`languageVersion`**, bumped when a revision changes what a program means (its PRNG, a builtin,\nnumeric behaviour, walker scheduling) and deliberately not the package or wire version; a run pins\nthe version it started under (§14.3) and a resume under another version is refused\n(`spec/cotal-lang.md` §8.4). A wire revision of this document therefore never invalidates an open\nrun, and a language revision never requires one here.\n\n### 14.3 The run record\n\nA run is described by the `run` record kind (§13.7): `run.<endpoint>.<runId>`, `.spec`/`.status`\nsplit, mediated, written by the driver's commit path only.\n\n- **Spec** (create-only, decided once): `{ v: 1, run, pins, createdAt, forkedFrom? }`. `pins` is\n the **resolved pin set** the run started under, `{ seed, startedAt, yieldEvery, stepBudget,\n effectCeiling, languageVersion }` (`spec/cotal-lang.md` §8.3): every one selects which effects run,\n so a resume MUST read them back and bind to them, and MUST refuse a caller value that differs.\n `startedAt` is the run's **logical epoch**, and a resuming host's own clock never moves a\n replayed program. The RESOLVED value is pinned, never the default: a default is a property of the\n interpreter, and the interpreter is the thing that may have changed between attempts. A spec that\n already exists MUST refuse a second start under the same id. A fork (`spec/cotal-lang.md` §11.3)\n is a new run with its own id and its own spec, and the child's spec names its lineage:\n `forkedFrom` is `{ run, step }`, the parent run and the step key the cut excluded, written with\n the spec and absent on a run started fresh. Absence reads as \"lineage unknown\" (a child recorded\n before the field existed), never as \"not a fork\". A later revision that adds a field to the spec\n half does so as its own binding revision, never by rewriting a spec that exists.\n- **Status** (last-value-wins, CAS-written): `{ v: 1, observedSpecRevision, state, holder, epoch,\n fencingToken, journalHigh, at }`. `state` is one of `running`, `released`, `completed`, `failed`,\n and `released` and `failed` are different facts: a failed program has a result and the journal has\n it, a released run has none, because its driver stopped holding it (`spec/cotal-lang.md` §9.2,\n L5012). `holder`, `epoch` and `fencingToken` name the driver that holds the run and the lease\n (§13.6 work pool) it holds it under. `journalHigh` is the highest journal ordinal (§14.4) the run\n is KNOWN to have reached, written at each activation and after each append the driver makes\n while the run is `running`, before that append resolves to the interpreter: it is the one anchor\n OUTSIDE the journal, so a replay whose last ordinal is below it has lost records from the\n journal's tail, which nothing inside the journal can see, and the driver MUST refuse to resume it.\n Interior loss is the journal's own ordinal chain's.\n\n**Turn notices.** A run's `turn` reaches its seat through the hosting manager, and the seat reads\nit with its own self-mode `turn-pending`. The manager MUST publish a turn notice to the seat\nwhenever the set that seat's `turn-pending` would answer changes: on accepting a turn, on its\nyield, cancellation or deadline, and once per seat holding a turn after the boot reconcile. The\nnotice is published by the manager's serve connection on the seat's own reply rail (§13.2), under\nthe reserved nonce `turn-pending-notice-v1`:\n`ep[.v1].reply.manager.<instanceId>.<epoch>.<owner>.<actor>.<uid>[.<generation>].turn-pending-notice-v1`,\non the versioned rail exactly when the seat's credential is an issuance (§13.15). Only that\ninstance's serve credential may publish it, every baseline seat credential may read its own, and\nno new grant exists for it. Its body is `{ \"v\": 1 }` and carries no turn, so a seat MUST treat the\nnotice only as a reason to pull; the pull's answer is the authority. A notice is at-most-once, so\nthe manager MUST repeat it, at most every 5 seconds, while the oldest turn it would serve a seat has\nnot yet been served to that seat by a `turn-pending`. A seat MUST subscribe before its first pull,\nand MUST pull again after a reconnect while it holds a turn, since a lost notice of that turn's\nending is not repeated. A seat MUST NOT\npull on a timer while it is connected and its last pull succeeded, except under a manager whose\n`turn-pending` answer lacks `notices: true`, which predates notices and is pulled every 15 seconds.\nA pull that fails because the manager is unavailable or unanswered MAY be retried at that same\ninterval until one succeeds; a refusal MUST NOT be retried on a timer.\n\n### 14.4 The step journal on the wire\n\nThe journal of a run is carried by the per-space **`WFJ_<space>` stream** (§13.12) on **one subject\nper run**, `cotal.<space>.wfj.<runId>`. An implementation MUST create the stream with limits\nretention, file storage, no `max_age`, and `allow_direct=false`, and MUST NOT let any removal cause\nevict a live run's prefix (§13.12 retention floor). Retirement of a run's journal is by subject\npurge.\n\nEvery message on the subject is one **journal record**, JSON, one of two kinds. Both envelopes are\nCLOSED: a reader MUST refuse a record that carries a field outside the shape below, and MUST refuse\nan unknown `kind`, because a journal is replayed by whoever holds the run next and a field one\nwriter meant and another ignores is a divergence nothing would name:\n\n- **activation**: `{ v: 1, kind: \"activation\", run, n, holder, fencingToken, epoch, replayedTo, at }`,\n the successor's first act, and the only record the runtime layer writes that is not a step.\n- **step**: `{ v: 1, kind: \"step\", run, n, at, entry }`, where `entry` is a language journal entry\n (`spec/cotal-lang.md` §10.1) carried verbatim: the wire layer MUST NOT read inside it. A step is\n appended TWICE, once `pending` before its effect is dispatched and once settled after; a reader\n folds by the entry's key and the last record wins.\n\n`n` is the record's **ordinal** in the run's journal, from 0, and a replay MUST require\n`records[i].n === i`: the chain is the only check that sees a record removed from the middle of a\nsubject, since counting cannot and no anchor at the front can. A writer MUST stamp `run` with the run\nthe subject names; its grant covers exactly one subject (§14.6), which is what enforces it. A reader\nSHOULD refuse a record whose `run` names another run; the reference reader relies on the grant and\ndoes not re-check it.\n\n**The activation barrier.** A run has exactly one authoritative appender at a time, and the STREAM\nis the acceptor: every append MUST carry `Nats-Expected-Last-Subject-Sequence` for the run's own\nsubject, so a publish lands only if the subject is exactly where the publisher believed it was, and\nthere is no read-then-publish window because there is no read. Takeover is replay-then-activate:\n\n1. The successor replays the run subject from the beginning, through a **per-takeover replay\n durable** it creates on the stream (`wfj_<runId>_<takeoverId>`, filtered to the run's subject,\n explicit ack, deliver-all, memory storage) and deletes when done. `<takeoverId>` is an id token\n (§13.2) minted by whoever hands the driver its lease and its journal grant (§14.6), one per\n takeover of a run and never reused for that run; the driver does not choose it, because a consumer\n name is one subject token that no grant pattern covers in part, so it has to be known when the\n grant is minted. The last replayed record's stream sequence is the only authoritative head there\n is (`STREAM.INFO`'s `last_seq` is stream-wide, and its subject filter answers counts, not\n sequences).\n2. Its first act is an **activation record** appended at that expected sequence, and it drives\n nothing before that record lands. Its authority is checked against the activation the journal\n already holds: a lower `fencingToken` is refused (stale lease); an equal token is refused unless\n `holder` AND `epoch` are the same (one process picking its own run back up); a higher token\n activates.\n3. Once the activation lands the subject has advanced, so any append still in flight from the\n superseded driver carries a stale expectation and the server rejects it.\n\nTwo CAS refusals are two different states and MUST NOT be conflated. A refused ACTIVATION means \"my\nreplay is stale\": the successor has driven nothing, the records that beat it are more prefix, and it\nMAY re-replay and activate again while it still holds the lease. A refused APPEND after an\nactivation that won means \"someone else activated\": that driver IS superseded, MUST stop, and MUST\nNOT refresh the sequence and retry, because a retry at the new head is the defect the barrier\nexists to prevent. A driver publishes one entry at a time from one serial queue per run and\nadvances its head only from each acknowledgement; once the bytes have gone out, any outcome without\none poisons the queue and nothing behind it reaches the wire (a record refused before it is sent,\nfor example one that cannot be serialized, fails only itself).\n\nThe journal is a language artifact, and its contents are decided by the language: a driver MUST\nawait the durable append of a `pending` entry before dispatching the effect it names, MUST settle\nthe entry from the handler's outcome, and MUST keep the settling append outside the handler's\nfailure domain, so a refused append is a durability failure (L5010) that stops the run and is never\nrecorded as the effect's failure (`spec/cotal-lang.md` §10.5). A cancelling scope's `cancel.issued`\nrecords whether the driver has discharged the intent against the world; the record states the\nintent and its discharge, and how a driver disposes of a losing arm's live work is a driver policy\nthis revision does not fix.\n\n### 14.5 Answers, notices, migrations\n\nThree record kinds carry the payloads a run's effects file (§13.7 for the grammar and the\nsentences that defend each shape). Their derived id tokens all take one form: **the unpadded\nbase64url of the SHA-256 over the strict RFC 8785 canonical JSON of the named object, 43\ncharacters**, which is an id token by construction. The reference implementation's canonicalizer is the one\n§13.7's `*Digest` fields use.\n\n- **`answer`**, `answer.<endpoint>.<token>.<answerId>`, atomic, create-only: `{ v: 1, token,\n answerId, value?, artifact?, by, at }`, filed BEFORE the checkpoint token is presented; the\n one-use settle fact (§13.6) then NAMES the id it accepted. For a checkpoint a run performed the\n `answerId` on a `resumed` settle is REQUIRED (§13.6 leaves it optional for other checkpoints): a\n run's handler reads the answer under the id the settle names, never by looking for \"the answer to\n this token\", and refuses a resumed settle that names none. `answerId` = the digest id of\n `{ token, by, value: value ?? null, artifact: artifact ?? null }`, so a retry of the same answer\n lands on the same key with the same bytes and two different answers race on the settle, which is\n what the settle is for. `by` is the answerer as the run's own authorization knows them, never the\n presenting principal (the driver, for every answer) and never a field in the answer request. A\n baseline managed seat reaches the answer door only through the self-targeted row above, after the\n manager has matched its exact caller incarnation to the pending relay for this open pause.\n An **amendment** is an answer filed after the pause settled: same key grammar under the token\n the pause settled under, with `supersedes` naming the `answerId` the settle accepted. It is filed\n through the same door and credential pinning as an answer, and nothing is presented, so the pause\n stays settled, the one-use settle is untouched, and the run never reads the record. Its\n `answerId` is minted fresh for each filing (32 random bytes, base64url, the first 43 characters)\n and is never derived from its content: a participant who returns to an earlier position files\n what an earlier filing said, and a content id would make the create-only write take it for a\n retry of that filing and record nothing. A step that is still open, or that settled\n without accepting an answer, has nothing to amend and is refused. The run surface lists a settled\n step's amendments beside its accepted answer in the order the records bucket committed them (each\n record's revision); `at` is the filer's clock and never decides the order. The last one listed is\n the step's current recorded position, and the accepted answer remains what the program acted on.\n A pause in a branch that lost a `race`, or one cancelled after it accepted an answer, settled\n with an answer the program never read: the run surface lists that answer as not acted on and\n names the branch the race took.\n- A held `once` step (`spec/cotal-lang.md` §7.8) is answered like a checkpoint, addressed by its\n step key; the driver presents the hold id (`spec/cotal-lang.md` §7.8) as the token, whatever kind\n the step is, and reads the step's accepted answer and amendments under the same id once it\n settles. The run's pause authority covers that id only while the step is pending with its hold\n bound.\n- **`notice`**, `notice.<endpoint>.<runId>.<addresseeId>.<noticeId>`, split: spec `{ v: 1, run,\n step, addressee, fact, at }` (create-only; `fact` is the language's bounded decision record and\n is checked against its bound BEFORE any record is written), status `{ v: 1, consumedAt, by,\n observedSpecRevision }` (create-only: the consumption is established once, by the turn that\n carried it). `addresseeId` = the digest id of `{ agent }` (the addressee's name); `noticeId` = the\n digest id of `{ requestId, addressee }`, where `requestId` is the `notify` step's request id, so\n one call to N agents files N notices and a re-run after a crash lands on the same ones. A driver\n that performs the addressee's turns MUST render an unconsumed notice ahead of its next turn and\n MUST NOT deliver it as a channel message. The reference driver performs that rendering: its turn\n plane is durable (`spec/cotal-lang.md` §6.5), and a relayed turn carries the addressee's\n unconsumed notices as its rendered context and marks them consumed with the turn's outcome.\n- **`migration`**, `migration.<endpoint>.<runId>.<migrationId>`, split: spec `{ v: 1, run,\n fromHash?, toHash, at, consumedThrough, orphans[], overrides[], actor }` (create-only), status\n `{ v: 1, appliedAt, by, observedSpecRevision }` (create-only). `migrationId` = the digest id of the\n spec without `at`, so a dry walk re-run after a crash files no second migration for one decision.\n `orphans[]` is `{ step, kind, verdict, code? }` per journal entry the new source no longer reaches,\n with the verdicts and refusals of `spec/cotal-lang.md` §11.2; `fromHash` is the caller's claim\n and is absent when not supplied, because the run record carries no program hash to verify it\n against. A migration never rewrites a journal.\n\n### 14.6 Driver grants\n\nGrants are DERIVED (§13.7, §13.9), and a run driver's are minted **per run and per takeover\nattempt**, never per space:\n\n- publish on exactly `cotal.<space>.wfj.<runId>`;\n- create, bind (info, next, ack) and **delete** its own replay durable `wfj_<runId>_<takeoverId>`\n on `WFJ_<space>`, named per takeover because a durable remembers how far it delivered and a\n successor needs the prefix from the top, and because a consumer name is one subject token that no\n pattern covers in part, so the takeover id belongs to the credential;\n- and, as the standing per-kind mediated writer path of §13.9 rather than anything minted per run,\n the commit path for the `run`, `answer`, `notice` and `migration` keys of its own endpoint.\n\nThere is no wildcard form of any of these, on purpose: a space-wide `wfj.>` publish would let one\nrun's driver append to another run's journal, which is not a read leak but a corruption (the other\nrun would replay a step it never took), and the barrier's premise is exactly one authoritative\nappender per subject. The provisioner holds `STREAM.CREATE`/`STREAM.INFO` on `WFJ_<space>` and\ncreates it at space setup; agents never hold `STREAM.CREATE` (§13.12).\n\n### 14.7 Conformance (workflow runs)\n\nA conformant driver (v0.5) MUST:\n\n1. Validate a program against `spec/cotal-lang.md` before running it, and run it with the language\n semantics that document defines, under a pin set resolved once and read back on every resume.\n2. Mint run ids itself and never reuse one; a fork is a new run under a new id.\n3. Append every journal record on the run's own subject under the subject-sequence fence, replay\n before activating, activate under an authorized lease tuple, stop on a refused append after\n activation, and never retry an append at a refreshed head.\n4. Write a `pending` entry durably before dispatching its effect, settle from the handler's outcome,\n and treat a refused append as a durability failure that stops the run rather than as the effect's\n outcome.\n5. Require the ordinal chain and the run id on replay, refuse a replay below the recorded\n `journalHigh`, and refuse to resume without the recorded pins or under a different language\n version.\n6. File answers, notices and migrations under their derived ids, create-only, and render notices\n ahead of the addressee's next turn rather than as channel messages.\n7. Hold only the per-run, per-takeover grant family of §14.6.\n8. Admit every run under §14.8 before launching it, check every channel effect against the\n admitted ceiling and the current revocation state, and never continue a run whose admission is\n missing, unreadable, mismatched or revoked.\n\n### 14.8 Run admission\n\nA hosted run performs channel effects on a caller's behalf. What it may do in channels is the\n**admitted ceiling**: the caller's issued permission ceiling (§13.15) as resolved at admission,\nrecorded once per run, and never widened afterwards.\n\n**The record.** Before the driver is launched and before a successful start reply, the hosting\nendpoint writes `admission.v1.<endpoint>.<runId>` in `cotal_admission_<space>`, create-only,\nunder a one-shot `run-admitter` credential pinned to that one run:\n`{ version: 1, space, endpoint, runId, instanceId, caller, ceiling, provenance, admittedAt }`.\nThe store is write-once per key at the broker (§13.12: one message per subject under `discard:\nnew`, no rollup header, no message delete, no purge), so the admitter's own key row can neither\nreplace the admission nor remove it once written, and a marker, once written, stays.\n`caller` is the admitting request's broker-authenticated caller, generation included; `ceiling`\nis the resolved evidence's `permissions`, verbatim; `provenance` is\n`{ kind: \"issued\", ref, resolvedRevision }` for a hosted admission or\n`{ kind: \"operator\", by, reason }` for a local one (below). A run-start arriving on the legacy\nrail is refused as §13.15 says. On an open mesh, which issues no authority, the endpoint hosts no\nrun. The driver holds no row on this store; the mediator and operator profiles hold its leader-\nserved read only.\n\n**Enforcement.** The trusted host re-reads the admission, leader-served, before every channel\neffect: opening a wait, each fetch on it, each re-read of a recorded match, and a conclave's\nchannel writes. A concrete channel is checked against the ceiling with the §3 matcher: a\npublish requires `chat.<owner>.<actor>.<channel>` under the caller's own triple to be allowed by\n`ceiling.publish`; a read requires every subject `chat.*.*.<channel>` matches to be covered by\n`ceiling.subscribe`. Deny wins; an explicit `none` is deny-all; a generated channel name is\nchecked after it is derived and no wildcard is invented to admit it. `notify` writes agent-\naddressed notices and is not channel publication; spawn and turn keep their separately checked\ndelegated authority.\n\n**Revocation.** `revoked.v1.<endpoint>.<runId>` is the run's revocation marker: create-only,\nidempotent, written under the same `run-admitter` profile, never removed. A revoked run performs\nno further channel effect, its open waits refuse at their next fetch (the linearization point is\nthe leader-served read the host makes before returning any channel bytes), and no resume,\ntakeover or boot reconcile continues it. An answer to one of its open checkpoints or asks MUST be\nrefused before anything is filed: the host reads the marker leader-served before it files the\nanswer record, and that read orders the answer against the revocation. A marker the host cannot\nread refuses the answer too. Revocation authorizes no new resource and no cleanup\nbeyond what the run's own journal already justifies. Caller disconnect or credential expiry after\nadmission does not revoke a run.\n\nThe issuing host accepts the closed `manager-run-revoke` request through its authenticated\nmanager-service authority door. The door verifies the IdP identity and reads that actor's current\nledger scope. Revocation requires that verified owner to equal the recorded admission's\n`caller.owner`, or that actor's fresh scope to carry `admin`. An assigned platform control manager\nis not an admin grant. The request accepts no owner, caller, `by` or timestamp assertion. The host\nchecks the current manager registration proof, space, account and process epoch, and requires the\nadmission to name that manager instance. It derives `by` as `<verified-owner>.<actor>` and writes the\nsame marker as a signer-holding host: `{ version: 1, runId, reason, by, revokedAt }`. A repeat returns\nthe existing marker, including its original attribution and time, without an overwrite.\n\n| Issuing-host request kind | Operation-specific input | Result |\n| --- | --- | --- |\n| `manager-run-admission` | `run: { runId, subject }` | the immutable admission and revision |\n| `manager-run-attempt` | one `attempt` or `operator` | fixed JWTs for manager-held public nkeys |\n| `manager-run-revoke` | `revoke: { runId, reason }`, with non-empty reason | `{ v: 1, kind, requestId, runId, revocation }`, naming the stored marker |\n| `manager-run-cancel` | `stage: \"inspect\"` or `\"commit\"`, `subject`, `cancel: { runId, reason }` | `{ v: 1, kind, requestId, runId, stage }` plus `authority` for inspect or `result` for commit |\n\nEach request carries the same registered-manager envelope: `v`, `kind`, `space`, `actor`,\n`instanceId`, `managerLifecycleUid`, `requestId`, `registrationProof`, `accountPublicKey`,\n`processEpoch` and public `identities`. Unknown fields refuse. These are issuing-host requests,\nnot endpoint commands. CLI and MCP revoke verbs require a separate served-command path.\n\n**Cooperative cancellation.** The ephemeral, untargeted `manager.run` command `run-cancel` accepts\nonly `{ runId, reason }`. The reason MUST be well-formed Unicode encoding to 1 through 512 UTF-8\nbytes. The request MUST ride the issued v1 instance rail and carry a bind naming the receiving\ninstance and current process epoch. Its deadline MUST be positive and at most 30,000 ms, measured\nfrom the original receive observation. A missing or different bind refuses; no epoch is repinned.\n\nA signer-holding manager accepts only the original admission's owner, actor and lifecycle UID,\nresolved under a currently live issued generation that permits this request subject. The generation\nneed not equal the admitting generation. A signerless manager asks its issuing host to inspect the\nrequest the host itself observed. That host accepts the original triple, or an independently\nattested interactive actor of the admitted owner with `run`, or an interactive actor with `admin`.\nAn actor name, managed seat, platform assignment or manager forward is not interactive authority.\nThe issuer checks current source liveness and issued permissions in every case. The local operator\nrevoke path above is separate.\n\nThe admission MUST be readable before cancellation. An absent admission yields an undetailed\n`permission-denied`; an unreadable admission or torn run record yields `unavailable`. Reads of the\nadmission, marker and run holder are leader-served. The manager's existing endpoint inventory\nreader supplies these reads even after revocation; it holds no checkpoint-answer writes. A\nrun-scoped read-only operator also remains issuable for status inspection after revocation, with\nthe admission's instance and endpoint checks unchanged. Revoked runs receive no new drive or\nanswering authority. A\nterminal completed or failed record returns an observation without writing a marker. A running\nrecord held elsewhere refuses before a write unless a marker already exists, in which case the\nreply reports `not-driven-here` without stopping a local handle. An absent run record, a spec\nwithout status, and a released run remain distinct from another holder's running attempt.\n\nThe closed `run-status` view also carries optional `revoked: { by, reason }` and\n`revocationUnreadable: string`, with the same meaning as the run list. The marker is read\nindependently of the recorded state. A running record with a marker does not prove cessation;\na released record with a marker cannot resume. A failed marker read MUST be reported as unreadable,\nnot as marker absence or permission to resume. A terminal record remains terminal whether or not\nit has a marker.\n\nThe `run-status` view also carries optional `programHash`, the language's hash of the run's\nrecorded program, which is the value the run list carries for that run. It is read from that run's\nprogram record alone. It is absent when the run has no recorded program. A program record that\ncannot be read or parsed MUST be reported as `programUnreadable: string`, with no `programHash`,\nand never as a hash or as an absent program.\n\nA `run-status` request MAY carry `journal: { offset }`, a row offset into the journal. The reply\nthen carries `journalTotal`, the journal's row count, and its `journal` holds the rows from\n`offset`, in journal order, that fit in one reply under the serving connection's payload limit: at\nleast one row while any remain, and none when `offset` is at or past the end. A record that does not\nfit in a reply with no rows, or a single row that does not fit, MUST be refused\n`resource-exhausted`. A request without `journal` returns the whole journal in one reply.\n\nEach cancellation intent is keyed by the full served subject, not just the envelope id. A pending\nintent prevents a new local launch but does not stop an existing drive. Only an observed durable\nmarker permits the manager to call the current eligible drive's cooperative `cancel(reason)`\nhandle. The manager rechecks an activated slot's recorded epoch, fencing token and holder before\nselecting that handle. A marker observed for a run promotes all its lingering local cancellation\nintents; keys are not aliased. A read failure or unknown write does not clear a pending intent.\nA definite no-dispatch refusal can clear only its own intent after confirming marker absence.\nIf its budget expires before that confirmation, the local launch block can remain even though\nno write was dispatched.\n\nAt a channel effect, a fresh revoked admission together with the same manager-local\nmarker-observed intent raises `Cancelled` rather than the ordinary revocation failure. This\nclassification does not signal the root or replace the current-holder check. Pending intent\nalone cannot reclassify a refusal; a local operator revoke without a cancellation intent keeps\nits existing failure behavior. If the required post-marker holder read fails or its original\nbudget expires, the manager MUST NOT signal a handle without the holder check or infer a stopped\ndrive from the marker alone. The marker can remain beside a running parked effect. The outcome remains unknown; a\nlater explicit cancellation request makes its own current observations.\n\nCancellation reaches the root signal in both language engines and the compiled worker bridge,\nincluding a cancellation latched before worker startup. It is separate from boundary release at\nmanager shutdown. A cancelled runtime drive reports `released` with a `Cancelled` reason; its\nstatus projection can lag its journal and handle outcome. Cancellation is cooperative: it does\nnot prove model or tool preemption, process interruption, resource cleanup or another host's\ncessation. Already-started external effects can still complete.\n\nThe reply contains `runId`, `authority` (`original`, `owner-interactive` or `admin`), optional\n`revocation: { by, reason, revokedAt }`, `duplicate` and `observed`. `duplicate` is false for a\nconfirmed new marker, true for a confirmed existing marker, and null when the write outcome was\nlost but a marker was subsequently read. The original stored marker is never overwritten.\n`observed` contains `processEpoch` and `phase`: `terminal`, `launch-abandoned`, `stop-requested`,\n`stopped` or `not-driven-here`. When read, it includes `recordedState`, `runEpoch`, `fencingToken`\nand `holder`; `driveOutcome` appears only when the local handle's outcome was observed. Budget\nexpiry after a stop request is not proof of cessation.\n\n**Issuer cancellation custody.** Inspection grants no later commit. The issuer independently\nobserves issued, untargeted instance requests for `run-cancel`, checks their closed input, and\nretains the original body fingerprint and deadline. The fingerprint includes the envelope id,\narguments, class, operation contract digests, bind and deadline. Identical redelivery does not\nextend that deadline. A different valid body under the same subject poisons that observation.\nThe manager's forward MUST match the observed body, instance, epoch and registered command.\n\nCommit atomically claims the observation before asynchronous authorization and store preparation,\nthen rechecks it at the actual marker dispatch boundary. The marker writer issues one conditional\nput, not a create helper that can retry after a deletion read. The closed commit result is one of:\n\n- `{ kind: \"committed\", outcome: \"created\" | \"existed\", revocation }`;\n- `{ kind: \"refused-before-dispatch\", code }`;\n- `{ kind: \"outcome-unknown\", code }`.\n\nThe code is `permission-denied`, `failed-precondition`, `deadline-exceeded`, `resource-exhausted`\nor `unavailable`. A lost transport result is unknown. The manager's earlier unknown history stays\nunknown even if a restarted or different issuer reports no observation. There is no cross-restart\nor multi-issuer exactly-once guarantee.\n\nObservation tombstones last for the issuer process lifetime, with no eviction. The default limits\nare 64 per caller triple, 256 per owner and 10,000 total; configuration MUST keep caller capacity\nat most owner capacity and owner capacity below the total. Static-addressed observations count\ntoo. Exhaustion refuses new identities rather than forgetting existing uncertainty. Inspection,\nclaims and equal redelivery cannot replenish these lifetime counters.\n\n**Resume, fork, local, restore.** A resume, takeover or reconcile continues under the ORIGINAL\nadmission and the current marker; the resuming caller's own authority is not consulted and cannot\nwiden it; a run with no admission stays parked, named in the host's log. A fork is a new run and\nneeds its own admission under the forking caller. A local drive (`cotal run start --local`) is\nadmitted from operator evidence named on the command line (the read and publish channel sets, or\n`none`), never from the host's own scope. The admission and revocation stores are retained with\nthe run, program and journal state they authorize; a restore that lacks them recreates them empty,\nand no run is taken back under authority the host cannot read.\n\n**User-auth runs.** A user-auth run is hosted by a signerless participant manager, and its issuing\nhost writes the admission. The issuing host admits a run-start whose caller has a derived user owner\nonly when that owner is the manager's registered owner, the owner whose `supervise` grant registered\nthe instance, so every user-admitted run on a participant manager belongs to that one owner. A\ncaller-requested resume and every principal answer or amendment ride the versioned rail. The manager\nforwards the request subject it served with the attempt or operator issuance it asks for, and the\nissuing host re-parses that subject, requires a user caller's owner to be the run's admitted owner\nfor a resume and the registered owner for an answer, resolves the caller's own issuance as live, and\nrequires its publish ceiling to permit that subject. The issuing host subscribes to the run-start,\nresume and answer request subjects itself, and to the keyed `run-start-keyed` and\n`run-submission-status` request subjects (§14), and never replies on any of them. It admits a forwarded run-start,\nand issues for a forwarded resume or answer, only when it observed a caller publish that request and\nhas not admitted or issued for it before, so a manager cannot forward a request its caller never\nsent. For a resume or answer it reads what that request's envelope asked for and issues only that: a\nresume attempt for the run its `runId` names, and an answering issuance for the endpoint the answer\nnames, the manager's own when it names none, for the run and step its `runId` and `stepKey` name,\nthat amends when the request set `amend: true` and answers when it did not. The\nmanager's request names that run and step, never a token. Every manager instance's pauses share one\ntoken namespace, so the issuing host requires the run to be admitted on the manager's instance and\nreads the pause's token off that run's journal, under a read it mints for that one run, before it\npins the token into the issuance. When the request carries a `bind` (§13.2) naming\nanother instance or epoch than the manager's current registration, it issues nothing, since that\nmanager refuses the request unrun. It issues nothing either for a request whose `class` or pinned\n`inputDigest` and `outputDigest` differ from the command's declaration in the manager's registered\ncluster (§13.7), which that manager also refuses unrun. An answering operator issuance always carries\nthe served subject. An amendment's issuance marks its pause with `amend: true`, and the issuing host\nthen requires that pause settled `resumed` with an accepted answer instead of waiting. A legacy-rail\nanswer is accepted only from a\nmanaged seat of that owner whose actor-ledger row is live, on the relay path of §14.5. A boot\nreconcile forwards no subject and continues under the original admission. A run's own caller holds\nno actor-ledger row, so when a participant manager asks its issuing host whether a caller of a run it\ndrives holds `admin` (§13.2), it asks for that run's admitted caller, whose current row decides. The\nissuing host pins every run mediator it signs for a participant manager, at issuance and at renewal,\nto a placement on that manager's own instance, the only instance such a run may place a spawn on.\nThe participant manager refuses a program that places a spawn on any other instance with\n`unimplemented`. This revision hosts no user-auth run on the signer-holding host's own manager.\n\n---\n\n## Appendix A: Reference implementation map\n\n| Spec section | Source |\n| --- | --- |\n| §2 Identity | `packages/core/src/identity.ts` |\n| §3 Subjects | `packages/core/src/subjects.ts` |\n| §5 Envelopes, §6 Presence, §7 Channels | `packages/core/src/types.ts` |\n| §8 Streams | `packages/core/src/streams.ts`, `packages/core/src/endpoint.ts` |\n| §9 Security | `packages/core/src/provision.ts` |\n| §10 Join link | `packages/core/src/link.ts` |\n| §13 Endpoint control surface | `packages/core/src/` (endpoint rails, envelope, contracts; lands with the control-surface campaign) |\n| §13.15 Issued authority | `packages/core/src/issued-authority.ts` (reference, evidence store, accepted row), `issuer-session.ts`, `endpoint-subjects.ts` / `endpoint-grants.ts` (the versioned rail) |\n| §14 Workflow runs, [`spec/cotal-lang.md`](spec/cotal-lang.md) | `packages/lang/src/` (the language, journal, keys, pins), `packages/core/src/run-record.ts`, `run-journal.ts`, `checkpoint-answer.ts`, `run-notice.ts`, `run-migration.ts`, `endpoint-binding.ts` (WFJ, grants), `run-admission.ts` (§14.8), `implementations/runtime/src/` (driver, migrate, fork), `implementations/manager/src/run-hosting.ts` (admission) |\n\n## Appendix B: Profile ACLs\n\nThis appendix is normative for the NATS binding. *(The operator-facing summary of these\ngrants is [docs/identity-and-auth.md](docs/identity-and-auth.md).)* Names below use these\nplaceholders:\n\n- `P = cotal.<space>`\n- `CHAT = CHAT_<space>`, `DM = DM_<space>`, `TASK = TASK_<space>`\n- `DLV = <Plane-3 per-member delivery stream>`; `INBOX = <mixed pre-auth fan-out stream>` (the durable-backstop handoff, §8): fan-out writes `INBOX` (`dinbox.<owner>.<actor>.<uid>`; lifecycle-bound from v0.4, so an inactive-gap or predecessor entry can never migrate to a same-name successor), the trusted reader re-authorizes and transfers to `DLV` (`dlv.<owner>.<actor>.<uid>`, same binding), and the agent binds its own `DLV` DELIVER consumer (filter pinned to its own triple). An agent gets **no** grant on `INBOX` (the mixed pre-auth store).\n- `KV = KV_cotal_presence_<space>`\n- `CHKV = KV_cotal_channels_<space>`; `DLVKV = <delivery lease/readiness KV>`\n- `MEMKV = KV_cotal_membership_<space>` (the derived channel-membership feed, §8)\n- `<owner>.<actor> = the authenticated principal` (§2): `<owner>` and `<actor>` are its two tokens; the dot-form is the wire/KV form, the dash-form `<owner>-<actor>` is the durable-name form\n- `connId = the authenticated connection id` (the connection nkey in static mode; the client-chosen nonce in user mode); distinct from the principal, and keys ONLY the reply inbox\n- `role = authenticated agent role`\n- `chatHistD = chathist_<owner>-<actor>-<uid>`, `dmD = dm_<owner>-<actor>-<uid>`, `dlvD = dlv_<owner>-<actor>-<uid>`, `svcD = svc_<role>` (per-instance durables are lifecycle-scoped from v0.4: keyed on the dash-form + lifecycle UID, §8/§13.1; `svcD` stays role-scoped)\n- `inbox = _INBOX_<connId>.>`\n\nGrouped placeholders such as `<CHAT|DM|TASK>` mean one concrete subject per listed token.\n\n### Agent\n\n`sub.allow`:\n\n- `inbox`\n- `P.live.<manager|delivery>.<owner>.<actor>.>` (replies to its own plane liveness probes, §6.1)\n- `P.ep.reply.*.*.*.<owner>.<actor>.<uid>.*` (exact arity; the agent's own endpoint reply rail: every endpoint's replies to THIS caller triple + nonce, §13.2; replies never ride the per-connection `inbox`)\n- `P.epe.…`; the exact fully-qualified event subtrees of every minted read capability\n (§13.9 event-read row), incl. the caller's own per-goal subtree\n `P.epe.*.*.*.goal.<owner>.<actor>.<uid>.>`; the live tail of watch, granted per\n capability, none by default\n- `P.chat.*.*.<ch>` for every `allowSubscribe` channel, the **live read boundary**: native core-sub join/leave is a `sub.allow`-bounded subscribe to this subject (wildcard sender owner+actor), so an agent whose ACL permits a channel joins it alone with no manager. Wildcards preserved (e.g. `P.chat.*.*.team.>` for `allowSubscribe: team.>`); a `team.>` grant matches strictly deeper channels, not the bare `team`; a `>` grant is read-all chat in the space on credential compromise\n\n`pub.allow`:\n\n- `P.chat.<owner>.<actor>.<ch>` for every `allowPublish` channel (post ACL; none by default)\n- `P.inst.*.*.<owner>.<actor>` (DM any recipient, forge-locked to me as sender)\n- `P.svc.*.<owner>.<actor>` (anycast any role, as me)\n- `P.live.<manager|delivery>.<owner>.<actor>` (plane liveness probe, as me, §6.1; the agent holds no `live` serve filter)\n- endpoint request forms per minted capability (§13.9): every agent gets the baseline set\n (`describe` on all endpoints; the delivery endpoint's durable join/leave/list commands;\n self-targeted manager commands with authz-mode `self`, including `run-answer`, which the manager\n narrows to an ask or escalation pending on that exact seat incarnation); the `spawn` capability adds the\n manager endpoint's lifecycle commands with authz-mode `owner`; `child`/`ledger` forms and\n wider target patterns only per explicitly minted capability. The caller triple\n `<owner>.<actor>.<uid>` is pinned in every granted form\n- control-surface durable reads (contract artifacts, decisions, goal results, receipts,\n event catch-up, record reads): **NO raw JetStream read grant of any kind**, no\n `DIRECT.GET`, no consumer `CREATE`, no bind-only `MSG.NEXT`/`ACK`, on `EPC`/`EPF`/`EPE`/the\n records KV. Per §13.9 \"Mediated reads\", every JetStream read delivers stored bytes to a\n caller-chosen destination the broker does not confine (push `deliver_subject`, pull\n `MSG.NEXT` reply, `DIRECT.GET` reply are the same vector), so an untrusted caller holds none\n of them. The caller reads through the trusted read mediator via a read command (an endpoint\n request form, above) and receives its own caller-scoped facts over its reply rail\n `P.ep.reply.*.*.*.<owner>.<actor>.<uid>.*` (already in `sub.allow`); the mediator owns the\n reader consumers and re-authorizes each read. Live event progress is the caller's own core\n subscription to granted `P.epe.…` subtrees within `allowSubscribe` (bytes land only on its\n own subscription, never a caller-chosen subject)\n- `$JS.API.INFO`\n- `$JS.API.STREAM.INFO.<CHAT|KV|CHKV|DLVKV>`: CHAT plus the world-readable presence/registry/lease KVs only; **not** DM/DLV/EPC (an agent reaches those by name — its own pre-created `dmD`/`dlvD`, or a subject-scoped `DIRECT.GET` on EPC — and `subjects_filter` is a request-body field, so INFO there would only leak inbox/delivery subject metadata). `TASK` rides the `role` gate below, not this row.\n- `$JS.API.CONSUMER.CREATE.<CHAT>.<chatHistD>.<P.chat.*.*.<ch>>` for every `allowSubscribe` channel (history reads; the single filter the server pins to the body, the agent's only CHAT consumer create. The live tail is the core `sub.allow` subscription above, not a JetStream consumer)\n- `$JS.API.CONSUMER.INFO.<CHAT>.<chatHistD>`\n- `$JS.API.CONSUMER.MSG.NEXT.<CHAT>.<chatHistD>`\n- `$JS.API.CONSUMER.DELETE.<CHAT>.<chatHistD>`\n- `$JS.API.CONSUMER.INFO.<DM>.<dmD>`\n- `$JS.API.CONSUMER.MSG.NEXT.<DM>.<dmD>`\n- `$JS.ACK.<DM>.<dmD>.>` (DM inbox: BIND-ONLY its own pre-created `dmD`, never create)\n- `$JS.API.CONSUMER.INFO.<DLV>.<dlvD>`\n- `$JS.API.CONSUMER.MSG.NEXT.<DLV>.<dlvD>`\n- `$JS.ACK.<DLV>.<dlvD>.>`, the **durable backstop**: BIND-ONLY its own pre-created per-member DELIVER consumer `dlvD` (the trusted reader's re-authorized handoff, §8). The agent holds NO grant on the mixed pre-auth `INBOX` fan-out stream.\n- `$JS.API.DIRECT.GET.<KV>` (the on-demand presence read, §6)\n- `$JS.API.CONSUMER.CREATE.<KV>.>`\n- `$JS.API.CONSUMER.INFO.<KV>.>`\n- `$JS.FC.>`\n- `$KV.cotal_presence_<space>.<owner>.<actor>`\n- `$JS.API.STREAM.MSG.GET.<CHKV>`\n- `$JS.API.DIRECT.GET.<CHKV>` (the one-shot registry read of the headless CLI commands, which connect on the user's bearer on a user-auth mesh; the same reply-subject vector as the consumer create below)\n- `$JS.API.CONSUMER.CREATE.<CHKV>.>`\n- `$JS.API.CONSUMER.INFO.<CHKV>.>`\n- `$JS.API.STREAM.MSG.GET.<DLVKV>` (delivery lease/readiness; read-only, non-gating)\n- if `role` is set: `$JS.API.STREAM.INFO.<TASK>`, `$JS.API.CONSUMER.INFO.<TASK>.<svcD>`,\n `$JS.API.CONSUMER.MSG.NEXT.<TASK>.<svcD>`, `$JS.ACK.<TASK>.<svcD>.>` (stream-level state is\n gated with the bind grants, so a role-less agent holds nothing at all on `TASK`)\n\n`pub.deny` (the agent binds these consumers, never creates them; its only consumer-create grant is the pinned per-channel `chatHistD` history create):\n\n- `$JS.API.CONSUMER.CREATE.<DM>`\n- `$JS.API.CONSUMER.CREATE.<DM>.>`\n- `$JS.API.CONSUMER.DURABLE.CREATE.<DM>.>`\n- `$JS.API.CONSUMER.CREATE.<TASK>`\n- `$JS.API.CONSUMER.CREATE.<TASK>.>`\n- `$JS.API.CONSUMER.DURABLE.CREATE.<TASK>.>`\n- `$JS.API.CONSUMER.CREATE.<DLV>`\n- `$JS.API.CONSUMER.CREATE.<DLV>.>`\n- `$JS.API.CONSUMER.DURABLE.CREATE.<DLV>.>`\n\nA bare/multi-filter consumer create on `CHAT` is **not** explicitly denied (that would also deny the\npinned `chatHistD` create the agent needs), so it is default-denied (the agent holds no such allow),\nleaving the single-filter history consumer above as the agent's only CHAT consumer.\n\n### Observer\n\n`sub.allow`:\n\n- `P.chat.>`\n- `inbox`\n\nApplication publish is denied. `pub.allow` contains only read/control verbs needed to read\nCHAT history, presence, and channel registry:\n\n- `$JS.API.INFO`\n- `$JS.API.STREAM.INFO.<CHAT>`\n- `$JS.API.STREAM.INFO.<KV>`\n- `$JS.API.CONSUMER.CREATE.<CHAT>`\n- `$JS.API.CONSUMER.CREATE.<CHAT>.>`\n- `$JS.API.CONSUMER.INFO.<CHAT>.>`\n- `$JS.API.CONSUMER.MSG.NEXT.<CHAT>.>`\n- `$JS.API.CONSUMER.DELETE.<CHAT>.hist_<readerId>_<n>` for each `n` in `0..7`\n- `$JS.ACK.<CHAT>.>`\n- `$JS.API.CONSUMER.CREATE.<KV>.>`\n- `$JS.API.CONSUMER.INFO.<KV>.>`\n- `$JS.API.STREAM.INFO.<CHKV>`\n- `$JS.API.STREAM.MSG.GET.<CHKV>`\n- `$JS.API.CONSUMER.CREATE.<CHKV>.>`\n- `$JS.API.CONSUMER.INFO.<CHKV>.>`\n- `$JS.API.STREAM.INFO.<MEMKV>`\n- `$JS.API.STREAM.MSG.GET.<MEMKV>`\n- `$JS.API.DIRECT.GET.<MEMKV>` (the membership snapshot read: paged batched Direct Gets that bind no consumer, since this profile may delete none)\n- `$JS.API.CONSUMER.CREATE.<MEMKV>.>`\n- `$JS.API.CONSUMER.INFO.<MEMKV>.>`\n- `$JS.API.STREAM.INFO.<DLVKV>`\n- `$JS.API.STREAM.MSG.GET.<DLVKV>`\n- `$JS.FC.>`\n\nThe membership feed (`MEMKV`) is read-only for this profile and, per §8's membership-feed\nparagraph, display-only and not part of the contract a client must implement.\n\nThe profile's only `CONSUMER.DELETE` rows name its eight history readers on `CHAT`,\n`hist_<readerId>_<n>`. A static credential's `readerId` is its user nkey, which its holder proves by\nsigning. Under the auth callout the inbox id is a nonce the client chooses, so the callout sets\n`readerId` to `<serverId>_<clientId>`: the admitting server's id and the client id that server\nassigned the connection, both in the callout request and in the server's `INFO` to the client. A\nreconnect is a new connection with a new `readerId`.\n\nA history read creates its consumers under one of those names, one at a time, and deletes each when\nits step ends, so one connection holds at most eight history readers on a stream however often it\npolls. Each create carries a description unique to that step. A create whose config equals the\nconsumer already under the name returns that consumer, delivery state included, so a client MUST\nNOT read through a consumer that does not carry its own step's description. A client MUST NOT delete\na consumer it finds under one of its names: another holder of the same credential, a process that\nstopped mid-read, or the client itself may have left it, and nothing the client holds tells which. It\nreads under a free name instead. After a delete fails without saying the consumer is gone, the\ndelete may have run with its answer lost and the name may be taken again, so the client keeps that\nname out of use until the reader's inactive threshold has passed.\n\nThe profile holds no other `CONSUMER.DELETE`. Its watch consumers are client-named ordered consumers\n(`oc_<nuid>_<serial>`, renamed on every rebuild), so the only expressible delete grant for them is\nstream-wide, and a stream-wide grant lets one holder delete another principal's watch cursors and\nthe delivery daemon's `fanout` durable. The broker removes these consumers at their inactive\nthreshold (five minutes after the last interest), and a client MUST treat a refused delete of its\nown watch consumer as that outcome rather than as a failure.\n\n### Admin\n\nAdmin has observer grants, with `sub.allow = [P.chat.>, P.inst.>, P.svc.>, inbox]`, the\ngod-view is the **messaging plane only**, enumerated: it deliberately excludes `P.ep.>`,\n`P.epe.>`, `P.epf.>`, `P.epj.>`, `P.ept.>`, `P.epr.>`, `P.epw.>`, `P.eps.>`, and `P.epc.>`\n(a space-wide `P.>` would plain-subscribe every `ep.one` request rail, collecting reply\nnonces the queue-qualified-only rule exists to protect, and every core-only session\nframe; §13.2, §13.11). Plus DM history read grants:\n\n- `$JS.API.STREAM.INFO.<DM>`\n- `$JS.API.CONSUMER.CREATE.<DM>`\n- `$JS.API.CONSUMER.CREATE.<DM>.>`\n- `$JS.API.CONSUMER.INFO.<DM>.>`\n- `$JS.API.CONSUMER.MSG.NEXT.<DM>.>`\n- `$JS.API.CONSUMER.DELETE.<DM>.hist_<readerId>_<n>` for each `n` in `0..7`, its DM history readers\n- `$JS.ACK.<DM>.>`\n\nAdmin still has no application publish grants.\n\n### Scoped host profiles (formerly `manager`)\n\nThere is **no allow-all credential**. The privileged host duties are split into scoped,\nsingle-function profiles, each granting only the verbs its function needs and none other:\n\n- `provisioner`: pre-creates the per-instance lifecycle-scoped durables (`dm_…-<uid>`,\n `svc_…`, the per-member `dlv_…-<uid>` handoff) AND the trusted control-surface consumers of\n the §13.9 matrix; `poolD`, `effD`, and the read mediator's reader durables\n (`decD`/`goalD`/`eveD-n`/`recD-n`, owned by the mediator, never by callers, §13.9\n \"Mediated reads\"), all PULL with exact full-tail filters; and mints scoped credentials;\n ephemeral onboarding authority. It also publishes `$SYS.REQ.USER.INFO` to observe its own\n native connection identity through the configured system account's import, with replies on\n its existing scoped inbox. It holds no arbitrary-user/account query or system credential;\n the response is not a permission ceiling, lifecycle or authorization to apply changes.\n- `deprovisioner`: target-pinned teardown of ONE retired lifecycle's footprint, minted per\n teardown with the target's `(principal, lifecycleUid)` in every exact-name grant; it can\n delete only lifecycle-keyed names, so it structurally cannot reach a same-name successor\n (§13.1). The footprint is the `dm_`/`dlv_` durables, the read-ACL row, and the durable\n membership row for each concrete channel the teardown names (one exact `memberKey` grant per\n channel). A wildcard channel is refused at mint. The manager names the launch's concrete read\n channels plus the channels the delivery daemon's read-only `lifecycleMemberships` admin verb\n lists for that exact `(principal, lifecycleUid)`. When that inventory cannot be read, rows on\n other channels stay retained, the teardown logs the inventory as incomplete, and retirement\n remains held pending retry rather than releasing the alias. The daemon MUST NOT hold that verb\n behind its other admin commands. Requests that arrive together MAY share one read of the members\n bucket, provided that read began after each of them arrived. Before it asks for that inventory,\n the manager MUST fence the lifecycle: it narrows the lifecycle's read-ACL row to an empty\n `allowSubscribe` with a compare-and-set update of the existing row, keeping its ceiling and never\n creating a row, under a deprovisioner credential pinned to that lifecycle. The daemon MUST read the\n lifecycle's exact ACL row immediately before a `durableJoin` writes the row that creates or reopens\n its membership, and again after that write. It MUST refuse the join when the channel is not within\n that row, and after the write it MUST first remove the row by its exact key. Every other membership\n write, such as a leave's tombstone or an activation, MUST update only the revision it read and MUST\n NOT recreate a removed key. A row of a fenced lifecycle that the inventory does not list is then\n never kept, whichever daemon process wrote it. The daemon also keeps its own fence, for a manager\n that does not narrow: once it takes a lifecycle's inventory request, it MUST refuse every\n `durableJoin` and `durableLeave` bound to that lifecycle, and it MUST begin the read only after the\n joins and leaves of that lifecycle already running have finished.\n- `supervisor`: the always-on agent-lifecycle daemon (the manager process's own connection). It\n is the manager endpoint's serve credential (§13.9) and the ONLY holder of the capabilities for\n the delivery endpoint's admin commands (below).\n- `delivery`: the server-side Plane-3 infra: fan-out, trusted-reader re-authorization, and the\n membership/ACL records the durable backstop authorizes against (§7). One process MAY hold this role\n for several spaces as one lane per space. Each lane presents only its own space's `delivery`\n credential, which that space's account signs, on connections of its own, and holds its own\n delivery lease, Plane-3 bindings and `$SYS` scan target; no credential, connection or lease is\n shared across spaces or accounts. It is the `delivery`\n endpoint's serve credential (§13.9); its admin commands, `reloadCreds`, the explicit adoption\n step of standing credential renewal (the daemon re-reads its re-signed creds file, pins the\n identity, swaps its connection, and reconnects the membership feed's rw connection, replying\n with the adopted JWT windows); `reloadStoreIdentity`, the store-identity challenge that\n names the SecretStore the daemon reloads from (the workstation root only when `--creds` is\n `<root>/.cotal/<spaceSegment(space)>/delivery.creds`; the file's own directory otherwise, an injected coordinate,\n the declared identity of an injected adapter, or the workstation root of the canonical arm; never a\n `findCotalRoot` ancestor walk). The first-party workspace filesystem adapter declares its workstation\n root, so passing that store explicitly names the real operator layout without an ambient coordinate.\n A filesystem identity is `{kind: \"fs\", root, id}`: `id` is a random value the store records once in\n `store.id` inside its own directory (`.cotal/store.id` for a workstation root, beside a `--creds`\n file otherwise, so that directory must be writable or already hold one). No key of a filesystem\n store and no `--creds` file may be its `store.id`, under that name or any other the filesystem\n resolves to the same file (a case-insensitive spelling or a link, found by device and inode), and a\n `store.id` that is a symbolic link or holds anything but a lowercase UUID is refused, because the id is published and a\n secret stored there would be published with it. Two filesystem identities\n match only when both `root` and `id` match, because a root is a local path and two hosts can mount\n different directories at one path. An answer whose filesystem identity has no `id` is refused. Uninjected `--creds`\n that names one real workstation while process cwd resolves another is refused at start, because\n membership-rw still uses `findCotalRoot`; a `--creds` path that is not under any `.cotal` tree is not that\n case. A manager whose remint store diverges is not that daemon's renewal owner: it starts and\n serves the space and skips the remint rather than being refused, including a daemon that bound\n after manager start. Matching that store identity is necessary but NOT sufficient to own the\n renewal, since the comparison carries no holder and no tiebreak and every manager sharing one\n store satisfies it; the owner is the manager that also holds the space's renewal lease, so a\n daemon's credentials have exactly one renewal owner at a time. And `evictPrincipal`, force-drop of a denied principal's live\n connections (system-account CONNZ scan → per-server KICK → re-scan verify, fail-closed on\n partial scans and on owners outside the principal namespace); carry a capability requirement\n minted to the `supervisor` profile **and to the trusted auth path** (§9/§10), which is the\n executor of the §13.1 takeover / terminal-retirement / handle-revocation barriers and calls\n `evictPrincipal` on each revoked credential's `holderPrincipal` (§13.1) as their eviction\n step; agents are broker-denied. `evictPrincipal` is\n wired into those barriers, not\n a standalone admin convenience. `evictPrincipals` is the same eviction for a set of at most 256\n distinct principals in ONE shared sweep: one CONNZ scan for the set, a KICK for every matching\n connection with at most 16 KICK requests in flight, and one re-scan per verify round covering\n every principal still pending. Every KICK settles before the re-scan that verifies it. Its reply\n is one `EvictionResult` per principal in request order, each read as `evictPrincipal`'s\n (an under-reported scan leaves every principal it would have decided `verifiedGone:false,\n scanComplete:false`). Frozen-gate reconciliation and an endpoint re-registration (§13.1) each\n verify-evict their whole holder set through it, so neither costs one sweep per family holder,\n and KICKing a live family costs one broker round trip per 16 live connections. A\n daemon that does not serve it refuses the verb, and the repair or re-registration then leaves\n the gate frozen. Its READ-ONLY twin `principalLiveness` answers whether one\n principal still holds a live connection (the same CONNZ sweep, observer credential only — the\n KICK credential is never opened on that path), reporting `live` / `gone` / `unknown` with scan\n completeness as a separate field and a reply bound to the exact principal queried. It exists\n because eviction cannot serve as its own precondition: a repair that must REFUSE while a holder\n is alive would, using `evictPrincipal` to find out, kill the holder before it could refuse.\n `gone` requires a complete, single-server-proven sweep (§13.13); an under-reporting sweep is\n `unknown`, which never authorizes. The former\n `delivery-admin` control tier is deleted with the v0 rail (§13.11).\n- `membership-rw`: the derived channel-membership graph feed reader/writer.\n- `operator`, `purger`, `teardown`, `channel-writer`, `control-caller-*`, `deployer`, `probe`: the\n human-CLI and maintenance surfaces, each scoped to its verbs. `teardown` also lists stream names,\n so space deletion finds the transfer buckets (§8), and holds `STREAM.INFO` and `STREAM.DELETE` on\n each transfer stream named at its mint. It also holds one non-fencing direct get on the records\n bucket, `DIRECT.GET.KV_cotal_records_<space>.$KV.cotal_records_<space>.run.*.*.status`, and no\n other read or write of it, so space deletion names the workflow runs it removes. The ephemeral teardown connection may read only its own\n broker user/account identity before native impact or deletion; this grants no other principal lookup.\n- `issuer`: an issuance window (§13.15), minted by the party holding the space signer; the issued\n and accepted stores plus one auth-store liveness read. A lifecycle terminal's retirement and every\n issuance other than the one below mint it per window, one-shot. An auth service, and each\n callout-only replica on its own, MAY hold one `issuer` session per account, space and\n authority-plane lifetime for the user-auth issuance its callout performs. A callout-only replica\n is one space's membership of that space's callout queue group, and one process MAY hold several,\n one session each; a process serving several spaces as their full auth service likewise holds one\n session per space. That session is private to its host and never shared across accounts or\n spaces. Its credential keeps the profile's five-minute\n expiry and is replaced with freshly minted credentials before it expires. Its connection never\n reconnects: it is closed and drained on a fence, a shutdown or a loss, and the next issuance dials\n a new one. Each issuance on it makes its own source, gate and accepted-row reads and its own\n create-only and CAS writes under the request deadline, and no issuance reuses what another read.\n A write in flight when the connection is lost has an unknown outcome and is never sent again.\n- `run-admitter`: one run's admission record or revocation marker (§14.8), minted per run for\n 60 seconds; two exact keys and nothing else.\n- `transfer-writer`: one carried resume transcript (§8), minted per CLI call for five minutes, or on\n a user-auth space exchanged per call as the `transfer-writer` view; the object's chunk and meta\n subjects in one instance's transfer bucket and a last-message direct get on each.\n- `transfer-reader`: one manager instance's `transcript-receive` or sweep (§8), minted per call for\n five minutes; its own transfer bucket's stream and nothing of any other instance. A remote manager\n receives it from the host's `transferReader` authority operation, which binds it to the\n authenticated manager's own instance.\n- `manager-service` is NOT a generic host profile: on a per-user-auth space only the\n loopback/operator exchange may issue this closed, one-owner/one-fixed-manager-actor/one-instance\n view to a signed-in user with ledger scope `supervise` (§13.1/§13.6). It reaches exactly the\n staged manager registration, contract, status, gate, credential, and same-owner descendant\n provisioning family; public exchange, managed-agent secret exchange, plain user bearers, and all\n other instances are refused.\n- `platform-control` is NOT a generic host profile either. It is the §13.1 service view a host\n issues, through its authority context's in-process door only, to one platform-run control\n manager per assigned account, under a `p_` platform owner and the host's current assignment. It\n reaches the same one-instance family as `manager-service` and same-owner descendants only. It\n never carries a human identity, never reads or implies `supervise`, and every exchange refuses it.\n\nStanding host credentials are **bounded and renewed**: one-shot profiles carry minutes-scale\nexpiry; `supervisor`/`delivery`/`membership-rw` carry a 24h expiry with the manager as the named\nrenewal owner (self-remint for its own credential; same-nkey re-sign + explicit `reloadCreds`\nadoption for the seed-less daemons); the two system-account credentials (`membership-observer`,\n`connection-evictor`) carry a 30d expiry and are renewable ONLY by a system-account rotation +\nbroker restart; no persisted system-account minting secret exists, by design. On per-user-auth\nspaces, static `agent`/`observer`/`admin` minting is retired entirely (the flip): agent identities\nexist only as owner+actor principals under a logged-in user, and the elevated profiles of this\nappendix are reached per-connection via the exchange-authored view claim instead (§10). The flip is\ndeny-new: a static\ncredential signed before it (or minted out-of-band with the account signing key) remains\nbroker-valid until signing-key rotation, which is the revocation lever for static material; the\nguarantee therefore applies to spaces that never issued static user-facing credentials.\n\nThe optional host-only `account-census` user has a fixed expiry of at most five minutes. Its only\npublish grant is `$SYS.REQ.ACCOUNT.<accountId>.CONNZ`; its only subscription grant is\n`_INBOX.cotal-account-census.<accountId>.>`. It has no KICK, account-event or response grant.\nThe account id is the DATA account public key. A registered SYS signer mints the user; the service\nclient never receives that signer or this credential. A pinned single-page observation is not a\nterminal retirement verdict. Incomplete or malformed observations remain unknown.\n\nThe live channel subscribe depends on none of these; it is broker-enforced via `sub.allow`, so\nself-serve live join works with no host present; only the durable backstop and its membership writes\nrequire a privileged host. None of these profiles is ever issued to ordinary agents. On the v0.4\nendpoint surface, every host profile's grant rows are **generated from the §13.9 ownership matrix**\n(matrix → grants, never the reverse): a profile with no matrix row holds no `ep*`, `$O.`, or\ncontrol-surface `$JS.API` authority, and `provision.ts` (`permissionsFor`) is the generated artifact\nthis appendix summarizes, not an independent authority. This appendix spells out the `agent`,\n`observer`, and `admin` profiles that make up the wire-facing security claim.\n\n## Appendix C: Normative references\n\n| Reference | Used for |\n| --- | --- |\n| RFC 2119, RFC 8174 | requirement keywords |\n| RFC 8259 | UTF-8 JSON envelopes (§5) |\n| RFC 4648 | base32 instance-id encoding (§2) |\n| RFC 8032 | Ed25519 keypairs behind nkeys (§2) |\n| RFC 8785 | JSON Canonicalization Scheme: every `*Digest` (§13.7), the program hash, input hashes and derived ids (§14, [`spec/cotal-lang.md`](spec/cotal-lang.md)) |\n| [ECMA-262, 14th edition (ECMAScript 2023)](https://262.ecma-international.org/14.0/) | the syntax and pure semantics the workflow language is a subset of ([`spec/cotal-lang.md`](spec/cotal-lang.md) §2) |\n| [NATS client protocol](https://docs.nats.io/reference/reference-protocols/nats-protocol) + [JetStream](https://docs.nats.io/nats-concepts/jetstream) | the v0 transport binding (§8) |\n| [NATS decentralized JWT auth](https://docs.nats.io/running-a-nats-service/configuration/securing_nats/auth_intro/jwt) + nkeys | identity and authorization (§2, §9) |\n\n## Appendix D: Change log\n\nNormative revisions of this document, newest first. Dated snapshots per §11; the wire\n`protocolVersion` is the compatibility signal, not these dates.\n\n| Date | Revision |\n| --- | --- |\n| 2026-10-28 | **A retiring lifecycle's fence is its ACL row (Appendix B).** The fence of the next entry lived only in one daemon's memory and was checked before a join wrote its row, so a join whose ACL lookup outlived the fence, a join from a still-connected seat after a daemon restart, or a join a quiesced predecessor finished after its successor's inventory each kept one row of a retired lifecycle. The manager now narrows the lifecycle's ACL row to an empty `allowSubscribe` before it asks for the inventory. The daemon re-reads that exact row before and after the write that creates a membership row, and removes the row and refuses the join when the channel is no longer within it. Other membership writes only update the revision they read. The daemon's own refusal and its wait for running writes stay, for a manager that does not narrow, as on a hosted daemon serving older managers. No wire change. |\n| 2026-10-28 | **A lifecycle's memberships stop changing once its inventory is requested (Appendix B).** A seat's eviction closes its connection but does not settle the daemon's own work: a `durableJoin` already running, or one queued on `ctl.delivery` and authorized after the inventory against the still-live ACL row, could commit a row the inventory never listed, and retirement then kept it. Once the daemon takes a lifecycle's `lifecycleMemberships` request, it MUST refuse every `durableJoin` and `durableLeave` bound to that lifecycle, and it MUST begin the read only after the ones already running have finished. No wire change. |\n| 2026-10-27 | **The membership inventory is not held behind other admin commands (Appendix B).** A manager stop retires many lifecycles at once, and each retirement asked the delivery daemon for its `lifecycleMemberships` inventory after its eviction. The daemon answered its admin commands one at a time, so the inventories waited behind every other seat's eviction, missed their deadline, and left rows retained. The daemon now MUST NOT hold that verb behind its other admin commands. Requests that arrive together MAY share one read of the members bucket, provided the read began after each of them arrived, so every answer stays as complete as a read of its own. No wire change. |\n| 2026-10-27 | **One auth service process MAY serve several spaces in full (§10, §13.13, Appendix B), additive.** One process may serve several spaces' exchange and JWKS as one full auth service per space. Each space's exchange is served on listeners of its own and mints only from that space's keys and ledger; each space keeps its own authority plane, claim row, scanner connections and fence, and a fence downs that space's service alone. Such a process holds one `issuer` session per space, never shared across spaces or accounts. |\n| 2026-10-27 | **Issued-authority rows are bounded by their generation's horizon (§13.12, §13.15).** The two issued-authority stores held every issuance forever, so their size was the cumulative number of exchanges. A generation now carries its horizon in its first 8 hex digits, and its last 24 are 96 bits of issuer entropy, so the 32-hex grammar is unchanged. The `issuer` gains only `STREAM.INFO` on the accepted store, so every issuer and resolver verifies both stores' shape when it binds. Every row of a generation in either store carries a per-message TTL to its horizon plus a 60-second margin, and both stores set `allow_msg_ttl` with no subject delete markers; `deny_delete`, `deny_purge` and the per-key shapes are unchanged. Every resolution, renewal and retirement refuses a generation at or past its horizon before it reads the store, and resolution checks the horizon again after its last read, so a removed key re-created later is never read. Horizons: the bearer expiry for a user-auth issuance, the credential expiry for an operator instrument, the assignment expiry for a platform supervisor duty, and 30 days after issuance for a static incarnation, whose renewals are capped at it. A store created before this revision is refused at bind and recreated. **Breaking pre-1.0 authority change: minor.** |\n| 2026-10-27 | **One delivery process MAY serve several spaces (Appendix B), additive.** One process may hold the `delivery` role for several spaces as one lane per space. Each lane presents only its own space's `delivery` credential on its own connections and holds its own delivery lease, Plane-3 bindings and `$SYS` scan target, never shared across spaces or accounts. The single-flight lease, its responder verdicts and the admin commands apply per lane unchanged. |\n| 2026-10-26 | **An operator instrument reads its pinned manager's `resolve-cwd` (§13.2, Appendix B), additive.** The folder question a managed launch asks had no caller that could make its check on a static mesh: `resolve-cwd` was carried by a `spawn` holder's `manager-caller` view and by no operator instrument, so every folder typed at that question was refused at the broker. Both instrument tiers now carry it on the instance their mint pins, beside the `spawn` row of the same `manager.spawn` capability class. The standing agent `spawn` set is unchanged, and no class, scatter or other-instance row is added. |\n| 2026-10-26 | **One callout process MAY serve several spaces (§10, Appendix B), additive.** A space's callout requests are served inside that space's dedicated auth account, so a responder holds one subscription per auth account it serves. One process may hold one subscription and one set of signing keys per space it serves. A response for a space must be signed only with that space's keys, and a bearer must be validated only against the issuer and audience of the space whose request it arrived on. Connect-limit buckets are per space, so a connect to one space never spends another's allowance. A callout-only replica is one space's membership of its queue group, and one process may hold several, one `issuer` session each. |\n| 2026-10-26 | **A held `issuer` session for user-auth issuance (§13.9, §13.15).** An auth service, and each callout-only replica on its own, may hold one `issuer` session per account, space and authority-plane lifetime for the user-auth issuance its callout performs, in place of one session per connect. It keeps the five-minute expiry and is replaced before it expires. It never reconnects, and it is closed and drained on a fence, a shutdown or a loss. Each issuance still makes its own reads and writes, and a write in flight at a loss is never sent again. Retirement at a lifecycle terminal and every other issuance window stay one-shot. The `issuer` principal is no longer one-shot only. |\n| 2026-10-26 | **Spawn readiness for a launch that waits for the operator (§13.6 item 6), additive.** A spawn whose agent application waits for the operator before its session joins, such as at a session picker, succeeds once its process runs, and its result's `waitingFor` names the screen. An `uncertain` result MAY carry `details[].kind = ai.cotal.goal.entity-running` when the owner saw the entity still running at the deadline. A reader that does not read `waitingFor` sees such a launch succeed before its session joins. |\n| 2026-10-23 | **A revoked run takes no answer (§14.8).** An answer to an open checkpoint or ask of a revoked run, or of a run whose marker cannot be read, is refused before anything is filed. The leader-served marker read before the answer record orders the answer against the revocation. |\n| 2026-10-23 | **A failed run records its cause (§13.7), additive.** A `failed` run status MAY carry `failure: { code?, message }`, the error the program failed with, so a reader of the record learns why without the host's log. It is optional on read and absent from every other state. |\n| 2026-10-21 | **Own-DM-only reader (§8), additive.** A client may read its DM inbox holding only its own `dm_` durable: it binds an existing durable, never creates one, refuses when it is missing, keeps the §5 sender check, and issues only CONSUMER.INFO, MSG.NEXT and ack requests on that durable. No credential profile is added. |\n| 2026-10-21 | **Handler refusals before any effect (§13.3), additive.** A handler that refuses before its command's first effect has started SHOULD carry `not-executed`, and one that refuses after an effect may have started MUST NOT carry it. |\n| 2026-10-21 | **User-mode chat sessions (§10, §13.1, §13.9), additive.** The auth service becomes a minting authority for chat sessions only. It admits one session per holder hash under the human's own `cli` grant, pins that grant, issues bearers of at most 900 s that it re-checks before and after signing, and mints the plain `agent` leaf with the session's lists. Three auth-bucket writer families (`chatholder`, `chatowner`, `chatsweep.cursor`) join the trusted auth path. |\n| 2026-10-21 | **Retirement-only manager composition (§13.1), additive.** An optional composition takes its own per-instance liveness lease before reading any lifecycle, slot or gate row. It records each slot as retired, already-retired, skipped-not-owned or held, never counts the latter two as retired, and introduces no new principal, credential profile or grant. |\n| 2026-10-19 | **A spawn-scoped `manager-caller` view reads its launch options (§9, §10), additive.** A person who may spawn on their own Manager could not read what a launch there needs: `status`, `models` and `resolve-cwd` were not in the view unless the actor held `admin`, and `resolve-cwd` was in no view at all. A view whose actor holds `spawn` now carries those three on its one pinned instance. A `run`-only or no-scope view gains nothing, `ps` and `slots` stay with `admin`, and no class, scatter or other-instance row is added. The standing `spawn` set is unchanged. |\n| 2026-10-19 | **Observer and admin history readers are deletable (Appendix B), breaking.** Each history read on these profiles left its consumers to the broker's five-minute inactive threshold, because the profiles held no `CONSUMER.DELETE` (#691). A dashboard polling history filled the stream's consumer limit, and every later read was refused with \"maximum consumers limit reached\". The observer now holds `CONSUMER.DELETE` on `CHAT` for `hist_<readerId>_<n>`, `n` in `0..7`, and admin holds the same names on `DM`. These are the connection's own history-reader names and no other consumer's: `readerId` is a static credential's nkey, or under the auth callout the server's id and the client id it assigned the connection, never the inbox nonce a client chooses. A history read uses them, deletes each reader when its step ends, and never deletes a consumer it finds under one of them. A credential minted without these rows cannot clean up, so a current client fails its history read and says to remint the credential. |\n| 2026-10-19 | **Private tool results (§13.19), additive; accepted, not implemented or enabled.** Defines the consent anchor role, managed-child serving request, consent and revocation record families, canonical START frontier, fixed audiences, exact-instance binding and bounded inert result journal. Revocation depends on a separately reviewed complete leader snapshot and an established enforced clock-skew bound; absent prerequisites answer `unavailable`. Activation requires every owner's qualified part and a stock release. Public tool arguments and results remain withheld. `protocolVersion` is unchanged. |\n| 2026-10-07 | **A role outside the token grammar is refused (§3), breaking.** A role was sanitized like every other routing token, so ` probe ` reached the `probe` queue and `pro.be` reached `pro_be` while the message kept the spelling sent, and an anycast to `*` was stored on a subject no role consumer matches. A client now refuses a role that is not one `[A-Za-z0-9_-]` token, both for the role it holds and for an anycast target, and refuses `*` as an anycast target. Existing `svc_<role>` durables keep their names, since they were always named from the sanitized token. |\n| 2026-10-07 | **A refusal for a target with no current mapping says that nothing ran (§13.2), additive.** It stays `expired` and now carries `outcome: not-executed` and `details[].kind = ai.cotal.ep.target-unmapped`. A manager resolves targets against the agents it hosts, so in a space with several managers the class queue could hand a targeted `despawn` to a sibling, which refused it the same way it refuses a retired target, with no outcome. The caller could not tell \"this agent is gone\" from \"this manager does not host it\", and repaired neither. With the marker a class-rail caller re-resolves and re-issues within its split-repair bound, and a target retired everywhere still ends in the same `expired` refusal once that bound runs out. A caller that ignores the marker sees the old code. |\n| 2026-10-04 | **Managed lifecycle handoff (§13.17), additive.** A managed agent already enrolled through §13.1 may run where the enrolling manager's filesystem is not visible. The manager releases one closed `cotal-managed-handoff/v1` document by value into that one child, carrying the issued owner, actor, lifecycle UID, sentinel, pinned exchange base, and the raw actor token, which the host never receives. The child's entry point removes the handoff file and its variable before it parses its arguments or does anything else, refuses a mismatched owner, actor, or lifecycle UID before any plane opens, never enrolls or mints, and uses the existing agent-bearer exchange unchanged. The manager refuses a spawn choice only its own host can honour before enrolling. Readiness stays presence-observed, a lost create acknowledgement stays held as uncertain and is never retried, a provider's answer that no resource exists is not an exit, and a close by the lifecycle-derived key is fenced against a create that could still land. A provider resource is bound to that key only by the provider's authenticated answer to its create, never by a derived identifier, a name or a listing. Retirement reuses prepare-retirement, then the known runtime handle's fenced close, then the terminal barrier, including after the manager is gone. A preservation cut that holds a handed-off lifecycle is refused, and a manager stop after a refused cut retires it. |\n| 2026-10-04 | **Platform control authority (§13.1, §13.6, §13.9), additive.** A closed server-authored `platform-control` view, beside the unchanged human `manager-service` view, lets a host run one pooled control manager per assigned account. Its holder's owner is a host-derived `p_` platform owner token, disjoint from every `u_` owner. The host's fresh platform-control assignment authorizes it in place of a ledger `supervise` scope. One closed envelope carries the existing typed manager requests through an in-process door of the host's authority context, served on no listener. The unchanged registration proof, process epoch, and all-duty renewal renew and fence it. Its host-owned maintenance reaches only the assigned instance under its own gate. An account has one assignment and so one control instance, which keeps its instance id and lifecycle UID across restarts and enters a deployment only after the assignment's named predecessor manager has left through its own path, read and never written by the host. It refuses human tokens, takeover of another owner's instance, local or custodial runtime, generic signing, exchange issuance, and cross-owner descendants. The reference host is `startAuthService` in `@cotal-ai/auth`. |\n| 2026-10-02 | **Plane liveness (§6.1), additive.** A credentialed peer can ask whether the manager or delivery plane has a bound responder, on `live.<plane>.<owner>.<actor>` with the reply under `<request>.reply.<nonce>`. The reply is `LivenessAnswer`: `plane`, a `ResponderState` verdict, and an optional opaque per-bind `instance` token that distinguishes responders without identifying them. Only the broker's no-responders answer grades `unbound`; every other failure to get a readable reply grades `unknown`. Agents gain the per-plane request and reply rows; the `delivery`, `supervisor` and remote-manager supervisor credentials gain their plane's serve filter and bounded reply grant. A responder binds again on every connection that replaces the one it bound on, and the manager is not `bound` while its service connection is closed or disconnected. |\n| 2026-09-28 | **The `auth` endpoint becomes a conforming registered endpoint (Cotal #399), closing the two gaps the prior two rounds named.** The plane's boot registers `svc.auth.<instanceId>` through the standard `registerServiceInstance` path and publishes its `retire-lifecycle` contract artifacts to the content-addressed contract store, so the endpoint now serves the reserved `describe` and answers the v1 envelope (`ep.v1`) instead of the legacy `{op,args}`/`{ok,data,error}` body this document states are deleted; a legacy body is refused `unsupported-version` as envelope validation, never an ACL denial. The requester side moves from a hand-built subject to the generic client (`resolveService` + `invokeCommand`), still minted in `exact` mode target-pinned to one incarnation at mint time, and gains the baseline `describe` row plus a bounded contract-store direct-get row so it can resolve the endpoint's registered digests before it calls; a body target that disagrees with the exact subject triple is refused `target-mismatch`. Two new §13.9 rows record the registered instance and the requester's describe/store-read grants. |\n| 2026-09-27 | **Id-less messages are not publish-deduplicated on the durable plane (§8).** The reference Plane-3 fan-out writer and membership-transfer frame publish carry no `Nats-Msg-Id` for a message whose `id` is `\"\"`, so two distinct id-less posts on a durable channel both reach a member and a redelivery of one id-less post may surface twice; a message with a real id keeps its idempotent publish key unchanged. Classification: reference-binding behaviour, no wire-envelope or schema change, protocolVersion unchanged. |\n| 2026-09-09 | **Issued authority and run admission (§13.15, §14.8).** A caller's request may ride a versioned rail (`ep.v1`) that pins the credential's issuer-accepted **generation** beside its triple; the issuer persists the generation's immutable permission ceiling as evidence before returning material, and a client learns its generation from an issuer-written accepted row. A hosted workflow run is admitted under the caller's resolved ceiling, recorded once per run in a dedicated store the driver cannot write, checked before every channel effect, and revoked by an independent marker; resume, takeover and reconcile continue under the original admission, a fork is a new admission, and a local run is admitted from operator evidence named on the command line. `run-start` on the legacy rail is refused by name. Three new per-space stores, two new one-shot profiles (`issuer`, `run-admitter`), and an admission read on the run mediator and operator profiles. **Breaking pre-1.0 authority change: minor.** |\n| 2026-08-24 | **Remote user manager authority.** A closed server-authored `manager-service` view permits one registered user-auth participant to operate one opaque manager instance only when their live actor-ledger row carries the dedicated `supervise` scope. `supervise` is distinct from `spawn` and `admin`; public and managed-agent exchanges refuse the view, and plain user bearers remain unprivileged. The host, never the participant, issues public-nkey JWT material through a lifecycle- and instance-bound, typed, replay-safe `prepare → activate → renew` protocol. The family is confined to one derived owner, fixed server-selected manager actor, lifecycle UID, instance registration/contracts/status, gate, and credential rows; descendant provisioning is host-validated for the same owner only. Revocation and renewal deny new material and unsafe restarts fail-closed while retaining live agents only within their independently valid authority. **Breaking pre-1.0 authority change: minor.** |\n| 2026-08-19 | **Receiver deduplication MUST NOT use the empty string as a key (§4), and id-less deliveries are individually addressable (§8).** Two distinct received messages MUST NOT be treated as one logical delivery solely because both carry `id: \"\"`; each remains independently deliverable, and copies that cannot be correlated by wire identity may surface more than once on an at-least-once path. The publisher's §5 obligation to supply a unique string id is unchanged; an absent or non-string id remains a malformed envelope, now enforced at each delivery pump (durable terminate, live drop, history and recall skip). §8 adds that the absence of a usable receiver dedup key does not relax acknowledgement ownership: a JetStream-consumed copy with `id: \"\"` that is surfaced or handled MUST be acknowledged independently, and the reference implementation realizes that through a per-delivery receive key (never wire identity, never dedup authority) at its drain and in-flight seams. Plane-3 durable fan-out still derives its publish msgID from `CotalMessage.id`, so distinct `id: \"\"` messages can be collapsed inside the broker's duplicate window on a durable channel before the receiver sees them; that path is its own tracked change and this revision's guarantee is scoped to the receiver. Classification: normative receive-side semantics, no wire-envelope or schema change, `protocolVersion` unchanged. |\n| 2026-08-18 | **v0.5 binding revision: workflow runs (§14), additive.** A deployment MAY host durable workflow runs: programs in the Cotal workflow language, defined by the new normative reference [`spec/cotal-lang.md`](spec/cotal-lang.md) (language version `1`: the syntax table, values and the boundary rule, the library, the effect primitives with their hashed projections, the four concurrency scopes and the clock-decided `race`, the step key grammar, journal entry schema, input hash and request id, resume, migrate and fork), whose every effect is recorded in a per-run step journal on the new per-space `WFJ_<space>` stream (one subject per run, no age eviction, no Direct Get, every append fenced by the run subject's own sequence, replay-then-activate takeover with a fencing-token authorization tuple, an ordinal chain and a `journalHigh` anchor). Four core record kinds join §13.7: `run` (split; the resolved pin set on the spec half, holder/lease/`journalHigh` on the status half; driver-minted, never-reused ids), `answer` (atomic, content-derived id, keyed per answer because every presenter is the driver), `notice` (split; addressee keyed by a digest of the name; consumption as status), `migration` (split; content-derived id; application as a create-only status). Driver grants are per run and per takeover, with no wildcard form. `languageVersion` is pinned per run and moves independently of the wire version. No existing kind, subject, grant row or shipped datum changes. |\n| 2026-08-16 | **A caller declares the incarnation it resolved against, and a responder that is not it refuses before any effect.** A class-addressed request is delivered to one member of a queue group, and the member that answers need not be the one the caller's `describe` resolved against. The caller could only detect that AFTERWARDS, from the reply subject, by which point the command had run: the split was observable but never preventable, and the reference client's recovery repeated the command. `bind` (§13.3) is the caller's declaration of `{ instanceId, epoch }`, checked by the responder against its own identity at the pre-effect seam, ahead of the governed gate and every handler. A mismatch is `failed-precondition` for a different instance and `expired` for another epoch of the same one, both carrying `details[].kind = ai.cotal.ep.bind-refused` and, per §13.3, `outcome: not-executed`. **ADDITIVE**: `bind` is MAY, a responder that does not implement the fence ignores it under §5 and executes, so the caller-side check remains the only protection in a skewed pair and `protocolVersion` stays 0.4. It confers nothing and narrows only, so it satisfies monotonic attenuation: a request carrying it reaches exactly the instances the subject already routes it to, and can only make one of them refuse. Absent on `describe` (the bootstrap that produces the bind) and on the scatter rail (which addresses every incarnation by construction); on the `inst` rail it MUST name the subject's instance and adds the epoch the subject grammar has no token for. Attribution still comes from the reply subject, never from this block: it is what the caller bound, not a claim about who answered. |\n| 2026-08-16 | **A command declares whether repeating it is safe, a responder reports whether a refusal already executed, and the two are separated from idempotency by `id`.** Three gaps that only bite together. **(1) `effect` (§13.7).** Nothing in a resolved command distinguished a read from a mutation — every manager command declares `class: \"ephemeral\"`, and `traits` carries no repeat-safety — so a client deciding whether to retry had nothing to consult, and the reference client repeats a mutation on a split. Precisely: the automatic repeat belongs to the high-level helper, not to the primitive — `invokeCommand` raises the post-reply currency refusal and stops, and the `invokeService` wrapper around it catches exactly that code, re-resolves, and invokes a second time. Measured on a live broker under a forced instance split, counting at the handler rather than on the wire, the repeated command executes TWICE. `effect` is `read` or `write`, with `read` defined OPERATIONALLY — repeating it changes nothing the command is TRYING to change, and the only excluded difference is the incidental trace of having been called (request ids, spans, logs, metrics, timing) — because the intuitive definition, indistinguishable to every observer, is satisfiable by no real command and would make the field decorative. The state in question is not only the endpoint's own: a command whose intended effect lands elsewhere is still a `write`, and `evictPrincipal` fixes that boundary, since dropping live broker connections while leaving the endpoint's own records untouched is the point of calling it. **(2) `error.outcome` (§13.3).** A refusal code cannot say whether the effect happened: the same code is correct for a request that ran and one that never left. `outcome` is emitted by the RESPONDER, which is the only party that knows — `not-executed` when it refuses before the handler, `executed` when it refuses after, `unknown` when it cannot tell. It describes a reply and only a reply — a caller-side refusal is not an `EndpointReply` and carries no `outcome` field — but it does NOT follow that the caller knows nothing, and the first cut of this amendment wrongly collapsed four distinguishable local cases into `unknown`. A refusal raised BEFORE publication is `not-executed`: the request never left, and calling that `unknown` suppresses a retry that is provably safe even for a `write`. A refusal raised while HOLDING a reply — the §13.2 post-reply currency check is the case in this document — takes what it knows from that reply: `ok:true` means the handler ran, and an `ok:false` reply carries the responder's own `outcome`, which the caller adopts rather than overwrites. A **broker-attested no-responders answer** on the reserved sentinel is also `not-executed`: it is positive evidence that the subject had zero subscribers, trusted only on that sentinel because the same status on an ordinary reply subject is a responder's own claim. Only \"no reply observed at all\" (deadline, transport failure after publication) is `unknown`. And **a reply proves the request was HANDLED, never that it was EXECUTED** — the version, class, target, sender, authz, contract, and guard checks all publish `ok:false` having executed nothing. It is also not a goal's terminal state (§13.6 owns that) and must not be used as one. **(3) Repeat versus resubmission (§13.8).** `effect` and \"idempotent by `id`\" are different axes and were unreconciled. They are now separated by CONVERGENCE rather than by token: a **resubmission** is a re-send the responder converges onto the decision it already recorded, a **repeat** is one it accepts as new work, and `effect` governs repeats whatever `id` they carry. Defining the split by the token instead left a hole — a post-horizon re-send under a reused `id` is accepted as new work, so it executes, while formally escaping a prohibition written as \"under a fresh `id`\". Reusing the token is how a caller ASKS for convergence; it is not the answer. Within the horizon `id` is what convergence is keyed on — and `id` is the whole key on the ephemeral rail but only ONE of the effect-defining dimensions the journal fingerprint binds — endpoint, command, `id`, `goalId`, `class`, args, both contract digests, the authorization mode, the target, `auth`, and the caller — where same id + different args is neither dedup nor a fresh call but a loud `conflict`. **Both rails are bounded by a horizon**, realized by decision-fact and result retention rather than by a clock, and outside it neither rule applies: the `id` carries no history, a re-send under it is a fresh call that WILL execute, and the same `id` with different args is no longer a `conflict`. A finite horizon is what keeps the decision store finite, so this is a fact callers must hold rather than a hole to close — and because a repeat is defined by acceptance rather than by token, a post-horizon same-`id` re-send of a `write` is exactly what §13.7 forbids a client to make automatically. A command idempotent by `id` is therefore NOT thereby `read`: safe to resubmit is not safe to repeat — and the dangerous reading is a reasonable one, since an operator who retries after a timeout mints a fresh `id` because the old request is gone. **NON-ADDITIVE, and versioned as such:** a client that ignored `effect` would keep performing exactly the retry the field exists to stop, so it rides `protocol.v` — the marker that ALREADY EXISTS on the service record spec and the describe descriptor, never a new field on the cluster document, which has no `protocol` and where §7 would drop it unread by exactly the clients this must stop. An instance whose clusters declare `effect` registers and describes at `v:2`; `v:1` descriptors stay valid, carry no `effect`, and every command served under one reads as `write`. The caller-side refusal of a `protocol.v` it does not implement is a requirement this cut CREATES, not one already met: today `describe`'s pinned output schema fixes `descriptor.protocol.v` to the constant `1`, so an unamended responder cannot publish a `v:2` descriptor at all, and the registry reader refuses a service record that is not `v:1` — but the resolving caller validates neither, and the shape it reads does not carry `protocol`. The responder-side fence is what protects old clients today, and only until this cut widens that constant. **Release order was the wrong instrument and is withdrawn**: a same-release ordering rule has no observable runtime meaning, since a release is not a deployment and an already-running v1 caller is unchanged by whatever a new artifact contains. **The cutover rule is §11's, and §13.7 does not state one.** Moving to `protocol.v: 2` IS a non-additive discovery change, so the §11 rule for one (previous row, landed first) is the sole authority on how it rolls out. §13.7 carries only what is specific to `2`: a caller that resolves a descriptor whose `protocol.v` it does not implement MUST fail the resolve (`unsupported-version`) and MUST NOT invoke against it — a descriptor it cannot read is no descriptor, and reading it as `v:1` reinstates the repeat — and implementing that refusal is what makes a caller count as having ADOPTED the section for §11's condition. Two intermediate drafts had to be withdrawn to reach that: one sited the cutover in §13.7 as a same-release ordering clause, which has no observable runtime meaning because a release is not a deployment; the next stated the cutover in BOTH sections, which is a single-source-of-truth defect, since two normative statements of one rule agree until either is edited and then silently become two conformance rules. The reason it cannot be sited here is the durable part: the condition is a property of the whole deployment, and a responder cannot evaluate it — no in-band negotiation, no caller version on the wire — so a rule stated here would bind the one party unable to check it. |\n| 2026-08-16 | **A non-additive discovery change is an out-of-band deployment cutover and rolls out CALLER-FIRST (§11).** The preceding §11 rule says v0 has no in-band capability negotiation and that deployments agree out of band; this says what that obliges when a discovery change CANNOT be ignored safely — where an unamended client that drops the new field per §7 would then behave in the very way the change exists to prevent, so no default value repairs the direction that matters. The obligation rests on the DEPLOYMENT, because neither participant can discharge it: a responder cannot tell an amended caller from an unamended one, since no request carries a caller version and `describe`'s answer is read by the caller without a version check. So every caller adopts the new rules BEFORE any responder registers or describes at the new version, and the two halves SHOULD ship in SEPARATE releases — **a release is not a deployment**, and an already-running caller is unchanged by whatever a new artifact contains, so the order of two source edits proves nothing about the processes on the wire. `protocol.v` on the registered service record is the observable marker: \"has any responder cut over\" is a checkable registry property, while \"has every caller adopted\" is the out-of-band agreement §11 already requires. **The residual is stated rather than engineered around**: an early cutover exposes unamended callers to exactly what the new version prevents, and within v0 nothing in band detects it — closing that needs negotiation v0 does not have, and the v1 marker owns it. Prose only: no schema, no wire field, no code. |\n| 2026-08-14 | **The auth-admin rail moves off the retired `ctl` surface onto the endpoint SUBJECTS (a subject-plane migration, NOT yet a conforming endpoint - see the residual below), and its authz description is corrected to what ships.** TWO defects on the same §13.9 rows, fixed together. **(1) The rail.** The rows served the auth plane's generic \"retire a lifecycle\" operation on `ctl.auth-admin.<owner>.<actor>` — a rail §13.11 retires in full and states MUST NOT be handled. New normative rows written onto a deleted rail are defects, not exceptions to it, so they are rewritten onto the v0.4 endpoint surface rather than given scoping language: `ep.one.auth.retire-lifecycle.handle.<tO>.<tA>.<tUid>.<cO>.<cA>.<cUid>.<nonce>`, served queue-qualified on the class rail, with the reply DERIVED from the parsed request (the bound-reply rule becomes structural — no caller- or payload-supplied reply target can arrive) and the request/reply planes disjoint, so the listener credential cannot express a request subject and the self-forge closes by grammar. The requester credential now pins its caller TRIPLE and exactly ONE target incarnation, so a leaked requester cannot be re-aimed. §13.11 is unchanged and gains no carve-out. **(2) The authz sentence.** These rows described serve-time authz as a space-manager-LEASE holder check; the implementation replaced that with the serve-issuance-gate check on 2026-07-22 without a spec change, so the normative text had been false since. It now describes what ships — a fresh leader-served read of `epgate.<serveEndpoint>.<serveInstanceId>` requiring presence, the declared epoch, and THE PRINCIPAL CROSS-CHECK (`row.principal` must equal the subject-derived caller principal), the last being new here: the two-token `ctl` subject could not express the caller beyond an alias, so the rail had accepted ANY registered instance's gate. The binding is stated as ALIAS-LEVEL, not incarnation-level: the gate is keyed by the persisted `instanceId` and its row carries no lifecycle uid, so a same-principal predecessor presenting the current epoch still passes; binding the publishing incarnation needs a gate-row schema change and is not attempted here. **NAMED RESIDUAL (Cotal #399) - THE RAIL IS NOT A CONFORMING ENDPOINT: it carries the endpoint SUBJECTS only. It still exchanges the pre-v0.4 `{op,args}` / `{ok,data,error}` bodies this document states are DELETED, registers no `svc.<endpoint>.<instanceId>` service record, does not serve the reserved `describe`, and has no contract/cluster artifact - so a GENERIC endpoint client can neither discover nor invoke this command. The exploitable half is closed in this change - the request carries a caller-chosen `id`, the responder echoes it on every reply, and the caller refuses any reply that does not echo, so a wrong-id `ok:true` cannot clear a retirement hold - but the versioned typed envelope, contract digests, `class`, deadline/`replyExpected` semantics, structured errors, service registration and `describe` are a separate cut tracked at #399, whose acceptance test is that a GENERIC client can discover and invoke the command. Recorded here rather than left implicit: serving a deleted envelope on the new rail is the same class of defect as serving on a deleted subject.** |\n| 2026-07-19 | **v0.4 amendment continuation: retirement cleaner inventory is discovery-only.** The terminal retirement barrier no longer accepts a caller-supplied `(endpoint, pools)` hint: the per-op cleaner and settlement-executor pool set is now DISCOVERY-ONLY, exactly the retiring lifecycle's accepted `oblig.<uid>.>` pool routes discovered from the just-drained obligation set. This SUPERSEDES the round-11 optional-hint clause (the 2026-07-15 row): the hint was a TRUSTED ADDITIVE AUTHORITY input that would mint a bounded per-op credential for a pool with no backing obligation, and the despawn rail never exercised it (always an empty hint), so it was grant-widening surface with no production caller. Every grant now scopes to exactly the pools the target holds accepted work on, and the §13.9 residuals cover only those discovered pools. The intent's `endpoints` field is removed from the closed operation-intent schema; a pre-change durable intent that still carries it fails the closed-schema check on resume (the v0.4 hard-cut window, where a clean broker holds none). |\n| 2026-07-16 | **v0.4 amendment continuation: connect-arm deny-new (production activation R1).** Every bearer carries its incarnation's root credential id (`act.credentialId`); the exchange mints the root credential RELEASE-LAST (active `cred.` row durable, gate finalize, lifecycle-head current-root CAS, bearer bytes last) and the connect authority requires the LIVE row (leader-served from the shape-proved primary auth store, re-proved on every rebind) plus root head equality, so revoking the row denies the next connect and a superseded or crash-orphaned root issuance never authenticates. The root credential is **incarnation-wide** (ratified): one row per incarnation, re-stamped (the same id) every exchange for its 90d life, never a fresh id per exchange, so one revoke denies every bearer of the incarnation, and a crash after the head CAS re-exports the same id by design (nothing unobserved to revoke; the only pre-release crash window is a durable unstamped row, denied by head equality). The authority store shape proof binds the stream to the actual KV bucket (exactly the one `$KV.<bucket>.>` subject + durable file storage, in addition to the primary/un-mirrored/non-evicting/`allow_direct` flags) at every bind and at boot ensure. Claimless bearers, revoked/expired/absent rows, and an unreadable authority store deny outright (no file-only fallback; a failed reader-credential renewal downs the reader immediately and denies). The head's current-root stamp moves only ABSENT to value: root rotation without the full family-revoke barrier is refused structurally. Named R1 residuals: a same-alias re-grant while the predecessor incarnation is live refuses the exchange (production issuance runs no takeover barrier yet), and the auth service's reader/mint-writer are seed-signed infra credentials (revoked by service stop or signing-seed rotation) pending the ledgered infra-mint family. |\n| 2026-07-16 | **v0.4 amendment continuation: retirement settlement authority split.** A seventh round (an independent cold read on the landed barrier plus the panel's authority ruling) split terminal pool cleanup across two profiles: the bounded cleaner keeps ONLY bind-scoped fetch, leader-served EPF terminal-observe reads, and ACK (its former own-pool `wrk` terminal-forge residual is REMOVED with the grant; its remaining residuals are terminal-free ACK suppression and the space-wide read exposure), while the op-bounded retirement settlement executor (a new §13.9 row) owns the intent-closed lease-record CAS and the lease-derived `wrk` terminal publish, carrying the relocated, intent-confined forge residual. Settlement is lease-fenced: an already-settled lease (a crashed owner's `committed`) dominates and is never overwritten. Effects-route completion is a new CLOSED `eff` fact (subject-bound caller and id; `fingerprint` and `sourceSeq` bound to the accepted decision), an action's completion requires the parsed `goal….result` fingerprint match, and subject presence never proves quiescence. The mediator's obligation-row residual is stated honestly (an operation/header-blind KV publish: valid-terminal overwrite or DEL/PURGE markers, refused loud by readers; the records stream denies stream-API message-delete/purge), and the caller-selected-reply confused-deputy injection residual is named for every raw `MSG.GET`/`MSG.NEXT` profile. |\n| 2026-07-15 | **v0.4 amendment (folds into the in-flight §13 revision below): lifecycle and admission fences.** Three-state lifecycle head (`active \\| retiring \\| retired`; currency only at `active`; `mappingRevision` = the head key's store revision), space-global never-deleted UID reservation (`uid.<lifecycleUid>`), per-kind issuance-gate operation intents and their allowed-transition sets, the locked terminal barrier order (obligation drain to quiescence before the exact-pool cleaner, both before frontiers), the §13.8 authority-head reservation/drain protocol (create-fence + proof-gated admission + per-class decision coordinates + writer≠target reclamation), the endpoint-wide admission-policy coordinate (the governance head + `policyRevision`) with drain-gated policy enforcement, the `ep` sentinel for untargeted admissions, and bind-time store shape proofs (§13.12). Refined per the re-verify round: the govern head's NORMATIVE policy selector `{ enforcedPolicyKey, enforcedPolicyRevision, pendingPolicy… }` with a stage/drain/promote mutation order (so the enforced policy is machine-selectable during the drain window), the `self`-class obligation's complete commit intent `{ commitKey, commitBaseRevision, commitValue, commitDigest }` (the pinned BYTES, not just a digest) with deterministic `accepted → terminal` recovery and full-intent create-join (an accepted-but-uncommitted row never blocks quiescence), the retirement barrier's cleaner-credential revoke + verified-eviction BEFORE any frontier records, the LIMITS-retention bind-time proof (a non-Limits authority store deletes rows on consumer ack), and the runtime gate parse rejecting impossible `retired`-under-takeover/registration state. A second re-verify round added: the head's `lastTakeoverOpId` (the epoch advance stamps the completing op, so a losing concurrent takeover never claims the winner's completion), the immutable revision-addressed admission-policy key (a mutable per-instance slot loses the old revision under history 1 during the drain), the `epgate.principal` and the rule that a ledger row's `holderPrincipal` is ALWAYS a CONNZ-attributable principal (the endpoint NAME forms the `epcred.` key in a separate field, never the eviction target), and the lifecycle barrier's session-pair teardown (a takeover revoking a `session.`-derived credential terminalizes the session and revokes the paired serving row). A third round (a convergent panel + independent cold read) added: the normative immutable `policy` record kind `policy.<endpoint>.<digest-hex>` (self-certifying content-addressed key; the govern selector names exactly this kind, replacing the per-deployment \"versioned key\" allowance), the CLOSED `commitValue` union (`{ enc: \"b64u\", bytes }` exact base64url value bytes, or `{ enc: \"ref\", key }` naming an immutable records key; `commitDigest` = `sha256:<hex>` over the raw value bytes), proof-issuance PAUSE for policy-admitted decisions while a `pendingPolicy…` is staged (which makes the policy drain converge and the after-final-enumeration no-admit rule hold for policy movement), the serving-principal JOIN into the lifecycle barrier's verified-eviction set (a session-pair teardown returns the paired serving row's holder principal and the barrier evicts it before the epoch CAS), and the torn-coordinate takeover guard (the intent capture re-proves head coherence, and the freeze CAS is preceded by a head-currency read, so a stale intent never freezes the winner's reopened gate). A fourth round (a convergent re-verify + independent cold read) added: the drain-window admission pause is now a NORMATIVE step of the §13.8 admission algorithm (the mediator's create-fence AND post-create recheck leader-read the govern head and refuse a policy-admitted decision while a `pendingPolicyKey` is staged, which also bounds the never-deleted `oblig` set during a long drain), the §13.9 matrix records the mediator's govern-head and policy-version read authority, the `policy` kind's immutability is stated honestly as a trusted-writer create-only-CAS invariant backed by read-time self-certification rather than a broker-level update/delete subtraction (KV operations share one subject), and the takeover barrier's crash-boundary recovery COMPLETES containment (revoke + reconcile + verified-evict every family holder) BEFORE it aborts a stale/torn freeze, so a crash after a partial revoke never leaves a revoked credential's connection live. A fifth round (panel + independent cold read on the B2 mediator) refined: `commitDigest` is the RFC-8785 canonical content digest of the committed value, `sha256:<hex>` (not a raw-bytes digest, so it is insensitive to a non-canonical storage stringify), and `commitValue`'s `b64u`/`ref` forms both resolve that same value; the policy publication is content-addressed by the same canonical digest (property-order-insensitive). The session expiry sweep now enumerates a marker-preserving stream read rather than the bucket's `keys()` (which filters DEL/PURGE), so a tombstoned session key is reported as corruption, not silently skipped. The terminal barrier's frontier record is pinned as the `frontier.<lifecycleUid>` kind (§13.7: create-only, never deleted, one key per retired lifecycle, recorded once under its own operation's `opId` before the gate/head terminals), and the exact-pool cleaner's `retired` disposition is a first-class `wrk` terminal fact carrying its operation and retiring-target binding. A sixth round (the D14 confinement review) pinned the two mediated-profile grant shapes: the admission mediator's enumeration consumer carries a deterministic (endpoint, connection)-bound name with name-literal CREATE/INFO/MSG.NEXT/DELETE rows (closing the name-wildcard cross-consumer reach; the own-name delete is what keeps the fixed name reusable across filters), both profiles' reply inboxes are connection-scoped (`_INBOX_<connId>.>`, never the account-wide default), and both payload-blind write residuals are named with equal explicitness: the mediator's own-endpoint acceptance-forge and the cleaner's own-pool `wrk` terminal-forge (work suppression or mis-settlement), each confined to its subject-expressible scope. A seventh round (the control-surface sealed-scanner seal) moved the dynamic-enumeration `CONSUMER.CREATE` off every standing/runtime credential (the takeover/retirement/handle-revocation barrier and the session sweep on `cotal_auth_<space>`, and the admission mediator plus the retirement obligation-drain on `cotal_records_<space>`) into dedicated SEALED scanners the trusted process opens for itself and NEVER hands out, because a consumer-create request BODY is not subject-ACL confinable (an extended name+filter grant still admits a `durable_name` + push `deliver_subject` exporter of every current/future row that survives connection close and revocation, nats-server#8274, reproduced live); each scanner is pinned to one literal consumer name under a forced pull/`LastPerSubject`/ephemeral/memory config, bind-verified before use and unconditionally deleted after, its CREATE filter confined to its subtree, space-bonded so a hand-assembled or foreign-space scanner never enumerates, and fence-free by construction (a `LastPerSubject` read carries no upper cutoff, so a same-subject overwrite during the scan is SEEN, not dropped). Its re-verify round hardened the seal from asserted to enforced: the scanner capability handle is immutable once branded (a swapped scan op throws rather than surviving the injection assert; that mutation vector was reachable only from inside the trusted process, the signing-seed residual class, never externally), every scan over a space's literal consumer name serializes process-wide (a second scanner instance can never interleave with a live scan and return a partial enumeration; cross-process duplication remains excluded by the one-authority-plane-per-space composition), every delivered subject is revalidated against the exact requested filter (an out-of-filter delivery from a foreign re-resolution of the literal name is refused loud; a foreign SAME-OR-NARROWER filter remains covered by the one-plane composition, not by this check), the two scanner profiles are explicit §13.9 matrix rows whose grant builders the mechanical matrix audit pins as the SOLE dynamic-enumeration `CONSUMER.CREATE` holders on the two authority streams (the provisioner's pre-created full-tail reader durables remain the one other records-stream consumer authority, and the audit pins that complete surface too), and the admission-mediator coordinate stays package-internal until a composition owns the one-records-scanner-per-space injection. An eighth round (the control-surface piece-2/4 wiring) landed: the record-reader provisioning seam is an ALLOWLIST over one canonical authority-def collection (a reader durable's kind must be a registered caller-readable record kind, so every authority-control kind and every unregistered kind refuse, and a dual-token kind whose atomic head is authority admits only a filter strictly deeper than the head, never one that can match or is shallower than the head key); that classification is runtime-frozen and the seam consults a private module-load snapshot, so a post-import mutation cannot remove the guard (the same integrity discipline is applied to every exported security-relevant collection: the baseline grant vocabularies, the credential-lifetime matrix, the session terminal states, the schema profile, and the broker floor are all frozen, and the minting-path consumers read private snapshots). The retirement barrier's cleaner authority is SPLIT into two per-operation credentials: a zero-write cleaner (its residual is terminal-free ACK suppression) and a settlement executor that alone holds the lease-record CAS and the lease-derived `wrk` terminal publish on the intent's exact pools plus the leader-served EPF and records fencing reads its own code path performs (NO EPW read: the settlement path settles or expires through the lease key before any EPW live-entry probe, so that read is unreachable and ungranted); the two are distinct CONNZ principals fenced independently before any frontier records, and the barrier runs settlement on the executor's own connection rather than its standing one. The retirement barrier is the `frontier.<lifecycleUid>` writer (the exact-arity `frontier.*` grant row), and the auth service's boot crash-resume finishes an owed retirement through the assembled deps (a per-endpoint short-lived drain client over the reviewed admission-mediator profile sharing the plane's sealed records scanner, and the per-op cleaner/executor split), fail-closed and loud like the takeover resume. Its re-verify round closed three composition gaps: the barrier now grants `STREAM.INFO` for exactly the CLOSED retirement-frontier stream set (the per-space lifecycle-data streams EPF/EPW/EPE/records, one source feeding both the intent validation and the grant, so a frontier read is never denied on a real broker nor a caller-selected arbitrary stream), the settlement executor drops the unreachable EPW live-entry read (the settlement path settles or expires through the lease key before any EPW probe, so that grant was dead), and the assembled drain completes every settleable obligation but fails CLOSED with an operator-legible frozen-not-lost message on accepted work that needs a confined commit-applier/route-reconciler authority (a scoped boundary whose full mechanics are a separate reviewed slice, never a broad records-write grant bolted onto the drain). A ninth round (the cross-process plane-ownership seal, §13.13) closed the last composition assumption the sealed scanners leaned on: at most one authority plane per space now holds them by a broker-visible claim, one exact never-deleted auth-KV `plane` row binding the two non-reconnecting scanner connections' broker identities, taken by create/revision-CAS with the candidates INERT until the win (no scan capability exists before it); a stale `held` row is reclaimed on LIVENESS ALONE (both claimed tuples conclusively absent under a COMPLETE connection sweep, adjudicated by the delivery daemon's closed read-only oracle over the delivery-admin rail; the auth process holds no `$SYS`), with no TTL, no heartbeat, and no sealed-scan-progress bit (a mid-scan crash reclaims; a paused-but-live plane keeps its connections and its ownership); the winner re-validates the claim before AND after every sealed scan (refuse or discard), an owned scanner disconnect fences the plane (invalidate exposure, close the sibling, never a transparent reconnect into a successor's consumer), clean close releases only after the scan clients are down, the three operator refusal faces carry distinct copy (live peer / inconclusive-fail-safe / mid-life fenced stop), and the launcher adds an exclusive-create pidfile belt. Its re-verify round hardened the reclaim and the fence: a `gone` verdict is valid only under the single-nats-server-process boundary, proven per observation from the responding server's own topology declaration in the `$SYS` reply envelope (any cluster self-report, multi-server observation, or missing declaration reads `unknown`; leafnode/gateway-extended accounts and backup-restore-onto-a-fresh-broker are named residuals; multi-server needs an incarnation/roster authority) — never inferred from which servers replied, which could neither be enforced by reply-counting (a partition shows one responder) nor flipped to require-the-claimed-server's-reply (a restarted server can never reply, the permanent-wedge horn); claim re-validation covers the two pinned scanner tuples (a tuple-only row rewrite is a lost claim); a scanner-death fence is FATAL to the whole authority plane (every authority operation refuses and the service exits loud, never a healthy-looking half-dead plane); the plane credentials' non-expiring boundary is normative (exactly the two non-reconnecting plane connections; every other authority credential keeps short-expiry + renewal); the claim row, connection tuple, oracle-query, and oracle-result schemas are closed exactly (unknown fields refuse, at every level); only successful well-formed CONNZ pages count toward a reclaim sweep (an API error, malformed envelope, non-string cluster declaration, id mismatch, or incomplete page poisons the observation); every sweep's reply inbox carries a per-call nonce (concurrent sweeps cannot cross-complete); the fenced plane's refusals are audience-split (a retryable unavailability to connecting agents, the state-3 restart copy to the operator's log and exit line); and the pidfile belt publishes atomically pre-populated (temp inode + no-overwrite `link(2)`; an empty slot is unpublishable and a pre-protocol one reclaims exactly once). A tenth round (the confined drain repairers) closed the retirement drain's accepted-work boundary functionally: the fail-closed applyCommit/reconcile interim is replaced by two per-op, per-repair principals — the COMMIT APPLIER (`local.epapl_<opId-hash>`, one exact records-KV publish row, minted only for a key inside the CLOSED self-commit class derived from the canonical frozen kind registry + the commit-path writer metadata, so a forged accepted-self row can never name an authority coordinate into a grant) and the POOL-ROUTE RECONCILER (`local.eprec_<opId-hash>`, one exact EPW item create-publish row, executing only a MEDIATOR-DERIVED closed repair command: the mediator reads and row-binds the durable acceptance decision itself and derives the exact subject + the §13.6 canonical acceptance item bytes, now a normative derivation so first enqueues and crash repairs are byte-identical) — each minted per repair, executed, closed, with the CAS-header and payload-blind residuals named per profile; an accepted self-commit now re-applies (or classifies landed/superseded) and an accepted pool route re-materializes, so a retirement with covered accepted work COMPLETES on resume, and an accepted EFFECTS route with no completion marker terminalizes through the RETIREMENT-CANCEL terminal (§13.8 option (i)): the effects completion fact becomes a closed two-member union (ran, or `cancelled: { opId, target }` — the same identity spine, never a forged success, written only for the retiring target's own acceptances), an action's goal union already carries the first-class `cancelled` state (the retirement attribution rides its digest-bound payload), the cancel publishes CREATE-ONLY on the SAME completion subject so first-terminal-wins is structural in both directions, and a third per-op principal (`local.epcan_<opId-hash>`, one exact completion-subject create row) executes the mediator-derived repair — so a retirement with in-flight accepted effects work now COMPLETES on resume with a reader-legible cancelled terminal instead of freezing. An eleventh round (the despawn→retirement trigger, the P1 closure) reserved the `auth-admin` control service (SPEC 13.2): the AUTH plane serves the GENERIC \"retire a lifecycle\" operation on the `ctl` grammar's subject-attributed rail (the delivery-admin discipline: broker-ACL caller attribution, bound replies, an unbound reply target dropped before processing), authorized at SERVE TIME by the fresh space-manager-lease holder check (one leader-served read of the manager bucket's single lease key; holder == the subject-attributed requester principal; DEL/PURGE markers and TTL-expunged rows read absent and refuse fail-closed — never mint-time trust, closing the post-lease-loss window), answering the four-outcome idempotence table in operator vocabulary with every refusal a stated COMPLETE no-op; the space manager triggers it per despawn through an ephemeral request-and-reply-only `retirement-requester` credential with a STABLE per-lifecycle opId (retries, same-name-spawn nudges, and boot resumes converge on one operation), holds the despawned name RESERVED-pending-retirement until the terminal (a same-name spawn refuses legibly and re-drives the request; the in-memory reservation's restart residual is named — the durable truth is the lifecycle head itself), and the retirement executes through the plane's own reviewed deps over its ONE sealed records scanner. The barrier's terminal cleaner/executor pool set is the operation's EFFECTIVE INVENTORY: the target's accepted `oblig.<uid>.>` pool routes discovered from the just-drained obligation set UNIONED with the intent's OPTIONAL trusted hint (the despawn rail passes none), superseding the round-8 \"intent's exact pools\" enumeration so an empty-hint despawn still settles every accepted pool item before the frontier; the durable-intent hint is a TRUSTED ADDITIVE AUTHORITY input (a hinted pool with no accepted obligation still receives a bounded per-op credential), and the compromised cleaner/executor residuals scope to that whole effective inventory, including any hint-only pool. |\n| 2026-07-10 | **v0.4 binding revision: endpoint control surface (§13).** One standardized typed surface for every endpoint (manager, delivery, wrapped third-party servers): class/instance/scatter rails with per-command broker enforcement and an authorization-mode gradient, lifecycle identity (recyclable alias + never-reused lifecycle UID + fenced process epoch, §13.1, §2/§6/§8 extensions), versioned envelope with structured errors and signed slots, three delivery contracts (ephemeral, split-key records, untrusted submissions → mediated canonical facts), verbs call/cast/watch/claim/scatter (claim owner-mediated: workers hold no pool grant), composites (action, checkpoint, guard, capability handle with redemption-pinned `handle`-mode targets, session, virtual endpoints), content-addressed cluster contracts + governed traits + describe, the ownership matrix (incl. exact reader/consumer/ack rows and pinned consumer-name grammars), takeover/retirement revoke-and-evict barriers over the full ledgered credential family (credential ledger, §13.1), mediated timer arming (request/armed/fire split with a scheduler-origin fire check), poison quarantine facts, an epoch-pinned record-write ingress plane (`epr`), a single-message digest-subject contract store (`epc`), pre-created pull-only reader consumers (no dynamic reader creates: a create's delivery target is body-set and unconfined), an alias CAS head for lifecycle activation, and receipts and trust anchors. **Hard cut:** deletes the v0 `ctl` rail, `ControlRequest`/`ControlReply`, the `self`/`manager`/`admin`/`delivery-admin` tiers, and the reserved `control.<instance>` subject. `protocolVersion` targets `0.4` at migration completion; `1.0` stays reserved as a later stability declaration. |\n| 2026-07-07 | Documentation revision, no wire change: layered authority statement (schema authoritative for shapes, prose for semantics), document-snapshot policy and this change log (§11), reciprocal links to the informative docs. |\n| 2026-07-03 | **v0.3 binding revision: owner+actor identity.** The wire identity becomes the two-token principal `(owner, actor)`: subjects carry the sender as `<owner>.<actor>`, and grants, durables, presence, and `from.id` re-key onto the pair (§2, §3, §6, §8, §9). The connection nkey remains only the transport credential (the per-connection reply inbox). Adds the per-user-auth authorization grammar and the owner-token format (§2, §9). Supersedes the single-id grammar. |\n| 2026-06-21 | **v0.3 binding revision: channel live delivery.** Channel live delivery moves from the mediated per-instance live-tail durable to native `sub.allow`-bounded core subscriptions, with an explicit per-channel `live`/`durable` delivery class and the per-member durable backstop (§4, §7, §8); membership moves to a privileged-written registry (§7). Supersedes the v0.2 single-durable live-tail. |\n| earlier | v0.2 and before predate change control: the v0.2 contract (single mediated live-tail durable binding) is superseded by v0.3 and kept only in history. |\n"
372
372
  },
373
373
  "lang": {
374
374
  "title": "Cotal Lang: the workflow language",