fix(sync): stop retrying permanently missing threads#4222
Conversation
|
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 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 Conventions — 1 issue found.
The new reason: "not-found" discriminator on OrchestrationGetSnapshotError is used to select caller control flow, which the conventions say should be modeled as a distinct error class rather than a single-value literal on an existing tag. See the inline comment.
Posted via Macroscope — Effect Service Conventions
ApprovabilityVerdict: Needs human review This PR introduces new infrastructure (EnvironmentShellMembership service, hasThreadById query, OrchestrationThreadNotFoundError) and changes sync subscription retry behavior across client and server. While framed as a fix, it's functionally a new feature that affects runtime behavior of the sync system. You can customize Macroscope's approvability policy. Learn more. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d479716. Configure here.

Summary
Root cause
Thread subscription failures were all retried every 250 ms. A permanent not-found failure therefore rebuilt subscription input forever, repeatedly running cold HTTP hydration, while deleted state did not stop later resubscriptions.
Impact
Stale references that receive a typed not-found response and are absent from the authoritative shell now settle in the existing unavailable/deleted state after one cold HTTP attempt and one WebSocket attempt. Shell-present and shell-unknown failures retain the existing retry behavior so creation/projection races can still recover; changing or bounding that retry policy is outside this fix.
Validation
vp test run packages/client-runtime/src/rpc/client.test.ts packages/client-runtime/src/state/threads-sync.test.ts packages/client-runtime/src/state/shell-sync.test.ts packages/client-runtime/src/state/shellMembership.test.ts(31 tests passed)vp test run apps/server/src/server.test.ts -t "tags a missing.*thread subscription as not found"(2 focused tests passed)git diff --checkpassedsubscribeThreadrequest, with no repeats over more than two secondsRefs #2761
Preserves the creation-race recovery reported in #4127.
Note
Medium Risk
Changes real-time sync and WebSocket error contracts for thread subscriptions; behavior is heavily tested but affects orchestration client/server coordination and deleted-thread UX.
Overview
Stops infinite 250ms retries when a thread is permanently missing by introducing
OrchestrationThreadNotFoundErrorand wiring it throughsubscribeThread(cold and resumed paths). Resumed subscriptions now usehasThreadByIdso archived threads still exist; missing threads get the typed error instead of a generic snapshot failure.On the client,
EnvironmentShellMembershiptracks whether a thread isunknown,present, orabsentfrom the authoritative shell snapshot, with revision guards so stale shell writes cannot restore authority after disconnect. Thread sync treats not-found as terminal when membership isabsent(clears cache, stops subscribing);unknownorpresentkeeps the existing retry path for projection/creation races.Shell sync adopts
subscribeDynamicWithContextso membership revisions stay bound to the subscription session; web/mobile runtimes includeenvironmentShellMembershipLayer. RPC client gains the sharedsubscribeDynamicStreamhelper plussubscribeDynamicWithContext.Reviewed by Cursor Bugbot for commit 1ce1c25. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Stop retrying permanently missing thread subscriptions by marking them deleted via shell membership
OrchestrationThreadNotFoundErrorto thesubscribeThreadWS RPC, returned when a thread is missing on initial load or whenhasThreadByIdreturns false for resumed subscriptions.EnvironmentShellMembershipservice to track per-environment thread membership (unknown/present/absent) with revision-guarded updates.absent; missing-thread errors are retried only when membership isunknownorpresent.hasThreadByIdtoProjectionSnapshotQueryto check non-deleted thread existence (including archived) without loading full thread details.subscribeDynamicWithContextto the RPC client to propagate per-session context (membership revision) alongside stream values across session switches.Macroscope summarized 1ce1c25.