T-4W64-extract-ensure-ready-mutate-script
Status: closed/done · Impact: medium · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to ready before picking up.
/sdlc:task-ensure-ready is implemented entirely as SKILL.md prose:
its Step-4 (pass) and Step-5 (fail) frontmatter mutations are described
in English. The new test suite at
plugin/skills/task-ensure-ready/tests/run_evals.py re-encodes those
mutations in Python so we can assert behaviour, but the encoding
drifts silently if the prose changes and the test doesn’t. Extracting
the mutation logic into a small script that both the skill and the
test suite call removes the drift surface entirely.
The contract carve-out introduced by
T-ZQ4H-task-ensure-ready-accepts-in-progress — “on fail, do
not downshift away from in-progress*” — is now described in three
places: the contract (plugin/entities/task/implementation-ready.md),
the SKILL.md (plugin/skills/task-ensure-ready/SKILL.md Section 5),
and the test simulation
(plugin/skills/task-ensure-ready/tests/run_evals.py). Each
re-statement is a chance to drift.
Proposed
Section titled “Proposed”A plugin/skills/task-ensure-ready/ensure_ready_mutate.py CLI
(co-located with its sole skill caller per
plugin/skills/CLAUDE.md — single skill family, no
plugin/scripts/ promotion until a second skill needs it). The
script takes the task path, a --mode pass|fail flag, the gap text
(for fail), and an optional --now <iso> for tests. It applies
exactly the mutations the contract prescribes (stamp on pass,
gap+clear+conditional-downshift on fail). The SKILL.md instructs
the agent to shell out to this script at the end of Step 4 / Step 5
rather than describing the mutations in prose. The test suite calls
the same script in lieu of its current simulate_pass/simulate_fail
re-encoding.
Approach
Section titled “Approach”- Author
plugin/skills/task-ensure-ready/ensure_ready_mutate.py. PEP-723 self-bootstrap, argparse, no third-party runtime deps beyond pyyaml. - Replace Section 4 and Section 5’s prose mutation steps in
plugin/skills/task-ensure-ready/SKILL.mdwith a shell-out to the new script. - Replace the simulate_pass / simulate_fail helpers in
plugin/skills/task-ensure-ready/tests/run_evals.pywith subprocess calls to the new script.
Files to touch
Section titled “Files to touch”plugin/skills/task-ensure-ready/ensure_ready_mutate.py(new)plugin/skills/task-ensure-ready/SKILL.md— replace mutation prose with shell-out.plugin/skills/task-ensure-ready/tests/run_evals.py— call the script instead of simulating in-process.
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: The carve-out logic is encoded in exactly one place
(
plugin/skills/task-ensure-ready/ensure_ready_mutate.py). - AC-2: The existing test suite still passes with the script- backed simulation.
Out of scope
Section titled “Out of scope”- Extracting other parts of ensure-ready (the contract evaluation itself, the commit step) — out of scope for this task.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-ZQ4H-task-ensure-ready-accepts-in-progress on 2026-05-19.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-05-21. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: auto —
command grepconfirmed the carve-out (IN_PROGRESS_STATUSESset,current_status not in IN_PROGRESS_STATUSESbranch) lives only inplugin/skills/task-ensure-ready/ensure_ready_mutate.py. SKILL.md andimplementation-ready.mdreference the behaviour in prose; the eval suite only mentions it in a docstring comment. - AC-2: auto —
plugin/skills/task-ensure-ready/tests/run_evals.pypasses 7/7 cases via subprocess calls to the new script. The fullrun_quality_checks.py --config sdlc.yaml --linegate reportsOK 6/6.
What worked
Section titled “What worked”- The pre-existing eval suite already had the right case shape; swapping the in-process simulate helpers for subprocess wrappers was a tight surgical edit.
- The new script bootstrapped via PEP-723 /
uv runon the first try. - The quality-checks gate caught the input-validation knock-on
immediately (old fixtures used schema-illegal
ready,proposed,proposed/needs-definition), forcing the fixture update in the same diff rather than leaving stale strings around.
Friction and automation gaps
Section titled “Friction and automation gaps”- The contract doc
implementation-ready.mdcarve-out section usedproposed/needs-definitionwhile the rest of the contract and SKILL.md usedplanning/needs-definition. The drift sat unnoticed because the prose-contract check inrun_evals.pywas asserting the wrong string. The repo would benefit from a status-enum check that grep-asserts every status-shaped token in prose docs underplugin/entities/andplugin/skills/against the task schema’s status enum — that one check would have flagged this on a regular CI tick. → T-5Z0H-lint-status-enum-strings-in-prose - Recovery from the prior aborted run required hand-resolving a
rebase conflict on the task file (the feat branch’s verify commit
carried
last_reviewed: 2026-05-20and an older stamp, main’s start-commit carriedlast_reviewed: 2026-05-21and an even older stamp). The current task-work flow lands these on two different branches with overlapping frontmatter edits; a resumption tool that diff-reconciles known-safe frontmatter keys (status, last_reviewed, readiness_verified_at) automatically would have skipped the manual edit. → T-1QO7-task-work-resumes-from-verify-stamp-commit
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-5Z0H-lint-status-enum-strings-in-prose — project-check linter for status-enum strings in prose (created).
- T-1QO7-task-work-resumes-from-verify-stamp-commit — task-work resume detection after verify-stamp commit (linked-existing).