009 — Legal numbering for ROADMAP.md (#32)

Status: shipped (v0.6.0)

Why

A project roadmap numbers its items legally (1, 1.6, 1.6.2) so a changelog, an ADR or a commit can cite a story by number. The numbers are kept by hand, and on gobank's roadmap they drifted: a stage inserted before a shipped one took a letter (1.6a), three stages were pushed back by renumbering, ticked items lacked the version stamp that says when they shipped, and every cross-reference in the prose had to be found by eye. Nothing checks any of it. The convention is cross-project, like the changelog format and md2html, so the check belongs in task-plus and in tp check, which tp release runs.

The rule the check enforces is that a legal number is positional, so an insertion either renumbers or takes a letter, and which one depends on whether the number has been cited yet: a frozen item (ticked and stamped, or with a stamped descendant) keeps its number for good, an insertion before a frozen number takes a letter, and unfrozen items are renumbered freely.

What changes

  • tp roadmap check: reads ROADMAP.md, finds every numbered item (a list line starting - **N** or - **N Title**, where N is dot-separated segments, each digits with an optional trailing letter, optionally followed by [x] and a stamp in parentheses) and reports every rule broken, with the line number. Exit 1 on any finding. A roadmap with no numbered item passes. The **N Title** form is how gobank writes its top-level items; without it every 1.x there would be an orphan.
  • tp roadmap renumber [--dry-run]: rewrites the headings of unfrozen items so siblings are consecutive after the last frozen one, carrying each change down to the item's descendants, and prints every other occurrence of a changed number in the file for the author to fix by hand; it never changes a frozen number. --dry-run prints the plan.
  • tp check runs tp roadmap check when ROADMAP.md exists.
  • docs/roadmap.md: the grammar, the rules and the frozen-number convention, linked from README.md.

Acceptance

Items in file order Frozen? tp roadmap check
1.6, 1.7, 1.8 any passes
1.7.1 with no 1.7 — orphan: parent missing
1.9 before 1.8 neither out of order
1.8 twice — duplicate
1.7, 1.9 neither gap: 1.8 missing (renumber makes 1.9 → 1.8)
1.6 then 1.8 1.6 gap: 1.8 → 1.7
- **1.5** [x] Core into packages — ticked without a stamp
- **1.5** [x] (v0.18.0) …, (go-luca v0.4.0), (unreleased) — stamp accepted
1.6a with 1.6a.2 stamped 1.6a passes: a letter on a frozen item
1.6b with nothing stamped under it no letter on an unfrozen item (renumber gives it the next number)
1.6a and 1.6a.2 stamped, then 1.7 1.6a passes: 1.6a sits between 1.6 and 1.7
no numbered item — passes, nothing checked
tp check with ROADMAP.md present — runs the check; a finding fails the check
tp roadmap renumber on Result
1.6 frozen, 1.6a frozen, 1.7, 1.9 with 1.9.1 1.9 → 1.8, 1.9.1 → 1.8.1; 1.6, 1.6a untouched
prose elsewhere in the file says "after 1.9" printed with its line number, not changed
--dry-run plan printed, file unchanged
nothing to do says so, exit 0

Out of scope

  • Ticking, stamping or archiving items: completion is a judgement, left to the person (or the roadmap skill that proposes it).
  • Numbers in CHANGELOG.md or ADRs: they cite roadmap numbers and are why frozen numbers never move.
  • Rewriting cross-references in prose: too easy to hit a version number or an ADR stage; the command lists them instead.
  • Section structure (phases, Now/Next/Later): the check reads numbered items wherever they are.

Decisions

The frozen-number convention is recorded in docs/roadmap.md; no ADR, since no fork was resolved against an alternative worth keeping.

Done when

  • tests express the acceptance tables and pass
  • docs/roadmap.md written and linked
  • roadmap ticked and stamped; changelog entry
  • issue closed with a link to the release (v0.6.0)