Skip to content

Commit 880d6be

Browse files
committed
docs: the README states three tiers, both languages state the same targets, and a check enforces it
The two top-level READMEs were outside every documentation check but the emoji rule, and had drifted from the implementation in three ways. The target table now carries the three tiers the engine actually stores -- `verified`, `preview`, `planned` -- and every canonical spelling in `modules/toolchain-model/src/triple.cppm`. The distinction is load-bearing: a build for a `planned` row is refused, while a `preview` row builds and links, and three rows the README called `planned` were `preview`. Three rows were absent altogether. The 简体中文 table was seven rows behind -- every bare-metal row, plus the footnote that says a freestanding target takes its C library, startup code and emulator from a board-support package -- so that README described a tool with no freestanding support at all. The Feature Overview gains the surfaces shipped since 2026.8 and previously unmentioned in either language: cross-compilation, bare metal and devices; heterogeneous builds and accelerators; and the extension model of `build.mcpp` and rule packages. `--release`, `--profile`, `--features`, `mcpp emit sbom` and the machine-readable output join the command list, and `mcpp why` regains its fourth topic. The Documentation section names the parts of the manual and points at the index that owns the reverse lookup, rather than naming seven chapters out of thirty-one. The benchmark keeps its table, its provenance and its control row, and loses half its lines. Two counts that rot with the tree -- "43+ C++23 modules" against 119 interface units -- are replaced by prose; the one count that is a measurement stays where it is measured. Rules 9 and 10 of `check_docs_structure.sh` now cover the README pair: the row counts are 61 and 61, and a row dropped from either side fails the check. Rule 14 is new -- a link labelled with a chapter number must point at that chapter. It was written for `[docs/13 -- ...](docs/40-baremetal.md)` in README.md and found six more of the same, left in `docs/` and `docs/specs/` by the renumbering in #590; all seven are corrected here. `triple.cppm`'s own tier legend named two of the three tiers it stores. The README now cites that file, so it is corrected in the same change.
1 parent 85ea09b commit 880d6be

10 files changed

Lines changed: 250 additions & 121 deletions

File tree

.github/tools/check_docs_structure.sh

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# 11. every chapter states its reader, its question and its exclusions
1818
# 12. a citation naming a section lands in the chapter that contains it
1919
# 13. every table the manifest reference documents is in the lookup index
20+
# 14. a link labelled with a chapter number points at that chapter
2021
#
2122
# What it deliberately does NOT check: whether a chapter documents what is
2223
# implemented, whether an assertion's strength matches its evidence, or whether
@@ -144,13 +145,17 @@ for f in .agents/docs/[0-9]*.md; do
144145
|| bad "$f: front matter declares no valid \`status\` (active | landed | superseded | abandoned)"
145146
done
146147

147-
# ── 9. every relative link in docs/ and examples/ resolves, fragment included
148+
# ── 9. every relative link in docs/, examples/ and the READMEs resolves ─────
148149
#
149150
# Rule 3 catches `docs/NN-*.md` named anywhere, including from source comments.
150151
# This is the other half: a Markdown link in a document that points at a file
151152
# which is not there. Both halves are needed -- a chapter moved in this batch
152153
# would satisfy one and break the other.
153154
#
155+
# THE TWO TOP-LEVEL READMEs ARE IN THE SET. They are the entry point to every
156+
# tree below them and they carry more relative links than most chapters, and
157+
# until they were added here nothing checked one of those links at all.
158+
#
154159
# THE FRAGMENT IS PART OF THE LINK. The first version of this rule discarded
155160
# it (`(?:#[^)]*)?`), so a link to a section that had been renamed resolved to
156161
# the file and was reported correct. Renaming 100 headings for register in one
@@ -195,7 +200,9 @@ def anchors_of(path):
195200
out.add(s if n == 0 else f"{s}-{n}")
196201
return out
197202
198-
files = list(pathlib.Path("docs").rglob("*.md")) + list(pathlib.Path("examples").rglob("*.md"))
203+
files = (list(pathlib.Path("docs").rglob("*.md"))
204+
+ list(pathlib.Path("examples").rglob("*.md"))
205+
+ [pathlib.Path("README.md"), pathlib.Path("README.zh-CN.md")])
199206
cache = {}
200207
bad = 0
201208
for f in files:
@@ -227,11 +234,19 @@ PYCHECK
227234
# 简体中文 `[features]` section had no body at all, and 简体中文 §2.11 was
228235
# missing the `identity` verdict table. Both predate this check and both are
229236
# invisible to every other one.
237+
#
238+
# THE PAIR AT THE ROOT IS CHECKED TOO, AND IT IS WHERE THE COST WAS HIGHEST.
239+
# `README.zh-CN.md` carried 14 target rows against the English 21: the seven it
240+
# lacked were every bare-metal row, so a reader of the 简体中文 README saw a
241+
# tool with no freestanding support at all. Heading count, code-block count and
242+
# `<details>` count were all equal, which is why every other check was green.
230243
python3 - <<'PYPARITY' || fail=1
231244
import pathlib, sys, re
232245
bad = 0
233-
for en in sorted(pathlib.Path("docs").glob("*.md")):
234-
zh = pathlib.Path("docs/zh") / en.name
246+
pairs = [(en, pathlib.Path("docs/zh") / en.name)
247+
for en in sorted(pathlib.Path("docs").glob("*.md"))]
248+
pairs.append((pathlib.Path("README.md"), pathlib.Path("README.zh-CN.md")))
249+
for en, zh in pairs:
235250
if not zh.exists():
236251
continue
237252
def count(f):
@@ -330,6 +345,36 @@ for k in missing:
330345
sys.exit(1 if missing else 0)
331346
PYLOOKUP
332347

348+
# ── 14. a link labelled with a chapter number points at that chapter ─────────
349+
#
350+
# Rule 3 checks that a named path exists and rule 9 that a link resolves. Both
351+
# passed on `[docs/13 -- Bare-Metal and Freestanding Targets](docs/40-baremetal.md)`
352+
# in README.md: the renumbering rewrote the path and left the label, so the
353+
# README told its reader to read chapter 13 for eleven of the twenty-one rows
354+
# in its own target table. A label that names a number is an assertion about
355+
# where the reader is being sent, and it is checkable against the path.
356+
python3 - <<'PYLABEL' || fail=1
357+
import re, pathlib, sys
358+
LINK = re.compile(r"\[([^\]]+)\]\((?!https?:|mailto:)([^)\s#]+)(?:#[^)\s]+)?\)")
359+
NUM = re.compile(r"(?:docs/|^|[^0-9a-zA-Z])(\d{2})(?:\s*(?:--|—|-|\s)|$)")
360+
files = (list(pathlib.Path("docs").rglob("*.md"))
361+
+ [pathlib.Path("README.md"), pathlib.Path("README.zh-CN.md")])
362+
bad = 0
363+
for f in files:
364+
for m in LINK.finditer(f.read_text(errors="ignore")):
365+
label, path = m.group(1), m.group(2)
366+
base = pathlib.Path(path).name
367+
target_no = re.match(r"(\d{2})-", base)
368+
label_no = NUM.match(label.strip())
369+
if not target_no or not label_no:
370+
continue
371+
if target_no.group(1) != label_no.group(1):
372+
print(f"FAIL: {f}: label `{label}` names chapter "
373+
f"{label_no.group(1)}, the link goes to {base}")
374+
bad += 1
375+
sys.exit(1 if bad else 0)
376+
PYLABEL
377+
333378
if [[ "$fail" -eq 0 ]]; then
334379
echo "OK: docs structure checks pass"
335380
fi

0 commit comments

Comments
 (0)