Treat missing thread snapshots as terminal#4235
Conversation
- Preserve authoritative thread-not-found snapshot failures - Mark missing threads deleted before opening socket subscriptions - Cover terminal missing-thread handling with sync tests - Document thread detail subscription reliability
- Delay draft detail loading until the server shell appears - Cover draft and normal thread subscription decisions - Document pre-creation draft synchronization behavior
- Verify decoded 404 and transient HTTP loader behavior - Cover draft detail subscription activation through the hook - Add structured metadata for terminal missing-thread cleanup
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Effect service review: one convention violation found. The new HTTP thread_not_found handling uses Effect.catchTag, but the conventions require Effect.catchTags for statically known tagged failures — including when handling a single tag.
Posted via Macroscope — Effect Service Conventions
ApprovabilityVerdict: Needs human review This PR changes subscription termination behavior for missing threads, which is a significant runtime behavior modification. Additionally, an unresolved review comment identifies a potential hydration race condition that could cause draft threads to be incorrectly marked as deleted. You can customize Macroscope's approvability policy. Learn more. |
- Match the convention for statically known tagged errors
…d-subscription-loop
…d-subscription-loop
…d-subscription-loop
…d-subscription-loop
…d-subscription-loop
…d-subscription-loop
…d-subscription-loop
- Gate direct route detail reads until local drafts have a shell - Interrupt subscribe input creation once thread state is deleted - Cover foreground resubscription and direct draft consumers
…d-subscription-loop
…d-subscription-loop
…d-subscription-loop # Conflicts: # apps/web/src/routes/_chat.$environmentId.$threadId.tsx # apps/web/src/state/entities.ts
…d-subscription-loop
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2d25d20. Configure here.
…d-subscription-loop

Summary
Treat authoritative missing-thread snapshot responses as terminal client state instead of falling through to a repeatedly failing WebSocket subscription, including after session replacement or application-foreground resubscription. Transient HTTP failures still retain the existing socket-snapshot fallback.
Delay detail synchronization for known local drafts across every detail consumer until the server shell observes thread creation, preserving the legitimate pre-creation flow while preventing a missing-resource response from deleting the draft.
What Changed
thread_not_founderrors through the thread snapshot loader while mapping transient failures to socket fallback.BRANCH_DETAILS.md.Why
While investigating renderer memory growth from roughly 300 MB after launch to nearly 2 GB after extended use and idle time, stale thread details were observed being prewarmed after their server resources no longer existed. Each HTTP lookup returned authoritative
thread_not_found, but the client treated that as a transient miss, opened a WebSocket subscription that also failed, and retried the cycle every 250 ms. Multiple stale subscriptions made this a concrete source of sustained allocation, retained state, and background CPU pressure, though it should not be assumed to explain every byte of renderer memory growth by itself.The terminal handling stops that loop, evicts the stale persisted detail, and prevents later session or foreground events from reopening the socket. Because a brand-new local draft also legitimately has no server thread before its first send, every draft detail consumer now waits for the shell's creation signal so the fix does not turn that expected pre-creation 404 into a deleted draft.
Validation
Proof
No additional proof artifacts are required; the focused automated coverage and integrated browser flow exercise the affected lifecycle directly.
Note
Medium Risk
Changes core thread sync and deletion semantics across HTTP and WebSocket paths; incorrect 404 handling or draft gating could wrongly delete threads or block legitimate sync, though behavior is covered by new tests.
Overview
Authoritative HTTP
thread_not_foundresponses now end thread-detail sync instead of being treated like transient misses that fall through to a WebSocket subscription and retry loop.ThreadSnapshotLoaderpropagatesEnvironmentResourceNotFoundErroron 404 while other HTTP failures still map to socket fallback. The thread state machine marks the thread deleted, clears persisted detail, and interrupts before opening or resubscribing the WebSocket stream (including on application-foreground wakeups).Local drafts no longer subscribe to server detail until a server shell exists:
shouldSubscribeToThreadDetail,useThreadDetailWhenReady, anduseThreadStatusWhenReadygate subscriptions so pre-creation 404s cannot delete a draft. The chat thread route anduseThreaduse this gate.Adds regression tests for the HTTP loader, sync lifecycle, and web hook gating, plus
BRANCH_DETAILS.mddocumenting the contract.Reviewed by Cursor Bugbot for commit 45dac5e. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Treat missing thread snapshots as terminal by marking 404 responses as deleted
ThreadSnapshotLoader.loadinthreadSnapshotHttp.tsnow propagatesEnvironmentResourceNotFoundError(404thread_not_found) as a failure instead of mapping it toOption.none.threads.tscatches this error during the HTTP snapshot phase, marks the thread state as deleted, and interrupts the subscription — preventing socket subscription and any retry on wakeup.useThreadDetailWhenReadyanduseThreadStatusWhenReadyhooks inentities.tsgate detail/status subscriptions for draft threads until a server shell exists.Option.none.Macroscope summarized 2d25d20.