🇬🇧 English · 🇩🇪 Deutsch
Consistency checker that verifies a repository's documentation against its actual state — Markdown references (links, images, anchors, identifiers) plus declarations (build targets, version pins, commit trace, planning). Deterministic, side-effect-free, shipped as a container image.
d-check checks Markdown documentation as a verifiable invariant network: every machine-decidable documentation invariant is a rule module that can be enabled individually, with its own requirement in the requirements spec — from the reference network (links, anchors, ID link obligations, reference matrix) through Markdown hygiene (span artifacts, host-path leaks), content drift and immutability (content/core pins, git diff) to version-pin, commit-traceability, planning-lifecycle and tracked-status consistency:
links— local link and image references: target exists, no repo escape (DC-FA-LINK-001)anchors— heading anchors (GitHub slug procedure) and inline HTML anchors (<a name>,id=) (DC-FA-ANCH-001)ids— link obligation for identifiers (e.g.ADR-NNNN) per declared patterns (DC-FA-ID-001)matrix— reference-direction rules between document classes (DC-FA-MTX-001), within an ordered class (order/direction⇒matrix-downward,DC-FA-MTX-002) and also as a bare ID token in the body (token⇒matrix-forbidden,DC-FA-MTX-003) plus status conditions; exceptions are structural (exclude-sections,allow-supersede-lineage) or declared via the provenance marker<!-- d-check:status-provenance -->external— reachability of external URLs, strictly opt-in (DC-FA-EXT-001)sources— content pin of external sources against upstream drift, opt-in and — besidesexternal— the second network door: a source pinned to asha256(via the marker<!-- source-pin: … -->on itshttp(s)link or the config blocksources:) is fetched, hashed and compared (source-driftwith the full actual hash,source-unreachableon a network failure); single file or archive (unpack: zip) (DC-FA-SRC-001)codepaths— explicit paths in inline code, opt-in; the opt-incheck-linesverifiesfile:<from>-<to>line references (citation-out-of-range,citation-inverted-range) (DC-FA-CODE-001)spans— Markdown span artifacts (unclosed code spans, nested links), opt-in (DC-FA-SPAN-001)hostpaths— host-local absolute paths (machine-layout leaks), opt-in (DC-FA-HOST-001)diagrams— identifier existence in diagram fences (e.g.mermaid): every identifier found in the diagram must be defined in itsdefined-insource, opt-in (DC-FA-DIAG-001)versions— version-pin consistency: pinnedghcrimage references must carry the current version (fromversion.md#aktuell), also reads fenced code, opt-in (DC-FA-VER-001)pins— content pin against content drift: a link with<!-- dpin: … -->is checked against the hash of its target span (findinglink-staleon drift), opt-in per link (DC-FA-PIN-001)immutable— immutability pin against core drift: a file with<!-- immutable: … -->is checked against the hash of its normalized core (without the marker line +exclude-sections) (findingcore-drifton drift), opt-in per file; hermetic (no git, read-only working tree) (DC-FA-IMM-001)vcs— git-diff immutability of the core over a commit range: mechanizes the ADR immutability as a distributable module (core-drift-vcs), pure-Go git in the read-only.git(no git binary, no network), opt-in (DC-FA-VCS-001)commits— traceability identifier in commit messages over a range (--range) or the pending message (--commit-msg): every commit message carries aDC-/ADR-/MR-/slice-ID (commit-untraceable), shares the VCS port withvcs, opt-in (DC-FA-COMMITS-001)planning— roadmap-↔-in-progress lifecycle consistency: the idle marker sits in the## Aktuelle Welleblock exactly when noslice-*is in the directory (planning-drift); hermetic (no git), fail-closed on a missing/ambiguous heading, opt-in (DC-FA-PLAN-001)tracked— tracked status of resolvable, existing link/image targets against the git index (target-untracked: an untracked/gitignored target is missing on every fresh clone); index truth (staged = tracked, no.gitignoreinterpretation), reads.gitread-only without a range, opt-in (DC-FA-TRK-001)targets— declaration consistency between docs and build targets: amake Xclaimed in a doc table row without a Makefile rule (gate-phantom), or a Makefile rule without an entry in the authority doc (gate-undocumented); hermetic (no git, no Makefile execution), fail-closed, opt-in (DC-FA-TGT-001)citations— verbatim quote verification: the directive<!-- d-check:cite <path>:<from>-<to> -->marks the following quote (a>-blockquote or inline„…"/"…"); the whitespace-normalized quote must be a contiguous substring of the source span (citation-mismatch), opt-in (DC-FA-CITE-001)
Every finding names file, line, target and reason; exit codes:
0 clean, 1 findings, 2 environment or configuration error.
Twelve functionally overlapping tool copies from three families
(verify-doc-refs.sh — Shell, check_refs.py — Python,
docs-check.js — JavaScript) grew across the sister repositories of the
development workspace — each with its own feature set, its own drift, its
own maintenance. d-check replaces them with one tool:
- Configuration instead of fork: repo-specific behavior lives
declaratively in
.d-check.yml(DC-FA-CONF-001), not in copied scripts. - Replaceability is measurable: every legacy tool must be replaceable by
d-check with matching configuration — at least the same real findings, no
false positives that break a green CI
(
DC-QA-04). - One distribution path: container image with digest pin instead of
n maintained copies
(
DC-FA-DIST-001).
Documentation is a reference graph with verifiable invariants. Whether a link reaches its target, an anchor exists, an identifier links to its definition, or a document class points downward is machine-decidable — d-check turns these invariants into a gate instead of a review opinion.
The principle: report, never repair. d-check is a purely read-only
tool (DC-QA-03);
deterministic findings are fixed, not suppressed. An opt-out
marker exists only where a non-existent target or an illustrative identifier
can be documented intent (d-check:ignore, per line) — it silences
exclusively the modules codepaths and ids
(DC-FA-CODE-001,
DC-FA-ID-001).
A checking tool whose own statements wobble is worthless — determinism and side-effect freedom are therefore core contracts of the spec, and both are measured, not asserted:
- Determinism: identical input ⇒ byte-identical output,
stably sorted; tested over ten repeated runs with
hash comparison
(
DC-QA-02). - Side-effect-free and network-free: never writes into the checked
repository, opens no network connections except in the opt-in modules
externalandsources— measured in the gate run with a read-only mount and--network none(DC-QA-03). - No silent defaults: every invalid
.d-check.ymlaborts with exit 2; checking never proceeds with guessed configuration (DC-FA-CONF-001). - Dogfooding: d-check validates its own docs on every gate run — with the self-configuration fully built out (eight modules incl. reference matrix, span artifacts, host-path hygiene and version-pin consistency).
- Container native-identical: the image's finding output and exit code
are byte-identical to native execution, tested automatically
(
DC-FA-DIST-001); CI consumption via digest pin.
Distributed as a container image via GHCR
(DC-FA-DIST-001):
docker run --rm -v "$PWD:/repo:ro" ghcr.io/pt9912/d-check:v0.51.1CI pipelines pin to the digest from the release notes rather than to
moving tags — details, options and exit codes:
docs/user/operations.md and
docs/user/releasing.md.
Optional in the repo root; without a file the default modules
links + anchors run over docs/, spec/ and the root *.md:
scan:
roots: ["."] # entire repo root
modules: [links, anchors, ids] # external + sources stay strictly opt-in (network)
ids:
patterns:
- regex: 'ADR-\d{4}'
target: docs/adr/ # identifiers must link hereThe full schema with all keys, defaults and
validation constraints is in the
specification §.d-check.yml;
a living example fully built out (incl. reference matrix) is
this repo's self-configuration. Every invalid
configuration aborts with exit 2 — checking never proceeds with
silent defaults
(DC-FA-CONF-001).
| Document | Contents |
|---|---|
docs/user/operations.md |
Invocation reference: options, exit codes, configuration |
docs/user/releasing.md |
Release process, digest-pin consumption |
spec/lastenheft.md |
Requirements (DC-FA-*, DC-QA-*), acceptance criteria |
harness/README.md |
Harness entry: source precedence, guides, sensors |
AGENTS.md |
Briefing for AI coding agents, hard rules |
docs/plan/planning/in-progress/roadmap.md |
Waves and slices |
CHANGELOG.md |
Change history |
The host needs only git, GNU make, bash and Docker
(see AGENTS.md §3.1).
make help # available targets
make gates # all inner gates (mandatory before handoff)This project is licensed under the MIT License.