ADR-005: References in prose are hyperlinks, enforced by lint
Status Active · Filed 2026-08-03 · Influenced ADR-025 · ADR-042 · DP-003 · DP-004 · DP-005
Context
A record whose whole value is being navigable was not navigable. In strata-g, SG-ADR-053 appeared as a link about sixty times and as bare text about thirty more — sometimes in the same paragraph. Following a bare one meant leaving the page, globbing the decisions directory, and coming back.
The drift wasn’t toward “unlinked”. It was toward random, which is worse: a reader can’t learn which references are worth clicking, so they stop clicking.
Decision
Every resolvable reference in prose is a hyperlink, and the lint fails on the ones that aren’t.
One scanner backs both the check and the fixer, so luria lint’s failure
message is a command rather than a puzzle, and the two can’t disagree about what
counts (DP-4).
A reference only counts in prose. Code fences and spans, HTML comments, bare URLs, both halves of an existing link, defined shortcut references, HTML tags — all masked. Four rules look like implementation detail and are load-bearing:
- Raw HTML blocks get
<a href>, not[…](…). Markdown isn’t parsed inside an HTML block, so a markdown link written there renders as literal brackets. - Backtick pairing is per paragraph. Pairing code spans document-wide lets one unbalanced tick invert which side of every later tick counts as code — observed symptom: a reference linked inside its own code span, while 809 real references in the same file were silently skipped as “code”.
- An ambiguous low
#Nis left alone. Docs number more things than issues — principles, open questions, stories. Above the highest principle number it can only be an issue; at or below, it takes an explicit cue or stays bare. A confidently wrong link costs a reader more than a number they look up. - Fragment links resolve from where the text lands, not where the file sits — otherwise every fragment link breaks at collection time, in a bot commit, long after the contribution that wrote it.
Frontmatter is data and stays plain, with one exception: a summary is prose,
and the generator rebases its links per output (ADR-004),
so it carries them. That rewrite is verified against the YAML — it must still
parse, leave every other key byte-identical, and reduce back to the original
when links are stripped — rather than assumed safe.
Alternatives considered
- Absolute URLs everywhere. Uniform, and immune to the fragment problem. Rejected: it breaks reading the docs offline or in any renderer that isn’t the forge, and most reading — including by agents — happens in an editor.
- A convention with no lint. Exactly the shape that produced the drift.
- Autolink at render time. The forge renders these files and we don’t own that pipeline; the source would stay bare.
- Warn instead of fail. A bare reference is mechanically fixable and always wrong, which is precisely the case where failing is right — contrast ADR-007, where it isn’t.
Consequences
- Writing
see ADR-004in a new document is a lint failure with a one-command fix. - The masking rules need tests more than the checks do: a false positive is a failure a contributor can’t fix by hand, and a false negative is a reference that stays bare forever.
- The fixer is idempotent, which is what makes it safe to run corpus-wide.