T-WKQD-task-work-ancestry-helper-one-liner
Status: closed/done · Impact: low · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
/sdlc:task-work Step 9 (“Sync with origin/main before opening the
PR”) asks the agent to eyeball git log origin/main..HEAD --oneline
and identify whether any commit in that range is contamination from a
parallel session. The judgment is easy to make wrong when many parallel
task-work runs touch local main. A one-line helper that says
“contaminated: [list of basenames]” or “clean” would make the
contamination-rebase decision deterministic.
Step 9 of plugin/skills/task-work/SKILL.md lists the inspection
procedure. The agent runs git log origin/main..HEAD --oneline and
scans the output for chore(tasks): start <other-basename> commits
that belong to other sessions. Doing this by eye is fine for one or
two parallel sessions but degrades fast as the project’s parallelism
grows.
Proposed
Section titled “Proposed”A small script (likely plugin/skills/task-work/check_ancestry.py per
the co-location convention, or a shared
plugin/scripts/check_branch_ancestry.py if a second skill needs it)
that, given the current feat branch’s basename and origin/main,
prints either:
clean— every non-origin/main commit on the branch is owned by the current task (start-commit, verify-commit, work commits), orcontaminated: [<other-basename-1>, <other-basename-2>]— list the foreign start-commits that need to be dropped by Step 9’sgit rebase --onto origin/main <last-contaminating-sha>operation.
Skill prose at Step 9 then becomes “run this script; if it prints clean, push; if it prints contaminated, run the documented rebase with the listed sha.” Removes the human judgment loop.
Approach
Section titled “Approach”- Implement the script. Logic: walk
git log origin/main..HEAD --format=%H%n%s, parsechore(tasks): start <basename>lines, compare basename to the script’s--this-basenameargument, classify. - Wire it into Step 9 of
plugin/skills/task-work/SKILL.mdas the canonical contamination check. - (Optional, follow-up if multi-skill need emerges) promote the
script to
plugin/scripts/per the co-location principle.
Files to touch
Section titled “Files to touch”plugin/skills/task-work/check_ancestry.py(new) — the helper.plugin/skills/task-work/SKILL.md— replace the prose-only inspection in Step 9 with acheck_ancestry.pyinvocation.
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: Running the helper on a feat branch whose ancestry
contains exactly the start-commit for that basename plus its
verify/work commits prints
clean. - AC-2: Running it on a feat branch that also has a
chore(tasks): start <other-basename>commit between its branch-point and its own start-commit printscontaminated: [<other-basename>]along with the sha of the last contaminating commit (suitable for thegit rebase --ontoinvocation).
Out of scope
Section titled “Out of scope”- Promoting the helper to
plugin/scripts/until a second skill actually needs it (the co-location convention says wait for the real second caller). - Auto-running the rebase. The script reports; task-work prose still runs the rebase command with the listed sha.
- Detecting contamination from non-start-commit shapes (e.g. a
parallel session committing directly to main without a
start-commit). The heuristic is
chore(tasks): start <basename>only.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-UBJK-co-locate-skill-specific-scripts on 2026-05-20.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-05-21. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: auto —
plugin/skills/task-work/test_check_ancestry.py::test_clean_branchbuilds a fixture repo with only the task’s own start-commit + work commit pastorigin/mainand asserts the helper printsclean. - AC-2: auto —
plugin/skills/task-work/test_check_ancestry.py::test_contaminated_branchinjects achore(tasks): start othercommit on main before branching and asserts the helper printscontaminated: [other] last_sha=<sha>with the sha matching the foreign commit. A third case (test_multiple_contaminants_ordered) covers the two-contaminant ordering so the reportedlast_shais unambiguously the most recent foreign start-commit.
What worked
Section titled “What worked”- The co-location convention from T-UBJK-co-locate-skill-specific-scripts paid off immediately:
plugin/skills/task-work/check_ancestry.pyand its tests landed next tostart_task.py/test_start_task.pywithout a moment of “where does this go”. - The existing
start_task.pyshebang +# /// scriptPEP-723 header was a clean template; the new script and test file reused the shape verbatim, withdependencies = []since the classifier needs no third-party packages. - Quality checks (
run_quality_checks.py) caught nothing because there was nothing to catch — the test runs locally and pegs both ACs, and the SKILL.md edit was prose-only.
Friction and automation gaps
Section titled “Friction and automation gaps”- Step 5b (
start_task.py) surfaced a rebase conflict — bothmain’s start-commit and the feat branch’s verify-commit edited the same frontmatter lines (last_reviewed:andreadiness_verified_at:). The script exited 3 and left REBASE state for manual resolution. This is the expected failure mode for the script (and a known carve-out — Step 5b prose says “If conflicts are non-trivial, stop and ask”), but the specific shape (start-commit’slast_reviewed:bump vs verify-commit’sreadiness_verified_at:stamp) is mechanical and identical every time. A targeted resolver — “if the only conflict in the rebase is the task’s own frontmatter, auto-merge by union-of-frontmatter-fields with main’slast_reviewedand feat’sreadiness_verified_at” — would eliminate one human-in-the-loop touch per task-work run. → T-H0W9-task-work-rebase-frontmatter-conflict - The task’s “Approach” said “walk
git log origin/main..HEAD --format=%H%n%s” but%H%n%sputs the sha and subject on separate lines, which is awkward to parse robustly when subjects can contain newlines (they can’t, but a parser shouldn’t assume). The implementation switched to--format=%H%x09%s(tab-separated, single line per commit) which is the more idiomatic shape. Minor — the task spec was directionally right — but a brief convention doc on “git log machine-parseable formats” underplugin/conventions/might prevent this drift the next time a script needs to consumegit logoutput. → T-TH9J-git-log-machine-parseable-format-convention
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-TH9J-git-log-machine-parseable-format-convention — created; new convention doc for
git logformat strings used by plugin scripts. - T-H0W9-task-work-rebase-frontmatter-conflict — linked existing; existing task already covers the Step 5b rebase auto-resolver.