Merge pull request #3125 from gsd-build/fix/3098-phase-insert-and-init-phase-op-disagree-

fix: make phase insert placeholder/dry-run preconditions explicit
This commit is contained in:
Tom Boucher
2026-05-04 23:54:44 -04:00
committed by GitHub
4 changed files with 34 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3125
---
Fixes for issue #3098 were applied to keep command/workflow behavior and SDK parity aligned with current documented usage.

View File

@@ -33,6 +33,9 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
}
phase.cmdPhaseAddBatch(cwd, descriptions, raw);
} else if (subcommand === 'insert') {
if (args.includes('--dry-run')) {
error('phase insert does not support --dry-run');
}
phase.cmdPhaseInsert(cwd, args[2], args.slice(3).join(' '), raw);
} else if (subcommand === 'remove') {
const forceFlag = args.includes('--force');

View File

@@ -571,6 +571,10 @@ function cmdPhaseInsert(cwd, afterPhase, description, raw) {
const afterPhaseEscaped = unpadded.replace(/\./g, '\\.');
const targetPattern = new RegExp(`#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:`, 'i');
if (!targetPattern.test(content)) {
const checklistPattern = new RegExp(`-\\s*\\[[ x]\\]\\s*\\*\\*Phase\\s+0*${afterPhaseEscaped}:`, 'i');
if (checklistPattern.test(content)) {
error(`Phase ${afterPhase} exists in roadmap summary but is missing a detail section (### Phase ${afterPhase}: ...).`);
}
error(`Phase ${afterPhase} not found in ROADMAP.md`);
}

View File

@@ -1252,6 +1252,28 @@ describe('phase insert command', () => {
assert.ok(roadmap.includes('**Requirements**: TBD'), 'inserted phase entry should include Requirements TBD');
});
test('reports actionable error for summary-only placeholder phase without detail section (#3098)', () => {
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n- [ ] **Phase 5: Placeholder**\n`
);
const result = runGsdTools('phase insert 5 Hotfix', tmpDir);
assert.ok(!result.success, 'should fail when phase is summary-only placeholder');
assert.ok(result.error.includes('missing a detail section'));
});
test('phase insert rejects unsupported --dry-run flag explicitly (#3098)', () => {
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 1: Foundation\n**Goal:** Setup\n`
);
const result = runGsdTools('phase insert 1 Hotfix --dry-run', tmpDir);
assert.ok(!result.success, 'phase insert should reject unsupported --dry-run');
assert.ok(result.error.includes('does not support --dry-run'));
});
test('handles #### heading depth from multi-milestone roadmaps', () => {
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),