ADR-022: url-ok acknowledges foreign codes only
Status Active · Filed 2026-08-04 · Influenced by ADR-007 · ADR-016 · Influenced ADR-023
Context
The url-ok directive acknowledges a link whose label is a composed foreign
code but whose URL is hand-written rather than constructed. The question this
records came up in review: the name reads generic, so why constrain it to the
remote namespace? A contributor might want to hand-target a link to one of
their own documents — an absolute URL to the file carrying a local DP, say —
and it seems harmless to let them make that explicit the same way.
The check behind the directive is a comparison: the written target against what ADR-016’s machinery would construct for the code in the label. Whether the directive can widen turns on whether that comparison means anything outside the remote namespace.
Decision
url-ok names composed foreign codes only, and the check inspects only links
whose label is one. Three reasons, in decreasing order of force:
A warning needs a well-defined wrong. A foreign code has exactly one constructed URL — that is the whole design of the remote namespace: one config entry, three resolution rungs, one answer. “The written target differs from the construction” is therefore a meaningful binary. A local code has a family of legitimate targets that depends on where the citing text renders and which aspect is being cited — the source file, the index row, an anchor in the assembled principles document, a book anchor for a journal entry. A check that adjudicated among those would flag correct links routinely, and a warning that is usually noise gets acknowledged by reflex — at which point the acknowledgement stops carrying information, which is the failure mode ADR-007’s report-don’t-fail philosophy exists to avoid.
The risk profiles are opposite. A local link is guarded by existence: its relative target either resolves or visibly breaks, the person who moves a local file can fix every inbound link in the same commit, and the tests sweep them. A remote hand URL fails silently — nothing in this repository breaks when the other project moves a file, renames a heading, or adopts the convention the hand URL was working around. The directive exists precisely to compensate for that invisibility; extending it to links that already fail loudly would spend annotation on a problem the filesystem solves.
The local want has a better answer, and the repo already models it. A
project that wants stable absolute citations to its own documents registers
itself as a remote — Luria’s own LU prefix exists for exactly this, so
the scaffold can cite Luria’s record by URL with the machinery’s guarantees.
The citation is then a composed code with a construction and a check behind
it; and where the construction genuinely runs out (a document that is a
section, not a file), url-ok applies — because the code is now
foreign-shaped. The escape hatch composes with the mechanism instead of
bypassing it.
The first reason deserves its sharpest form, because the obvious rejoinder is that a hand URL looks like the same anti-pattern in both namespaces — a defect with a mechanical remedy. It is not the same. A local hand URL restates a fact the machinery already owns: the fixer can compute the correct relative target from the repository itself, with zero new information, so the hand version is redundant and the remedy is a rewrite. A foreign hand URL exists precisely because the construction lacks information — which document carries the code, what its anchor is. The human is supplying a fact that has no home in the machinery. Same-looking artifact, opposite information content; an annotation is the honest way to hold a fact that has nowhere better to live, and dishonest where the fact is redundant.
Which points at what url-ok is for, beyond any single citation: each
acknowledgement’s reason is a description of a gap in what remote
configuration can express, and a recurring shape is the cue to grow the
config rather than keep annotating. The worked example is exact: strata-g
is a Luria project on a legacy layout, and its principles are a
document-rendered scheme — a shape Luria itself has. A remote on current
conventions has a constructible target for a DP code
(docs/design-principles.md#dp-18; the stable #dp-N anchors exist for
exactly this), so the gap is per-scheme remote mappings, not anything
essential about foreignness. What survives even that feature is the residue:
strata-g’s legacy anchors are heading-derived, no template can produce a slug
from a code, and discovery cannot read a private repository. The residue is
url-ok’s permanent jurisdiction; everything else it holds is a bridge, kept
visible until the config learns the shape.
Alternatives considered
- Any known code, local included. Requires first defining a canonical target for every local citation, which would adjudicate among legitimate variants and drown the report in false positives. The directive vocabulary maps names to checks; a name whose check is mostly wrong teaches people to suppress.
- A second directive for local hand URLs. An absolute URL to a file in the same repository freezes a ref, bypasses the relative-link guarantees, and breaks on the next branch rename — it is a defect with a mechanical remedy (a relative link the fixer will happily write), not a deliberate state to acknowledge. An annotation for it would bless an anti-pattern.
- Grow the remote model now, instead of adding the directive. The right direction and the wrong sequencing. Per-scheme remote mappings would let a Luria-shaped remote’s DP codes construct, and that feature should follow — but it cannot retire the directive, because the residue (legacy heading-derived anchors that need a slug no template can compute, private repositories discovery cannot read) still needs an acknowledged home. Build the escape hatch first, let its accumulated reasons specify the feature.
- No check at all (the state before this PR). The hand URL is a projection frozen at writing time (DP-3); invisible was how it got written wrong once already — the constructed guess that pointed at a file which never existed is what ADR-016’s “discovery is authoritative” rule answers.
Consequences
- The directive vocabulary keeps its shape: every name maps to exactly one
check, and a directive that stops applying reports itself.
url-ok’s scope is the scope of the construction it overrides. - A contributor who wants a hand-targeted local link just writes one — the lint has never demanded anything of an existing local link, so there is nothing to acknowledge. If a canonical-target check for local links is ever wanted, that is a new check first; whether it earns an acknowledgement directive can be judged when its false-positive rate is known.
- Anyone asking “why can’t I
url-okmy own DP?” should hear the short version: register yourself as a remote and cite the composed code — you get the check instead of exempting yourself from it. - When per-scheme remote mappings land, existing acknowledgements whose gap
the config now covers become fixable: delete the hand URL, let the citation
construct, and the stale-directive report retires the
url-ok— the full loop, closing the way it was designed to.