Repository navigation
fix(agent-runtime): isolate delegate mutation recovery and failure results - #1446
Merged
Merged
Conversation
…sults Concurrent delegates reused parent recovery keys, allowing one writer to spend another's retry budget and fail the parent. Scope recovery to each executing agent and carry exhaustion into the Task result so earlier prose cannot disguise a failed run as completed. Keep failed chains resumable and preserve permission and cancellation behavior. Controlled provider tests cover parallel edits, shell patches and resume.
The summary is outside the delegate recovery fix and duplicates the shared root path added by other ready maintenance PRs. Drop it so the PR stays scoped and later conflict resolution covers only the E2E plan entries.
The latest main contains the session index and UTF-16 fixes. Refresh this PR and preserve both E2E scenarios in the combined delivery document. # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md
muzimu217
reviewed
Oct 7, 2026
muzimu217
left a comment
Contributor
There was a problem hiding this comment.
Verified locally on head 7a03669b0: packages/agent-runtime runtime.test.ts passes 287/287 (including the expanded coverage), full pnpm build:js clean.
The scoping mechanism matches the described fix:
delegateMutationTerminationskeys terminal-failure state bytoolCall.id, so concurrent delegates no longer share — and can no longer prematurely exhaust — the parent's recovery budget; entries are released when a delegate settles and the map is cleared on a new parent prompt, which keeps the "three failures" semantics per run instead of per session.- Carrying exhaustion into the delegate's own failed
Taskresult while preserving its earlier report and resumable chain fixes thecompleted-despite-failed-editing case the body describes, and the honest-retry exemption set (EDIT_TAG_MISMATCH/EDIT_TAG_UNKNOWN/EDIT_LINES_UNSEEN) is consistent with the line-anchored edit contract's §9.3 reveal semantics. - Both failure modes say they reproduce on unmodified 0.17.0, and
scripts/e2e-subagent-edit-isolation.mjscovers the isolation end-to-end — the right regression shape for a concurrency bug.
Non-blocking notes: the mutationTerminationAdvice strings are a nice touch (they point the model at the specific recovery action per error code); worth watching that the advice set stays in sync with the recoverable-codes set as both evolve.
Nothing blocking from a correctness standpoint; fix scope fits the current contribution window.
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.
Concurrent Task delegates currently share the parent's mutation recovery keys.
Failures from two writers editing the same path can terminate one writer before
its third failure and set the parent's terminal error. A delegate that wrote
introductory text before exhausting recovery can also return
completed, eventhough its editing work failed. Both failures reproduce on upstream 0.17.0
with a controlled local provider and no fork-specific features.
Scope retry counts and per-code graces to the executing parent or delegate run.
Carry exhaustion into that delegate's failed Task result, preserve its earlier
report and resumable chain, and release its recovery state when it settles.
A new parent prompt resets only the parent's budget. The existing three-failure
limit, permission checks and cancellation precedence remain unchanged.
The shared mutation descriptions are extracted to a small module so the runtime
entry point shrinks despite the added ownership handling.
Reproduction and validation:
node scripts/e2e-subagent-edit-isolation.mjs: real Runtime, pi Agent andSubagentRun over local HTTP/SSE. On upstream, A terminates after only two
failed Edits as B spends the shared budget. After the fix, A fails on its own
third attempt, B completes after two failures, and the parent has no mutation
error. Resuming A succeeds.
--single: upstream reports A ascompletedand reportsMUTATION_RETRY_BUDGET_EXHAUSTEDon the parent. The fixed result isfailedon A, without the parent error; resume succeeds.
--patch: the same isolation and resume flow passes for shell patch commands.with a still-running delegate under default and explicit permissions.
All three provider-boundary scenarios and the 327 regressions were also run on
this standalone PR branch. Only provider responses and the host tool boundary
are controlled fixtures; no paid provider or user profile is used.
Related work: #1193 classifies output-token truncation, #1394 preserves resume after a parent error, and #283 publishes settlement updates. This change fixes per-delegate mutation recovery ownership and exhaustion classification.
Validation candidate:
7a03669b0f0c661f75c26e7b463b0a7f50dd4272; upstream main:72b5e826cb7a9928467091ccf745aa9b225eeb04.