012 — Numbered section headings in ROADMAP.md (#36)
Status: shipped (v0.7.0)
Why
tp roadmap (story 009) reads numbered items wherever they sit and
treats the whole ROADMAP.md as one tree; section headings are out of
scope. On gobank that passes only because Phase 2 is the only phase with
numbered items (75, all under 1 to 12). A Phase 2 item cannot be
cited as 2.12, because that parses as a child of item 2; the first
numbered item of Phase 3 (**1 …**) duplicates Phase 2's item 1 and
fails tp check, which tp release runs; and prefixing the existing
items by hand (2.1, 2.1.6.2) is blocked by the frozen rule, rightly,
since 1.1 to 1.8.8 are stamped and cited 43 times in gobank's
changelog and ADRs (#36).
What changes
- A numbered heading — a markdown heading whose text opens with a
legal number,
## 2 Phase 2 — Mobile apps— is an item. Its number is written in full. It cannot be ticked or stamped; like any parent it is frozen when a descendant is. - Its scope runs to the next heading of the same or a higher level,
numbered or not. Lower-level unnumbered headings inside it
(
### To Do) are transparent, as now; a nested numbered heading (### 2.1 …) opens its own scope. - A list item inside a scope keeps its written number but is relative
to the innermost numbered heading:
**12**under## 2is2.12; the frozen**1.6.2**stays written as it is and cites as2.1.6.2. The**1 Title**form stays allowed. checkapplies every rule to the full numbers, so each heading's sibling group is checked on its own, andrenumberrewrites only the written part of a relative item, carrying a renumbered heading down to its children without touching their text. The reference scan looks for a changed number in full everywhere and in its relative form inside its heading's scope.- Citations: a bare number inside a phase is phase-relative; a
cross-phase citation carries the prefix. Recorded in
docs/roadmap.md. - A file with no numbered heading behaves exactly as today.
Acceptance
| File | tp roadmap check |
|---|---|
## 2 Phase 2, **1 Title**, **1.1** [x] (v0.4.0), **2**, ## 3 Phase 3, **1** |
passes: items are 2, 2.1, 2.1.1, 2.2, 3, 3.1 |
## 2 Phase 2, **1**, **3** |
gap: 2.2 missing; 2.3 should be 2.2 |
## 2 Phase 2, **2.1** |
orphan: 2.2.1 has no parent 2.2 — a list number inside a scope is always relative |
## 2, **1**, ### To Do, **2** |
passes: the unnumbered heading is transparent |
## 2, **1**, ## Telemetry, **3**, ## 4, **1** |
passes: 2.1, then an absolute 3 outside any scope, then 4.1 |
## 2, ### 2.1 Sub, **1** |
passes: 2, 2.1, 2.1.1 |
## 2, ## 4 |
gap: 3 missing; 4 should be 3 |
## 2 [x] (v1.0) Phase 2 |
not a numbered heading: the tick is text |
## v0.1.0 — MVP, ## 2026-10 |
not numbered headings |
| no numbered heading | exactly as story 009 |
tp roadmap renumber on |
Result |
|---|---|
## 2, **1**, **3** |
line rewritten to **2**; change reported as 2.3 → 2.2 |
## 2, **1**, **3**, **3.1** |
**3** → **2**, **3.1** → **2.1** |
## 3, **3**, ## 4, **1** with **1.1** [x] (v1.0) |
## 3 keeps its number (first sibling); ## 4 is frozen; nothing changes |
## 2, **1**, ## 4, **1**, nothing stamped |
## 4 → ## 3; 4.1 → 3.1 reported, its line untouched |
| prose in scope says "see 3", prose outside says "see 2.3" | both listed, neither changed |
Out of scope
- Ticking or stamping a heading.
- Relative numbers in headings: a heading's number is written in full.
- Renaming gobank's items to the full form: the point is that they stay as written.
Decisions
A heading has no frozen state of its own (the issue's second open point):
it is a parent, and parents are frozen by their descendants. Stamping a
heading when every child is stamped would be a second notion of done for
no new behaviour. The **1 Title** form stays (first open point) so
gobank's file changes only at its phase headings.
Done when
- tests express the acceptance tables and pass
-
docs/roadmap.mdupdated - roadmap ticked and stamped; changelog entry
- issue closed with a link to the release