Docs Quality Checks

This page describes the documentation-quality CI checks the project enforces. The framework is pre-implementation; the checks below are a proposed contract that will be enforced in CI before v0 ships.

Warning

Pre-implementation. This page describes proposed contracts. Class signatures, parameter types, config field names, and behavior are subject to change before code lands. Once implementation exists, content here will be regenerated from docstrings or sourced from running tests.

Audience

Two audiences:

  • Contributors writing or editing docs: use this page to understand what the CI will reject before you push.

  • Maintainers reviewing PRs that touch the docs/ tree: use this page as the authoritative checklist when evaluating a diff.

Why

As the docs grow, drift between concept pages and reference, broken anchors, stale terminology, and out-of-date examples accumulate silently. Each of those failures is invisible until a reader hits a dead link or a wrong term. CI catches them before merge, keeps the pre-implementation blueprint coherent, and reduces review burden.

Required checks

Each row is one gate. All gates are blocking; a PR touching docs/** must pass every check before merge. The Status column distinguishes checks that are wired into CI today from those that are still proposed.

Check

Status

What it does

Fails if

Fix

bash scripts/docs_build.sh (wraps sphinx-build -W)

live

Build the docs as HTML; treat warnings as errors. Intersphinx-fetch failures are tolerated as environmental.

Any other Sphinx warning (broken reference, unresolved cross-link, malformed directive, duplicate label, unused toctree entry, etc.).

Resolve the warning per Sphinx output.

python3 scripts/docs_lint.py

live

Style lint: em-dashes (banned per STYLE.md), LLM-voice phrasings (“it’s worth noting”, “importantly,”, etc.).

A new em-dash or banned phrase is introduced.

Replace per STYLE.md (commas, semicolons, rewrite).

sphinx-build -b linkcheck docs docs/_build/linkcheck

proposed

Verify every external URL and every internal cross-link resolves.

A URL returns 4xx/5xx, or an internal link points to a missing anchor.

Update or remove the broken link.

MyST/markdown lint

proposed

Lint heading levels, table alignment, code-fence languages, duplicate anchors.

Lint rule failure.

Run the lint locally with --fix or hand-edit.

Stale-link guard

proposed

Hard-coded denylist of deleted pages (e.g. plugin-interfaces.md, _target_: ReceiverFrontend).

A doc references a denylisted name.

Update the link to its replacement (use the maturity matrix to find the canonical replacement).

Terminology check

proposed

Canonical capitalization for: rfgen, Sionna, TorchSig, WebDataset, Zarr, Phase 1, Phase 2, BaseChannel, ChannelPipeline, RecordAxis.

A doc uses a non-canonical form (e.g. “Pytorch”, “torchsig”, “BaseChannel(BaseChannel)”).

Use the canonical name from STYLE.md / glossary.md.

Pre-impl admonition coverage

proposed

Every page documenting API surface (concept pages naming specific classes, all reference/api/*.md) carries the canonical pre-impl admonition.

A new API-surface page is added without the admonition.

Add the admonition per STYLE.md’s canonical wording.

Enum-vs-string lint

proposed

Python code blocks must use enum members for framework-owned closed choices. YAML keeps strings.

A Python code block uses direction="uplink" instead of Direction.UPLINK, or similar.

Replace with the enum member; check reference/api/enums.md for the right enum.

Heading consistency

proposed

Cross-link section heading is ## See Also (not “Where to look next” or any variant).

A new page introduces a non-canonical heading.

Rename to ## See Also.

Code-span linking

proposed

Code spans referencing a class, method, or config field documented in the API reference must link to the anchor. (scripts/check_code_links.py exists and reports violations; not yet wired into CI.)

A bare code span like `Signal` appears in prose without a link.

Replace with [`Signal`](anchor). Sample 3-5 cases per page rather than enumerating every instance.

Maturity-label consistency

proposed

Every reference page that documents a class, config field, signal family, preset, or backend has a maturity label drawn from STYLE.md (planned, proposed-contract, implemented, verified, runtime-isolated, reference-only, deprecated).

A new entry lacks a label or uses a non-vocab label.

Add the appropriate label.

Future checks (post-implementation)

These gates come online after the framework’s code lands. They are not blocking today.

  • Config-example parser: parse YAML config snippets in docs against the Pydantic models in rfgen.config. Fails if a snippet uses an unknown field or a wrong type.

  • Doctest of code blocks: run Python code blocks that are marked :::{eval-block} against the live framework. Fails on exception.

  • Signal-catalog parity: every class_name in scenario presets must exist in the signal catalog.

  • Schema-version compat: every doc-cited schema version must be in the compat table.

  • Determinism contract: golden-fixture round-trip between TorchSig HDF5 and rfgen Zarr stays bit-identical.

Local development workflow

Install the docs extras into a dedicated virtualenv, then run the same commands CI runs.

python3 -m venv .venv-docs
.venv-docs/bin/pip install -r docs/requirements.txt

Build and lint:

# Build with warnings-as-errors (intersphinx fetch flakes tolerated).
bash scripts/docs_build.sh

# Style lint: em-dashes, LLM-voice phrasings.
python3 scripts/docs_lint.py

Future linkcheck and markdown-lint commands will be added here as those gates come online.

CI integration

Docs CI runs on every PR that touches docs/**. The live checks are blocking; merge requires green CI. The pipeline is .github/workflows/docs-check.yml. The deploy workflow .github/workflows/docs.yml builds the published site on pushes to main.

See Also