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 2 commits 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 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 introduces new state tracking ( You can customize Macroscope's approvability policy. Learn more. |
| yield* finalizeTurn(context, "completed", undefined, { | ||
| drainTrailingChunks: true, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Empty-drain continuation can wedge
Medium Severity
When an empty-drain midTurn continuation starts with carryover live subagents, hasDeferredBackgroundWork is true so the new branch calls rearmDeferredFinalize, which no-ops under that same condition. Nothing later rearms from child-session subagent completion, so the continuation never finalizes. Previously empty drain finalized immediately, so this wedge is new.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit cd0348b. 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
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a62ed92. Configure here.
| (yield* Ref.get(runningBackgroundTaskIds)).size === 0 | ||
| ) { | ||
| yield* Ref.set(midTurnUnreportedCompletedTaskIds, new Set()); | ||
| } |
There was a problem hiding this comment.
Mid-turn wake evidence cleared too early
Medium Severity
After a midTurn-only offer, finalizeTurn clears midTurnUnreportedCompletedTaskIds whenever the running set is empty, including right after offerContinuationRun. That path often has an empty wakeBuffer, so if continuation dispatch later fails and clears continuationRequested, no residual wake evidence remains to re-offer. A genuinely unhandled mid-turn completion can then disappear with hasPendingBackgroundWork already false.
Reviewed by Cursor Bugbot for commit a62ed92. Configure here.


Base
This branch is stacked on #4193 (
fix/ctm-post-merge-ci) so CI's Test jobruns against aligned post-#3578 fixtures. The first commit
(
test(orchestrator): Align post-merge CTM fixtures) belongs to #4193;please review only the second commit here. Once #4193 lands in
codex-turn-mapping, this branch rebases back to a single commit above thestack base.
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).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 orchestration turn finalization, continuation offers, and wake buffering in AcpAdapterV2—high interaction complexity with edge cases, though heavily tested. Minor test/fixture path updates are low risk.
Overview
Fixes Grok/ACP post-settle continuation so synthetic
Background task completed.runs do not fire while a root turn is still active or after monitors were already reported in-turn.AcpAdapterV2addsmidTurnUnreportedCompletedTaskIdsto defer wake offers for unhandled mid-turn completions untilfinalizeTurn, blocksofferContinuationRunduring an active un-finalized turn, and stops late monitor mutations from clearing in-turn handled marks. In-turn-handled agent/thought chatter is filtered beforewakeBufferretention; non-continuation user turns clear stale buffer residue. Injected report streaming clears matching mid-turn arms; empty-drain continuation turns use the deferred-finalize quiet window when enabled.Adds extensive
AcpAdapterV2.test.tscoverage for settle-hold, staggered monitors, multiturn ack chatter, and empty-drain continuations.Also updates CLI config tests to expect
userdata-v2state paths and refreshes Claude replay fixtures (query.opentool lists) for post-merge alignment.Reviewed by Cursor Bugbot for commit a62ed92. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix spurious wake runs after in-turn monitor completions in
AcpAdapterV2midTurnUnreportedCompletedTaskIdsto track background tasks that reach a terminal state mid-turn without being reported in-turn, deferring wake offers until after turn finalization.Background task completed.continuations.wakeBuffer, preventing spurious post-settle wake runs for already-handled background work.midTurnUnreportedCompletedTaskIdson interrupted/quarantined turns and when injected reports stream, preventing stale deferred wakes.Macroscope summarized a62ed92.