Skip to content

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.

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.

  1. Author plugin/skills/task-ensure-ready/ensure_ready_mutate.py. PEP-723 self-bootstrap, argparse, no third-party runtime deps beyond pyyaml.
  2. Replace Section 4 and Section 5’s prose mutation steps in plugin/skills/task-ensure-ready/SKILL.md with a shell-out to the new script.
  3. Replace the simulate_pass / simulate_fail helpers in plugin/skills/task-ensure-ready/tests/run_evals.py with subprocess calls to the new script.
  • 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.
  • 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.
  • Extracting other parts of ensure-ready (the contract evaluation itself, the commit step) — out of scope for this task.
  • none

Spawned by /sdlc:task-work post-mortem of T-ZQ4H-task-ensure-ready-accepts-in-progress on 2026-05-19.

Captured by /sdlc:task-work on 2026-05-21. PR: pending.

  • AC-1: auto — command grep confirmed the carve-out (IN_PROGRESS_STATUSES set, current_status not in IN_PROGRESS_STATUSES branch) lives only in plugin/skills/task-ensure-ready/ensure_ready_mutate.py. SKILL.md and implementation-ready.md reference 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.py passes 7/7 cases via subprocess calls to the new script. The full run_quality_checks.py --config sdlc.yaml --line gate reports OK 6/6.
  • 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 run on 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.
  • The contract doc implementation-ready.md carve-out section used proposed/needs-definition while the rest of the contract and SKILL.md used planning/needs-definition. The drift sat unnoticed because the prose-contract check in run_evals.py was asserting the wrong string. The repo would benefit from a status-enum check that grep-asserts every status-shaped token in prose docs under plugin/entities/ and plugin/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-20 and an older stamp, main’s start-commit carried last_reviewed: 2026-05-21 and 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

← Back to Tasks