The rel arm required a leading `./` or `../`, so `[x](swarm/services.md)` —
the form a sibling link is usually written in — matched none of the three
arms. That is exactly the shape a directory move breaks: during #3911 a link
in that form moved into a new directory, resolved to nothing, and the lint
stayed green. Reproduced by putting the broken form back with `sed`
(MUTATED_DIRTY=1) and re-running: exit 0, a control that fails to fail.
Widening the pattern surfaces 116 links the arm never saw (76 -> 192 matches).
111 are in `.md` files and all 111 resolve today, so this adds coverage
without a single new failure in the tree; the other 5 are the interesting
part, and they are why the arm now selects on file type.
A link is only resolvable against its own directory when the file is
*rendered where it is stored*. The four in `nix/docs/default.nix` are inside
a markdown string this derivation writes to `$out`, and the one in
`hive-c0re/src/workers/knowledge.rs` is template text for another repo's
README — resolving either from the source directory certifies a path no
reader ever requests. `lint:allow` is the wrong tool for them: the marker
lives inside the generated text, so it would ship in the published page.
The `.rs` arm keeps its error, narrowed to doc-comment lines. Its premise
still holds — the repo has zero relative links in `.rs` doc comments — but
without the narrowing the widened pattern reports the knowledge.rs template
string with a message about rustdoc that is wrong for it.
Measured: the old arm's 76 hits are all in `.md` files, so restricting
resolution to `.md` removes no existing coverage.
Closes#4076
mara on #3923: "any gate we add should not have false positives". This is
the gate, and the reason it can exist without a skip-list is the prose fix
in the previous commit -- every false positive this arm would have raised
was a sentence naming where something used to live.
A third arm on the existing doc-pointer lint rather than a fourth CI job:
it inherits the job that already runs on every PR and in pre-push, the
`lint:allow` hatch the sibling arms honour, and the ::error annotation
format. A new job is a thing that can ship without ever running.
Scope is any repo-relative source path, not only `docs/**.md`. A comment
naming a moved .rs or .nix file misleads exactly as much as a dead doc
link, and nothing was checking it: 1123 such paths resolve on this tree
and none were verified before now.
Both ends of the pattern are anchored, each because its absence invented a
path -- an unanchored extension matched the prefix of a longer one, and an
unanchored prefix matched mid-path inside a nested directory, conjuring a
top-level twin of a real file. Those failures now surface as dead paths and
fail the build rather than passing silently, so they need no separate
control.
Written with placeholders, because the first draft named the two phantom
paths literally and the new arm immediately reported the script to itself.
The header already warned about exactly that, two lines above where I put
them.
Refs #3923
check-doc-refs.sh's relative arm resolved every link against the linking
file's directory. That is right for markdown and wrong for a .rs doc
comment: rustdoc emits the href verbatim onto a page under
target/doc/<crate>/<module...>/, so the link resolves against THAT
directory instead.
The consequence was a false pass, not a miss -- a link resolving from the
source dir got certified while rendering broken in the published docs.
Reproduced against main's script: a `](../../docs/README.md)` planted in
hive-forge/src/client.rs resolves from hive-forge/src/ and the old rule
exits 0.
Refused rather than resolved rustdoc-aware. The repo has zero relative
links in .rs doc comments (measured on 54daf9ac), so nothing needs the
second reader, and the backticked repo-root form the root arm already
gates renders correctly under both. Inferring module nesting would be
machinery in service of a form nothing uses.
Closes#3928
Pointing at a doc instead of duplicating its prose next to the code is what
the comment-block lint pushes people toward, and nothing checked that the
pointers still resolve. The reorg that prompted the preceding commit broke
41 references and every one of them merged green.
Two arms: repo-root-relative `docs/` paths, and relative markdown links
resolved against the linking file. Scope is every tracked file rather than a
type list — the dead references were in css, html and an ignore file as well
as in markdown and nix.
Three controls, because a link checker whose extractor quietly matches
nothing passes forever while checking nothing: each arm must have found
candidates, and at least one pointer must have resolved. Any of those failing
exits non-zero and says the script is broken rather than the tree.
Escape hatch is the `lint:allow` marker the tracker-tag lint already uses.
Its only current users are in reference-docs.nix, where a path naming a file
the derivation synthesizes into $out is correct precisely because the repo
does not have it.
Also runs in the pre-push hook alongside the other two.