story-017: Decide an implementer's test edits by reverting them - #16
Merged
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implemented by the l5 harness story workflow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Four story artifacts asserted that the implementer's
changed-filesrecord lists nothing undertests/. The harness enforced something narrower —may_not_create: ["tests/"], creation only — and never escalated on the difference. Every finding the prose rule produced was a deviation the verifier confirmed was forced, and each was adjudicated by hand: story-011's schema inventory, story-012's working-tree endpoints. story-013 removed one cause and its own validation tests promptly created another.The causes are unenumerable. The rule was the constant.
This story stops adjudicating and starts deciding. An implementer's edit under a governed prefix is permitted iff reverting it makes the suite fail. A forced repair breaks the suite when reverted; new coverage does not — and that is the authorship the rule existed to prevent. No judgement, no prose, no human in the loop.
Changes
orchestration/story_coordinator.py— after a stage that declares both achanged_filesrecord and amay_not_createlist, the coordinator collects that stage's ownmodifiedanddeletedentries under those prefixes (with the story's granted prefixes subtracted), reverts them fromHEADinside a clone, and runs the configured suite. Suite fails → forced repair → permitted. Suite passes → the edit was not load-bearing → escalate.createdentries are not collected, because stage output ownership has already escalated on them.workflows/story-workflow.json— the implementer declaresrevert_check: "revert-check-result.json". As withclean_clone, the key is what turns the check on: removing the declaration disables it with no orchestration change, and the artifact name never appears in code.schemas/revert-check-result.schema.json(new) — records whether the check ran, exactly which paths were reverted, the command, the interpreter, the verdict and an output tail. Coordinator-written likeclean-clone-result; nothing routes on it.schemas/manifest.json— the new schema declared. Second use of story-013's mechanism: adding a schema touchesschemas/only.prompts/planner.md— the planner is told to restate an injected restriction exactly as the workflow declares it, or not at all, because a tightened restatement "is not a stricter version of an enforced rule; it is an unenforced rule the harness cannot see broken, and one a legitimate change can make impossible to satisfy."Testing
834 passedin the working tree, and834 passedin 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.The verifier drove the check against real git targets with real pytest suites rather than accepting it on description:
src/app.pythat the existingtests/test_app.pycannot survive.Notes for review
pathsfield states exactly what was reverted so a reader can tell what the decision covered rather than assuming it discriminated per file. That was the known cost of the coarse form; per-file or per-hunk narrows it later if evidence justifies the noise.revert-check-result.jsonis absent from its run directory — the coordinator loaded the workflow beforerevert_checkexisted in it. Same self-reference as story-014's clean-clone check and story-012's retry history. Its implementer did modifytests/test_story_007_validation.py, and the verifier examined that repair by hand, as every story before this one had to.HEAD— a "could not run" outcome, not a passing one. The repair is right, the stated mechanism was wrong, and the verifier said so rather than accepting the narrative.HEAD-baseline rule, so it is not the enforcement here — the revert check is. Guidance reduces how often a planner writes the over-strict sentence; it does not stop it. The mechanical closure belongs to plan-time validation, which the book now also asks for, and is tracked separately.🤖 Generated with Claude Code