Skip to content

Doc CI

The portal's static checks (markdown lint, link check, terminology scan, TBD scan) don't live in docs/ — they live in tools/docs/ at the repo root, alongside the GitHub Actions pipeline at .github/workflows/docs-ci.yml. This README is the doc-side forward-pointer.

Convention: tooling sits next to other repo tooling under tools/, not inside docs/. This page exists so the reader who clicks a [Doc CI] link from inside the portal lands somewhere — not so docs duplicates the script docs.


What runs and when

CI workflow: .github/workflows/docs-ci.yml. Triggers on push to main and on every pull_request that touches docs/**, tools/docs/**, or the workflow itself. Four jobs run in parallel; a fifth summary job aggregates the artifacts into the GitHub step summary.

Job Tool Blocking? Catches
mdlint tools/docs/mdlint.sh (markdownlint-cli2 + Python fallback) yes Heading hierarchy, single H1, ATX style, fenced-block spacing
link-check tools/docs/check-links.sh yes Broken relative paths; URL HEADs (skipped in CI by default)
terminology tools/docs/check-terminology.sh warn-only Canonical spellings from ../STYLE.md §6 (OTel, BullMQ, p95, …)
tbd-scan tools/docs/find-tbd.sh XXX-only {{TBD}} (info), TBD/TODO/FIXME (warn), XXX (error)

Each tool — when it fails, what to do

The full per-tool reference is in tools/docs/README.md. Short version:

  • mdlint.sh — read the rule code (e.g. MD025 = single H1) and fix the heading. To genuinely need an exception, wrap the offending lines in a <!-- markdownlint-disable MDxxx --> / <!-- markdownlint-enable MDxxx --> pair with a justifying comment.
  • check-links.sh — the file moved, was never written, or you spelled the path wrong. Search the portal — most often the doc you meant to link is one directory over.
  • check-terminology.sh (warn-only today) — replace the variant with the canonical spelling. Quoting an upstream proper noun? Wrap in inline backticks; the scrubber skips fenced/inline code automatically.
  • find-tbd.shXXX always fails the build. Convert to {{TBD: …}} if the work is deferred; the portal uses one marker on purpose so the count is meaningful.

Per-line escapes for false positives:

Annotation Effect
<!-- skip-link-check --> check-links.sh ignores links on this line
<!-- skip-terminology --> check-terminology.sh ignores this line
<!-- skip-tbd --> find-tbd.sh ignores this line
<!-- markdownlint-disable MDxxx --><!-- markdownlint-enable MDxxx --> markdownlint-cli2 block escape

Local pre-commit hook

Three lines in .git/hooks/pre-commit:

#!/usr/bin/env bash
exec ./tools/docs/run-all.sh docs/

Make it executable:

chmod +x .git/hooks/pre-commit

run-all.sh is the same combined runner the CI summary job uses; passing locally is a strong predictor of passing in CI. Network HEADs are slow — EBIT_DOCS_NET_LINKS=0 ./tools/docs/run-all.sh docs/ matches CI exactly.


Adding a new check

  1. Drop a script under tools/docs/<check-name>.sh. Mirror the conventions in the existing scripts: takes $1 as the docs dir (default docs), exits non-zero on failure, prints one finding per line in path:line: message format.
  2. Add a job to .github/workflows/docs-ci.yml following the existing four-job shape (actions/checkout → run script → upload artifact). For warn-only checks, set continue-on-error: true.
  3. Add a row to the table in tools/docs/README.md §"What each check does" plus the "When a check fails" section.
  4. If the check enforces a STYLE.md rule, add (or update) the canonical row in ../STYLE.md §6.
  5. If the check needs a per-line escape, add <!-- skip-<name> --> handling and document it under §"Skip annotations" in tools/docs/README.md.

Pre-flight before running

The 4 jobs assume:

  • python3 is on $PATH (stdlib only; no pip install).
  • markdownlint-cli2 is available (CI installs markdownlint-cli2@0.13.0 via npm); locally, mdlint.sh falls back to a Python checker if it's missing.
  • The repo is checked out at the path shape the workflow expects — docs/ lives at the repo root. The tools/docs/README.md §"Integration target" section discusses the standalone-repo vs in-product-repo home choice.

Cross-references