Files
get-shit-done/tests/bug-2384-post-merge-deletion-audit.test.cjs
Tom Boucher d1b56febcb fix(execute-phase): post-merge deletion audit for bulk file deletions (closes #2384) (#2483)
* 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>
2026-04-20 18:37:42 -04:00

55 lines
1.9 KiB
JavaScript

'use strict';
/**
* Regression test for #2384.
*
* During execute-phase, the orchestrator merges per-plan worktree branches into
* main. The pre-merge deletion check (git diff --diff-filter=D HEAD...WT_BRANCH)
* only catches files deleted on the worktree branch. A post-merge audit is also
* required to catch deletions that made it into the merge commit (e.g., files
* that were in the common ancestor but deleted by the merged worktree) and to
* provide a revert safety net.
*/
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const EXECUTE_PHASE = path.join(
__dirname, '..', 'get-shit-done', 'workflows', 'execute-phase.md'
);
describe('execute-phase.md — post-merge deletion audit (#2384)', () => {
const content = fs.readFileSync(EXECUTE_PHASE, 'utf-8');
test('post-merge deletion audit uses merge-commit diff', () => {
assert.match(
content,
/git diff --diff-filter=D --name-only HEAD~1 HEAD/,
'execute-phase.md must diff HEAD~1..HEAD with --diff-filter=D for post-merge deletion audit'
);
});
test('post-merge audit includes threshold gate + escape hatch + revert path', () => {
assert.match(
content,
/\[\s*"\$MERGE_DEL_COUNT"\s*-gt\s*5\s*\]\s*&&\s*\[\s*"\$\{ALLOW_BULK_DELETE:-0\}"\s*!=\s*"1"\s*\]/,
'execute-phase.md must gate on MERGE_DEL_COUNT threshold and ALLOW_BULK_DELETE override'
);
assert.match(
content,
/git reset --hard HEAD~1/,
'execute-phase.md must revert the merge commit when bulk deletions are blocked'
);
});
test('post-merge audit computes deletion count outside .planning/', () => {
assert.match(
content,
/MERGE_DEL_COUNT=.*grep -vc '\^\\\.planning\//,
'execute-phase.md must count non-.planning deletions for the bulk-delete guard'
);
});
});