Skip to content

story-019: Revert an implementer's edits to where the stage found them, not to HEAD - #17

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

story-019: Revert an implementer's edits to where the stage found them, not to HEAD#17
jerodw merged 1 commit into
mainfrom
story/story-019

Conversation

@jerodw

@jerodw jerodw commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

story-017's revert check decides whether an implementer's edits under a governed prefix were forced, by reverting them and seeing whether the suite fails. It reverted them with git checkout HEAD -- <paths>, which is the right baseline only for files that existed before the story.

On a retry, the implementer routinely edits a test the tester created earlier in the same run — a file with no version at HEAD, because the coordinator commits only at _complete. The checkout fails, the check reports it could not run, and the run escalates. story-018 hit exactly that:

[10:24:41] implementer edits under tests/ permitted: the suite fails with
           tests/test_story_006_single_reader.py, tests/test_story_007_validation.py reverted
[10:40:33] clean-clone suite failed; retry 1 of 2 rerouted to implementer
[10:50:44] escalated: … pathspec 'tests/test_story_018_validation.py'
           did not match any file(s) known to git

Attempt 1 is the check working as designed. Attempt 2 is it unable to decide, on the ordinary shape of a retry — a clean-clone or verifier failure is frequently a defect in a test written this run, and the retry sends the implementer to fix it.

This story reverts each governed path to the state it was in when the stage started, not to HEAD. For a file that predates the story that is its HEAD version and nothing changes; for a file created during the run it is the content the previous stage left.

Changes

  • orchestration/story_coordinator.py — a per-attempt baseline is captured before a stage runs, and never re-captured over one that already exists. The revert check restores from it instead of from HEAD.

  • workflows/story-workflow.jsonrevert_check becomes an object naming both artifacts:

    "revert_check": { "result": "revert-check-result.json", "baseline": "stage-baseline" }

    The key still turns the check on, and both names still come off the loaded definition rather than out of orchestration.

  • schemas/revert-check-result.schema.json — the paths description no longer says "reverted from HEAD".

  • tests/test_story_019_validation.py (new, tester stage) — 44 tests.

  • tests/test_story_010_validation.py, tests/test_story_017_validation.py — repaired by the implementer, which the revert check itself permitted: "the suite fails with tests/test_story_010_validation.py, tests/test_story_017_validation.py reverted."

Testing

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

Notes for review

  • The "never re-capture" rule is what makes resume possible, and it is the part worth reading closely. A resumed stage re-enters with its own work already in the working tree; if the baseline were captured at stage start, it would capture that work, the revert would be a no-op, the suite would pass, and the check would report a permission it never established. Reusing the interrupted attempt's baseline avoids restoring or discarding anything. story-020 (resume) depends on this holding.
  • This story could not govern its own run. The run directory has no stage-baseline/ — the coordinator loaded the workflow before the baseline key existed in it. Same self-reference as story-014's clean-clone check, story-012's retry history and story-017's own revert check. The first story it governs is the next one.
  • The check permitted this story's own test edits under the old mechanism, visible in the log line above. Both files needed repair because the story changes the shape of a workflow key they assert on.
  • The storage cost is real and worth knowing. The baseline captures the governed prefix, which is tests/ at 4.1 MB across 26 files, per stage per attempt. Run directories were ~3.3 MB total for sixteen runs before this. It is gitignored and removed with the run, but a long retry chain is no longer cheap on disk.
  • Two paths the verifier flagged as unexercised: no test triggers a real git clone failure — both cannot-run tests monkeypatch _build_clone to raise — and the pre-change end-to-end run was confirmed by reading HEAD rather than re-executed.

🤖 Generated with Claude Code

…m, not to HEAD

Implemented by the l5 harness story workflow.
@jerodw
jerodw merged commit e9bae50 into main Aug 8, 2026
3 checks passed
@jerodw
jerodw deleted the story/story-019 branch August 8, 2026 19:13
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