fix(3559): skip W006 for unchecked future phases

This commit is contained in:
Tom Boucher
2026-05-15 12:53:43 -04:00
parent 1a4e6df6b3
commit 1ba9e55998
2 changed files with 32 additions and 0 deletions

View File

@@ -643,6 +643,30 @@ describe('validateHealth', () => {
expect(w006s.some(w => String(w.message).includes('Phase 7'))).toBe(false);
});
it('does not emit W006 for unchecked future phases with no directory (#3559)', async () => {
await createHealthyPlanning();
await writeFile(join(tmpDir, '.planning', 'ROADMAP.md'), [
'# Roadmap',
'',
'## v1.1: Current',
'',
'- [x] **Phase 21: Active**',
'- [ ] **Phase 22: Future planned**',
'',
'### Phase 21: Active',
'',
'### Phase 22: Future planned',
'',
].join('\n'));
await mkdir(join(tmpDir, '.planning', 'phases', '21-active'), { recursive: true });
const result = await validateHealth([], tmpDir);
const data = result.data as Record<string, unknown>;
const warnings = data.warnings as Array<Record<string, unknown>>;
const w006s = warnings.filter(w => w.code === 'W006');
expect(w006s.some(w => String(w.message).includes('Phase 22'))).toBe(false);
});
it('does not emit I001 when plan file has descriptor but summary uses canonical stem (#3473)', async () => {
await createHealthyPlanning();
await mkdir(join(tmpDir, '.planning', 'phases', '68-bug-surface'), { recursive: true });

View File

@@ -598,6 +598,13 @@ export const validateHealth: QueryHandler = async (args, projectDir, workstream)
while ((m = phasePattern.exec(roadmapContent)) !== null) {
roadmapPhases.add(m[1]);
}
const notStartedPhases = new Set<string>();
const uncheckedPattern = /-\s*\[\s\]\s*\*{0,2}Phase\s+(\d+[A-Z]?(?:\.\d+)*)[:\s*]/gi;
let um: RegExpExecArray | null;
while ((um = uncheckedPattern.exec(roadmapContent)) !== null) {
notStartedPhases.add(um[1]);
notStartedPhases.add(String(parseInt(um[1], 10)).padStart(2, '0'));
}
const diskPhases = new Set<string>();
try {
@@ -627,6 +634,7 @@ export const validateHealth: QueryHandler = async (args, projectDir, workstream)
for (const p of roadmapPhases) {
const padded = String(parseInt(p, 10)).padStart(2, '0');
if (!diskPhases.has(p) && !diskPhases.has(padded)) {
if (notStartedPhases.has(p) || notStartedPhases.has(padded)) continue;
addIssue('warning', 'W006', `Phase ${p} in ROADMAP.md but no directory on disk`, 'Create phase directory or remove from roadmap');
}
}