Conversation
`sendTurn` decided steer-vs-new-turn from the cached `activeTurnId`, which the event pump clears asynchronously once native idle evidence is processed. A follow-up submitted during that gap reused the finished turn's id, skipped `turn.started`, and accrued its tokens to the previous turn, so the message could look like it did nothing. Confirm the native session status before reusing `activeTurnId`, but only where an idle reading is authoritative for that turn. It is not authoritative while idle evidence is deliberately withheld — admission, post-interruption, and reconciliation each mean a known-stale idle is in flight and the prompt is a genuine mid-turn steer — nor before OpenCode has reported the turn busy, since it then describes the state before the turn started. An unavailable or undecodable status keeps the previous behavior. Completing a turn from the preflight leaves the native idle it stood in for still in flight, so arm idle reconciliation: the next idle is checked against live status instead of trusted, and retires the turn it belongs to rather than the turn the follow-up just opened. The status request is itself a suspension point, so re-read `activeTurnId` after it rather than trusting the id captured before it: the pump can retire the turn while the request is in flight, and that is exactly the race being fixed. Fixes pingdotgg#10973 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe OpenCode adapter now tracks native busy status before reusing an active turn. It performs a status preflight when required, completes stale turns, and preserves newer turns across delayed idle events. Two regression tests cover these concurrency races. ChangesOpenCode turn boundary
Estimated code review effort: 3 (Moderate) | ~20 minutes Severity of issue fixed: Low Sequence Diagram(s)sequenceDiagram
participant FollowUpCaller
participant sendTurn
participant OpenCode
participant TurnState
FollowUpCaller->>sendTurn: submit follow-up
sendTurn->>OpenCode: request session.status
OpenCode-->>sendTurn: idle or missing status
sendTurn->>TurnState: complete stale active turn
sendTurn->>OpenCode: start distinct follow-up turn
Suggested reviewers: Merge Risk: ⚪ Minimal · up to This change separates completed OpenCode follow-up turns from legitimate mid-turn steering by checking native status before reusing cached turn IDs. Focused tests and validation checks pass, with no concrete current-head correctness or availability issue identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
What Changed
sendTurnno longer decides steer-vs-new-turn from the cachedactiveTurnIdalone. Before reusing it, the adapter confirms the native session status — but only where an idle reading is actually authoritative for that turn.An idle reading is not authoritative when idle evidence is deliberately withheld (prompt admission, post-interruption, or pending reconciliation each mean a known-stale idle is in flight and the prompt is a genuine mid-turn steer), nor before OpenCode has reported the turn busy, since it then describes the state before the turn started rather than after it ended. An unavailable or undecodable status keeps the previous behavior: never guess idle.
Two follow-on details the change needs to be correct:
activeTurnIdis re-read after it rather than trusting the id captured before it — the event pump can retire the turn while the request is in flight, which is the same race in a narrower window.Two deterministic regression tests cover both orderings: the idle event arriving before the follow-up, and the idle event landing during the preflight. Both were verified to fail against the unfixed adapter with the reported symptom (the follow-up reusing the finished turn's id).
Why
Fixes #10973.
After an OpenCode task finished and the thread went idle, the first follow-up message was ignored.
activeTurnIdis cleared asynchronously by the event pump once native idle evidence is processed, so a prompt submitted during that gap reused the finished turn's id. That skippedturn.startedand accrued the new work's tokens to the previous turn — from the user's side, the message looked like it did nothing.The narrow fix is to confirm the provider's real status before trusting a cached turn id, while leaving every case where the cached id is legitimately still live untouched. In particular, the existing coverage for a mid-turn steer racing a stale idle status is unchanged and still green: that path is classified as withheld idle evidence and skips the status read entirely.
Verification: focused adapter suite 112/112 (run repeatedly for stability), all eight OpenCode test files 195/195,
apps/servertypecheck clean, targeted lint and format clean.Checklist
🤖 Generated with Claude Code
Summary by CodeRabbit