* fix(#4478): anchor collectAnalyzePhases's phase-heading regex to line start phasePattern (src/roadmap.cts, backing `gsd-tools roadmap analyze`) had no line anchor -- #{2,4} could match a `### Phase N:`-shaped mention ANYWHERE the global regex scan reached: mid-sentence prose, inside a blockquote, inside an inline code span (backtick-quoted on the same line, not a fenced code block tokenizeHeadings would exclude). Any such line minted a phantom phase entry, inflating phase_count and able to collide on a phase NUMBER with a real heading nearby. Two correctly-anchored reference implementations already exist for the same heading grammar in this codebase: tokenizeHeadings (src/markdown-sectionizer.cts:453) and findRoadmapPhaseInContent (src/roadmap-parser.cts:1385), which anchors against the tokenizer's own output. collectAnalyzePhases was the one path scanning raw content directly instead. Anchored to line start with the same 0-3 leading-space tolerance tokenizeHeadings uses (rather than routing through the tokenizer, which the issue offers as the more thorough fix but which would require re-deriving this function's bracket/number/name capture groups and section-boundary lookup from tokenized output instead of a single combined regex scan -- a materially larger refactor than a bug fix warrants; the issue itself offers anchoring as the sufficient fallback). Added coverage to the existing tests/roadmap.test.cjs "roadmap analyze command" describe block (not a new file -- the roadmap module already had 4 test files and lint-test-file-count.cjs's own remedy is to consolidate, not add a 5th) against the issue's own 5-row prose-lookalike table, its duplicate-number consequence, and a boundary case (a legitimately-indented real heading must still count). Independent code review on this same diff found one more consequence: the "next heading" section-boundary lookup (nextHeader, a few lines below phasePattern) lacked the SAME {0,3} leading-space tolerance -- a legitimately-indented NEXT phase heading was invisible to it, letting the prior phase's own goal/mode/depends_on extraction bleed across the section boundary into the next phase's body. Confirmed via a targeted repro (**Depends on:** -- a field only the second phase has, so the bleed is directly observable) and fixed with the same tolerance, plus its own regression test. CI-adjacent findings caught by gsd-test on a stale sha, fixed inline: (1) my own explanatory comment block was inserted BETWEEN a pre-existing `phase-id-owner:` sanction comment and the regex it sanctions, pushing it out of the "line directly above" position lint-phase-id-drift.cjs requires -- reordered so the sanction stays immediately above the regex; (2) the standalone test file this fix originally added tripped lint-test-file-count.cjs's per-module cap -- consolidated into the existing describe block as described above. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs(#4478): backfill changeset PR number Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
5
.changeset/fierce-pumas-dance.md
Normal file
5
.changeset/fierce-pumas-dance.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4578
|
||||
---
|
||||
**`roadmap analyze` no longer mints a phantom phase from a mid-line mention** — a sentence, blockquote, or inline-code-span reference to a `### Phase N:`-shaped heading anywhere in the ROADMAP was previously counted as a real phase, inflating `phase_count` and able to collide on a phase number with a real heading nearby. The phase-heading extraction is now anchored to line start, matching this repo's other heading parsers.
|
||||
Reference in New Issue
Block a user