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 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 High severity unresolved comment identifies accidentally committed personal Expo project configuration that could break production OTA updates. Additionally, the PR modifies runtime behavior for interrupt resolution and steering acknowledgment, warranting human verification. 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
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 06e38dc. Configure here.

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 now clear as soon as the server projects the exact submitted user message, while interruption resolves the provider's live active turn instead of relying on potentially stale projected state.
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.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 upstream merge also introduced an Expo OTA endpoint that still targeted the upstream EAS project after this branch restored the fork's owner and project id. Aligning all three values prevents installed Quicksaver builds from querying the wrong update project.
Validation
pnpm exec vp check(passes with existing lint warnings)pnpm exec vp run typecheckpnpm exec vp test apps/web/src/components/ChatView.logic.test.ts apps/server/src/provider/Layers/CodexSessionRuntime.test.ts(45 tests passed)pnpm exec vp test apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts(32 tests passed)APP_VARIANT=production pnpm exec expo config --json(owner, project id, and OTA endpoint match)pnpm exec vp run lint:mobileProof
Note
Medium Risk
Changes user-visible send/stop behavior and Codex interrupt targeting; logic is well-tested but affects running-turn orchestration. The bundled mobile EAS project/owner switch affects OTA/update routing if unintended.
Overview
Fixes repeated steering while a turn is running and makes Codex stop target the live active turn.
The web chat now records the expected user message id on each local send and treats a steer as server-acknowledged when that exact message appears on the thread—without waiting for a new turn or session transition.
beginLocalDispatchis wired to pass the outgoing message id through send/retry paths.On the server, Codex
interruptTurnno longer defaults straight to cachedsession.activeTurnId. It resolves the turn via a boundedthread/read(with turns), picks the newest in-progress turn (timestamp order, with provider order when timestamps are missing), uses the cached id only when the lookup fails or times out, and does not revive a stale cached id when a successful read shows no active turn.Also updates mobile Expo/EAS config (
updates.url,eas.projectId,owner) to a different project id and owner—orthogonal to the chat/Codex behavior.Regression tests cover steer acknowledgement, active-turn selection, interrupt resolution edge cases, and related helpers.
Reviewed by Cursor Bugbot for commit 06e38dc. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix repeated steering and add reliable stop by resolving active turn via live thread read
interruptTurnin CodexSessionRuntime.ts now performs a live provider thread read (with a 2s timeout) to resolve the correct active turn before sending an interrupt; if no active turn is found, the interrupt is skipped entirely.expectedUserMessageIdon the local dispatch snapshot, treating projection of that message onto a running thread as server acknowledgement even when turn/session fields are unchanged.expectedUserMessageIdintobeginLocalDispatch, wiring the new acknowledgement logic end-to-end.interruptTurnmay now skip sending the interrupt if the live thread read returns no active turn, rather than always sending to the session-projected turn id.Macroscope summarized 06e38dc.