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 ## 2 is 2.12; the frozen **1.6.2** stays written as it is and cites as 2.1.6.2. The **1 Title** form stays allowed.
  • check applies every rule to the full numbers, so each heading's sibling group is checked on its own, and renumber rewrites 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.md updated
  • roadmap ticked and stamped; changelog entry
  • issue closed with a link to the release