Skip to content

story-036: A stage that failed mechanically runs again, in place - #35

Merged
jerodw merged 4 commits into
mainfrom
story/story-036
Aug 14, 2026
Merged

story-036: A stage that failed mechanically runs again, in place#35
jerodw merged 4 commits into
mainfrom
story/story-036

Conversation

@jerodw

@jerodw jerodw commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Three mechanical failures ended a run that a second attempt would plausibly fix: the agent process died, a required output was never written, or a required output was a previous attempt's. None is a judgement about the work — the stage simply did not produce what it declared. A stage may now declare a small consecutive budget for running again in place.

Unspecified means escalate, so this changes nothing until a stage opts in. workflows/story-workflow.json declares max_self_routes: 1 on the implementer and nothing else.

The feature fired during its own run

[10:44:14] self-routed: implementer runs again in place (implementer agent process failed); self-route 1 of 1

That is the failure that escalated story-028 on 2026-08-10 and cost $14.12 of abandoned implementer work. Here it was absorbed and the run continued.

The baseline interaction, amended mid-flight

story-036 escalated before story-037 merged. story-037 keyed the stage baseline by stage alone and made re-entry a per-path merge — necessary for a backward retry, where the tester creates a governed file between two invocations of the implementer and deleting it would make the revert check pass vacuously.

That merge is wrong for a self-route. No other stage has run, so the only thing it can admit is the crashed invocation's own leftovers, and deciding a re-run against its own partial work is the failure the baseline rule exists to prevent. Confirmed by driving it, not by argument.

The plan was amended to narrow what the merge admits rather than to make it depend on the route:

  • recorded_by_other_stages(run_dir, stages, stage_name) returns every path some other stage's changed-files record names, read off the workflow. An absent or unreadable record contributes nothing rather than raising — what another stage is known to have touched is the question, and an unestablished answer is not one.
  • capture_stage_baseline takes that set as accounted_for and, on a re-capture only, skips a path it does not name. A first capture admits everything, having nothing of this stage's to mistake for the tree's.

Authorship rather than route, because the harness records the first and a resume can defeat the second. Both halves are tested: test_a_path_another_stage_created_between_invocations_is_still_merged and test_a_re_capture_admits_the_accounted_path_and_not_the_unaccounted_one.

The retries are worth reading

Iteration Verdict Finding
1 failed → implementation A self-route in a resumed run overwrites the escalated run's self-route evidence and try-suffixed prompt
2 failed → validation That fix is correct but driven by no test — verified end to end by the verifier itself
3 passed

Iteration 2 is the first validation route in this repository. Every prior retry went to the implementer whatever failed, which is the defect story-028 existed to remove; here a test-shaped defect went to the tester.

Verification

  • 2002 passed under Python 3.14 and under Python 3.10
  • Verification passed on the third iteration; retry ceiling reached exactly (2 of 2); clean-clone green with the story committed
  • self_route_count: 0 at completion, having been spent and reset

CI minutes are exhausted on this account, so the checks on this PR are expected to fail to run. The two local runs above are the substitute, and 3.10 is the version the clean-clone check uses.

jerodw and others added 4 commits August 14, 2026 06:46
The run escalated and this commit is a holding place for what it left in the working tree, so the work survives a checkout of another branch. It is not a decision about that work: the story did not finish and nothing here has been accepted or reviewed.

Escalation reason: implementer edited tests/test_coordinator_contract.py, tests/test_story_005_validation.py, tests/test_story_020_validation.py, tests/test_story_022_validation.py under tests/, which it declared it must not create under, and the suite still passes with those edits reverted

To put these changes back in the working tree:
    git reset --mixed HEAD~2
The run escalated and this commit is a holding place for what it left in the working tree, so the work survives a checkout of another branch. It is not a decision about that work: the story did not finish and nothing here has been accepted or reviewed.

Escalation reason: implementer edited tests/test_coordinator_contract.py, tests/test_story_005_validation.py, tests/test_story_020_validation.py, tests/test_story_022_validation.py under tests/, which it declared it must not create under, and the suite still passes with those edits reverted

To put these changes back in the working tree:
    git reset --mixed HEAD~2
…eated

story-036 escalated before story-037 merged. story-037 keyed the stage
baseline by stage alone and made re-entry a per-path merge, which is
necessary for a backward retry — the tester creates a governed file between
two invocations of the implementer, and deleting it would make the revert
check pass vacuously.

It is wrong for a self-route. No other stage has run, so the only thing the
merge can admit is the crashed invocation's own leftovers, and deciding a
re-run against its own partial work is the failure story-036's baseline rule
exists to prevent. Confirmed against the merged code rather than inferred:
tests/test_story_036_validation.py::test_the_stage_baseline_is_the_one_the_first_invocation_captured
fails on main's capture with the crash leftover present in the baseline.

The amendment narrows what the merge admits rather than making it depend on
the route: a governed path is merged in only when another stage's
changed-files record accounts for it. Whoever created the path is the fact
that matters, the harness already records it, and a route-dependent rule
would be a proxy a resume can defeat.

Also repointed two assertions in this story's validation file that named the
attempt-keyed baseline story-037 removed — the helper's glob and a
capture_stage_baseline call still passing an attempt number. Mechanical, and
the same repoint story-037 made to stories 017, 019 and 020.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implemented by the l5 harness story workflow.
@jerodw
jerodw merged commit acb6482 into main Aug 14, 2026
3 checks passed
@jerodw
jerodw deleted the story/story-036 branch August 14, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant