fix(coding-agent): revive archived sessions on prompt instead of dead-ending - #1039
fix(coding-agent): revive archived sessions on prompt instead of dead-ending#1039junhoyeo wants to merge 28 commits into
Conversation
…-ending A window attached to a session the daemon later archives (idle eviction, RLM subagent archived after its final answer, parent deleting a finished child) stayed open but every keystroke failed with 'Unknown active session' forever, even though the transcript is saved and resumable. DaemonAgentConnection.prompt/promptAndWait now catch the unknown-session error, resume the saved session file via the daemon's idempotent create command, re-attach, emit session_resynced, and retry the prompt once. The revived binding is never published early: attach now takes an explicit target (attachSessionBinding) and the connection keeps its previous binding until the attach succeeds, so no concurrently started prompt can target a session this client has not attached to, and there is no rollback that could stomp a newer binding installed by a concurrent transition. A revival superseded by a session switch, reconnect, or update recovery fails, leaves the newer binding untouched, and releases the revived session's attachment (plus complete_owned_session for owned lifecycles, also on disposal mid-revival). attach() rejects a superseded response instead of rebinding backwards. The unknown-session match is exact and bound to the id the prompt targeted, and a concurrent prompt joins only a sibling revival of that same session. Reviving a killed session on a later prompt is deliberate: the agents view reply flow already resumes killed sessions, and a revived transcript is strictly recoverable.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 502e7a496c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…, and failed snapshot streams Address three review findings on the revival path: - The revived worker's create command now carries this invocation's telemetry opt-out; without it the worker launched under the daemon's default policy and assertTelemetryAttachAllowed rejected the attach after the worker had already started with telemetry enabled. - Revival resolves with the revived active session id and both retry paths verify the binding still equals it before re-sending the prompt, closing the window where a switch to an already-active session lands between the revival resolving and the retry continuation running. - A revived attach whose response was applied but whose streamed snapshot failed no longer fails the revival: the binding is published and the client is attached server-side, so the revival falls through to the snapshot reads, which recover or schedule a background resync instead of stranding a coherent binding and losing the prompt.
There was a problem hiding this comment.
💡 Codex Review
When the revived attach response publishes its ID and then waits for a chunked snapshot, a concurrent switchSession or reconnect can bind and apply a different session before this await completes. The late revived snapshot is nevertheless applied to latestSnapshot (and completeSnapshotAssembly also updates the attached identity), so the active binding can point to the newly selected session while cached state and a subsequent session_resynced event describe the revived one; that revived attachment is not released either. Fresh evidence beyond the earlier retry finding is this unguarded post-publication snapshot await: the new check before retrying the prompt runs only after these state mutations have already occurred.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…oves mid-stream A concurrent session switch or reconnect can rebind the connection while the revived attach's chunked snapshot is still streaming. The late snapshot then described a session the window no longer shows: attachSessionBinding applied it to latestSnapshot after the await, and completeSnapshotAssembly rewrote the attached identity and snapshot cache from the frame handler, while the revived attachment was never released. attachSessionBinding now revalidates the published binding after awaiting the streamed snapshot and throws the supersession error instead of applying it (the revival's catch then releases the revived attachment), completeSnapshotAssembly only mutates shared identity and cache state - and only emits replacement/resync events - for snapshots belonging to the published binding, and the revival's own resync emission is skipped once the binding has moved on.
|
@codex review Addressed in 4d987e7: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4d987e7008
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…current switch The revived attach publishes its binding and then awaits the chunked snapshot stream; a switch/reconnect landing in that window could rebind the connection while the late revived snapshot was still applied to the shared snapshot cache and attached identity, and a session_resynced describing the revived session could follow. - attachSessionBinding revalidates the published binding after awaiting the streamed snapshot and rejects as superseded instead of applying a snapshot for a session the connection no longer shows - completeSnapshotAssembly only mutates shared identity/cursor/snapshot state and emits session_replaced/session_resynced when the snapshot belongs to the published binding (pending-transition waiters still get their resolved snapshot) - the revival's own resync emission re-checks the binding, and a revived attachment released on the superseded-attach path now completes owned workers (releaseRevivedSession) instead of only detaching Pinned by two new tests: the mid-stream switch race (snapshot discarded, revived attachment released, next prompt targets the switched session) and the owned-worker release on a failed post-revival attach (red-green verified against the raw-detach variant).
…nding targets The pending-target admission added for the same-buffer attach race let EVERY outbound frame addressed to the pending id through, not just the snapshot transfer it exists for. After a supersession the revived id stays pending until the snapshot waiter finishes, so a live session_event, session_status, session_resynced, or session_closed for the superseded session was processed against the newly switched binding - a session_closed would emit a terminal close for a window showing a different session. isMessageForActiveSession now admits a pending target's frames only for session_snapshot_begin/chunk/end/failed; those handlers are keyed by snapshotId and completeSnapshotAssembly already refuses to mutate shared state for a non-published binding. Live frames for a pending target are dropped. Red-green verified: with the broad admission the new test observes the spurious terminal close.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a59f857cd9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…prompt When a signal-carrying prompt's unknown-session failure races its abort, promptWithAdmissionCancellation rethrows the failure as an AgentConnectionPromptAdmissionError carrying the same 'Unknown active session: <id>' message, which canReviveFromSavedSession matched — so cancelling a prompt against an archived session created and attached a revived worker only for the retry to observe the aborted signal and reject. promptWithSessionRevival now refuses to start or join a revival once the prompt's signal has aborted and surfaces the failure as-is. Pinned by a red-green-verified test that races the abort against the gated unknown-session response and asserts no create is issued.
…nding was pending The daemon queues events that land during an attach snapshot and delivers them afterwards as a catch-up resync. When that resync is addressed to a revival target that is still pending - sharing the socket buffer with the attach response and completing before the attach continuation publishes the binding - it had no waiter: completeSnapshotAssembly stored it in completedSnapshots, nothing consumed it, and the older attach snapshot became current with the intervening events lost until some later resync. completeSnapshotAssembly now buffers the newest unsolicited catch-up per pending target, and attachSessionBinding applies it via applyReplacementSnapshot once the binding publishes, so the revival's resync emission carries the caught-up state. A failed or superseded transition discards the buffered catch-up along with the admission, and transport resets clear the buffer. Red-green verified: without the flush, the new test observes the revival resync carrying the older attach snapshot instead of the catch-up.
|
@codex review Round-4 findings addressed: the pending-target catch-up buffering in df0cf07 (thread 3742775069) and the cancelled-prompt revival guard in 6470a60 (thread 3742775074), plus the owned-worker release on the superseded-attach path in 3201db6. Head is df0cf07: tsc clean, biome clean, 88/88 connection tests (18 revival-specific), 353/353 across the six related suites, all new behaviors red-green pinned. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: df0cf07528
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…tion targets session_snapshot_failed is admitted for pending binding targets so the transfer can settle, but the handler then ran recoverFailedSnapshot for replacement/resync purposes unconditionally. For a catch-up that fails while its revival target is still pending, recovery re-read state against the still-published archived selector, failed with the same unknown-session error, and emitted a terminal close - killing the window even though the revived attach was about to succeed. Recovery now runs only when the failed snapshot belongs to the published binding. A failed pending catch-up needs no recovery: once the binding publishes, the transition re-reads fresh state anyway, and on supersession the buffered state is discarded. Red-green verified: without the gate the new test observes the spurious terminal close.
|
@codex review Round-5 finding addressed in 50b835d (recovery gated to the published binding; failed pending catch-ups settle without terminal-close side effects). Head is 50b835d: tsc clean, biome clean, 89/89 connection tests (19 revival-specific), 354/354 across the six related suites, all behaviors red-green pinned. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50b835d498
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…e publication The round-5 gate stopped terminal recovery for a catch-up that fails while its transition target is pending, but the events that catch-up carried were then silently dropped: the successful attach snapshot was cached fresh, so the transition's post-publication read served the cache instead of re-reading from the daemon. A failed pending catch-up is now recorded per target (pendingBindingCatchupFailures). At publication, a buffered successful catch-up supersedes it (newest wins, applied from the buffer); with no successful catch-up the cached attach snapshot is invalidated so the mandatory read actually re-reads. The marker is discarded with the admission on failed/superseded transitions and cleared on transport resets. Red-green verified: with the invalidation disabled, the revival resync serves the stale attach snapshot instead of the re-read state.
|
@codex review Round-6 finding addressed in 8109307 (failed pending catch-ups invalidate the attach snapshot's freshness at publication unless a later successful catch-up superseded them, so the post-publication read is genuinely fresh). Head is 8109307: tsc clean, biome clean, 90/90 connection tests (20 revival-specific), 355/355 across the six related suites, all behaviors red-green pinned. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8109307ac3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…led one Round-6 made a buffered successful catch-up clear an earlier failure marker, but the symmetric ordering leaked stale state: a success buffered at T1 followed by a NEWER catch-up failing at T2 left the T1 snapshot in the buffer, so publication applied state-at-T1, cleared the failure marker, and the [T1, T2] events carried by the failed catch-up were lost with no re-read. Recording a pending-target failure now also drops any buffered snapshot for that target - newest wins in both directions - so publication finds no buffer, consumes the marker, invalidates the cached attach snapshot, and the mandatory read fetches state at or beyond T2. Red-green verified: without the drop, the new test observes the revival resync serving the stale T1 buffer instead of the re-read state.
|
@codex review Round-7 finding addressed in ba1ad54 (a newer failed catch-up evicts an older buffered success, so publication re-reads instead of serving stale state; the pending catch-up state machine is closed under both orderings, each red-green pinned). Head is ba1ad54: tsc clean, biome clean, 91/91 connection tests (21 revival-specific), 356/356 across the six related suites. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba1ad540dd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…apshot await The daemon can deliver the attach snapshot's end frame and a queued catch-up resync in one socket read. With the binding already published, completeSnapshotAssembly applies the newer resync (and emits it) before the waitForSnapshot continuation resumes; the continuation then overwrote latestSnapshot with the OLDER attach snapshot and re-marked it fresh, so the revival's resync served stale state and the intervening events were dropped. The binding-supersession check cannot catch this: the binding never moved. The continuation now skips its assignment when a fresh snapshot other than the pre-await one carries a higher event sequence - newest wins by sequence, guarded by an identity check first because a sequence is only comparable within one session (an unchanged latestSnapshot can still describe the previous binding). Red-green verified: without the guard, the new post-publication wire-order test observes the attach snapshot overwriting the catch-up.
|
@codex review Round-8 finding addressed in 0d2e4ed (a catch-up applied to the published binding during the attach snapshot await is kept by sequence-based newest-wins instead of being overwritten by the older attach snapshot). Head is 0d2e4ed: tsc clean, biome clean, 92/92 connection tests (22 revival-specific), 357/357 across the six related suites, red-green pinned. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d2e4ed732
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…blished the same binding A concurrent switchSession targeting the connection's own saved session file lands as SessionAlreadyActiveError for the id the revival's create just produced; reattachSession publishes that id as the new binding. The revival's post-create supersession check then released the revived session — detaching the connection's currently PUBLISHED binding, so it stayed bound locally but stopped receiving daemon events. The supersession path now releases the revived session only when the newer binding differs from the revived id; the supersession error is still thrown (the switch's reattach owns the binding, the failed prompt surfaces its original error, and subsequent prompts flow to the live binding). Pinned by a red-green-verified test asserting no detach or complete_owned_session is issued for the revived id and the next prompt targets it.
Both openAgentsViewSession attach paths omitted reviveConfig, so a chat opened from the agents view - the archetypal window for the revive-on-prompt fallback - recreated its session under daemon defaults instead of the launch context resumeSavedAgentsViewSession uses. The resume-config computation is extracted into agentsViewSessionRuntimeConfig (shared by resumeSavedAgentsViewSession and both attach call-sites, so the revival's create is byte-identical to the resume's), the live-attach path derives it from the summary, and the resume path passes through the exact config it just created with. Pinned by a parity test covering the intact-cwd and missing-cwd-fallback cases.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 837be68249
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… transcript The wasAttached reliance is now gated on a negotiated attach_ownership server capability. Against a daemon that cannot report ownership the client keeps the historical unconditional detach on a superseded revival: skipping it there would leave a stale socket attachment that inflates attachedClients and blocks the revived worker's idle eviction until the socket closes, which is worse than the pre-existing shared-client edge that detach carries. Both mixed-version directions are pinned: capability present + duplicate attach preserves the sibling's subscription; capability absent keeps the legacy detach. The revival config also stops leaking across session switches: the connection records which transcript its reviveConfig was computed for (first attach), and reviving a different transcript drops the config's cwd - the daemon then resumes in the switched transcript's own directory instead of treating the previous project's cwd as an explicit override. Red-green verified for both changes.
|
@codex review Round-15 findings addressed in c5e9a2a: attach_ownership is a negotiated server capability with legacy fallback to the historical detach (both mixed-version directions pinned), and the revival config tracks its transcript — a session switch drops the stale cwd so the revived prompt runs in the switched transcript's own directory. Both red-green verified. Please re-review. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c5e9a2a5f7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…nse, not post-stream state A replacement snapshot landing while the revived attach snapshot was still streaming could rewrite the attached identity before the revival captured its transcript binding; matchesRevivedBinding then passed against the switched transcript and the failed prompt was resent into it. The identity published by the attach response is now recorded before the snapshot await (lastAttachPublishedIdentity) and the revival builds its binding from that, so a mid-stream replacement fails the identity check and the prompt's original error surfaces. Red-green verified. The agents-view reply fallback (the telemetry-disabled sendPrompt attach) also carries reviveConfig now, computed from the reply target's summary with the shared agents-view helper - the last attach site that could revive under daemon defaults.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae2db8c32c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…lback cwd A transcript switched in over a missing recorded directory only opened because the user selected a fallback cwd; the revival's stale-cwd strip then recreated it with no override, so the create failed on the missing directory and the prompt dead-ended - the exact failure this branch exists to fix. switchSession records the cwd override alongside the transcript it switched to (cleared when a switch needs none), and the revival re-applies it whenever it recreates that transcript, independent of whether an invocation config is present. Red-green verified: without the retention, the new test observes the recreate dropping the fallback cwd.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 48fae2a5a2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…connection A reply that resumed an inactive transcript recomputed the delivery connection's revive config from the now-live summary, stripping a fallback cwd the resume was opened with (its recorded directory is missing); a revival of that connection then failed on the missing directory. The resume's own config now travels through sendPrompt and wins over the summary-derived recomputation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8436157579
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… path A switch to a missing-cwd transcript that resolves as a reattach (the transcript is live under another worker) skipped the override recording, so a later revival of that transcript recreated it against the still-missing recorded directory and dead-ended. The catch path now records the override too, keyed by the canonical file the reattach reported. Red-green verified. Also adds the old-client/new-daemon direction test the wire-change rule requires: a daemon that reports wasAttached against a client without the negotiated capability behaves identically to a pre-revision-15 client - the field is ignored and the historical unconditional detach is kept.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2bb37bb27
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…transcript A --no-session chat's initial attach has no session file, leaving the revive-config transcript marker unset; a transcript resumed later then matched the undefined marker check and inherited the launch cwd as an explicit override into the wrong directory. The marker now records null for a fileless first attach, so any later transcript counts as foreign and the cwd is dropped. Red-green verified.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c3adf81be0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…onnects The null marker for a fileless first attach was assigned with ??=, which re-assigns over null - a reconnect after resuming a saved transcript adopted that transcript as the config's own and the launch cwd leaked back into its revival. The capture now checks strictly for undefined. Red-green verified.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1ca7353702
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Thank you for the report and proposed work. This root cause is now covered by maintainer-owned stacked PR #1162, authored independently from We did not inspect or reuse this PR's diff, branch, commits, implementation code, or tests; its public description/comments were used only as a bug report. To keep one review surface, this PR is superseded by #1162 and is being closed. The complete review stack is #1158–#1165. It is being left unmerged for human review after CI and review-bot findings are cleared. |
Problem
A terminal window attached to a daemon session can outlive the session: the daemon archives an RLM subagent after it delivers its final answer, evicts idle workers, and parents delete finished children. The window receives
session_closed, shows the "The daemon stopped this agent session…" banner, and stays open — but every subsequent prompt sends the staleactiveSessionIdand dead-ends withUnknown active session: <id>forever.The transcript is saved and resumable the whole time. The agents view already offers exactly this affordance twice — resume-on-open (
openAgentsViewSessioncatches the unknown-session error and resumes the saved file) and resume-on-reply for inactive rows — but the open chat window had no revive path at all.Observed in the wild: a subagent window left open after the child replied to its parent; the parent archived the child ~20s later, and every keystroke in the still-open window produced
Supervisor command prompt failed: Error: Unknown active session: f4e077f832dcwith no recovery.Fix
DaemonAgentConnection.prompt/promptAndWaitnow treat a typed message as "resume & send": on an unknown-session failure they resume the connection's saved session file via the daemon's idempotentcreate {sessionPath}, re-attach, emitsession_resynced, and retry the prompt once. Revival failure surfaces the original unknown-session error.Design points (each pinned by a test):
attach()is refactored intoattachSessionBinding(target, resetCursors); the connection keeps its previous (dead) binding until the attach to the revived session has succeeded. A concurrently started prompt therefore targets the dead id, fails, and joins the in-flight revival — it structurally cannot race ahead into a session this client has not attached to. Because nothing mutates before attach success, there is no rollback path that could stomp a newer binding.createand inside the attach (attachSessionBindingrejects a response whose binding moved mid-flight instead of rebinding backwards). A session switch / reconnect / update recovery landing mid-revival wins; the revival releases the revived session's attachment (pluscomplete_owned_sessionfor owned lifecycles, also when disposal begins mid-revival).session_snapshot_beginfor the revived session into one socket buffer, so those frames can be parsed before the awaiting continuation publishes the new binding.isMessageForActiveSessionnow also admits ids inpendingReattachActiveSessionIds(the same setreattachSessionalready maintains), andattachSessionBindingregisters a foreign target there for the duration of the attach. Pre-existing attach paths always target the published id, so their behavior is unchanged. The regression test for this was verified red-green against the unfixed filter.SessionSummaryattach result the resync snapshot comes from separate reads; if those fail the revival still succeeds (the binding is coherently bound and attached, prompts work) and a bounded background retry delivers thesession_resyncedso the window cannot keep rendering the dead transcript silently.killed), and a revived transcript is strictly recoverable. Documented in the revival docstring.Tests
17 new tests in
agent-connection-daemon.test.ts(80 total in the file, all passing): happy path +promptAndWait, signal-carrying prompts, revival failure surfacing the original error, no-session-file and wrong-id negatives (including an id the attempted id merely prefixes), attach-failure recovery on the next prompt, concurrent prompts sharing a singlecreate, dispose-during-create releasing the revived session, owned-lifecycle propagation, prompts staying on the dead binding until the revived attach completes, a mid-revival session switch winning with cleanup, the same-buffer snapshot-frame ordering, and the background resync retry.daemon-mode,daemon-supervisor-eviction,daemon-supervisor-lazy-subagents,agents-view-mode, andagents-view-inactive-replysuites all pass unchanged (265 tests).Note
Revive archived daemon sessions on prompt instead of returning unknown-session errors
DaemonAgentConnectionnow transparently revives the session from its saved file and continues, rather than surfacing an unknown-session error.LocalAttachmentTrackertracks per-socket attachment ownership so sharedDaemonClientusers don't accidentally detach a sibling connection's session.reviveConfigis threaded from call sites (agents-view and main attach) through toDaemonAgentConnection.attach, ensuring revived workers use the same runtime config as the original session, including cwd overrides.wasAttachedflag to support ownership-aware cleanup.Macroscope summarized d5bc1ee.