Surfaced during the mesh review of #23 (session resume). These are pre-existing manager gaps, but session-resume is the first feature to make them both operator-reachable and retry-amplified, so tracking them as a scoped follow-up.
Two related gaps, one root: on a detached cotal start / MCP cotal_spawn, startAgent returns {ok:true} the moment runtime.spawn() hands back a PTY handle — before the child (claude) actually runs.
1. Unsupported-connector resume mints before it fails (early-fixable)
buildLaunch throws for opencode/hermes resume inside startAgent's try — i.e. after provisionAgent mints scoped creds + broker durables (auth mode). So cotal start --agent opencode --resume x fails loud but late, orphaning the minted DM/DLV/role-TASK durables + a creds file for a peer that never launched.
Fix: a declared supportsResume capability on the Connector SPI + a central early preflight check (before the reserve/mint, beside the binary/transcript prechecks). This also makes the default fail-loud for any future connector that neither declares support nor reads opts.resume — closing the fallback-by-omission hole that hermes exemplified (it references opts.resume/opts.mcpServers nowhere; the guard is hand-plugged today). The LaunchOpts.resume doc-comment is the type-level contract; the capability is the runtime-enforcement half TS can't provide.
2. Supported-path async early-exit is neither surfaced nor cleaned up (the dominant leak)
On the claude path a bad id / cwd-mismatch / old-CLI-rejecting---fork-session makes claude exit inside its PTY, and:
- (i) not surfaced: the caller already saw
✓ started; the peer just never joins the roster. Diagnosable only via cotal attach.
- (ii) leaks under auth:
identity = newIdentity() is a fresh nkey per attempt, and onAgentExit → freeSlot does agents.delete + a cooling stamp only — no deprovision, no creds unlink. The creds file is per-name (bounded/overwritten), but the broker durables are per-identity, so each failed attempt orphans a distinct durable set. Retry-amplified: debugging a typo'd id retries 5–10× → 5–10 orphaned durable sets.
Fix: detect the early child exit before returning ok (or a short presence-wait), and deprovision on early exit (auth-mode scoped — open mesh has no mint, so no leak).
Scope / notes
- Auth-mode only. Open mesh mints nothing.
- Manager-internal for part 2 (no core/wire change); part 1 adds one optional
Connector capability.
- Not resume-specific: part 1's late throw is shared by
opencode+mcpServers and hermes+win32; part 2's async-exit affects every detached launch. Resume just makes them reachable.
- Related nice-to-have (from the review): the
loadRoster field-picker silently drops an unknown resume: key (can't cause false-resume since it never reaches buildLaunch, but it's the one declarative surface that ignores rather than rejects).
Follow-up to #23 / PR #157.
Surfaced during the mesh review of #23 (session resume). These are pre-existing manager gaps, but session-resume is the first feature to make them both operator-reachable and retry-amplified, so tracking them as a scoped follow-up.
Two related gaps, one root: on a detached
cotal start/ MCPcotal_spawn,startAgentreturns{ok:true}the momentruntime.spawn()hands back a PTY handle — before the child (claude) actually runs.1. Unsupported-connector resume mints before it fails (early-fixable)
buildLaunchthrows foropencode/hermesresume insidestartAgent's try — i.e. afterprovisionAgentmints scoped creds + broker durables (auth mode). Socotal start --agent opencode --resume xfails loud but late, orphaning the minted DM/DLV/role-TASK durables + a creds file for a peer that never launched.Fix: a declared
supportsResumecapability on theConnectorSPI + a central early preflight check (before the reserve/mint, beside the binary/transcript prechecks). This also makes the default fail-loud for any future connector that neither declares support nor readsopts.resume— closing the fallback-by-omission hole thathermesexemplified (it referencesopts.resume/opts.mcpServersnowhere; the guard is hand-plugged today). TheLaunchOpts.resumedoc-comment is the type-level contract; the capability is the runtime-enforcement half TS can't provide.2. Supported-path async early-exit is neither surfaced nor cleaned up (the dominant leak)
On the claude path a bad id / cwd-mismatch / old-CLI-rejecting-
--fork-sessionmakesclaudeexit inside its PTY, and:✓ started; the peer just never joins the roster. Diagnosable only viacotal attach.identity = newIdentity()is a fresh nkey per attempt, andonAgentExit → freeSlotdoesagents.delete+ a cooling stamp only — no deprovision, no creds unlink. The creds file is per-name (bounded/overwritten), but the broker durables are per-identity, so each failed attempt orphans a distinct durable set. Retry-amplified: debugging a typo'd id retries 5–10× → 5–10 orphaned durable sets.Fix: detect the early child exit before returning
ok(or a short presence-wait), and deprovision on early exit (auth-mode scoped — open mesh has no mint, so no leak).Scope / notes
Connectorcapability.opencode+mcpServers andhermes+win32; part 2's async-exit affects every detached launch. Resume just makes them reachable.loadRosterfield-picker silently drops an unknownresume:key (can't cause false-resume since it never reachesbuildLaunch, but it's the one declarative surface that ignores rather than rejects).Follow-up to #23 / PR #157.