Skip to content

T-VFGF-extract-start-task-script

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

Auto-generated from a /sdlc:task-work post-mortem. Review and promote to ready before picking up.

/sdlc:task-work Step 5b — the “flip the task to status: in-progress on main, commit chore(tasks): start <basename>, rebase the feat branch” sequence — currently lives as prose only. Sub-agents skip it silently (twice now on T-ZQ4H-task-ensure-ready-accepts-in-progress, where the task on main is still status: ready even though a feat branch and PR exist). A prose-only “now do this” step is too easy to drop. Lifting Step 5b into a script the orchestrator must shell out to closes the gap the same way new_task.py and migrate_entities.py closed theirs.

plugin/skills/task-work/SKILL.md Step 5b walks through seven sub- steps (edit frontmatter, validate, stage, commit on main, sanity-check, rebase the feat branch, surface conflicts). The skill expects the implementer-agent to follow every sub-step manually. Two consecutive runs on this very task skipped Step 5b entirely, leaving main in a state where git log shows no start-commit and the task frontmatter on main is still status: ready.

plugin/skills/task-work/start_task.py is a PEP-723 self-bootstrapping CLI that takes the task path and worktree path, flips the task to status: in-progress on main, runs the frontmatter validator, commits on main with the canonical message, then rebases the named feat branch onto the new main tip. Step 5b in SKILL.md becomes “shell out to plugin/skills/task-work/start_task.py with these args; surface any non-zero exit to the user”. The script lives co-located with its single caller (task-work) per plugin/skills/CLAUDE.md — promote to plugin/scripts/ only when a second skill actually needs it.

  1. Author plugin/skills/task-work/start_task.py mirroring the shape of plugin/scripts/new_task.py (PEP-723 shebang, argparse, no third-party runtime deps beyond pyyaml).
  2. Replace Step 5b’s seven-step prose with a single shell-out instruction in plugin/skills/task-work/SKILL.md.
  3. Add unit tests for start_task.py at plugin/skills/task-work/test_start_task.py. Cover the happy path (task flips to in-progress on main, start-commit lands, feat branch rebases) and at least one failure mode (rebase conflict surfaces a non-zero exit). Tests run against an ephemeral fixture git repo built in a tmp_path — no SKILL eval harness, no live sub-agent fan-out.
  • plugin/skills/task-work/start_task.py (new)
  • plugin/skills/task-work/SKILL.md — replace Step 5b prose with shell-out.
  • plugin/skills/task-work/test_start_task.py (new)
  • plugin/skills/task-work/invariants.yaml — pin start_task.py as a required_tool_refs.
  • AC-1: A fresh /sdlc:task-work run lands a chore(tasks): start <basename> commit on main automatically without sub-agent judgment.
  • AC-2: plugin/skills/task-work/test_start_task.py includes a happy-path case asserting the start-commit lands on main and the feat branch rebases onto it, plus a rebase-conflict case asserting start_task.py exits non-zero with a message that names the conflicting paths.
  • AC-3: lint_skill_prose.py enforces the start_task.py reference in plugin/skills/task-work/SKILL.md.
  • Lifting the Step 11a close-out into a script (related but separate).
  • 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: agent-manual — Step 5b in this very run shelled out to the new script (after it was authored), landing commit df5ac07 chore(tasks): start 2026-05-19-extract-start-task-script on main with no sub-agent free-form judgment. Also covered by test_happy_path in plugin/skills/task-work/test_start_task.py, which asserts the start-commit subject and the rebased feat-branch history shape.
  • AC-2: auto — plugin/skills/task-work/test_start_task.py includes test_happy_path (asserts the start-commit lands on main and the feat branch is rebased onto it) and test_rebase_conflict (asserts start_task.py exits with status 3 and the diagnostic names the conflicting paths). Two further cases (test_idempotent_when_already _in_progress, test_rejects_closed_task) cover the script’s contract beyond the spec’s minimum.
  • AC-3: auto — invariants.yaml now lists start_task.py under required_tool_refs. Verified during this run by deleting the reference from SKILL.md and observing lint_skill_prose.py exit with status 1 and message required tool reference 'start_task.py' not cited in SKILL.md.
  • The new_task.py PEP-723 script was a clean template — same shebang, same argparse shape, same YAML frontmatter round-trip. Reusing that shape kept the new script under 350 lines including docstrings.
  • The fixture-based test pattern in plugin/entities/task/migrations/test_v1_to_v2.py extended cleanly to a script that needs a real git repo. tempfile.TemporaryDirectory
    • git -C was enough; no test framework required.
  • The first run of the test suite caught a real YAML-date round-trip bug (yaml.safe_load returns datetime.date for bare ISO dates; the script was comparing against a string and so flagged a spurious semantic change). Lesson: when a script edits frontmatter, always normalize dates to isoformat() before comparing — consider factoring a tiny _normalize_frontmatter helper into plugin/validators/ so future frontmatter-mutating scripts inherit the same normalization for free. → T-07DV-frontmatter-edit-helpers-normalize-yaml-dates
  • plugin/skills/task-work/test_start_task.py is not currently listed in sdlc.yaml’s quality_checks: — it only runs if a contributor invokes it directly. The other co-located skill tests (plugin/skills/*/tests/run_evals.py) are listed. Either promote this test to the same tests/ layout or add a one-line quality_ checks: entry; otherwise a regression in start_task.py will pass CI silently. → T-8DQQ-start-task-tests-in-quality-checks
  • Step 5b’s rebase in this very run surfaced a non-trivial merge conflict on last_reviewed: because the feat branch’s ensure-ready commit edited the same field. The skill prose says “something is wrong with the local state” if the rebase conflicts — but in fact a same-field conflict is the expected shape when the start-commit on main and the verify-ready commit on feat both touch last_reviewed:. The prose should be updated to say “trivial conflicts on last_reviewed: are expected; resolve by taking HEAD” — or, more durably, start_task.py should set last_reviewed: to a value that won’t conflict with whatever ensure-ready wrote (e.g. derive both stamps from the same UTC clock-call captured at task-work entry). → T-H0W9-task-work-rebase-frontmatter-conflict

← Back to Tasks