story-034: The resume guard can refuse when the harness is its own target - #32
Merged
Conversation
…rget 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.
unchanged_since_escalationrefuses a resume that would provably repeat itself: the story, the branch and the harness all unchanged since the escalation. In this repository — where the harness is the target — it could never refuse.Why it could never fire
harness_revisionis recorded on the first line of_escalate, before the escalation makes its two commits. Whenharness_root == target_root, those commits move HEAD, so the third leg compares a pre-escalation revision against a post-escalation one and always differs. And when the tree was clean enough that no commits were made,escalation_commitis empty and the second leg returns early instead.There was no path on which the guard refused. story-028 resumed on 2026-08-12 for that reason and not because anything about it had changed.
What changed
same_repository(target_root, harness_root)decides the case fromgit rev-parse --show-toplevelin each root, shared only when both succeed and report the same path. Under a shared root the harness leg is skipped and the branch comparison stands alone — which is sound rather than convenient: if the two roots are one tree, the branch leg already establishes that it is exactly the escalation commit with nothing uncommitted, and that covers every change to the harness source too.The tree-hash alternative — hashing the harness's own source directories rather than comparing HEAD — was considered and rejected, and
ARCHITECTURE.mdrecords why rather than leaving the next reader to think of it and wonder.The bias is preserved
A failing
rev-parseon either side reports not shared, matching the one-directional bias_revision,dirty_paths,completion_commitsandbase_problemsalready take. This story makes a refusal possible where none was; it must not make a false one possible, and a developer who did change something being told they did not is worse off than one who wastes a run.Consequence worth knowing
Escalations of story-028's shape now stop resuming without an argument.
--stageis the intended override and the refusal message names it, so the escape hatch is in place — but the working habit changes, and the escalation summary's promise that a resume is refused while the story, branch and harness are unchanged becomes true for the first time.Verification
1681 passed, 18 written; verification passed first iteration, no retries; clean-clone green with the story committedl5-runagainst this repository's own checkout was deliberately not run, since that would move this run's own state🤖 Generated with Claude Code