Skip to content

T-ZQ4H-task-ensure-ready-accepts-in-progress

Status: closed/done · Impact: low · Complexity: small

/sdlc:task-ensure-ready’s allowed-status set is {draft, proposed, backlog, ready}. When a task is already in-progress (set by /sdlc:task-work’s Step 3) and someone re-runs task-ensure-ready against it — directly, or via task-work’s own Step 5a — the contract downshifts the doc to proposed/needs-definition and clears readiness_verified_at, even when the body hasn’t drifted and the stamp is still fresh. That silently destroys a valid in-progress state. Closing this gap removes the only foot-gun preventing a strict by-the-book run of /sdlc:task-work on a task that was already started in a prior session.

The friction surfaced in a /sdlc:task-work run on the pumice repo (originating task: pumice’s docs/planning/tasks/2026-05-19-engine-review-update-completed-rows-affected.md, PR sksizer/pumice#220). The relevant bullet from that post-mortem:

/sdlc:task-work Step 3 sets status: in-progress, but Step 5’s /sdlc:task-ensure-ready contract requires status in {draft, proposed, backlog, ready}. Re-running task-ensure-ready in Step 5 would clobber the Step 3 commit by flipping status back to proposed/needs-definition. I skipped the re-run because the readiness_verified_at stamp was fresh from earlier this session and the body hadn’t drifted — but a strict-by-the-book run breaks here.

plugin/skills/task-ensure-ready/SKILL.md and the contract at plugin/entities/task/implementation-ready.md both enforce the 4-status allowlist. There is no carve-out for in-progress or in-progress/blocked even when the doc clearly carries a valid readiness_verified_at stamp.

(Step ordering in plugin/skills/task-work/SKILL.md puts Step 3 “flip to in-progress” before Step 5 “ensure ready”. The friction would persist even if those steps were reversed, because the contract itself excludes in-progress from valid input states — any re-run on a previously-started task hits the same downshift.)

/sdlc:task-ensure-ready treats in-progress and in-progress/blocked as valid input states. On pass it refreshes readiness_verified_at and leaves status untouched. On fail it records a definition_gap and clears the stamp, but does NOT downshift status away from in-progress — the task is already mid-flight; downshifting would corrupt task-work state. The skill’s spec, contract doc, and any validators are updated together so a strict run of /sdlc:task-work against a previously-started task no longer requires a manual skip.

  1. Update plugin/entities/task/implementation-ready.md to widen the allowed-status set to include in-progress and in-progress/blocked. Document the fail-mode carve-out (no downshift away from in-progress*).
  2. Update plugin/skills/task-ensure-ready/SKILL.md to match — accept the new statuses on input; refresh readiness_verified_at on pass without touching status; on fail leave status alone for in-progress* inputs (the definition_gap still gets recorded and the stamp still gets cleared).
  3. Audit plugin/validators/*.py for hardcoded {draft, proposed, backlog, ready} checks; widen them to the 6-status superset where the readiness gate runs.
  4. Confirm /sdlc:task-work’s Step 5a behaviour stays correct (Step 5a’s initial ensure-ready call still hits a {draft, proposed, backlog, ready} task — the relaxation doesn’t affect that flow). Add a one-line note to plugin/skills/task-work/SKILL.md saying that re-running ensure-ready against an in-progress task is now a safe no-op when the stamp is fresh.
  • plugin/entities/task/implementation-ready.md — widen the allowed-status set; document the in-progress fail-mode carve-out.
  • plugin/skills/task-ensure-ready/SKILL.md — update the input contract and fail-path behaviour.
  • plugin/validators/validate_frontmatter.py (and any other validator with a hardcoded allowlist) — audit and widen as needed.
  • plugin/skills/task-work/SKILL.md — clarify in Step 5/8 that re-running ensure-ready against an in-progress task is safe.
  • AC-1: Running /sdlc:task-ensure-ready <basename> against a task with status: in-progress and a body that satisfies the contract returns READY: and leaves status: in-progress unchanged; readiness_verified_at is refreshed.
  • AC-2: Running it against a status: in-progress task whose body has drifted records a definition_gap, clears readiness_verified_at, and leaves status: in-progress unchanged (no downshift to proposed/needs-definition).
  • AC-3: Existing happy-path behaviour for {draft, proposed, backlog, ready} inputs is unchanged.
  • AC-4: /sdlc:task-work can complete an end-to-end run without the implementer skipping Step 5’s ensure-ready re-run on a previously-started task.
  • Adding new in-progress sub-states.
  • Re-architecting the task lifecycle (separate larger work).
  • none

Spawned from a /sdlc:task-work post-mortem on sksizer/pumice#220 (originating task: docs/planning/tasks/2026-05-19-engine-review-update-completed-rows-affected.md in the pumice repo). The post-mortem documents the foot-gun in context — see the “Friction and automation gaps” section there.

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

  • AC-1: auto — plugin/skills/task-ensure-ready/tests/run_evals.py case in-progress-pass-refreshes-stamp simulates the documented Step-4 (pass) mutation against an in-progress fixture and asserts readiness_verified_at refreshes while status: in-progress stays put.
  • AC-2: auto — same suite, cases in-progress-fail-preserves-status and in-progress-blocked-fail-preserves-status. Both apply the Step-5 (fail) mutation and assert definition_gap recorded, readiness_verified_at cleared, status untouched.
  • AC-3: auto — same suite, cases ready-pass-keeps-status, ready-fail-downshifts, proposed-fail-downshifts exercise the original four-status happy and fail paths.
  • AC-4: agent-manual — verified by reading task-work SKILL.md Step 5a’s success condition: it now accepts status: in the six-status set, and the new “if the resolved task was already in-progress*, skip Step 5b” branch closes the previously-broken resumed-session path. Spot-check across a real resumed run still pending.
  • The schema (plugin/entities/task/schema.json) already permitted in-progress and in-progress/blocked, so the change was purely contract / SKILL.md prose plus one new test harness. No validator edits needed.
  • The test harness pattern was easy to lift from sibling skills (entities-migrate, import-planning). PEP-723 self-bootstrapping scripts mean no setup friction.
  • The orchestrator dispatched task-work to a sub-agent that stopped at READY: from ensure-ready (Step 5a) instead of continuing through Steps 6-10. Happened twice. task-work’s Step 5 narrative should call out explicitly that a sub-agent picking up this skill must NOT treat the READY: marker as the end of the flow — that marker only completes Step 5a; Steps 5b through 10 still need to run. Possible automation: emit a distinct task-work final marker (e.g. TASK-WORK COMPLETE:) whose absence is unambiguous evidence the sub-agent stopped early. → T-Y0SQ-task-work-emit-completion-marker
  • The orchestrator that handed off this brief also skipped Step 5b (flipping the task to status: in-progress on main and rebasing the feat branch onto that start-commit). The task file on main was still status: ready when this PR opened; Step 11a will reconcile by going straight from readyclosed/done. Possible automation: lift Step 5b into a script (plugin/scripts/start_task.py) the orchestrator must shell out to — same shape as new_task.py. A prose-only “now do this” step is too easy for a sub-agent to skip. → T-VFGF-extract-start-task-script
  • ensure-ready’s implementation lives entirely in SKILL.md prose, so there is no executable to unit-test directly. The new test harness re-encodes the prose’s mutations in Python — useful, but it drifts silently if SKILL.md changes and the re-encoding doesn’t. Possible automation: extract the frontmatter-mutation step of ensure-ready into a plugin/scripts/ensure_ready_mutate.py that both the skill and the test suite call. That would collapse the spec and the test’s “implementation” into one source. → T-4W64-extract-ensure-ready-mutate-script

← Back to Tasks