Files
get-shit-done/tests/execute-phase-step-5-5-deviation-doc.test.cjs
Tom Boucher d8a93ad12d fix(3264): document cross-wave-deviation cleanup tail in execute-phase step 5.5 (#3273)
* fix(3264): document cross-wave-deviation cleanup tail in execute-phase step 5.5

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

* chore(changeset): add fragment for #3273

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 00:14:54 -04:00

141 lines
4.9 KiB
JavaScript

// allow-test-rule: source-text-is-the-product
// The workflow .md file is the installed AI contract — its text IS what the orchestrator
// executes at runtime. Testing structural content of step 5.5 guards against accidental
// deletion of the cross-wave-deviation cleanup documentation (#3264).
/**
* Regression tests for #3264: cross-wave-dependency deviation cleanup documentation
*
* Guards that step 5.5 of execute-phase.md documents both skip conditions and
* contains a self-contained cleanup-tail snippet for the deviation path.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const WORKFLOW_PATH = path.join(
__dirname,
'..',
'get-shit-done',
'workflows',
'execute-phase.md',
);
/**
* Locate the step 5.5 block in the workflow file.
* Returns the substring from "5.5." up to (but not including) "5.6.".
* Throws if the block cannot be found.
*/
function extractStep55Block(content) {
const start = content.indexOf('\n5.5.');
assert.ok(start !== -1, 'execute-phase.md must contain a step 5.5 block');
const end = content.indexOf('\n5.6.', start + 1);
assert.ok(end !== -1, 'execute-phase.md must contain a step 5.6 block after 5.5');
return content.slice(start, end);
}
describe('execute-phase step 5.5: cross-wave-deviation cleanup documentation (#3264)', () => {
const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
test('workflow file exists', () => {
assert.ok(fs.existsSync(WORKFLOW_PATH), 'workflows/execute-phase.md should exist');
});
test('step 5.5 block exists and is bounded', () => {
// extractStep55Block throws on failure — this test validates the helper itself
const block = extractStep55Block(content);
assert.ok(block.length > 0, 'step 5.5 block must be non-empty');
});
test('step 5.5 documents the standard wave contract', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('Standard wave contract'),
'step 5.5 must name the standard wave contract explicitly',
);
});
test('step 5.5 names cross-wave dependency deviation as a supported execution mode', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('Cross-wave dependency deviation'),
'step 5.5 must name the cross-wave dependency deviation as a supported mode',
);
});
test('cleanup-tail snippet contains git worktree prune', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('git worktree prune'),
'step 5.5 cleanup-tail snippet must include git worktree prune',
);
});
test('cleanup-tail snippet contains git worktree remove --force', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('git worktree remove') && block.includes('--force'),
'step 5.5 cleanup-tail snippet must include git worktree remove --force',
);
});
test('cleanup-tail snippet contains git worktree unlock', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('git worktree unlock'),
'step 5.5 cleanup-tail snippet must include git worktree unlock',
);
});
test('cleanup-tail snippet contains git branch -D', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('git branch -D'),
'step 5.5 cleanup-tail snippet must include git branch -D',
);
});
test('skip conditions enumerate empty-WAVE_WORKTREE_PLANS case', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('WAVE_WORKTREE_PLANS'),
'step 5.5 must document the empty-WAVE_WORKTREE_PLANS skip condition',
);
});
test('skip conditions enumerate custom-merge-deviation case', () => {
const block = extractStep55Block(content);
// The deviation skip condition must reference the cleanup-tail as the alternative
assert.ok(
block.includes('cleanup-tail'),
'step 5.5 must document the custom-merge-deviation skip condition with a pointer to the cleanup-tail',
);
});
test('cleanup-tail uses inclusion-based filter for agent namespace', () => {
const block = extractStep55Block(content);
// Must use .claude/worktrees/agent- inclusion filter, not exclusion (per #2774 precedent)
assert.ok(
block.includes('.claude/worktrees/agent-'),
'cleanup-tail must use inclusion-based filter matching .claude/worktrees/agent- namespace',
);
});
test('cleanup-tail reads git worktree list --porcelain line-by-line', () => {
const block = extractStep55Block(content);
assert.ok(
block.includes('git worktree list --porcelain'),
'cleanup-tail must parse git worktree list --porcelain output',
);
// Line-by-line reading requires IFS= read -r pattern
assert.ok(
block.includes('IFS= read -r'),
'cleanup-tail must read line-by-line to preserve paths with whitespace',
);
});
});