Skip to content

B-P502-commit-task-state-and-planning-docs-via-ephemeral-worktrees

Status: closed/abandoned

Task-state commits (start / verify / close) and planning-doc commits (task / backlog / decision creation) land on main through the single shared primary checkout that many parallel /sdlc:* sessions write to at the same time. This is a working-tree race.

One session’s uncommitted edit sits dirty in the shared working tree while another session stages and commits there:

  • A /sdlc:task-close-out mid-flight sdlc task update --set flips a task in-progressclosed/done (+ completion_note), leaving that task file dirty in the shared tree before it commits.
  • A concurrent planning-doc or task-state commit then runs in the same tree. git pull --rebase --autostash (close-out Step 4.8 and other flows) stashes/reapplies the whole working tree — it has no notion of “my files” — carrying the other session’s edit across the rebase.
  • Worse: the generated docs (task roster tasks.md, sidebar.mjs, docs/index.md) are union artifacts regenerated from every entity’s current working-tree state. So even an explicit git add <my-paths> plus a roster regen bakes the other session’s uncommitted status change into the committed roster — and project-check-docs-drift blocks the commit on the other session’s dirty state.

Net effect: forward clobbering (my commit silently carries their close-out’s roster flip), reverse clobbering (their broad git add site/src/content/docs sweeps in my generated artifacts), or a commit blocked on drift that isn’t mine. “Stage explicit paths only” does not protect against this because the generated roster is a shared union.

2026-06-20: a parallel T-CW4K close-out’s in-progressclosed/done edit was swept into a T-ACX9 planning-doc commit attempt via pull --rebase --autostash; the commit also blocked on the T-CW4K docs-drift. Landing T-ACX9 cleanly required an isolated worktree off origin/main (where T-CW4K was still committed-in-progress), then a plain git push origin HEAD:main.

Task-state and planning-doc commits should run in throwaway worktrees off origin/main (the isolation /sdlc:task-work already uses for implementation, and sdlc backlog create already uses for its rolling backlog-capture branch) — or acquire a main-checkout lock — so concurrent sessions never share a working tree. Candidate scope: a small “commit-on-main-via-ephemeral-worktree” helper that the task-lifecycle and entity-create flows call instead of committing on the shared checkout.

  • [T-6R73-pre-commit-drift-hooks-gate-unconditionally-forcing-no](/planning/tasks/pre-commit-drift-hooks-gate-unconditionally-forcing-no/) — that is the task-state-origin hook’s base-ref (origin/main vs local main), a different failure. This item is the shared-checkout write race itself, which persists even with the hook fixed.

Closed 2026-08-16: absorbed by ledger phase E6 of D-VSLI-distributed-work-runner-architecture. The corpus-writer actor owns every main-branch write, which dissolves the shared-checkout race class this describes.


← Back to Backlog