Fix stale background response state after renderer recovery - #115
Fix stale background response state after renderer recovery#115sambitcreate wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — initial review of the detached-generation recovery fix at 6bfd04c4, verified with the focused and adjacent suites plus npm run type-check and lint.
renderer/lib/chat-terminal-sync.ts— addsDetachedLifecycleChatReconciliation,pendingDetachedLifecycleChats(),captureDetachedLifecycleChat()(exact stream-id capture at event time), andclearInactiveDetachedLifecycleChat(), which removes only the captured ids from the detached/fallback/projection maps and re-validates chat+workspace against the current owner before deleting.renderer/main/root-view.tsx—reconcileDetachedLifecycleChat()waits for bounded main idle, refetches the exact transcript and chat list, then reads a fresh activity snapshot and clears only when the chat is inactive; thechats:settledhandler now routes through it, and a new effect subscribes tochats:activity-changedbefore its one-shot bootstrap snapshot so a settle transition cannot fall between the two.renderer/lib/chat-terminal-sync.test.ts/renderer/main/chat-transition.test.tsx— behavioral coverage for inactive repair, active preservation, same-chat newer-generation exactness, and workspace isolation, plus a source-contract test pinning the subscribe-before-snapshot ordering and the clear-after-fresh-snapshot wiring..papercuts/troubleshooting.md— investigation notes for the incident.
Two independent deep passes (mine plus two focused subagent traces) found no path where the new clear deletes still-running work — waitForChatIdle gates on generation ownership, the clear uses a snapshot taken after the refetch, and newer same-chat streams are excluded by capture — and no app-reachable path where a retained owner survives indefinitely. The residual best-effort property (a failed bootstrap snapshot read with no later activity event) is already documented in the code comments.
DeepSeek Flash | 𝕏

Summary
Production incident
A completed chat could remain stuck on “Response continues in the background…” with a sidebar spinner after a renderer route error. Main had durably persisted and settled the generation, but the renderer retained its detached lifecycle owner after missing the one-shot terminal payload.
Verification
npx tsx --test renderer/lib/chat-terminal-sync.test.ts renderer/main/chat-transition.test.tsxnpm run type-checknpm run lintnpm testnpm run buildThe regressions cover missed terminal delivery, genuine active work, same-chat newer-generation races, workspace isolation, and root recovery subscription ordering.