Repository navigation
fix: close a Step only when it says - Status: done - #102
Merged
Merged
Conversation
The gate read the field as a blacklist: `pending`, `in_progress` and `blocked` were named, and everything else counted as finished. So `completed` archived an unfinished Plan, and so did a misspelling, an empty value, and a Step with no Status line at all. Measured 2026-10-27 by driving the gate directly: `completed`, `complted`, `skipped`, `wip`, `DONE`, an empty value and a missing line each returned exit 0. `hooks/task progress` has only ever accepted `pending|in_progress|done| blocked`, so none of those spellings could have been written by the tool. They are hand edits made because the two sides disagreed, and reading anything unknown as closed is that disagreement, not a fix for it. Closed is now a whitelist of the one word the writer accepts. The block is located by its `### Step <number>` heading anywhere in the Plan, which is how `task progress` finds the block it edits; scanning only `## Steps` would give the reader a different set of Steps than the writer changes. Knowingly still open and pinned by an assertion: a Plan with no `### Step` at all is not refused, because "must a Plan have Steps" is a separate rule. Five archived Plans read as unfinished under the new rule and are not rewritten -- `achieved/` is read-only in place, and editing history to pass a check that no longer applies to it would make the record untrue. Run over all 91, only two change verdict; the other three were already refused on main for unrelated reasons. smoke grew by 19 completion-gate assertions. Five mutations were run against them, each reddening a named assertion; the fourth showed the first version of the assertions did not pin the trailing-whitespace tolerance, so two fixtures were generated with printf to cover `\r` and trailing spaces.
hkwuks
marked this pull request as ready for review
October 27, 2026 14:28
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
A Step counts as closed only when it says
- Status: done. Every other value —completed, a misspelling, an empty value, a missing line — now counts as unfinished, because the check was a blacklist and everything it did not recognize read as finished.Measured 2026-10-27 by driving
hooks/completion-gatedirectly:completed,complted,skipped,wip,DONE, an empty value and a Step with no- Status:line each returned exit 0 and "finished".hooks/task progresshas only ever acceptedpending|in_progress|done|blocked, so none of those spellings could have been written by the tool — they are hand edits made precisely because the reader and the writer disagreed. This makes them agree.The block is located by its
### Step <number>heading anywhere in the Plan, which is howtask progressfinds the block it edits. Scanning only## Stepswould have given the reader a different set of Steps than the writer changes.TaskFlow traceability
TaskFlowDocs/achieved/2026-10-27-close-step-status/hooks/completion-gate(the Step condition and how a block is located),hooks/smoke-test(19 new assertions),skills/taskflow/SKILL.md,skills/taskflow/references/runtime.md,CHANGELOG.md.hooks/task progressis deliberately unchanged — it already accepts onlydone.mainVerification
Hooksworkflow reports pass for this branch — run 40519266846 atf03b806,success, all seven jobs:changes,evals,release,todo-merge-audit, andsmokeonubuntu-latest(20s),windows-latest(39s),macos-latest(1m7s)git diff --checkpython3 <skill-creator>/scripts/quick_validate.py skills/taskflow—Skill is valid!## Verification / Reviewin the archived Plan carries the CI run and the local runsLocal, before CI existed for this branch:
bash hooks/smoke-test—ALL SMOKE PASSED. Five mutations were run against the new assertions, each reddening a named assertion:FAIL completion-gate clean: rc 1 != 0## StepsFAIL completion-gate unfinished: rc 0 != 1, and the new fixture catches it independentlyENDflushFAIL completion-gate unfinished: rc 0 != 1doneto an exact line(done|completed)FAIL completion-gate closed-completed: rc 0 != 1Review boundaries
TaskFlowDocs/todo.mddiff is three entries recorded earlier the same day, from the same requests that produced this taskKnown limitations
### Stepblock at all is not refused. That is "must a Plan have Steps", a separate rule with its own arguments, and it is not smuggled in here. It is pinned by an assertion (no-step-blocks) so it stays a decision rather than an oversight.achieved/is read-only in place, so no task is affected. They are2026-09-07-repository-standards-and-doc-root,2026-10-11-gate-host-coverage,2026-09-08-token-efficiency,2026-09-14-personal-docs-git-boundary, and2026-10-22-taskflow-drift-guard. Run over all 91 archived Plans, only two change verdict — the other three were already refused onmainfor unrelated reasons.### Step <number>reused as an ordinary subheading is now read as a Step.2026-10-22-taskflow-drift-guarddoes exactly that under## Verification / Review. This is not a new split:task progressalready treats that block as a Step and edits it. Forbidding the reuse would be a separate rule.printf(a CRLF line ending, and trailing spaces) closed the gap. The mutation found the hole in the assertions, not in the code.