Skip to content

D134 — Documentation site: MkDocs, Diátaxis, decision records, Doxygen

Context

By release 0.10.0 the project had 19 numbered design docs, 131 decisions in one table in docs/12-decisions.md (about 100 KB, D115 onwards appended under the risk register), milestone records in bench/records/ and reports, but no published site, nothing written for a user who wants to install and route a board, no reference that is guaranteed to match the code, no C++ API reference, and nothing that said which docs describe the code as it is and which are plans. A single decision could not be linked to, and a replaced decision could not be marked as such.

Decision

  1. A documentation site built by MkDocs with the Material theme from docs/ (mkdocs.yml), published to GitHub Pages from the gh-pages branch by .github/workflows/docs.yml, versioned with mike: dev from main, X.Y and the latest alias from a tag vX.Y.Z. Pull requests build it with --strict.
  2. Organised by Diátaxis (Procida, Diátaxis, diataxis.fr): tutorials, how-to guides, reference, explanation, plus a project section. The numbered design docs keep their file names and place in docs/, and the navigation sorts them; links to files outside docs/ are pointed at GitHub by scripts/mkdocs_hooks.py.
  3. One Architecture Decision Record per decision (Nygard, "Documenting architecture decisions", 2011) in docs/decisions/DNNN.md with a status (accepted, superseded with superseded_by, proposed, rejected); docs/12-decisions.md keeps the risk register and an index generated by scripts/decisions.py. D1–D131 were converted from the table with their text unchanged and short titles added; D19, D31, D36 and D53 are marked superseded by D121, D52, D58 and D56. D87 is reserved for open PR #21.
  4. A header on every page: status (current, partly-built, plan, historical), code (the paths the page describes) and an optional reviewed date. scripts/docs_check.py fails on a bad header and warns when the code has had more than 25 commits since the page changed or was reviewed. Non-current pages get a banner on the site.
  5. Generated reference pages, committed and checked by CI: the command line from each program's --help (scripts/gen_reference.py cli) and the benchmark results from bench/records/*/summary.json (scripts/gen_reference.py bench).
  6. A C++ API reference by Doxygen (docs/api/Doxyfile), published under api/ of each site version. The headers keep their plain // comments: scripts/doxygen_filter.py reads the block above a declaration (and a trailing member comment) as its documentation. scripts/check_api_docs.py counts undocumented declarations per header against a committed baseline (1385 in 75 headers at the start) and warns in CI when a header's count rises.

Alternatives

  • Sphinx with Breathe/Exhale: the strongest C++ API integration, but reStructuredText or MyST for prose, a heavier build, and most of these docs are prose.
  • Moving the design docs into docs/explanation/: a tidier tree, but it breaks every "doc 05 §34" and docs/05-routing.md reference in code comments, commits, issues, reports and PDFs.
  • Rewriting every header to /// comments: the style the Doxygen manual expects, but it touches all 82 headers, conflicts with branches in flight, and changes the house comment style for no gain in content.
  • Failing CI on undocumented declarations: 1385 exist today; a ratchet that warns on new ones moves the count the right way without blocking work.
  • A hand-entered "verified in version" field: it would claim reviews nobody made; reviewed is set only by someone who checked, and staleness otherwise comes from git.

Consequences

  • Nothing in the engine changes; no routing or placement output can change, so the quick tier was not run.
  • A branch that appends a row to the old decision table must convert it with scripts/decisions.py import before merging (CI's decisions.py check says so).
  • GitHub shows each page's YAML header as a small table at the top of the file.
  • GitHub Pages has to be pointed at the gh-pages branch once, by the owner.
  • The site needs Python packages pinned in docs/requirements.txt; the engine build does not.