T-O4I9-refactor-task-work-step-2-via-skill-refine
Status: closed/done · Impact: medium · Complexity: small
/sdlc:task-work Step 2 (“verify task is workable”) carries ~40 lines of prose for a bundle of
deterministic checks: status enum gate, worktree-exists, branch-exists, PR-exists, plus a
5-condition resume-detection. The PR-exists check uses a freetext gh pr list --search "<basename>"
that incorrectly matches spec PRs on docs/ branches whose file lists contain the task spec
(concrete repro: PR #134). The original framing of this task was a surgical fix to that one query,
but the entire Step 2 block is script-shaped — the deterministic parts belong in a
precheck_task.py (or the unified sdlc task precheck CLI), and the SKILL.md should reduce to “run
the precheck; act on the marker.”
This is the second user of T-ELV7-prototype-skill-refine-skill, following the Step 4 refactor in T-33C0-refactor-task-work-step-4-via-skill-refine. Same extraction pattern; same depends_on gate.
Drop the feat/ legacy prefix entirely from the new code path. The branch-naming convention has
finished its transition; in-flight feat/<basename> branches are rare and should be renamed by
their owners, not accommodated indefinitely by every reader.
| Location | Role today |
|---|---|
plugin/skills/task-work/SKILL.md (Step 2) | ~40 lines of prose for status enum gate, worktree-exists check (git worktree list), branch-exists check (git branch --list 'task/<basename>' 'feat/<basename>'), PR-exists check (gh pr list --search "<basename>"), planning/* prompt branch, and 5-condition resume-detection sub-block. All deterministic except the planning/* AskUserQuestion prompt. |
plugin/skills/task-work/SKILL.md (resume-detection sub-section of Step 2) | A second gh pr list --search "<basename>" call. Same freetext-search problem. |
plugin/conventions/branch-naming.md | Documents task/<basename> as the implementation prefix; docs/<basename> for spec PRs. feat/<basename> is named as the legacy prefix during transition. |
plugin/skills/task-work/invariants.yaml | Pins phrases from Step 2 (the gh pr list line). Will need updating once Step 2 prose is replaced. |
plugin/scripts/ | Has no precheck_task.py. The current closest analogue is start_task.ts (used by Step 5b), which is also a small deterministic helper called from a SKILL.md Step. |
Proposed
Section titled “Proposed”Step 2 of task-work/SKILL.md reduces to roughly:
## 2. Verify the task is workable
Run the precheck:
${CLAUDE_PLUGIN_ROOT}scripts/precheck_task.py <basename>
Act on the stdout marker:
- `OK` — proceed to Step 2a (lease acquire).- `BLOCKED-CLOSED status=<closed/...>` — surface and stop.- `BLOCKED-IN-PROGRESS status=<in-progress[/blocked]>` — surface and stop.- `BLOCKED-WORKTREE path=<...>` — surface and stop.- `BLOCKED-BRANCH name=<task/<basename>>` — surface and stop.- `BLOCKED-PR pr=#<N>` — surface and stop.- `RESUME-AT-5B` — ask the user (resume vs start-over) via AskUserQuestion; on resume, skip Steps 3, 4, 5a and jump to 5b.- `PROMPT-PLANNING status=<planning/...>` — ask the user (proceed-anyway vs stop) via AskUserQuestion; default stop.
Relevance check still happens in prose (it requires LLM judgment).The new script (plugin/scripts/precheck_task.py, or sdlc task precheck under the unified CLI)
owns:
- The status enum gate (closed/, in-progress/, planning/, open/ — emits the right marker per status family).
- The worktree-exists check (parse
git worktree list). - The branch-exists check — only
task/<basename>, notfeat/. - The PR-exists check — scoped to
head:task/<basename>, not freetext. A spec PR ondocs/...stops matching by construction; no file-list inspection needed. - The 5-condition resume-detection (status on main = open/ready AND worktree exists AND branch
exists AND HEAD commit subject = “docs(tasks): verify
implementation-ready” AND no PR open) — emits RESUME-AT-5Bwhen all five hold.
Output is one line per call: <MARKER> [key=value].... The SKILL.md branches on the marker;
AskUserQuestion is the SKILL’s job, not the script’s (judgment lives in prose).
The extraction is performed by /skill-refine from T-ELV7-prototype-skill-refine-skill, same as
the Step 4 refactor.
Approach
Section titled “Approach”- Wait for T-ELV7-prototype-skill-refine-skill to ship. Same gate as the Step 4 refactor task.
- Invoke
/skill-refine plugin/skills/task-work/SKILL.md "## 2". Review the extraction proposal. - Confirm the proposal includes the
feat/deletion. This is the spec’s explicit request; the script does NOT searchfeat/<basename>branches. - Confirm the PR-search uses
head:task/<basename>scoping. The freetext-search bug from the original framing is fixed by construction. - Let skill-refine generate the script and rewrite Step 2. Verify the resulting SKILL.md passes
check_skill_prose.pyand the pipe-tail check. - Migrate
plugin/skills/task-work/invariants.yaml— drop pinned phrases from old Step 2 prose; pin the new shape (presence of the script call line, AskUserQuestion branches for planning/* and resume). - Add regression tests for the new script. Cover at least: each of the 7 markers, the
head:task/scoping (a spec PR ondocs/<basename>does NOT block), the 5-condition resume detection (all four “any-but-not-all” cases of the conditions surface asOK, notRESUME-AT-5B). - Update
docs/skills/task-work.mdflowchart if Step 2 nodes change shape.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/scripts/precheck_task.py | new | The extracted script. Owns status enum gate, worktree/branch/PR existence checks, resume detection. No feat/ legacy. |
plugin/skills/task-work/SKILL.md | modify | Replace ~40 lines under ## 2 with the script call + marker-branching prose. Drop the prose resume-detection sub-section (its logic moves to the script; the AskUserQuestion gate stays in prose). |
plugin/scripts/tests/test_precheck_task.py | new | Regression tests for every marker and the resume-detection truth table. |
plugin/skills/task-work/invariants.yaml | modify | Drop pinned phrases from old Step 2 prose; pin the new shape. |
docs/skills/task-work.md | modify | Update Step 2 nodes in the flowchart if needed. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
${CLAUDE_PLUGIN_ROOT}scripts/precheck_task.py <basename>exits 0 and emits exactly one stdout line whose first whitespace-delimited token is one of:OK,BLOCKED-CLOSED,BLOCKED-IN-PROGRESS,BLOCKED-WORKTREE,BLOCKED-BRANCH,BLOCKED-PR,RESUME-AT-5B,PROMPT-PLANNING. - AC-2: Against a task with an open spec-only PR on
docs/<basename>(whose file list contains the task spec), the script emitsOK— it does not block. The original freetext-search bug is fixed by construction. - AC-3: Against a task with an open PR on
task/<basename>, the script emitsBLOCKED-PR pr=#<N>. - AC-4: The script does NOT search for branches or PRs on the legacy
feat/<basename>prefix. In-flightfeat/branches are accepted as a no-op; the operator is expected to rename them. - AC-5: When all five resume-detection conditions hold (open/ready status on main, worktree
exists,
task/<basename>branch exists, branch HEAD subject isdocs(tasks): verify <basename> implementation-ready, no PR open), the script emitsRESUME-AT-5B. Any one condition false yields a different marker. - AC-6:
plugin/skills/task-work/SKILL.mdStep 2 body is ≤25 lines (a shell-out + marker-handling prose + AskUserQuestion branches), and the file still passescheck_skill_prose.pyand the pipe-tail check. - AC-7: A live
/sdlc:task-work <some-basename>run end-to-end against a real task succeeds — Step 2 fires the new script, the right marker is emitted, and downstream Steps 2a–7 still work.
Out of scope
Section titled “Out of scope”- Cross-repo task PRs. Branch-naming applies to this repo; cross-repo handling is a separate concern.
- Re-scoping merged/closed PRs. The script filters to
--state open. - File-list classification of PRs. The earlier draft of this task proposed a
classify_pr.pyhelper that inspected PR file lists; the branch-prefix approach is strictly simpler and uses an existing convention. - A
--dry-runflag on the precheck. The script is itself read-only; rehearsal is unnecessary.
Dependencies
Section titled “Dependencies”- T-ELV7-prototype-skill-refine-skill — same gate as the Step 4 refactor; the extraction is performed via skill-refine.
Discovery context
Section titled “Discovery context”Original framing (a surgical fix to Step 2’s PR-search) spawned 2026-05-27 from PR #134’s repro (a
spec PR’s file list matched freetext-search and blocked Task A pickup). Rewritten 2026-05-28 during
an open/ready audit: the bug is real but it’s a symptom of the larger pattern — Step 2’s prose is
mostly script-shaped, same as Step 4. Better to extract the whole Step than to patch the one query.
Depends on
Section titled “Depends on”T-ELV7-prototype-skill-refine-skill