ADR-0466: mkdocs strict-mode pre-push hook¶
- Status: Accepted
- Date: 2026-05-15
- Deciders: Lusoris, Claude (Anthropic)
- Tags:
docs,ci,git,hooks,mkdocs
Context¶
Audit slice G established that 38 of 50 master pushes failed the docs.yml CI lane for trivial mkdocs strict-mode breakage: broken in-doc anchors, orphan pages, and missing nav entries. The docs.yml lane (see ADR-0403 for the strict-mode parameterisation) takes approximately 6 minutes per run on GitHub Actions. Every failure required a corrective push and a second CI round-trip, costing 12+ minutes of wall time per affected push.
The root cause is that no local check mirrors mkdocs build --strict before the push reaches CI. Contributors (and agents) discover the failure only after the CI cycle completes. The errors are mechanical — mkdocs emits the exact filename, line, and anchor that caused the failure — so a local 5-second pre-push run catches 100% of them before any network traffic.
Decision¶
Add scripts/git-hooks/pre-push-mkdocs-strict.sh as a dedicated pre-push gate. The script:
- Detects whether the push touches
docs/ormkdocs.yml; exits 0 immediately if not (no latency penalty on non-docs pushes). - Skips silently when
mkdocsis not on PATH (contributors who never touch docs are not required to install the docs toolchain). - Runs
mkdocs build --strict --quietagainst a temporary output directory. - On failure: prints the exact mkdocs error lines and exits 1, blocking the push with a human-readable message.
- Provides a targeted bypass (
SKIP=mkdocs-strict git push) in addition to the standardgit push --no-verifyescape hatch.
Wire-up via two complementary mechanisms:
- Omnibus
scripts/git-hooks/pre-push: delegates to the new script so contributors using only the symlinked hook (installed viamake hooks-install) pick it up automatically with no re-install step. .pre-commit-config.yamllocal hook (id: mkdocs-strict,stages: [pre-push],files: '^(docs/|mkdocs\.yml)'): allowspre-commit run --hook-stage pre-pushto exercise the gate in isolation, consistent with the pattern established byvalidate-pr-body(ADR-0435).
make hooks-install requires no change: the existing symlink from .git/hooks/pre-push → scripts/git-hooks/pre-push already covers the new delegation call.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| A — Standalone pre-push hook + pre-commit wiring (chosen) | 5 s local catch; zero CI round-trips for docs errors; no new dependencies beyond existing mkdocs toolchain | mkdocs must be installed in the active env; skips silently when absent | Best fit — identical pattern to ADR-0435's validate-pr-body hook |
B — make docs-check target only | Zero-friction manual invocation | Requires contributor to remember; does not block a push; agents skip it | Does not eliminate the CI round-trip failure mode |
| C — CI path-filter to skip docs.yml on non-docs pushes | Reduces CI load | Removes the gate entirely for those pushes; errors only caught on docs-touching PRs | Weaker coverage; the gate should fire on every docs touch |
D — Promote mkdocs validation into make lint | Always runs with the lint pass | make lint is slow (clang-tidy + semgrep); adding mkdocs makes it slower for C-only contributors | Disproportionate cost for a docs-only check |
Consequences¶
- Positive: The 38/50 docs.yml failure rate drops to near-zero for contributors who have the docs toolchain installed. Broken anchors, orphan pages, and missing nav entries are caught in under 5 seconds before push.
- Positive: The hook is opt-out (SKIP=mkdocs-strict) rather than opt-in, so it activates for all contributors who run
make hooks-installwithout any additional step. - Negative: Contributors who have not installed
docs/requirements.txtskip the check silently. CI remains the authoritative gate for those contributors. - Neutral:
make hooks-installdoes not need to be re-run by existing contributors — the delegation is in the omnibuspre-pushscript which the existing symlink already resolves. - Neutral: The temporary site directory is cleaned up via
trapon both success and failure paths; no build artefacts are left in the worktree.
References¶
- Audit slice G: "38/50 master pushes failed docs.yml CI for trivial mkdocs strict-mode breakage" (per user direction 2026-05-15).
- ADR-0403:
docs/adr/0403-mkdocs-strict-gate-validation-policy.md— parameterises the--strictcategories this hook mirrors. - ADR-0435:
docs/adr/0435-pr-body-pre-push-validation.md— the validate-pr-body hook this follows as a pattern. - ADR-0108:
docs/adr/0108-deep-dive-deliverables-rule.md. .github/workflows/docs.yml— the CI lane this hook pre-empts locally.scripts/git-hooks/pre-push-mkdocs-strict.sh— implementation.