fix(3815): phase.insert handles checked-bullet ROADMAP format (#79)
* fix(3815): phase.insert parser handles checked-bullet ROADMAP format
phaseInsert (TS) and cmdPhaseInsert (CJS) previously used a heading-only
regex (#{2,4}\s*Phase\s+N:) to locate the target phase. On projects whose
ROADMAP uses the checked-bullet format (- [ ] **Phase N: name** or
- [ ] Phase N: name), the lookup always failed with "Phase N not found".
Extend the locator to also accept the bullet form — mirroring the patterns
already used by phaseRemove and phaseComplete. When bullet-style is
detected, insert a new bullet entry after the matched line (preserving
bold/plain style to match surrounding entries). The heading-style code
path is unchanged.
Also fix a pre-existing test timeout: the first registry-integration test in
phase-lifecycle.test.ts was failing with STACK_TRACE_ERROR (masked timeout)
because the cold import of index.js takes >5 s. Added { timeout: 30_000 }.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(3815): refine hybrid-ROADMAP detection, preserve #3098 parity
Tighten the bullet-style branch guard: only treat a ROADMAP as
bullet-style (and apply the bullet-insert path) when it contains
ZERO heading-style phase entries (anyHeadingPattern test). A
mixed (hybrid) ROADMAP — headings for some phases, bullet summaries
for others — is the #3098 case where the detail section is absent;
that path must still error with "missing a detail section".
Adds a regression test (#3098 preserved) in both TS and CJS to
confirm that a heading-style ROADMAP with a bullet-only entry for
the target phase still fires the "missing a detail section" error,
not the bullet-insert path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: add changeset for #3815 phase.insert bullet-roadmap fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1357,13 +1357,20 @@ describe('phase insert command', () => {
|
||||
});
|
||||
|
||||
test('reports actionable error for summary-only placeholder phase without detail section (#3098)', () => {
|
||||
// #3098: a hybrid ROADMAP that has heading-style phases for some phases
|
||||
// but only a bullet summary entry for phase 5 (the detail section is
|
||||
// missing). Insert must fail with "missing a detail section" rather than
|
||||
// silently inserting in bullet-style — because the surrounding ROADMAP
|
||||
// uses headings, so the absent `### Phase 5:` is a genuine omission.
|
||||
// (Compare with the #3815 case below: a purely bullet-style ROADMAP that
|
||||
// has NO heading-style phases at all is valid and insert should succeed.)
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
||||
`# Roadmap\n\n- [ ] **Phase 5: Placeholder**\n`
|
||||
`# Roadmap\n\n### Phase 4: Foundation\n**Goal:** Setup\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.success, 'should fail when phase is summary-only placeholder in a heading-style ROADMAP');
|
||||
assert.ok(result.error.includes('missing a detail section'));
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user