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.
The hazard
Section titled “The hazard”One session’s uncommitted edit sits dirty in the shared working tree while another session stages and commits there:
- A
/sdlc:task-close-outmid-flightsdlc task update --setflips a taskin-progress→closed/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 explicitgit add <my-paths>plus a roster regen bakes the other session’s uncommitted status change into the committed roster — andproject-check-docs-driftblocks 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.
Observed
Section titled “Observed”2026-06-20: a parallel T-CW4K close-out’s in-progress → closed/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.
Proposed direction
Section titled “Proposed direction”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.
Not a duplicate of
Section titled “Not a duplicate of”[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.