Skip to main content

Documentation-Sync Gates (tiered)

In one line: Documentation-sync is enforced the way code is — as fitness functions, tiered by what a machine can judge: objective checks block (fail-closed), judgment checks advise (fail-open).

Living documentation (§11) is a discipline, not a stage; v3.2 gives it teeth without the blanket-age-gate friction the earlier advisory hook deliberately avoided.

TierCheckMechanism
Blocking (fail-closed)Link integritythe rendered build (onBrokenLinks: throw) + a repo-level markdown link pass
Blocking (fail-closed)ADR-register integrityevery ADR file has a register row (check-adr-register.sh)
Blocking (fail-closed)Scoped code↔doc drifta code path in the doc-pointers manifest (§11.4) changes without its mapped doc → block; clear with [skip-docs: <reason>], logged for the §2.8 census
Blocking (fail-closed)Generated-artifact freshnessa committed generated tree (e.g. a Docusaurus site built from canon *.md) must equal a fresh run of its generator — check-generated-fresh.sh seeds a throwaway dir from the committed tree, regenerates into it, and diffs; any difference blocks. Closes the "generated copy lags source" class (edit source, forget to regenerate)
Advisory (fail-open)Blanket 30-day stalenesscheck-doc-staleness.sh warns; a blanket age-gate that blocks commits surprises contributors, so it advises (never shipped armed)
Advisory (fail-open)Prose quality, Diátaxis classificationhuman judgment; tooling (vale, etc.) is Recommended, not Core

The split is scope, not predicate: a scoped, code-change-triggered check blocks; a blanket, calendar-age check advises. Core blocking checks use plain scripts plus the existing build — zero new Core dependencies. The scoped code↔doc gate ships behind DOC_SYNC_BLOCKING until a dry-run over recent PRs shows a sub-10% false-positive rate (the §7 gate-admission cost/mechanism/retirement rule).

The generated-artifact freshness gate, by contrast, blocks immediately with no warm-up flagregenerate-and-diff is deterministic and ungameable (it runs the real generator, not a hand-maintained source→output map), so its false-positive rate is structurally near-zero whenever the generator itself is deterministic (no timestamps, no randomness). The one precondition is that determinism; a generator that stamps the current date will diff against itself and must be made reproducible before the gate is armed. The check is generic — point --generator at any script that takes its output dir as $1 and --out at the committed tree — so the same gate pins a Docusaurus site, generated protobufs, or an OpenAPI client.

Why: enforcing every documentation concern as advisory is the weak form — subjectively-evaluated concerns end up sparsely evaluated. Tiering keeps the objective concerns honest (they block) while refusing to arm the one gate — blanket age — that trains bypass behavior.