T-H0W9-task-work-rebase-frontmatter-conflict
Status: closed/done · Impact: high · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem in rust-path-opener
(2026-05-19-obsidian-vault-id-uri). Review and promote to
open/ready before picking up.
/sdlc:task-work Step 5b’s gate-then-flip design produces a
deterministic merge conflict on every run: the verify-commit (on the
feat branch) adds readiness_verified_at: and the start-commit (on
main) changes status: and last_reviewed: — both edits sit in the
same YAML frontmatter block, on adjacent lines, so the rebase always
conflicts. The conflict’s resolution is mechanical (union the fields)
but the skill text says “stop and surface to the user” on conflict.
Either pre-resolve automatically or restructure so the conflict
never arises.
- Step 5a (
/sdlc:task-ensure-ready) commitsreadiness_verified_at: <ts>on the feat branch. No status change. - Step 5b then edits the task file on main: sets
status: in-progressandlast_reviewed: <today>. Commits on main. - Step 5b.6 runs
git rebase maininside the worktree to bring the feat branch onto the updated main. Both commits touched the frontmatter YAML on adjacent lines, so the rebase reliably emits a CONFLICT (content) on the task file. - The resolution is always the same: take
statusandlast_reviewedfrom main, takereadiness_verified_atfrom feat, leave all other fields intact. There is no real ambiguity. - The skill text at Step 5b.6 says: “If
git rebase mainat 5b.6 surfaces a conflict, something is wrong with the local state… Stop and surface to the user; do not auto-resolve.” This is the wrong guidance for the structural conflict, since “something is wrong” is in fact “the design produces this conflict every time.” - Reproduced in
rust-path-opener/sdlc:task-workrun on2026-05-19-obsidian-vault-id-uri.
Proposed
Section titled “Proposed”Restructure the commits so they don’t touch adjacent lines.
/sdlc:task-ensure-ready always writes readiness_verified_at: as
the LAST frontmatter key (after related:/tags:). Step 5b’s
start-commit only edits the top fields (status, last_reviewed).
The two hunks are now physically separated by every other frontmatter
key plus the closing ---, well outside git’s ~3-line conflict
context, so the rebase sees disjoint hunks and merges without
conflict.
Rejected alternatives (kept here for posterity):
- (b) Custom git merge driver / rerere for
docs/planning/tasks/*.mdthat auto-unions YAML frontmatter. Solves the symptom; more plumbing than the source-structure fix. Revisit if other frontmatter-conflict scenarios surface. - (c) Flip commit order — start-commit first, then verify.
Architecturally cleaner (no rebase needed) but flips the semantics
to mark-then-verify, leaving an orphan
in-progresson main if verify fails, and requires reworking ensure-ready’s “skip if input was already in-progress” carve-out. Larger change for the same outcome.
Approach
Section titled “Approach”- Update
/sdlc:task-ensure-ready’s frontmatter-edit logic inplugin/skills/task-ensure-ready/SKILL.mdStep 4 soreadiness_verified_at:is always Edited in as the LAST key of the frontmatter block, afterrelated:andtags:. If a previous stamp exists not-at-bottom, move it. - Update
plugin/skills/task-work/SKILL.mdStep 5b.6 to remove the “stop and surface to the user; do not auto-resolve” guidance — the structural conflict is eliminated. Keep the warning only for genuine ancestry conflicts (parallel sessions, manual edits). - Add a regression case to
plugin/skills/task-ensure-ready/tests/run_evals.pythat runs the gate-flip sequence on a fixture task (verify on feat, start-commit on main, rebase feat onto main) and asserts the rebase exits 0 with no conflict markers in the task file.
Files to touch
Section titled “Files to touch”plugin/skills/task-ensure-ready/SKILL.md— Step 4 frontmatter- write prose: always placereadiness_verified_at:last.plugin/skills/task-work/SKILL.md— Step 5b.6 prose: remove the “stop on conflict” structural-conflict guidance.plugin/skills/task-ensure-ready/tests/run_evals.py— add the gate-flip regression case.
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: Running
/sdlc:task-work <slug>end-to-end on a fresh task produces no rebase conflict at Step 5b.6. - AC-2: Step 5b.6’s “stop on conflict” guidance is removed from
plugin/skills/task-work/SKILL.md; the warning that remains mentions only genuine ancestry conflicts (parallel sessions / manual edits), not the structural case. - AC-3:
plugin/skills/task-ensure-ready/tests/run_evals.pycontains a case that builds a fixture git repo, runs the verify-then-start-then-rebase sequence, and assertsgit rebaseexits 0 with no conflict markers in the task file.
Out of scope
Section titled “Out of scope”- Conflicts that arise from genuine concurrent edits to the task file by parallel sessions. Those are real and should still stop and surface.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”- Surfaced 2026-05-20 by
/sdlc:task-workrunning2026-05-19-obsidian-vault-id-uriinsksizer/rust-path-opener. Step 5b.6 emitted the documented conflict on first attempt; the user had to authorize the union-merge resolution manually.
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 —
gate-flip-rebase-cleaninplugin/skills/task-ensure-ready/tests/run_evals.pybuilds a throwaway repo and exercises the verify-then-start-then-rebase sequence end-to-end; the rebase exits 0 with no conflict markers. Note: this very run’s Step 5b.6 still hit the conflict, because the task’s pre-fix stamp lived mid-block — that was expected and is the last time it will fire on a fresh run. - AC-2: agent-manual — read the edited prose in
plugin/skills/task-work/SKILL.mdStep 5b “Exit code 3” bullet; the structural-conflict guidance is gone, the remaining text scopes exit 3 to parallel sessions, manual main edits, and origin/main divergence. - AC-3: auto —
run_evals.pynow reports9/9 case(s) passedincluding the newgate-flip-rebase-cleancase.
What worked
Section titled “What worked”- The fix surface (one-line behaviour change in
apply_pass—pop+ re-insert at the end) was as small as the spec’s “Proposed” section promised. No reordering of other keys, no schema change. - The new test exercises real
git rebaseon a real fixture repo, so it would fail loudly if the structural conflict ever returned — exactly the regression shape the AC asked for.
Friction and automation gaps
Section titled “Friction and automation gaps”/sdlc:task-workStep 5b.6 hit the very conflict the task was fixing, on the task that was fixing it. Auto-resolution would have been mechanical (union the two YAML hunks), but the skill’s prose says “stop and surface.” A future improvement: havestart_task.pydetect the structural-conflict shape (only the task file conflicts, only frontmatter, the two hunks are non-overlapping when unioned) and apply the union automatically. Lower priority now that the fix lands, since fresh runs will not hit it — but the next bootstrap task that edits ensure-ready’s stamp logic could still trip it. → T-H98A-last-reviewed-rebase-collision- The task’s prior stamp at
'2026-05-21T04:02:38Z'was idempotently refreshed by ensure-ready inside the worktree to a fresh'2026-05-21T15:43:38Z'— no friction, but worth noting that re-running ensure-ready bumps the stamp even when the contract has not actually been re-verified against new code. Not a gap to file, just a behaviour to remember.
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-H98A-last-reviewed-rebase-collision — existing task
already covers the broader “auto-union mechanical frontmatter
conflicts in
start_task.py” gap; linked rather than duplicated.