Skip to content

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.md Step 3 flips frontmatter to status: in-progress and commits before any quality gate runs.
  • plugin/entities/task/implementation-ready.md (the contract ensure-ready validates against) requires status to be in {draft, proposed, backlog, ready}. Running ensure-ready against an in-progress task would either fail or — depending on the skill’s failure mode — downshift the status and clear readiness_verified_at, corrupting state mid-task.

Quoting the post-mortems verbatim:

/sdlc:task-ensure-ready’s contract literally disqualifies status: in-progress, but /sdlc:task-work Step 3 sets in-progress before 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-ready can’t be re-run from inside task-work after Step 3 — Step 3 sets status: in-progress, but ensure-ready’s contract requires status in {draft, proposed, backlog, ready}. Running it would corrupt the verified state. Orchestrator had to skip Step 5.” — T-3A6G-implement-entities-migrate

Either:

  • Option A (preferred): Move the status: in-progress flip 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-progress when readiness_verified_at is 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.

  1. 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.
  2. 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.
  3. Re-run task-work end-to-end against a draft task to confirm ensure-ready passes without the soft-skip.
  • 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 the in-progress carve-out.
  • plugin/skills/task-ensure-ready/SKILL.md — only if Option B is chosen; widen the allowed-status check.
  • AC-1: A fresh /sdlc:task-work run against a status: draft task invokes /sdlc:task-ensure-ready and 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 gaps section.
  • AC-3: /project-check still passes after the edits.
  • none

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.

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.

  • 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.md passes; the wider linter run across all four invariants-bearing skills also passes.
  • The prose-invariant linter (plugin/scripts/lint_skill_prose.py) immediately confirmed that the rewrite still asserts the load-bearing claims (/sdlc:task-ensure-ready in Step 5, Delegate implementation to a sub-agent in Step 6, spawn-from-post-mortem.md reference in Step 8, required H2 Notes and Failure modes, validate_frontmatter.py reference). Pinning those phrases in invariants.yaml made the reorder safe to perform mechanically without re-reading every cross-reference.
  • The contract in plugin/entities/task/implementation-ready.md didn’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.
  • 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 --oneline should show exactly two commits before Step 6 runs).
  • none

← Back to Tasks