fix(3804): worktree.cleanup-wave rescues uncommitted SUMMARY.md (#81)

* fix(3804): rescue uncommitted SUMMARY.md in executeWorktreeWaveCleanupPlan

Ports the shell-fallback SUMMARY rescue logic from quick.md into
executeWorktreeWaveCleanupPlan. Before the dirty-state check, all
*SUMMARY.md files under <worktree>/.planning/ are copied to the main
tree (if absent or divergent), then filtered out of the git-status
porcelain output. A worktree whose only dirty file is the executor's
uncommitted SUMMARY.md now proceeds to merge+remove instead of
returning cleanup_blocked/worktree_dirty.

Adds two TDD tests (#3804):
- Rescue-only dirty state (SUMMARY.md alone) → cleanup succeeds
- SUMMARY + non-SUMMARY dirty files → cleanup still blocks

Refs: #2296, #2070, #2838, #3804

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(3804): normalize relPath to forward slashes for Windows porcelain match

On Windows, `path.join` produces backslash separators while `git status
--porcelain` always emits forward slashes. The rescued-paths Set would
never match porcelain output, causing the dirty-check filter to ignore
SUMMARY rescue and block cleanup on Windows.

Also normalize the test assertion for `rescued[0].dest` to use
forward slashes so the test passes on both platforms.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-05-22 11:23:34 -04:00
committed by GitHub
parent 3c6bf06679
commit cda3d7a5ab
3 changed files with 243 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3804
---
**`worktree.cleanup-wave` no longer blocks on executor's uncommitted SUMMARY.md** — `executeWorktreeWaveCleanupPlan` previously returned `cleanup_blocked` / `worktree_dirty` when the executor left `<quick_id>-SUMMARY.md` uncommitted in the worktree's `.planning/` directory (the documented contract — the orchestrator commits it). The fix ports the shell-fallback rescue logic from `quick.md` into the CJS function: before the dirty-state check, all `*SUMMARY.md` files under `<worktree>/.planning/` are copied to the main tree (if absent or divergent), then filtered out of the porcelain output. Only non-SUMMARY dirty files now block cleanup. (#3804, mirrors #2296/#2070/#2838)