fix(orchestrator/grok): Prevent spurious wake run after in-turn monitors#4218
fix(orchestrator/grok): Prevent spurious wake run after in-turn monitors#4218mwolson wants to merge 1 commit into
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 modifies complex orchestration state machine logic controlling when wake/continuation runs are offered after background task completion. While well-tested, the changes affect runtime behavior in the orchestration layer and involve intricate state transitions that warrant human review. You can customize Macroscope's approvability policy. Learn more. |
1e58e65 to
a286c60
Compare
3a467b5 to
f62b5d4
Compare
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 f62b5d4. Configure here.
- Defer continuation offers for background completions that land while a root turn is active and un-finalized; finalize offers exactly one wake only when unhandled completed work remains - Stop late monitor-event mutations from erasing in-turn handled marks, so injected-turn ack chatter is never retained as wake evidence - Clear stale wake buffer frames at non-continuation user-turn start - Make the late-mutation suppress logic's running/terminal branches mutually exclusive

Base
Single commit on
codex-turn-mapping. #4193 (fix/ctm-post-merge-ci) haslanded, so the earlier stacked-commit note no longer applies.
Summary
"Background task completed." continuation run while the original turn was
still streaming, after the agent had already reported the monitor result
in-turn.
<monitor-event>acknowledgement chatter for work alreadyreported in-turn is never retained as wake evidence for later turns.
deferral, the legitimate unhandled-completion wake, and the
settle-without-report hold interaction.
Problem and Fix
x.ai/task_completedext notification landing mid-turn reachedapplyLateBackgroundMutation, which had no notion of an active un-finalized root turn. With the running set empty and stale frames inwakeBuffer, it calledofferContinuationRunand dispatched a "Background task completed." run (queue_after_active) while the original turn was still streaming its own report.midTurnUnreportedCompletedTaskIdsset, andfinalizeTurnoffers exactly one continuation after finalize when legitimate evidence remains (settled statuscompleted, no running tasks). The arming also requires the prompt not to have settled, so the settled-held window still uses the pre-existing injected-report path.<monitor-event>turn hit the late-mutation path, which deleted the task id from the in-turn handled set. The subsequent injected ack chatter then failed the handled-chatter guard and was buffered as wake evidence, surviving into later turns (the buffer was intentionally not cleared at turn start).wakeBufferframes are cleared at non-continuation user-turn start. Frames cleared there cannot be legitimate: a genuinely unhandled completion is tracked by the mid-turn set and offered at finalize instead.Defensive Fixes
suppressPostSettleMonitorPromptwas set true and then unconditionally set false two lines later for terminal mutations on already-ended tasks, making the intent unreadable and the true branch dead.quarantineStoppedRunalso clearsmidTurnUnreportedCompletedTaskIds.midTurnUnreportedCompletedTaskIdssurvived the settle-hold: when the CLI's injected report streamed into the held turn, onlypendingInjectedReportwas cleared, sofinalizeTurnstill saw the armed id and offered a duplicate continuation right after the report projected (Bugbot round 1).midTurnUnreportedCompletedTaskIds. If no report ever streams, the id survives and finalize offers exactly one wake, as before.wakeBuffer(the buffer cannot grow while the root turn is active), so if the CLI's late frames had not arrived by the wake run's start, the empty drain finalized a blank continuation run immediately (Bugbot round 1).wakeBufferclear at the start of a non-continuation turn. An orchestrator-injected wake is not a user turn: #4499 (fix/delegated-task-parent-wake) dispatches app-owned delegated-child wakes ascreationSource: "server", which is non-continuation, so once both land such a wake would discard this session's pending native wake frames and lose real agent output.acpIsAppOwnedWakeTurnexempts orchestrator-injected wakes from the clear, matching whatClaudeAdapterV2already does on its own buffer. The exemption is inert on this branch alone, since nothing currently dispatchescreationSource: "server"; it only takes effect once #4499 lands, and it is included here because this PR introduces the clear it guards.finalizeTurnclearedmidTurnUnreportedCompletedTaskIdsunconditionally, but the offer gate requires the running set to be empty. A task armed pre-settle lost its mark when the turn finalized while a second task was still running, and the second task's bare end-notice frame is excluded from wake evidence, so no continuation was ever offered for either completion (Bugbot round 2).completedand background work is still running, so the post-finalize gate offers exactly once when the last task ends. Interrupted and failed turns still clear unconditionally, and non-continuation turn start clears too, so kept marks cannot wake after an interrupt or arm a later user turn.Validation
vp check: pass (0 errors, 63 pre-existing warnings)vp run typecheck: pass (all packages)AcpAdapterV2.test.ts,GrokAdapterV2.test.ts): 98/98,including 9 new tests
original two-turn repro produced no spurious wake and no replayed acks;
legitimate post-settle monitor and detached-command scenarios each produced
exactly one continuation; interrupt/steer/queue scenarios stayed clean
Note
Medium Risk
Changes continuation timing, wake-buffer clearing, and finalize behavior in orchestration-v2 ACP; regressions could miss legitimate wakes or wedge turns on empty continuations.
Overview
Fixes spurious "Background task completed." wake runs in the Grok/ACP adapter when monitors were already handled in-turn, while preserving a single legitimate continuation when background work finishes unreported.
AcpAdapterV2defers continuation offers while a root turn is still active: mid-turn terminal mutations armmidTurnUnreportedCompletedTaskIdsinstead of callingofferContinuationRun, andfinalizeTurn(or post-finalize late mutations) offers once when the running set is empty and wake evidence or those marks remain. In-turn hydration/reporting clears matching marks; streaming an injected report into a held turn clears them too so finalize does not double-wake.Wake buffering no longer retains agent/thought chatter after in-turn-handled background work (guard runs before buffer). Late monitor-event mutations stop removing
handledBackgroundTaskIdsInActiveTurn. User turns clear stalewakeBufferand mid-turn marks at start;acpIsAppOwnedWakeTurn(agent+creationSource: "server") skips those clears so delegated-child wakes do not drop native pending frames.Continuation attach with an empty drained buffer uses the deferred-finalize quiet window when the flavor defers for background work, instead of finalizing immediately. Quarantine and interrupt paths clear mid-turn marks appropriately; staggered multi-monitor finalize keeps marks until the last task ends.
Adds extensive
AcpAdapterV2.test.tscoverage for settle-hold, pre-settle arms, multiturn ack chatter, empty-drain quiet window, and related edge cases.Reviewed by Cursor Bugbot for commit c2a9e0f. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix spurious wake runs triggered by in-turn monitor completions in
AcpAdapterV2midTurnUnreportedCompletedTaskIdsto track background tasks that reach a terminal state mid-turn without being reported in-turn, deferring any continuation offer until afterfinalizeTurn.agent_message_chunk/agent_thought_chunkchatter from monitors after in-turn-handled background work no longer fillswakeBufferor triggers synthetic continuation runs.acpIsAppOwnedWakeTurnpredicate to detect orchestrator-injected agent/server wake turns; these turns no longer clear pending wake evidence or mid-turn marks.deferFinalizeForBackgroundWorkis true) instead of finalizing immediately, allowing late frames to attach.AcpAdapterV2.ts.Macroscope summarized c2a9e0f.