Documentation
¶
Overview ¶
Command doccheck verifies that every documentation reference in the repository resolves to a file that exists.
It checks three surfaces that nothing off-the-shelf covers together:
Relative links in Markdown — `[text](../spec/foo.md)`, including links that point at source files. External URLs and pure `#anchor` links are skipped.
Repo-relative Markdown paths cited inside **Go comments** — the `docs/spec/manifest-system.md`-style references the packages use to point at their contract, and the ones that live next to the code they describe, like `internal/git/manifestedit/DECISION.md`. These are the ones that rot silently: a doc gets moved, the comment keeps pointing at the old path, and nothing notices. Seventeen of them were dangling before this check existed.
The same repo-relative paths cited in **YAML and shell** — Taskfiles, CI workflows, chart values, hack scripts. This surface was added after a docs reorg left eight of them dangling: the Markdown and Go citations had all been repointed, and nothing was looking at the Taskfiles.
A citation must contain a slash. A bare `README.md` in prose names no particular file — relative to which directory? — so it is not treated as a reference.
The Go side parses the AST and reads only comments, never string literals. That distinction matters: the gittargetignore tests build in-memory filesystems whose entries are named like documentation paths. Those are fixtures, not citations. A regex cannot tell the two apart; the parser can.
YAML and shell have no comparable parser worth carrying, so they are scanned as plain text. The one distinction that must be made there is a docs path in a URL (`https://github.com/…/docs/spec/foo.md`), which names a rendered page rather than a repo-relative file; those are skipped.
Only git-tracked files are scanned, so gitignored scratch notes and the local upstream checkouts under external-sources/ are out of scope for free.
A reference must resolve to a git-tracked file or directory, not merely to something on disk. Resolving against the filesystem would make this check pass on the author's machine and fail in CI: a link into a gitignored path — `.agents/`, a local scratch file, an untracked upstream checkout — exists locally and does not exist in a fresh clone. That is precisely the reference this check must catch, so existence is decided by `git ls-files`, never by os.Stat.
Usage:
doccheck [-root DIR]
Exits non-zero and prints file:line for every unresolved reference.