Files
msd-core/tests/fixtures/adversarial/roadmap
Tom Boucher 325fc25c01 fix(#3569): require a digit-bearing phase id in the stats heading scan (#3591)
* test(#3569): pin stats phase-id shape — inline-code mentions produce no phantom row

Failing-first regression for #3569: cmdStats' heading scan accepted any
word as a phase id, so prose mentioning ### Phase N: inside inline code
inflated phases_total and disagreed with roadmap analyze. New adversarial
fixture phase-heading-inside-inline-code.md (blockquote + bare mention),
parity assertion against roadmap analyze, and over-narrowing guards for
decimal / milestone-prefixed / letter-prefixed ids.

* fix(#3569): require a digit-bearing phase id in the stats heading scan

cmdStats' hand-rolled heading pattern captured any word as a phase id,
so a ### Phase N: token inside an inline code span (the issue's
blockquote) produced a phantom Not-Started row that could never
complete, inflating phases_total and deflating percent forever. The id
capture is now the canonical #3036 shape roadmap.cts uses (digit
required; letter-prefixed, decimal, and milestone-prefixed ids keep
counting), so stats and roadmap analyze agree.

* fix(#3569): sanction the stats id-shape literal; correct zero-padded expectation

Review findings: the phase-id drift guard requires the // phase-id-owner:
comment directly above the regex (same form as roadmap.cts); the
milestone-prefixed over-narrowing guard must expect normalizePhaseName's
zero-padded 02-01 form, not the raw 2-01 token.

* chore(#3569): add changeset fragment

* chore(#3569): backfill changeset pr number

---------

Co-authored-by: sim <sim@local>
2026-08-17 11:39:01 -04:00
..

Adversarial Roadmap Fixtures (#3594)

Hostile / messy ROADMAP.md inputs for gsd-core/bin/lib/roadmap.cjs (searchPhaseInContent, cmdRoadmapGetPhase, cmdRoadmapAnalyze) and the SDK roadmap parser in sdk/src/query/roadmap.ts.

Tests in tests/feat-3594-parser-adversarial-roadmap.test.cjs and tests/feat-3594-parser-property-style.test.cjs consume these.

Categories:

  • phase-heading-inside-fenced-code.md — a md block contains a ## Phase 999: fake heading. The parser MUST ignore headings inside fenced code blocks. Historical regression #2787.
  • nested-fenced-code.md — outer block with inner ``` ``` ``` ``` block. Headings inside either layer must be ignored.
  • unicode-phase-titles.md — phase titles with non-ASCII characters. Parser must preserve them in the returned phase_name.
  • repeated-phase-ids.md — same integer phase number listed twice. Parser behavior must be deterministic (first-wins or last-wins is fine; the test pins whichever).
  • decimal-phase-mixed.md — integer phase 2 and decimal phase 2.1 share a prefix. Parser must not return phase 2 when asked for 2.1 (or vice versa). Historical regression #3537.
  • markdown-headings-inside-html-comment.md — <!-- ## Phase 999 --> patterns. Parser must not be fooled by comments.