Repository navigation
Description
Problem
Only the implement job has a failure class (roadmap/failure.py: FailureClass, ACTION_BY_CLASS, classify_failure, from #3065). classify_failure reads text and exit status. A stage, refine or intake error is a Python exception, not log text.
The stage item record holds the Python exception class name (stage.failed_error) and the time (stage.failed_at). _record_failures writes both. The record has no failure class and no step. So explain and inbox cannot show them, and a later issue cannot choose a retry time by class.
StageFailure (stage.py) carries the class name as a string. _failure_of (plan) and _write_failure (write) build it from the exception. The exception type is lost at that point.
FailureClass has 19 members. They already cover what the stage needs: provider, parser, plan_defect, ci_infra and head_moved. No new class is needed.
Expected
In roadmap/failure.py add two things, and use both in the same pull request:
StepName, aStrEnumwith the steps that the stage records:planandapply. Other issues add members when they use them.CLASS_BY_EXCEPTION, one tuple of (exception type,FailureClass), read withisinstance, most specific first.
The table:
RoadmapItemChangedErrorgiveshead_moved. It is aGitHubOperationError, so it comes first. It means that the item changed while the job worked, and the next round reads it again. It does not mean that a person must act.StructuredOutputValidationErrorgivesparser.AIClientErrorgivesprovider.RoadmapStageErrorgivesplan_defect.GitHubOperationError,GitOperationError,ToolExecutionErrorand any otherDevOpsCLIErrorgiveci_infra.
Add failure_class and step fields to StageFailure. _failure_of sets the step plan. _write_failure sets the step apply.
On the stage item record, add the keys stage.failed_step and stage.failed_class to StageRecordKey (stores/store.py). _record_failures writes them in the existing failure write, with no extra request. A staged item or an item stopped on the budget clears them, as it clears stage.failed_at today.
Update the table row of the stage keys in docs/ROADMAP_WORKFLOW.md (line 126).
Not in this issue:
- the retry time (the issue feat(roadmap): stage retry time follows the failure class #4060);
- a comment on the issue;
explainorinboxoutput (feat(roadmap): explain and inbox show the state of a stopped item #3648).
Acceptance criteria
-
uv run pytest tests/roadmap/stage/test_roadmap_stage_failure_class.py- a provider error records the classproviderand the stepplan. A refused plan recordsplan_defect. A failed write records the stepapply. An item-changed error recordshead_moved. A staged item clears the three keys. -
uv run pytest tests/roadmap/test_roadmap_failure.py -k 'class_by_exception or step_name'- each mapped exception gives its class byisinstance. A subclass with no entry gives the class of its parent. The values ofStepNameare unique one-word strings. -
grep -q 'stage.failed_class' docs/ROADMAP_WORKFLOW.md && uv run devops docs generate --check- the workflow document names the new keys and the generated documents are up to date (the grep part fails today).
Every command above fails on the unchanged code. The pull request cites the fail-to-pass run (devops ci fail-to-pass --base <ref>).
Feasibility
I read these files at origin/main: failure.py, stage.py (_failure_of, _write_failure, _record_failures, StageFailure), stores/store.py (StageRecordKey), exceptions/roadmap.py and exceptions/git.py. I checked the exception tree: RoadmapItemChangedError is a GitHubOperationError, and StructuredOutputValidationError is an AIClientError. I did not run the code or the tests.
The consumers in this pull request are the writer of the two keys (_record_failures) and the tests. The reader is the issue #4060. RETRY_AFTER is not added here, because nothing would read it.
Existing tool considered
roadmap/failure.py (FailureClass, #3065) and plain isinstance. No library is needed.
Cost
Build: about 40k tokens and 2 h (one tuple, one enum, two record keys, 6 tests). Keep: about 2k tokens per quarter. Fix: about 8k tokens and 0.5 h.
Related
Part of #3027. #3258 (failure classes in the stage context; different), #3648 (explain and inbox; see the comment there), #3650, #3727. Order: before the issue #4060.
Activity
dan-petty commentedon Nov 7, 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 enables later retry and reporting work but does not fix a current user-facing defect.It makes stage failures classifiable and step-aware, improving diagnostics for roadmap users.It touches four files with well-specified changes and a clear acceptance test list.Both work on the failure classification system; #3065 created the taxonomy for the implement job, this candidate adds step and class recording to stage items.