A reference that leaves its project names it, <project>:<local-route>, and resolves against that project's own registry through one resolver
Accepted
Context
adr-103 made a class of governed reference DECLARED: each kind states its addressing (id_prefix, id_pad, route_prefix) and the id pattern is derived from it. It covers one project. adr-129 made a project's root a fact of the machine's registry (~/.config/ontoref/projects.ncl), never of a versioned file. Nothing joins the two: a reference to another project's artefact has no form and no resolver.
Measured on 2026-10-17 across DD-eca, ontoref, provisioning and website-htmx-rustelo, read-only:
- The qualified form already exists in prose and nothing reads it: provisioning:adr-053, provisioning:adr-054, stratumiops:adr-007, ontoref:adr-087 (about 13 occurrences), plus about 17 of the form «libre-wuji adr-022». DD-eca cites 11 ontoref ADRs unqualified (40, 62, 72, 73, 108, 119…); in DD-eca `ADR-005` is either its own superseded record or opus's. provisioning's archived ADRs reuse 012 and 013. An edge whose target is ambiguous cannot be routed. - The form collides with the frozen route vocabulary of biop.ncl: `qa:<slug>` and `biop:<slug>` already put a kind before the colon, and `adr:adr-111` and `bl:bl-116` occur in the tree. - `kinds resolve` decides by shape only: `provisioning:adr-53` resolves as qa, biop and mode at once, and any slug «matches» every slug kind whether or not it exists. - Three resolvers of an ADR reference disagree: adr.nu ref-identity accepts exactly three digits, validate.nu adr-ref-resolves any number, kinds.nu the registry's pad. librosys numbers with four (adr-0002), which the first would not read. - The registry of projects is read by three functions (biop.nu, registry.nu, domain.nu); only domain.nu load-registry returns the slug.
The principal set the frame: there is no global registry of ADRs and none is wanted; each project is autonomous inside its namespace; what is needed is that a reference across project, domain and ontoref is valid and routable, with a validity that «depends» rather than true or false.
Decision
A REFERENCE THAT LEAVES ITS PROJECT NAMES IT. The form is `<project>:<local-route>`, where `<local-route>` is the route the addressed project would write for itself under adr-103 and the frozen vocabulary of biop.ncl: `provisioning:adr-053`, `ontoref:qa:bond-carrier-layout-howto`, `librosys:adr-0002`. `<project>` is the slug the machine's registry carries (adr-129). A reference inside its own project stays unqualified; qualifying it with the project's own slug is allowed and means the same address.
THE HEAD BEFORE THE FIRST COLON IS READ AS A KIND FIRST. The reserved heads are DERIVED from the reading project's registry — every kind id and every route stem (`adr`, `backlog`, `bl`, `qa`, `biop`, `mode`, and whatever a registry adds) — never listed by hand. `adr:adr-111` therefore stays a kind-qualified local route. A registered project whose slug equals a reserved head is still registered; the resolver reads the head as the kind and reports the collision, and such a project is addressed only by its full route under a slug that does not collide.
THE ADDRESSED PROJECT NORMALISES ITS OWN IDS. A qualified route is resolved against the addressed project's root, found through the registry, and normalised by THAT project's kinds.ncl: `fx:adr-2` is `adr-0002` when fx pads to four. A target with no kinds.ncl is read through the protocol's registry, and the answer says which registry it used.
RESOLUTION IS A GRADED VERDICT WITH ITS CAUSE. pass (the occupant exists), fail (the project answers and has no such occupant), unknown (the project is not registered on this machine, or its store cannot be read), each non-pass with its cause. Absence on one machine is not a broken reference: adr-129 makes the registry a fact of the machine, so the same route may be pass on one host and unknown on another. The same holds inside one project: a target that lies in a member the constellation declares (.ontoref/ontology/constellation.ncl) and that is absent from this checkout — an agent's workspace, the copy `iter accept` judges — reads unknown with the member named, never fail; a missing target in a tree that is present still fails. What a consumer DOES with unknown is the consumer's disposition, never the resolver's. A slug reference is decided by existence in the stores, never by shape.
ONE RESOLVER. kinds.nu is the only place that parses a route and normalises an id. validate.nu, adr.nu and backlog.nu delegate to it and carry no id pattern of their own — validate.nu's check of qa `related` asks route-resolve for every token its local universe does not hold, keeping only the stricter whole-slug rule for ADR tokens — and the registry of projects is read through domain.nu load-registry, the constellation's members through domain.nu constellation-members. The Nickel contracts keep checking the SHAPE of a route only (biop.ncl): a data contract that resolved would need the whole graph to export one record, and it would be a second copy of the grammar.
The nodes of core.ncl become a declared kind, `core`, so local references to axioms, practices and tensions resolve instead of reading as dangling. The audit that walks every typed reference field (`kinds audit`) is delivered by the same SOW and is NOT decided here: its cadence, runtime and routing belong to the decision bl-075 exists to force.
Delivered by sow-artifact-routes-v2, successor of sow-artifact-routes (contracts C1–C6). The constraints below invoke that SOW's signed contracts by id; they do not restate them.
Constraints
- Hard `<project>:<local-route>` parses into project, kind and id; an unqualified route is local; a head that is a kind id or route stem of the registry is read as a kind, and a registered slug that collides with one is reported
- Hard A qualified route is normalised by the addressed project's registry and resolved against its stores, with pass, fail or unknown and a cause for each non-pass; a slug reference is decided by existence
- Hard validate.nu, adr.nu and backlog.nu use kinds.nu and carry no id pattern written by hand
Alternatives considered
- A global registry of ADRs across projects — rejected: Rejected by the principal: no global registry and no consensus over ids is wanted. It would also make one store the owner of every project's ids, against each project's autonomy in its namespace.
- `<project>:<kind>-<id>` as a new grammar — rejected: It collides with `qa:` and `biop:`, cannot express the slug kinds, and is a second grammar beside adr-103's addressing.
- Qualify every reference, local ones included — rejected: It rewrites hundreds of local citations across four repositories with separate VCS for no gain in routability; a local route is already unambiguous inside its project.
- Paths or URLs as references — rejected: adr-129: no versioned file of a project carries where a project lives. A path is a fact of one machine.
- Resolve inside the Nickel contracts — rejected: biop.ncl already refused it: exporting one record would require the whole graph, and the contract would become a resolver and a second copy of the grammar.
- Refuse every reference whose target cannot be reached — rejected: It turns a fact of one machine into a broken reference everywhere else, and it is a 'Hard biconditional on a question whose answer depends on who reads it and when.
Anti-patterns
- The route grammar written a second time — A regex for routes in a Nickel contract, a list of reserved heads next to the parser, or an id pattern inside a validator. Each copy is right on the day it is written and falls behind the first kind declared after it.
- A target this machine cannot reach read as a broken reference — Turning unknown into fail because the addressed project is not registered here. adr-129 makes the registry a fact of the machine; the same reference is valid on the host that has the project.
- Normalising another project's id with the reader's registry — Padding `librosys:adr-2` to adr-002 with the reader's width issues an id the owner never did, and the reference then fails against an occupant that exists.
Related ADRs
· reads
Perspectives