* fix(execute-phase): post-merge deletion audit for bulk file deletions (closes #2384) Two data-loss incidents were caused by worktree merges bringing in bulk file deletions silently. The pre-merge check (HEAD...WT_BRANCH) catches deletions on the worktree branch, but files deleted during the merge itself (e.g., from merge conflict resolution or stale branch state) were not audited post-merge. Adds a post-merge audit immediately after git merge --no-ff succeeds: - Counts files deleted outside .planning/ in the merge commit - If count > 5 and ALLOW_BULK_DELETE!=1: reverts the merge with git reset --hard HEAD~1 and continues to the next worktree - Logs the full file list and an escape-hatch instruction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(test): tighten post-merge deletion audit assertions (CodeRabbit #2483) Replace loose substring checks with exact regex assertions: - assert.match against 'git diff --diff-filter=D --name-only HEAD~1 HEAD' - assert.match against threshold gate + ALLOW_BULK_DELETE override condition - assert.match against git reset --hard HEAD~1 revert - assert.match against MERGE_DEL_COUNT grep -vc for non-.planning count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(inventory): update workflow count to 81 (graduation.md added in #2490) 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:
@@ -623,6 +623,21 @@ Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZAT
|
||||
break
|
||||
}
|
||||
|
||||
# Post-merge deletion audit: detect bulk file deletions in merge commit (#2384)
|
||||
# --diff-filter=D HEAD~1 HEAD shows files deleted by the merge commit itself.
|
||||
# Exclude .planning/ — orchestrator-owned deletions there are expected (resurrections
|
||||
# are handled below). Require ALLOW_BULK_DELETE=1 to bypass for intentional large refactors.
|
||||
MERGE_DEL_COUNT=$(git diff --diff-filter=D --name-only HEAD~1 HEAD 2>/dev/null | grep -vc '^\.planning/' || true)
|
||||
if [ "$MERGE_DEL_COUNT" -gt 5 ] && [ "${ALLOW_BULK_DELETE:-0}" != "1" ]; then
|
||||
MERGE_DELETIONS=$(git diff --diff-filter=D --name-only HEAD~1 HEAD 2>/dev/null | grep -v '^\.planning/' || true)
|
||||
echo "⚠ BLOCKED: Merge of $WT_BRANCH deleted $MERGE_DEL_COUNT files outside .planning/ — reverting to protect repository integrity (#2384)"
|
||||
echo "$MERGE_DELETIONS"
|
||||
echo " If these deletions are intentional, re-run with ALLOW_BULK_DELETE=1"
|
||||
git reset --hard HEAD~1 2>/dev/null || true
|
||||
rm -f "$STATE_BACKUP" "$ROADMAP_BACKUP"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Restore orchestrator-owned files (main always wins)
|
||||
if [ -s "$STATE_BACKUP" ]; then
|
||||
cp "$STATE_BACKUP" .planning/STATE.md
|
||||
|
||||
Reference in New Issue
Block a user