Fix repeated steering and reliable stop#3903
Conversation
- Resolve the provider runtime’s authoritative active Codex turn - Treat projected steer messages as server dispatch acknowledgement - Avoid stale root turn IDs when interrupting for steering - Cover active-turn lookup and running-thread steer behavior
- Resolve active Codex turns from timed, observable thread reads - Match projected steer acknowledgements to the dispatched message - Add realistic regression coverage for interrupt and steer paths
|
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 modifies core runtime behavior for steering acknowledgement and interrupt resolution, including new RPC calls with timeout/fallback logic and changed dispatch acknowledgement criteria. These are significant behavioral changes to user-facing interaction flows that warrant careful review. You can customize Macroscope's approvability policy. Learn more. |
- Fall back to provider response order when start times are absent - Cover both mixed timestamp ordering cases
- Merge upstream/main through Android mobile support - Keep Quicksaver Expo ownership in the mobile config - Preserve repeated steering and live Codex interruption behavior - Extract and test active turn ordering and interrupt fallbacks
- Use the Quicksaver EAS project id for the OTA endpoint
- Capture exact message acknowledgement and interrupt routing contracts - Record Codex live-turn selection and fallback safeguards - Reserve branch-specific web and server development ports
…ng-and-stop # Conflicts: # apps/server/src/provider/Layers/CodexSessionRuntime.test.ts # apps/web/src/components/ChatView.logic.ts # apps/web/src/components/ChatView.tsx
- Match dispatched steering IDs across all projected user messages - Read the session fallback only after live Codex lookup failures - Cover multi-client steering and timeout races with regression tests
- Make timeout tests wait for the live lookup explicitly - Clarify replacement and dispatch snapshot naming - Scan projected messages from the latest entry first
- Record assessment fixes and review outcomes - Update validation counts and branch divergence
- Document conflict-resolution guidance for web and Codex runtime changes - Preserve dispatch-correlation and interruption-resolution coverage
- Enable the global virtual store - Correct prerelease package extensions and refresh the lockfile
- Match exact projected messages independently of snapshot status - Cover ready and missing dispatch session status regressions - Document authoritative exact-id acknowledgement
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 c3852d1. Configure here.
- Log unexpected live thread lookup defects - Fall back to the latest projected active turn - Cover defect recovery in focused interrupt tests

Summary
Allow users to send consecutive steering prompts while a conversation is running and reliably stop the active Codex turn after any number of steers. Steering dispatches clear as soon as the server projects the exact submitted user message, even when the frozen dispatch snapshot has stale or absent session status, while root interruption resolves the provider's live active turn instead of relying on potentially stale projected state.
Explicit child-turn interruptions continue to target the requested child directly. Root lookup is bounded and failure-tolerant: typed failures, timeouts, and unexpected defects fall back to the cached active turn, while a successful read with no active turn suppresses a stale interrupt.
The workspace configuration also enables pnpm's global virtual store and makes the prerelease
@effect/vitestpackage extension resolvevite-plusconsistently.What Changed
thread/readrequest with turns included, selecting the newest in-progress turn by timestamp and falling back to provider response order when timestamps are absent.@effect/vitestpackage extension, and refresh the lockfile.Why
Running conversations could leave the composer busy after steering because acknowledgement depended on turn or session transitions that do not occur for an in-turn steer. After steering, stop could also target a stale cached turn rather than the provider's actual active turn. Together, these behaviors prevented repeated steering and made interruption unreliable precisely when users needed it most.
The pnpm workspace update keeps dependency resolution stable across worktrees and ensures the patched Effect Vitest package receives the runtime dependency it imports.
Validation
pnpm exec vp test apps/web/src/components/ChatView.logic.test.ts apps/server/src/provider/Layers/CodexInterruptResolution.test.ts apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts(71 tests passed)(cd apps/web && pnpm exec vp test run --passWithNoTests --project unit src/components/ChatView.logic.test.ts)(27 tests passed)pnpm exec vp fmt --check apps/web/src/components/ChatView.logic.ts apps/web/src/components/ChatView.logic.test.ts BRANCH_DETAILS.mdpnpm exec vp lint apps/web/src/components/ChatView.logic.ts apps/web/src/components/ChatView.logic.test.ts5738/13778: two consecutive exact-id steers each re-enabled the composer while the turn remained running, and Stop after two later steers settled the thread without a stale completion reply.pnpm --filter @t3tools/web typecheckremains blocked by existing errors in unrelated web files; neither changed source file appears in the failure list.pnpm exec vp test run apps/server/src/provider/Layers/CodexInterruptResolution.test.ts(13 tests passed)pnpm exec vp fmt --check apps/server/src/provider/Layers/CodexSessionRuntime.ts apps/server/src/provider/Layers/CodexInterruptResolution.test.ts BRANCH_DETAILS.mdpnpm exec vp lint apps/server/src/provider/Layers/CodexSessionRuntime.ts apps/server/src/provider/Layers/CodexInterruptResolution.test.tspnpm --filter t3 typecheckpassed with pre-existing suggestion-level diagnosticsProof
Note
Medium Risk
Changes live conversation send acknowledgement and Codex interrupt targeting; regression tests cover the new paths but mistakes could leave the composer busy or stop the wrong turn.
Overview
Repeated steering no longer leaves the composer stuck in a sending state. Local dispatch now records the exact outbound user message id and
hasServerAcknowledgedLocalDispatchtreats server acknowledgement as seeing that id in projected messages—even when turn/session fields are stale—so consecutive in-turn steers can re-enable the composer without waiting for a new turn. Send paths callbeginLocalDispatchonly afternewMessageId()so the snapshot matches what was sent.Reliable stop for root Codex turns replaces interrupting the cached
activeTurnIdwithresolveCodexInterruptTurnId: a livethread/readwith turns (2s timeout), picking the newestinProgressturn (timestamps, else provider order). Explicit child turn ids still pass through unchanged. Failed or timed-out lookups fall back to the session’s projected turn; a successful read with no active turn skips interrupt so a stale id is not revived.Adds
BRANCH_DETAILS.md,CodexInterruptResolution.test.ts, and expandedChatView.logictests; minor pnpm workspace/lockfile tweaks for@effect/vitestresolution.Reviewed by Cursor Bugbot for commit d8b15e2. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix repeated steering and reliable stop by improving interrupt resolution and dispatch acknowledgement
resolveCodexInterruptTurnIdnow performs a live provider thread read (with a 2s timeout viaCODEX_INTERRUPT_THREAD_READ_TIMEOUT) to find the most recent in-progress turn, falling back to the cachedactiveTurnIdonly when the live read fails or times out. A successful empty read no longer revives a stale projected turn id.interruptTurnexits early if no effective turn id is resolved, preventing spurious interrupts.hasServerAcknowledgedLocalDispatchnow triggers when the server projects a user message matching the exactexpectedUserMessageIdstored at send time, enabling steers to re-enable the composer without waiting for a turn/session change.ChatViewContentgenerates the message id before callingbeginLocalDispatchand ties acknowledgement to that exact id rather than a latest-message heuristic.Macroscope summarized d8b15e2.