🤖 fix: goal follow-ups yield to direct user sends; G4 follow-ups from #5536 - #5585
Merged
Merged
Conversation
…5536 - #5506: follow-up idle probes count the session's own manual send preflight. - #5546 item 1: drop a terminal-error record overtaken during its preference read. - #5546 item 3: a pre-stream runtime_not_ready failure settles the G4 advancement. - #5546 item 4: test that a dequeued manual send in preflight blocks the advancement.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Member
Author
|
Readiness record for head 32cebd2:
Generated with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Goal follow-ups from #5505 and #5536 (G4). One defect per item:
AgentSessionitself (for examplexum run) arms no WorkspaceService ticket. A goal follow-up redispatched during that send's preflight was admitted, moved the turn, and the user's send was refused. The three idle probes indispatchPendingCompactionFollowUpIfNeedednow also count the session's ownmanualSendsInPreflight.recordGoalAdvancementAfterStreamErrorawaits the auto-retry preference read. If automatic successor work started and failed during that await, both failures handed over a resume. Each record that gets past its early returns now takes a generation number. A record that a later such record overtook is dropped after the read. A failure that records nothing (aborted, retried, plan or compact) does not make an earlier record stale.runtime_not_readyfailure stranded the goal. This failure takes the runtime branch ofhandleStreamWithHistoryFailure. That branch emits no stream error event, sohandleStreamError's G4 settlement never ran. The failed kickoff then stayed installed and was eligible again at once, with no backoff and no bound. The branch now runs the same settlement: it retires the failed kickoff and records a boundedstream_errorresume.runtime_start_failedtakes the same branch, but RetryManager retries it, so it records nothing.Fixes #5506
Background: the remaining #5546 items
This PR resolves items 1, 3 and 4 of #5546 and leaves that issue open (Refs #5546).
goal.jsonread error. A backend restart re-arms the active goal. The stream-end path has the same exposure today, and the fix needs a retry timer.The maintainer's G4 rules are unchanged. A UI pause, an agent pause or completion, a budget or turn limit, a user Stop, and the auto-retry opt-out (errors only) still win over every resume. Resumes keep the bounded backoff: at most
GOAL_STREAM_ERROR_RESUME_MAX_ATTEMPTSper failure episode.Implementation notes
hasFollowUpBlockingSendPreflight()=manualSendsInPreflight > 0 || hasExternalSendPreflight(). Only user sends raisemanualSendsInPreflight(synthetic !== trueand originmanual). The redispatched follow-up is a synthetic automatic send, so its own probe cannot trip itself.preparingQueuedInputcheck inuserInputBlocksGoalAdvancementcannot change the result today.completePreparationclearspreparingQueuedInputbeforefinishPreparationpublishes idle, andreevaluateGoalAdvancementreturns early for any non-idle phase. I instrumented it across 61 session and goal test files: it was only reached during dispose, whereclosingstops the hand-over anyway. So the new test passes when only that clause is removed. It fails when the preparation guards are removed (the phase check and that clause together):I kept the clause as defense in depth.
followUpAdmissionStalelines that 🤖 fix: no heartbeat turn after the heartbeat is unset or disabled (G2, G2b) #5549 edits.Validation
Pre-fix failures (each new test, run against main):
#5506: the user's direct send is refused
#5546 item 1: a second resume is handed over
#5546 item 3: the failed kickoff stays eligible at once
Expected: 1, Received: 0in "a successor whose failure records nothing leaves the earlier record").goalAdvancement.test.ts,agentSession.*.test.ts,workspaceGoal*.test.ts,workspaceGoals.formalRepro.test.ts,workspaceService.sendMessage.test.ts: 1497 pass, 0 fail.formal/workspace-goals/check.shon the head commit (32cebd2): exit 0. Every result matches its expectation (MC_codestill violates onlyNoHeartbeatWhenOff, the open G2 that 🤖 fix: no heartbeat turn after the heartbeat is unset or disabled (G2, G2b) #5549 fixes).Risks
Medium-low, in goal advancement and the follow-up idle rule.
runtime_not_ready. The resume is bounded and fenced like every other error resume.Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$3.13