* fix(#1551): match dash-separated milestone phase IDs in roadmap analyze checklist scan The checklist scanner in cmdRoadmapAnalyze allowed only a dot separator (?:\.\d+)* while the detail-heading scanner allows [.-], so milestone-prefixed IDs (1-01) truncated at the dash (-> 1) and reported phantom missing detail sections on every well-formed milestone roadmap. Widen the char class to (?:[.-]\d+)* to match the detail scanner and the shared phaseMarkdownRegexSource helper. Fixes #1551 Claude-Session: https://claude.ai/code/session_01H96MxPGMJJUiJLV2NgzV16 * chore(changeset): Fixed fragment for #1552 (roadmap milestone-id checklist scan) Claude-Session: https://claude.ai/code/session_01H96MxPGMJJUiJLV2NgzV16 --------- Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
This commit is contained in:
5
.changeset/sunny-deer-roar.md
Normal file
5
.changeset/sunny-deer-roar.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 1552
|
||||
---
|
||||
roadmap analyze no longer reports phantom missing_phase_details for milestone-prefixed (M-NN) phase IDs
|
||||
@@ -426,8 +426,11 @@ function cmdRoadmapAnalyze(cwd: string, raw: boolean): void {
|
||||
const totalSummaries = phases.reduce((sum, p) => sum + p.summary_count, 0);
|
||||
const completedPhases = phases.filter(p => p.disk_status === 'complete').length;
|
||||
|
||||
// Detect phases in summary list without detail sections (malformed ROADMAP)
|
||||
const checklistPattern = /-\s*\[[ x]\]\s*\*\*Phase\s+(\d+[A-Z]?(?:\.\d+)*)/gi;
|
||||
// Detect phases in summary list without detail sections (malformed ROADMAP).
|
||||
// The char class must allow `-` (not just `.`) so dash-separated milestone-prefixed
|
||||
// IDs (e.g. `1-01`) match the detail-heading scanner above; otherwise they truncate
|
||||
// at the dash (`1-01` -> `1`) and every such phase reports a phantom missing detail.
|
||||
const checklistPattern = /-\s*\[[ x]\]\s*\*\*Phase\s+(\d+[A-Z]?(?:[.-]\d+)*)/gi;
|
||||
const checklistPhases = new Set<string>();
|
||||
let checklistMatch: RegExpExecArray | null;
|
||||
while ((checklistMatch = checklistPattern.exec(content)) !== null) {
|
||||
|
||||
@@ -541,6 +541,40 @@ describe('roadmap analyze missing phase details', () => {
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.missing_phase_details, null, 'missing_phase_details should be null');
|
||||
});
|
||||
|
||||
test('does not report phantom missing details for milestone-prefixed (M-NN) phase IDs', () => {
|
||||
// The checklist scanner truncated dash-separated IDs at the dash (1-01 -> 1)
|
||||
// while the detail-heading scanner kept the full ID, so every milestone-prefixed
|
||||
// ROADMAP spuriously reported the truncated major as a missing detail section.
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
||||
`# Roadmap
|
||||
|
||||
- [ ] **Phase 1-01: Foundation** - Set up project
|
||||
- [ ] **Phase 1-02: API** - Build REST API
|
||||
- [ ] **Phase 2-01: Ship** - Release
|
||||
|
||||
### Phase 1-01: Foundation
|
||||
**Goal:** Set up project
|
||||
|
||||
### Phase 1-02: API
|
||||
**Goal:** Build REST API
|
||||
|
||||
### Phase 2-01: Ship
|
||||
**Goal:** Release
|
||||
`
|
||||
);
|
||||
|
||||
const result = runGsdTools('roadmap analyze', tmpDir);
|
||||
assert.ok(result.success, `Command failed: ${result.error}`);
|
||||
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(
|
||||
output.missing_phase_details,
|
||||
null,
|
||||
'milestone-prefixed phases with matching detail sections should report no missing details'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user