fix(desktop): stop status-stack remounts from re-arming a dead-runtime poll storm (#98434) - #98455
Closed
chelsealong wants to merge 1 commit into
Closed
chelsealong wants to merge 1 commit into
chelsealong wants to merge 1 commit into
Conversation
…e poll storm (NousResearch#98434) A boot-restored chat can stay bound to a dead runtime id and remount its composer status stack repeatedly with no genuine rebind ever occurring. The stack's mount effect cleared the gone-polling latch on every mount, so each remount re-armed process.list + slash.exec('goal status') against the same phantom id forever, churning the composer every ~5s. Real rebinds already reset the latch at the runtime-mint seams (use-gateway-boot.ts, store/gateway.ts). Drop the redundant per-mount reset so the latch actually holds across a remount.
Contributor
98455 — Stop clearing background-polling latch on ComposerStatusStack mount
Non-blocking:
Verdict: Targeted fix for endless 4001 polling with faithful reproduction test. Non-blocking — please use your judgment. |
Contributor
|
Superseded by #99664. Same poll-loop class — status-stack remounts re-arming a dead runtime. The latch on main covers it. Closing so we don't double-merge. |
3 tasks
Contributor
|
Superseded by #99891. The remount latch ( Thanks for isolating the remount clear. |
This was referenced Sep 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the client-side half of #98434 ("Desktop: boot-restored chat stays bound to dead runtime id — status-stack polls it every 5s forever (composer flicker + focus loss)").
What's wrong
apps/desktop/src/store/composer-status.tsalready has a "gone-session" latch: onceprocess.listcomes back 4001session not foundfor a runtime id, that id is added togoneSessionsand every later poll against it short-circuits — this is exactly what stops the storm the issue describes. ButComposerStatusStack's mount effect (apps/desktop/src/app/chat/composer/status-stack/index.tsx) calledresetBackgroundPollingGuard(sessionId)on every mount, clearing that latch unconditionally:A component mount/remount is not proof of a fresh runtime binding — the issue's own repro shows a boot-restored tile that stays bound to the same dead runtime id across repeated remounts. Each remount re-cleared the latch and re-fired both RPCs against the phantom id, so the storm never actually stopped; it just restarted itself every cycle. This is the exact failure the AI reviewer on the original PR that added this line (#94950) flagged before merge: "The rebind-reset may not fire on runtime re-mint for the same id... consider wiring the reset into whatever store/event tracks runtime-binding changes." That hardening landed separately, at the actual rebind seams —
resetBackgroundPollingGuard()(no-arg, full clear) is called from the gateway reconnect path inapps/desktop/src/app/gateway/hooks/use-gateway-boot.ts:378and the runtime re-mint path inapps/desktop/src/store/gateway.ts:484— but the redundant per-mount reset in the status stack itself was never removed, so it kept defeating the latch on its own.Fix
Remove the
resetBackgroundPollingGuard(sessionId)call from the mount effect. Real rebinds (gateway reconnect, runtime re-mint) already clear the latch at their own seams; the status stack no longer needs — and must not perform — its own reset on mount.Test
Added
apps/desktop/src/app/chat/composer/status-stack/polling-guard.test.tsx, which rendersComposerStatusStackbound to a session id whoseprocess.listcall always rejects with "session not found", unmounts it, and remounts it — assertingprocess.listis called exactly once total (the latch must survive the remount).Confirmed it fails without the fix (
git checkout HEAD~1 -- apps/desktop/src/app/chat/composer/status-stack/index.tsx, i.e. the pre-fix version with the reset call restored):Restored the fix and reran — passes:
(
src/app/chat/composer/status-stack+src/store/composer-status.test.ts)Full suite:
Scope note
This addresses the second of the issue's two "cooperating defects" (the gone-latch being defeated by remount) — the fix that's minimal, mechanical, and provably correct from the code alone. The first defect (boot-restore re-binding the view to the runtime id instead of resolving and resuming the stored id) is a separate, larger client-boot-restore change and isn't attempted here.
Disclosure
This PR was prepared with AI assistance (an autonomous Claude Code session), with the diff, test, and repro reviewed before submission.