fix(autofix): give the repair pass a budget it can finish in (#9691)

* fix(autofix): give the repair pass a budget it can finish in

The repair attempt ran on a hardcoded 18-minute agent budget while the
primary attempt gets 120 minutes from a configurable default. Raise the
repair budget to 45 minutes and carry the step and job caps that bound it.

The repair attempt is handed strictly less to work with than the primary
one: a deterministic rejection is an opaque check failure, not the
structured review feedback the primary attempt receives, so it must first
re-derive which change caused the rejection before it can amend anything.
Giving that 15% of the primary budget inverted the difficulty and the
allowance.

Measured on four takeover PRs over nine rounds on 2026-08-21: the primary
attempt reported `Autofix agent completed address-review successfully.` in
9 of 9 rounds, and the repair attempt hit `timeout (1080000ms)` in 9 of 9.
Every one of those rounds discarded work the primary attempt had already
finished — on #9340 a completed `origin/main` conflict resolution across
three files with two mutation probes and `vitest run src/commands/review/`
green at 97 files / 4335 tests. Three such rounds tripped
TIMEOUT_WINDOW_CAP and parked the PR at its round cap with
`autofix/needs-human`.

The rejections themselves were a mix — a flaky unrelated test (#9648), a
genuine defect in the PR, and a scope violation — so this is not a
substitute for fixing any one of them. It is the step they all funnel
through: whatever the gate rejects on, the repair attempt has to be able
to finish before the round can push.

Carried bounds, each preserving its documented margin:

- repair step cap 20m → 55m (budget + the same 10-minute margin the
  primary attempt keeps, so the internal kill path still writes
  `agent-timeout` before the step cap fires)
- review-address job cap 300m → 330m (the four long steps now sum to 305m
  plus the 25m setup/report reserve)
- PENDING_STALE_MIN 330 → 360 (its 30-minute margin over the job cap, so a
  live review-address run is never aged out mid-flight)

45 minutes is deliberately a fraction of the primary budget: a repair that
cannot land in 45m is a handoff, not a longer retry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgTjRF91xANQh6SY9YGyCf

* fix(autofix): carry the raised repair bounds through sibling prose

* fix(autofix): revert design-record edits outside this PR's footprint (#9691)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
qqqys 2026-08-23 00:32:36 +00:00 committed by GitHub
parent 1007bcacfc
commit acc46e58cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 27 additions and 16 deletions

View file

@ -119,7 +119,7 @@ reject_fix() {
if [[ "${preexisting}" == 'true' ]]; then
# NOT retryable: the repair agent is only allowed to amend this round's
# fix, and a failure that exists without the fix is outside that boundary
# by definition — the 18-minute repair budget cannot reach it. The remedy
# by definition — the 45-minute repair budget cannot reach it. The remedy
# is a base update (merge main into the branch), not a repair.
echo "preexisting=true" >> "${GITHUB_OUTPUT}"
elif [[ "${retryable}" == 'true' ]]; then
@ -1047,7 +1047,7 @@ fi
# a DEFECT-CLAIM round only when resolved-comments.txt marks a finding
# resolved-in-code whose thread is Critical-tagged or belongs to a
# CHANGES_REQUESTED review (matched in rc.json/rv.json). Those rounds get a
# non-retryable rejection on all-green — the 18-minute repair pass cannot
# non-retryable rejection on all-green — the 45-minute repair pass cannot
# make a nonexistent defect reproduce; the next full round re-reads the
# feedback with the evidence in LAST_REJECTION and can decline or escalate
# instead. Every OTHER src+test round (a refactor pinning existing