T-OHT5-resolve-ensure-ready-in-progress-contract
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-work Step 3 sets the task’s status: in-progress before
invoking /sdlc:task-ensure-ready in Step 5, but ensure-ready’s
contract refuses any status outside {draft, proposed, backlog, ready}.
Two consecutive task-work runs (T-DHGL-build-import-planning-skill,
T-3A6G-implement-entities-migrate) hit this and resolved it by
hand — soft-skipping Step 5 or applying the contract “pragmatically.”
This task closes the contradiction so future task-work runs never need
that judgment call.
The conflict surfaces in two places:
plugin/skills/task-work/SKILL.mdStep 3 flips frontmatter tostatus: in-progressand commits before any quality gate runs.plugin/entities/task/implementation-ready.md(the contract ensure-ready validates against) requiresstatusto be in{draft, proposed, backlog, ready}. Running ensure-ready against anin-progresstask would either fail or — depending on the skill’s failure mode — downshift the status and clearreadiness_verified_at, corrupting state mid-task.
Quoting the post-mortems verbatim:
“
/sdlc:task-ensure-ready’s contract literally disqualifiesstatus: in-progress, but/sdlc:task-workStep 3 setsin-progressbefore invoking ensure-ready in Step 5. Applied the contract pragmatically (spec quality verified, status check soft-skipped) — but this is a real design contradiction inside the SDLC plugin.” — T-DHGL-build-import-planning-skill“
task-ensure-readycan’t be re-run from insidetask-workafter Step 3 — Step 3 setsstatus: in-progress, but ensure-ready’s contract requiresstatusin{draft, proposed, backlog, ready}. Running it would corrupt the verified state. Orchestrator had to skip Step 5.” — T-3A6G-implement-entities-migrate
Proposed
Section titled “Proposed”Either:
- Option A (preferred): Move the
status: in-progressflip from task-work Step 3 to after Step 5 (ensure-ready passes). The status flip then signals “spec is implementation-ready AND work has begun,” which is more honest anyway. - Option B: Widen ensure-ready’s allowed-status set to include
in-progresswhenreadiness_verified_atis recent (e.g. within the current task-work invocation). Document the carve-out in the contract.
Pick one, implement it, and update both skills + the contract so the end-to-end task-work flow runs ensure-ready cleanly with zero manual intervention.
Approach
Section titled “Approach”- Choose Option A or B. Option A is preferred because it keeps ensure-ready’s contract pure and matches the intuition that “in-progress” means the implementer has started, not that the spec might be ready.
- Edit
plugin/skills/task-work/SKILL.md: move the status flip + the commit that announces it from Step 3 to Step 5’s success path. Step 3 becomes a pre-flight + worktree-init step; Step 5 becomes “ensure-ready + start work” combined. - Re-run task-work end-to-end against a draft task to confirm ensure-ready passes without the soft-skip.
Files to touch
Section titled “Files to touch”plugin/skills/task-work/SKILL.md— reorder Step 3 vs Step 5 so the status flip happens after ensure-ready passes.plugin/entities/task/implementation-ready.md— only if Option B is chosen; document thein-progresscarve-out.plugin/skills/task-ensure-ready/SKILL.md— only if Option B is chosen; widen the allowed-status check.
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A fresh
/sdlc:task-workrun against astatus: drafttask invokes/sdlc:task-ensure-readyand the call returns a clean pass (no soft-skip, no manual intervention, no contract violation noted in the run log). - AC-2: The contradiction is no longer noted in the next
task-work post-mortem’s
Friction and automation gapssection. - AC-3:
/project-checkstill passes after the edits.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-DHGL-build-import-planning-skill on 2026-05-19. The same gap was independently surfaced by the post-mortem of T-3A6G-implement-entities-migrate.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-05-19. PR: pending.
This task ran in stack #6 of a 6-PR sequential stack. The orchestrator instructed Option A explicitly and skipped Step 9 (rebase against origin/main) and Step 11 (close-out), per the stacked-PR overrides.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: agent-manual — walked the new SKILL.md flow on paper; Step 5a runs ensure-ready while status
is still
draft, so the contract’s allowed-status set is satisfied and the gate cannot soft-fail. Future task-work runs will exercise this end-to-end. - AC-2: agent-manual — the contradiction is structurally resolved by the reordering, so the next post-mortem cannot list it as friction.
- AC-3: auto —
plugin/scripts/lint_skill_prose.py plugin/skills/task-work/SKILL.mdpasses; the wider linter run across all four invariants-bearing skills also passes.
What worked
Section titled “What worked”- The prose-invariant linter (
plugin/scripts/lint_skill_prose.py) immediately confirmed that the rewrite still asserts the load-bearing claims (/sdlc:task-ensure-readyin Step 5,Delegate implementation to a sub-agentin Step 6,spawn-from-post-mortem.mdreference in Step 8, required H2NotesandFailure modes,validate_frontmatter.pyreference). Pinning those phrases ininvariants.yamlmade the reorder safe to perform mechanically without re-reading every cross-reference. - The contract in
plugin/entities/task/implementation-ready.mddidn’t have to change. Option A keeps the gate pure, so the contradiction is resolved purely in the orchestrator’s prose. That’s the cleaner design.
Friction and automation gaps
Section titled “Friction and automation gaps”- The
description:field in the SKILL.md frontmatter narrates the step order in one sentence (“mark it in-progress, spin up a worktree”). When that order changes, the description has to be hand-edited to match. Future skill-prose work could lift the description into a generated artifact, or add an invariants.yaml clause that pins the description against the actual step ordering. - Step 9’s contamination-rebase logic now relies on a slightly subtler invariant: the feat branch
carries exactly
<verify>then<start>then implementation commits, with<start>having landed on main rather than originating on the feat branch. The reorder commit-trace is correct, but a future automation could assert this with a small post-Step-5b sanity check (git log origin/main..HEAD --onelineshould show exactly two commits before Step 6 runs).
Out of scope
Section titled “Out of scope”- none