Repository navigation
Description
Problem or Motivation
Only a failed ruff, mypy or hook, and a missing tick, get a repair round today. A failed verification command (a lost or failing test) stops the step at once, though the agent has the failure text and could fix it. Examples: #2570, #2531, #2524, #2469. Split from #3053.
Proposed Solution & Architectural Design
- A verification command that exits 1 gives the agent one round with the class (
test,types,lint), the evidence and a diagnosis hint. - The turn may change the files of the step only, as the turn for a static check does.
- A failure of class
plan_defectorpremise_falsestill stops at once. - Acceptance: a replay where the first attempt fails its verification command and the second passes ends done, and the trace shows both attempts.
Target Subsystem
src/devops_cli/roadmap/implement_step.py (_extra_ask, _exit_failure).
Existing Tool Considered
pydantic-ai gives ModelRetry for output validation. The step already has the turn for a static check; this change extends it to one more kind of failure: about 40000 tokens to build, 2000 each quarter to keep, 8000 to fix one miss, about 3 hours.
Source: #3053
Proposed design
Problem statement
A failed verification command stops the implement step at once. A lost test also stops the step with no repair turn. The agent has the failure text and can fix the failure. This change gives one repair round to a failed verification command and to a lost test. A plan defect and a false premise still stop at once.
Acceptance criteria
Requirement: Verification failure gets a repair turn
When a verification command that is not a negative search exits 1, the step SHALL give the agent one repair turn with the command's class, its masked output and a diagnosis hint.
Scenario: The repair turn makes the verification pass
- WHEN The first attempt fails a verification command with exit 1 and the repair turn makes the command pass.
- THEN The step ends done, and the trace holds one attempt for the failure and one attempt for the repair.
Requirement: Lost test gets a repair turn
When the step loses a test that existed at the base commit and the test is not recorded, the step SHALL give one repair turn that may restore or edit the test file.
Scenario: The repair turn restores a lost test
- WHEN A step removes a test from a test file that existed at the base commit, and the repair turn restores the test.
- THEN The step ends done, and the trace holds one attempt for the lost test and one attempt for the repair.
Requirement: Plan defect and false premise stop at once
A failure of class plan_defect or premise_false MUST stop the step with no repair turn.
Scenario: A plan defect gets no repair turn
- WHEN The step fails with class
plan_defectorpremise_false. - THEN The step stops, and the trace records no repair attempt.
Requirement: Repair turn changes only step files
The repair turn for a failed verification command or a lost test MUST change only the files of the step and the change's tasks.md.
Scenario: The repair turn edits an outside file
- WHEN The repair turn changes a file that the step did not change.
- THEN The step stops, and the reason names the paths that the turn changed.
Existing Tool Considered
No alternatives check has run. pydantic-ai ModelRetry covers model output validation. It does not cover a failed shell verification command or a lost test, and it cannot limit the changed files to the step. The project extends the existing _extra_ask and _repair_rounds path. The written cost is about 40000 tokens to build, 2000 each quarter to keep, 8000 to fix one miss, and about 3 hours.
Key questions
- Should a failed verification command get a repair turn?: Yes. Extend
_extra_askand_repair_roundsso a verification command that exits 1 gets one bounded repair turn. (best practice) [sources: src/devops_cli/roadmap/implement_step.py:1496, src/devops_cli/roadmap/failure.py, tests/roadmap/test_roadmap_implement_step_repair.py, docs/ERRORS.md:83]- Chosen: Extend the existing repair rounds. The step already counts rounds and checks the changed files, so one new failure with repair paths reuses the path.
- Rejected: Build a pydantic-ai
ModelRetryloop.ModelRetryhandles tool and output validation, not the exit status of a shell verification command. - Rejected: Keep the immediate stop. The agent has the failure text and can fix a failing test.
- Should a lost test also get a repair turn?: Yes.
_exit_failuremust carry the lost test files asrepair_pathsso_extra_askgives the turn. (best practice) [sources: src/devops_cli/roadmap/implement_step.py, src/devops_cli/roadmap/implement_test_names.py, tests/roadmap/test_roadmap_implement_step_repair.py]- Chosen: Give a lost test a repair turn. The lost test is a failure that the agent can fix, and the reply records the case.
- Rejected: Keep the current stop with class
TESTS_LOST._exit_failurereturns norepair_paths, so the agent gets no turn.
- Which files may a repair turn change?: Only the files that the step changed, plus the change's
tasks.md. (best practice) [sources: src/devops_cli/roadmap/implement_step.py, tests/roadmap/test_roadmap_implement_step_repair.py]- Chosen: Limit the turn to the step files.
_foreign_changealready compares the checkout with the tree before the turn. - Rejected: Allow the whole checkout. A repair turn could hide an unrelated edit or a stray file.
- Chosen: Limit the turn to the step files.
- Which failures must stop at once?: A failure of class
plan_defectorpremise_falsestops at once with no repair turn. (best practice) [sources: src/devops_cli/roadmap/failure.py, src/devops_cli/roadmap/implement_step.py]- Chosen: Stop
plan_defectandpremise_falseat once. No attempt can fix a wrong plan or a false premise. - Rejected: Give every failure a repair turn. A repair turn would spend tokens on a failure that it cannot fix.
- Chosen: Stop
- How does the step assign the class of a failed verification command?: The step reads the effective program of the command after
uv run:pytestistest,mypyistypes, andruffislint; another allowed command uses the verification class. (best practice) [sources: src/devops_cli/roadmap/implement_shell_policy.py, src/devops_cli/roadmap/implement_step.py, src/devops_cli/roadmap/failure.py]- Chosen: Class from the command program. The program is stable and the allowlist already admits it.
- Rejected: Class from the command output. The output is model-visible and can name another tool.
- Rejected: One generic verification class. The issue names
test,typesandlintas distinct classes.
- Should the change add a new repair-round setting?: No. Reuse
roadmap.implement.repair_rounds, as the static-check turn does. (best practice) [sources: src/devops_cli/roadmap/implement_step.py, src/devops_cli/config/settings.py]- Chosen: Reuse the existing setting. The step already counts rounds and names the setting in a spent stop.
- Rejected: Add a verification setting. The issue asks for one more failure kind, not a new budget.
Fit
Fits in one pull request.
Suspected block
None.
Dependencies
None.
Alternatives check of 2026-11-07: in-use.
The item already names this tool.
Tool: pydantic/pydantic-ai (https://github.com/pydantic/pydantic-ai), MIT, last activity 2026-11-07, maintained.
Activity
dan-petty commentedon Nov 5, 2026
Intake placed this item to the backlog: intake puts every new item in the backlog. A person plans the milestones.
featprefix of the title gives the type.(roadmap)scope of the title gives the scope.It saves tokens on failed verification commands but the step still completes without it.It prevents token loss when a test or type check fails, but the work is not blocked.The mechanism exists for static checks; this extends it to one more failure class.Both add a repair round in implement_step.py, but #2795 targets static checks and the candidate targets verification command failures.feat(roadmap): a step stops at its budgets and records attempts (#3580)
dan-petty commentedon Nov 5, 2026
This item now holds acceptance criterion 2 of #3098, which is closed as superseded: "A replay with a removed pinned test restores and edits the test in a repair step."
The body of this item names a lost test and #2570, but its acceptance line names only a verification command. The two paths differ on
origin/mainat cfcbd3d._exit_failurereturns_Failure(lost, klass=FailureClass.TESTS_LOST)with norepair_paths, so_extra_askgives no turn. So the plan of this item must also give a lost test a repair turn, and add a test for this case. #3490 holds a removal that the plan records.feat(roadmap): ask for a smaller edit after a parser failure (#3737)
devops-cli-service commentedon Nov 6, 2026
Status set to Ready at bd65ef6 (see proposed design in issue body).
devops-cli-service commentedon Nov 7, 2026
Alternatives check: in-use
Reason: Web searches for a library that gives a failed verification command a bounded repair round timed out, so the check rests on the fact reads of the tool the issue itself names. pydantic-ai is an active library and its ModelRetry covers the retry half of the need — a turn is re-run with an error message when a tool or output validator rejects the model's result — but it has no notion of a shell verification command's exit status, of failure classes such as test/types/lint versus plan_defect/premise_false, of a lost test, or of limiting a turn's edits to the step's files. The issue's own design reaches the same conclusion and keeps the existing
_extra_ask/_repair_roundspath.The item already names this tool.
Tool: pydantic/pydantic-ai (https://github.com/pydantic/pydantic-ai)
Covers:
Lacks:
Tools considered:
Searches run:
Sources:
Checked on 2026-11-07. A person decides what this means for the item. The check changes no label and closes no issue.
dan-petty commentedon Nov 7, 2026
Evidence from pull request #4031 (issue #2163):
In group 2 of the change, the runner executed
uv run devops ci --check --only actionlint,zizmoras the verification command. The command exited with status 1 due to a workflow syntax issue during the model edit.Because verification commands are returned as
_Failure(early)withrepair_paths=Noneinsrc/devops_cli/roadmap/implement/implement_step.py,_extra_ask()returnedNoneand the runner provided zero repair rounds.The runner pod stopped immediately, marked the issue
status/blocked, and left the pull request in draft with an incomplete placeholder body. This demonstrates the real-world impact of giving verification command failures a repair round with the command output on the changed files.