Docs quality checks

How the EMMA (Electromagnetic Multi-task Model Assessment) documentation is kept at the design-review and implementation-blueprint bar. The documentation is the contract before src/emma/ lands, so the checks that enforce it are load-bearing, not cosmetic. Two mechanisms carry the bar: a mechanical build and lint that fails on style violations, and a human review held to the rules in PRINCIPLES.md and STYLE.md.

Note

The docs-review skill that automates the eight-dimension review below is to be ported; until it lands, the review runs manually against the same dimensions. The mechanical build and lint already run today.

Build and lint

Two commands must finish clean before a documentation change is ready for review. Run them with the docs virtual environment active (see Contributing for setup).

# Build the Sphinx docs with warnings treated as errors (-W, --keep-going).
PATH="$PWD/.venv/bin:$PATH" bash scripts/docs_build.sh

# Lint every Markdown file under docs/ plus README.md and CLAUDE.md.
python3 scripts/docs_lint.py
  • scripts/docs_build.sh runs sphinx-build -W --keep-going -b html docs docs/_build/html. With -W, any Sphinx warning fails the build: a broken cross-link, an unresolved {ref} anchor, a malformed directive, or a duplicate heading anchor.

  • scripts/docs_lint.py scans every Markdown file for the style rules STYLE.md defines: em-dashes (U+2014), LLM-voice phrasings, and bare code spans that name an API symbol without a {ref} link to its anchor.

Both commands exit non-zero on any finding. A change that passes one but not the other is not ready.

The rules enforced

PRINCIPLES.md holds the engineering and documentation posture: calibrated humility, domain over generic vocabulary, encode-don’t-describe, propagate-then-close, and the done-checklist. STYLE.md holds the writing conventions. The checks above enforce the mechanical subset; the human review enforces the rest.

Area

Rule

Enforced by

Em-dashes

No U+2014; use a comma, semicolon, colon, or rewrite

lint

LLM voice

No “it’s worth noting”, “importantly”, “this allows us to”, “as we can see”, “deep dive”, “leverage”

lint

Acronyms

Define every acronym on first use, on every page

review (build catches unresolved anchors, not acronyms)

Code-span linking

Every code span naming an API symbol links to its anchor via {ref}

lint (heuristic) and scripts/check_code_links.py (full, once API pages land)

Anchor resolution

Every {ref} target resolves to a heading anchor and an entry in _code_links.json

build (-W)

Maturity labels

Only the closed vocabulary in STYLE.md: planned, proposed-contract, implemented, verified, deprecated

review

Version badges

Render via the badge / badge-live classes from docs/_static/custom.css

review

References

Every load-bearing claim cites a source in Literature; unverifiable citations carry (verify)

review

The eight-dimension review

The docs-review skill (to be ported) runs an eight-dimension review against a documentation change. The dimensions are the surfaces the rules above map to, checked together so a change that passes the mechanical lint but fails a human-readable contract is still caught. The exact dimension list is pinned when the skill lands; the coverage is:

  1. Style and voice. Em-dashes, LLM-voice phrasings, acronym-on-first-use, sentence and paragraph length.

  2. Code-span linking. Every API symbol in prose carries a {ref} link to its canonical anchor.

  3. Anchor and link-map consistency. Every {ref} target and _code_links.json entry resolves; no dangling anchors after a rename.

  4. Citation integrity. Every ## References entry resolves to Literature; (verify) flags are honored.

  5. Maturity and version consistency. The version badge and maturity label on a page match the maturity matrix and the source page.

  6. Recipe completeness. Every dataset recipe pins the required fields (rfgen commit, emitters, array, channel environments, label extraction, SNR regime, sample counts, splits, seeds, domain), or flags an open dependency.

  7. Table and reference conventions. Column headers carry canonical field names; one row is one entity; enum cells show the member.

  8. Build and lint clean. docs_build.sh and docs_lint.py both exit zero.

A change is not ready until all eight dimensions pass. The first four and the last are mechanical; dimensions five through seven are judgment calls a reviewer makes against the source pages.

The PR contract

A documentation pull request is ready for review when:

  • bash scripts/docs_build.sh and python3 scripts/docs_lint.py both succeed on a clean checkout.

  • Every new claim is testable today or marked proposed-contract, open question, or (verify).

  • Every rename is swept across docs, schemas, recipes, examples, anchors, and _code_links.json in the same change (the propagate-then-close principle).

  • Every new code span naming an API symbol links to its anchor.

  • The maturity matrix and any source pages touched by the change agree.

Reviewers check the PR against the eight dimensions. A change that defers a substantive item names the deferral explicitly in the PR body so it is not silent, per the done-checklist in PRINCIPLES.md.

See Also

  • PRINCIPLES.md: the engineering and documentation posture the checks enforce.

  • STYLE.md: the writing conventions the build and lint check.

  • Contributing: the dev setup and contribution flow.

  • Maturity matrix: the per-feature status a consistency check reads.

  • Literature: the master reading list the citation-integrity check resolves against.