fix(#1838): exclude backlog 999.x milestone phases (#1843)

* fix(#1838): exclude backlog 999.x milestone phases

* chore(#1838): add changeset fragment
This commit is contained in:
Tom Boucher
2026-06-30 21:29:35 -04:00
committed by GitHub
parent 88a7500e91
commit be54c0dbf5
3 changed files with 48 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 1843
---
**`init milestone-op` now ignores backlog `999.x` headings when counting milestone phases** — parked backlog items no longer inflate `phase_count` or pin `all_phases_complete` false for an otherwise finished milestone. (#1843)

View File

@@ -1189,6 +1189,7 @@ function cmdInitMilestoneOp(cwd: string, raw: boolean): void {
const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
let m: RegExpExecArray | null;
while ((m = phasePattern.exec(currentSection)) !== null) {
if (/^999(?:\.|$)/.test(m[1])) continue;
roadmapPhaseNumbers.push(m[1]);
}
} catch {

View File

@@ -976,6 +976,7 @@ describe('cmdInitMilestoneOp', () => {
path.join(tmpDir, '.planning', 'config.json'),
JSON.stringify({ project_code: 'PROJ' }, null, 2)
);
fs.writeFileSync(
path.join(tmpDir, '.planning', 'STATE.md'),
[
@@ -1008,6 +1009,47 @@ describe('cmdInitMilestoneOp', () => {
assert.strictEqual(output.all_phases_complete, true);
});
test('backlog 999.x headings do not inflate milestone phase counts (#1838)', () => {
const phase1 = path.join(tmpDir, '.planning', 'phases', '01-setup');
fs.mkdirSync(phase1, { recursive: true });
fs.writeFileSync(path.join(phase1, '01-01-PLAN.md'), '# Plan');
fs.writeFileSync(path.join(phase1, '01-01-SUMMARY.md'), '# Summary');
fs.writeFileSync(
path.join(tmpDir, '.planning', 'STATE.md'),
[
'---',
'gsd_state_version: 1.0',
'milestone: v1.0.0',
'milestone_name: Test Milestone',
'status: completed',
'---',
'',
].join('\n')
);
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
[
'# Roadmap',
'',
'## 🚧 v1.0.0 Test Milestone',
'### Phase 1: Setup',
'',
'## Backlog',
'### Phase 999.1: Deferred Idea',
'### Phase 999.2: Another Deferred Idea',
'',
].join('\n')
);
const result = runGsdTools('init milestone-op', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_count, 1);
assert.strictEqual(output.completed_phases, 1);
assert.strictEqual(output.all_phases_complete, true);
});
test('archive directory scanning', () => {
fs.mkdirSync(path.join(tmpDir, '.planning', 'archive', 'v1.0'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, '.planning', 'archive', 'v0.9'), { recursive: true });