Wave Execution Policy
Established 2026-05-10 from the Phase 233.2 retrospective. Governs how parallel
gsd-executoragents are dispatched within a phase wave.
The problem
Section titled “The problem”Phase 233.2 dispatched four parallel gsd-executor agents in Wave 2 (plans 02 / 03 / 04 / 05) with gsd-plan-checker having explicitly verified zero files_modified overlap. Despite that, Plan 04 self-aborted with all 10 of its files reverted to their pre-edit state. Plan 03 also got reverted once mid-execution but recovered.
The root cause is not file-level conflict — it is worktree-state-level conflict: when one executor’s commit-protocol cycle (git stash / git reset --hard HEAD) fires while another executor’s edits are still unstaged in the same worktree, the unstaged edits are wiped. The files_modified overlap check cannot detect this because the conflict is at the index/working-tree boundary, not at the file-content boundary.
Plan 02 happened to commit progressively (1–2 files per batch); it survived. Plan 04 batched its commits at the end of each task; it lost everything.
Policy
Section titled “Policy”When dispatching multiple gsd-executor agents in the same wave on a shared worktree, exactly one of the following MUST apply:
Option 1 — Force commit-as-you-go (preferred for mechanical refactors)
Section titled “Option 1 — Force commit-as-you-go (preferred for mechanical refactors)”Add an explicit clause to every parallel executor prompt:
COMMIT-AS-YOU-GO: to bound any potential clobber, commit after every 1–2 files (not after the whole task batch). Use the plan’s commit message convention. Run
pnpm typecheckafter each batch.
This is the lightest-weight option. It does not require infrastructure changes. The only downside is more commits in the squash-merge unit; this is harmless because squash-merge collapses them.
When to use: mechanical wrapper swaps, CSS/className migrations, codemod-style refactors. Anything where the executor naturally edits one file at a time.
Option 2 — Run sequentially in foreground
Section titled “Option 2 — Run sequentially in foreground”Drop run_in_background=true from each Agent() call. Wait for plan N to complete before dispatching plan N+1.
When to use: the parallelism savings would be small (< 30% wall-clock), or the plans inherently produce overlapping edit ranges, or the wave has only 2 plans.
Option 3 — Isolated worktree per executor
Section titled “Option 3 — Isolated worktree per executor”Pass isolation="worktree" when spawning each Agent() (the gsd-executor scaffold supports this). Each executor gets its own copy of the working tree; the orchestrator merges results sequentially as each agent completes.
When to use: the plans touch many files each, parallelism savings are large, and provisioning isolated worktrees is acceptable. This is the most robust option but has the highest setup cost.
What NOT to do
Section titled “What NOT to do”- DO NOT rely on
files_modifiednon-overlap alone. That check is necessary but not sufficient. Two plans with disjoint file lists can still clobber each other through the worktree-state cycle described above. - DO NOT batch all commits at the end of the executor run when running in parallel on a shared worktree. That maximizes the clobber window.
- DO NOT silently retry a self-aborted executor if the abort report mentions
git reset --hardin the reflog. That signal means another agent’s commit-protocol fired during this agent’s edit window — re-running without changing the dispatch policy will recreate the same race.
Detection signals
Section titled “Detection signals”If an executor reports any of these, the wave is suffering the clobber bug and the dispatch policy needs to change:
git reflogshows unexplainedreset: moving to HEADentries during the executor’s run.- Files the executor never touched appear in its
git statusoutput. - “Modified by user or linter” warnings on files the executor just edited, with the diff matching the file’s pre-edit state.
Plan-checker integration
Section titled “Plan-checker integration”gsd-plan-checker should treat parallel-wave plans (wave: 2 with multiple wave: 2 siblings) as requiring an explicit dispatch-policy choice in the plan frontmatter or a parallelization-strategy block in the plan body. If neither is present, the checker should flag this as a HIGH advisory before execution.
Related artifacts
Section titled “Related artifacts”- Phase 233.2 retrospective:
.planning/phases/233.2-card-system-migration-retire-shell-card-and-hero-shell-to-sh/233.2-RETROSPECTIVE.md - Phase 233.2 deferred items (logs the actual incident):
.planning/phases/233.2-card-system-migration-retire-shell-card-and-hero-shell-to-sh/deferred-items.md - Memory entry for cross-session reuse:
~/.claude/projects/-Users-ordnas-Code-cinatra/memory/feedback_parallel_executor_clobber.md