Skip to content

story-020: Resume an escalated run, and commit its work when it escalates - #18

Merged
jerodw merged 1 commit into
mainfrom
story/story-020
Aug 8, 2026
Merged

story-020: Resume an escalated run, and commit its work when it escalates#18
jerodw merged 1 commit into
mainfrom
story/story-020

Conversation

@jerodw

@jerodw jerodw commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

An escalated run's work lived only in the working tree, surviving exactly until someone checked out another branch — which is a normal thing to do while deciding what to do about the escalation. _complete ends a successful run with a commit; _escalate committed nothing. The one terminal state a developer most needs to inspect was the one the harness did not preserve.

This story fixes both halves: escalation commits its work, and an escalated run can be resumed rather than restarted.

l5-run <story-id>              # resumes at the recorded stage
l5-run <story-id> --stage <s>  # resumes at a stage the workflow defines

Changes

  • orchestration/story_coordinator.py_escalate commits the run's work before returning. state.json gains fields recording the escalation commit, the story artifact digest and the harness revision, each with a default so a state.json written before this story still loads. Resume re-enters at the recorded stage, carrying retry_count and verification_iterations forward.
  • scripts/l5-run — gains --stage, refusing a stage the loaded workflow does not define.
  • tests/test_story_020_validation.py (new, tester stage) — 49 tests.
  • Four existing test files repaired, each permitted by the revert check rather than adjudicated: "the suite fails with tests/test_coordinator_contract.py, tests/test_story_010_validation.py, tests/test_story_012_validation.py, tests/test_story_019_validation.py reverted."

Testing

930 passed in the working tree and 930 passed in a fresh clone with the story committed, on Python 3.10.20 (clean-clone-result.json, exit_code: 0). Verification passed on the second iteration with zero blocking issues.

Notes for review

  • The retry found a real defect, and it was the criterion's own demonstration that caught it. Attempt 1 committed the escalation before writing the escalation's own evidence, so in a repository whose run directory is tracked the escalation left an unclean tree — and git checkout main then failed outright with "Your local changes would be overwritten." The developer is stranded on the story branch. As the verifier put it, that is a stronger failure than work being carried across: the act the story exists to make safe is refused outright, and a test that only inspected the other branch afterwards would not have seen it. The same root cause meant the unchanged-since-escalation guard could never fire.
  • An escalation now ends in two commits, and that is forced rather than chosen. state.json records the sha of the commit containing it, and a commit cannot carry its own sha. The verifier recorded this as a consequence, not a defect.
  • A narrowness the verifier recorded rather than reported: unchanged_since_escalation compares the recorded commit against HEAD~1, which the criterion's wording does not settle either way.

A defect this run exposed, which is not this story's

The shipped test-results.json says the suite failed. It reports status: "failed", 927 run, 923 passed, with four named failures — while the verifier and the clean-clone check both independently report 930 passed, 0 failed.

The record is attempt 1's, never replaced. Write times settle it:

test-results.json          13:54   ← attempt 1's tester (13:39–13:54)
prompt-tester-attempt-2.md 14:22   ← attempt 2's tester ran 14:22–14:26
verification-result.json   14:35   ← attempt 2's verifier

Attempt 2's tester ran and did not rewrite its own declared output. The coordinator's post-stage check asks only whether a required artifact exists, not whether the stage that just ran produced it, so a stale artifact from a superseded attempt satisfies it silently.

This is not introduced by story-020 — it is a gap in the coordinator's output check that any retried run can hit. story-012 retried and its record is current, so it does not always happen; that makes it a silent, intermittent hazard rather than a consistent one. The verifier ran the suite itself and the clean-clone check ran it again, so the work here is verified twice over by evidence that is fresh. What is stale is one artifact, and it is the one a reader would most reasonably trust.

Filed separately; flagged here because a reviewer opening this run's artifacts will see a failing test record on a passing run.

🤖 Generated with Claude Code

…ates

Implemented by the l5 harness story workflow.
@jerodw
jerodw merged commit 98456f5 into main Aug 8, 2026
3 checks passed
@jerodw
jerodw deleted the story/story-020 branch August 8, 2026 21:22
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