Files
msd-core/tests/execute-phase-wave.test.cjs
Tibsfox d1ff0437f1 feat(config): add workflow.use_worktrees toggle to disable worktree isolation
Adds `workflow.use_worktrees` config option (default: `true`) that
allows users to disable git worktree isolation for executor agents.

When set to `false`:
- Executor agents run without `isolation="worktree"`
- Plans execute sequentially on the main working tree
- No worktree merge ordering issues or orphaned worktrees
- Normal git hooks run (no --no-verify needed)

This provides an escape hatch for solo developers and users who
experience worktree merge conflicts, as worktree ordering issues
are inherently difficult when parallel agents modify overlapping
files.

Usage:
  /gsd:settings → set workflow.use_worktrees to false

Or directly:
  gsd-tools config-set workflow.use_worktrees false

Changes:
- config.cjs: add workflow.use_worktrees to valid keys
- planning-config.md: document the option
- execute-phase.md: read config, conditional worktree + sequential mode
- execute-plan.md: conditional worktree in Pattern A
- quick.md: conditional worktree for quick executor
- diagnose-issues.md: conditional worktree for debug agents
- 2 new tests (config set + workflow structural check)

Closes #1451

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 10:11:49 -07:00

125 lines
4.8 KiB
JavaScript

/**
* Execute-phase wave filter tests
*
* Validates the /gsd:execute-phase --wave feature contract:
* - Command frontmatter advertises --wave
* - Workflow parses WAVE_FILTER
* - Workflow enforces lower-wave safety
* - Partial wave runs do not mark the phase complete
*/
const { test, describe } = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const path = require('path');
const COMMAND_PATH = path.join(__dirname, '..', 'commands', 'gsd', 'execute-phase.md');
const WORKFLOW_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'execute-phase.md');
const COMMANDS_DOC_PATH = path.join(__dirname, '..', 'docs', 'COMMANDS.md');
const HELP_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'help.md');
describe('execute-phase command: --wave flag', () => {
test('command file exists', () => {
assert.ok(fs.existsSync(COMMAND_PATH), 'commands/gsd/execute-phase.md should exist');
});
test('argument-hint includes --wave, --gaps-only, and --interactive', () => {
const content = fs.readFileSync(COMMAND_PATH, 'utf-8');
const hintLine = content.split('\n').find(l => l.includes('argument-hint'));
assert.ok(hintLine, 'should have argument-hint line');
assert.ok(hintLine.includes('--wave N'), 'argument-hint should include --wave N');
assert.ok(hintLine.includes('--gaps-only'), 'argument-hint should keep --gaps-only');
assert.ok(hintLine.includes('--interactive'), 'argument-hint should preserve --interactive');
});
test('objective describes wave-filter execution', () => {
const content = fs.readFileSync(COMMAND_PATH, 'utf-8');
const objectiveMatch = content.match(/<objective>([\s\S]*?)<\/objective>/);
assert.ok(objectiveMatch, 'should have <objective> section');
assert.ok(objectiveMatch[1].includes('--wave N'), 'objective should mention --wave N');
assert.ok(
objectiveMatch[1].includes('no incomplete plans remain'),
'objective should mention phase completion guardrail'
);
});
});
describe('execute-phase workflow: wave filtering', () => {
test('workflow file exists', () => {
assert.ok(fs.existsSync(WORKFLOW_PATH), 'workflows/execute-phase.md should exist');
});
test('workflow parses WAVE_FILTER from arguments', () => {
const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
assert.ok(content.includes('WAVE_FILTER'), 'workflow should reference WAVE_FILTER');
assert.ok(content.includes('Optional `--wave N`'), 'workflow should parse --wave N');
});
test('workflow enforces lower-wave safety', () => {
const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
assert.ok(
content.includes('Wave safety check'),
'workflow should contain a wave safety check section'
);
assert.ok(
content.includes('finish earlier waves first'),
'workflow should block later-wave execution when lower waves are incomplete'
);
});
test('workflow has partial-wave completion guardrail', () => {
const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
assert.ok(
content.includes('<step name="handle_partial_wave_execution">'),
'workflow should have a partial wave handling step'
);
assert.ok(
content.includes('Do NOT run phase verification'),
'partial wave step should skip phase verification'
);
assert.ok(
content.includes('Do NOT mark the phase complete'),
'partial wave step should skip phase completion'
);
});
});
describe('execute-phase docs: user-facing wave flag', () => {
test('COMMANDS.md documents --wave usage', () => {
const content = fs.readFileSync(COMMANDS_DOC_PATH, 'utf-8');
assert.ok(content.includes('`--wave N`'), 'COMMANDS.md should mention --wave N');
assert.ok(
content.includes('/gsd:execute-phase 1 --wave 2'),
'COMMANDS.md should include a wave-filter example'
);
});
test('help workflow documents --wave behavior', () => {
const content = fs.readFileSync(HELP_PATH, 'utf-8');
assert.ok(
content.includes('Optional `--wave N` flag executes only Wave `N`'),
'help.md should describe wave-specific execution'
);
assert.ok(
content.includes('Usage: `/gsd:execute-phase 5 --wave 2`'),
'help.md should include wave-filter usage'
);
});
test('workflow supports use_worktrees config toggle', () => {
const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8');
assert.ok(
content.includes('USE_WORKTREES'),
'workflow should reference USE_WORKTREES variable'
);
assert.ok(
content.includes('config-get workflow.use_worktrees'),
'workflow should read use_worktrees from config'
);
assert.ok(
content.includes('Sequential mode'),
'workflow should document sequential mode when worktrees disabled'
);
});
});