fix(server): reconcile stopped sessions after restart#4562
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 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 |
ApprovabilityVerdict: Needs human review This PR adds new session reconciliation behavior after server restart, including ~80 lines of new logic that dispatches orchestration commands to update session states. Despite the 'fix' label, this introduces significant new runtime behavior affecting session lifecycle management, warranting careful review. 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 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 dca27c9. Configure here.

Summary
Fixes #4561
Verification
pnpm exec vp test run apps/server/src/provider/Layers/ProviderSessionReaper.test.ts apps/server/src/orchestration/decider.settled.test.ts— 21 tests passedpnpm exec vp run --filter t3 typecheckpnpm exec vp run --filter @t3tools/contracts typecheckstartingwith no active turn, durable runtimestopped, and an abandoned pending turn; the sidebar was initially stuck Working, then looked idle after a recovery message while settling remained blockedNote
Medium Risk
Changes thread session projection paths after restart and adds server-initiated orchestration dispatches on every reaper sweep for stopped bindings; guarded by optional concurrency checks but still affects settling/working UI state.
Overview
Fixes threads that stay stuck in a transient session state (e.g. starting / working) when shutdown persisted a durable stopped provider binding but never updated the thread projection.
Provider session reaper now treats
stoppedbindings as reconciliation targets on each sweep: it reads the projected session, skips when already stopped or when the binding’slastSeenAtis older thansession.updatedAt, and otherwise dispatchesthread.session.setwith a server-generated command id to project stopped (clearingactiveTurnId). Invariant rejections are logged and retried on later sweeps with a new command id.Orchestration adds optional
expectedSessionUpdatedAtonthread.session.set; the decider rejects the command withOrchestrationCommandInvariantErrorwhen the projected session’supdatedAtno longer matches, so reconciliation cannot clobber a concurrent restart or newer session write.Regression tests cover shutdown divergence, stale-binding ordering, concurrent session updates, and retry behavior.
Reviewed by Cursor Bugbot for commit 56da49d. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Reconcile stopped provider sessions after server restart
reconcileStoppedBindingtoProviderSessionReaper, which dispatches athread.session.setcommand for bindings persisted asstoppedso their projected session status is updated after a restart.lastSeenAtis older than the projected session'supdatedAt, preventing stale writes from overwriting newer state.expectedSessionUpdatedAtfield to thethread.session.setcommand schema inorchestration.tsfor conditional write semantics.decider.tsnow returnsOrchestrationCommandInvariantErrorwhenexpectedSessionUpdatedAtis provided but does not match the projected session'supdatedAt.OrchestrationEngineServiceandCrypto; misconfigured environments missing these services will fail at startup.Macroscope summarized 56da49d.