Repository navigation
Description
Expected behavior
After an app restart, a restored pane (tile leaf or Grid Dispatch lane selection) that shows a composer accepts a prompt: if the backend for that session id is not alive in this app run, the send path wakes/recovers it first (same-SessionId recovery, as agent-index navigation and #691's lane-placement path already do) and then delivers.
Actual behavior
Typing into a restored pane and pressing Enter fails with Cannot deliver prompt: <id> is not a live agent session, journaled by main as delivery.reject { code: not-ready, registryHit: false, reason: "never-owned" } — an id main has never spawned in this run. The pane looks perfectly live; the user has no reason to know the backend was never started.
Evidence
Debug bundle ~/.config/agent-code/debug-bundles/manual/2026-08-30T23-51-06-471-9bd68e14 (build b4d64c1c, app run started 23:41:21 after a prior force-quit/power-loss shutdown):
23:42:57.179 delivery.reject sessionId=82fa0abe… reason=never-owned23:45:21.812 delivery.reject sessionId=39e22d50… reason=never-owned
39e22d50… is verifiably a session id from the previous app run — it is the subject of the earlier bundle 2026-08-30T22-36-11-605-39e22d50 (the PR #702 acceptance-timeout investigation). Its pane was restored at rehydrate, the user typed into it, and main correctly reported it had never owned that id this run.
Why the existing guards don't cover this
rehydrate.tsdeliberately does not respawn detached (hibernated) sessions — the wake is supposed to happen at first use.- PR fix(dispatch): wake a hibernated agent before placing it in a Grid Dispatch lane #691 (
selectTiledLaneSession) wakes on every lane placement gesture (index click, strip click, ⌥↑/↓, ⌘N). But a restored workspace re-establishes lane selections without any placement gesture, so the wake never runs; the first gesture is typing into the composer, which goes straight todeliverPromptToAgent. - PR fix(dispatch): wake a hibernated agent before placing it in a Grid Dispatch lane #691 explicitly deferred the sibling gap: "grid-placed-but-dead sessions still rely on the pane's own Retry" — same class, reachable from classic tiles too, but most visible in Grid Dispatch because lanes surface many hibernated agents after a restart.
- The reject result is already shaped for recovery (
code: not-ready,retrySafe: true,disposition: session-unusable) but the composer send path does not act on it.
Fix direction
Make the composer send path liveness-aware, mirroring #691's contract at the delivery boundary instead of only at placement: on submit, if the runtime/backing session is not live this run (or when delivery rejects with not-ready + never-owned/entry-lost-after-owned), run ensureSessionLive(sessionId, 'composer.send') (same-SessionId recover, joining any in-flight wake) and retry the delivery once. Refuse with the existing toast if the wake fails. This removes the last "typing lands on a dead backend" path regardless of which surface restored the session.
Notes
- The
entry-lost-after-ownedrejects in the same bundle (sessions4ac948fd,9bd68e14) are downstream of the trust-dialog regression (bug(claude): trust dialog accept confirms "No, exit" — new default highlight kills the session #705): the CLI exited 300ms earlier because trust-accept confirmed "No, exit". Fixing bug(claude): trust dialog accept confirms "No, exit" — new default highlight kills the session #705 removes that trigger; this issue covers the never-owned/restored-session half, which bug(claude): trust dialog accept confirms "No, exit" — new default highlight kills the session #705 does not. - Related: bug(dispatch): prompt to a hibernated agent in a Grid Dispatch lane is rejected as not a live agent session #690 (fixed by fix(dispatch): wake a hibernated agent before placing it in a Grid Dispatch lane #691 for placement gestures), Fix runaway loop/crash when opening worktree panel #150 (unrelated worktree-panel loop).
Environment
agent-code b4d64c1c production build, 2026-08-30, macOS; two windows open (multi-window #692 active) — ownership routing not implicated: the registry is process-wide and the reject is registry-membership, not window routing.
Activity