ops-warden/docs/adr/ADR-0001-catalog-is-a-pointer-layer.md
tegwick 35aff380a3
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Lift ops-warden's binding rules into owned ADRs
Five rules that governed this repo lived in wiki prose, a workplan, and a
comment at the top of catalog.yaml. All were followed; none was addressable.
A reader outside ops-warden could not cite one, could not tell whether it was
current, and — the point of this change — could not tell whether it was ours
to change or someone else's that we merely obey.

  ADR-0001  The routing catalog is a pointer layer, never a second copy
  ADR-0002  ops-warden is a transparent conduit, never a secret broker
  ADR-0003  Cover gaps, but never silently own them
  ADR-0004  High-risk lanes refuse raw value streaming to agent sessions
  ADR-0005  Implement one lane narrowly, route everything else

Each carries owner: ops-warden, which is the load-bearing field. It says we
follow the rule AND we are responsible for changing it — by superseding ADR,
never an in-place edit. The failure this prevents runs both ways: a rule we own
mistaken for inherited canon never gets fixed, because we wait for an owner who
does not exist; inherited canon mistaken for ours gets quietly bent, and the
drift is invisible until it breaks a repo that trusted the canonical version.

Rules we follow but do not own — NetKingdom canon, the IAM profile, the
credential-management standard, the-custodian's ADR-001 workplan convention —
are cited, never copied into docs/adr/. Copying them would recreate exactly the
second-source-of-truth failure ADR-0001 exists to prevent. architecture.md also
now flags the three-digit/four-digit ADR-001 vs ADR-0001 collision, which is
itself an ours-versus-inherited confusion waiting to happen.

Publication verified rather than assumed: all five render through policy-nexus
tools/render.py, and owner reaches the reader in three places — the page eyebrow
(render.py:346), the index Owner column (build_site.py:123,137), and the
publication manifest. build_site.py:179 makes title/status/owner required, so
ownership cannot be dropped on the way out. policy-nexus publishes and never
writes back; docs/adr/ stays the source of truth.

Documentation adapted: SCOPE.md gains a Governing rules section and an orientation
entry; .claude/rules/architecture.md replaced its stub with the ADR index, the
owned-versus-inherited rule, and ADR-over-wiki precedence; finding-routing.md's
ADR-gap section closed; catalog.yaml's no-double-source header now cites ADR-0001
rather than the originating workplan.

uv run pytest -q → 338 passed, 4 deselected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 13:35:13 +02:00

90 lines
3.8 KiB
Markdown

---
id: ops-warden-adr-0001
type: adr
title: "ADR-0001 — The routing catalog is a pointer layer, never a second copy"
domain: infotech
repo: ops-warden
status: accepted
version: "1.0"
revision: "1"
owner: ops-warden
binds: "ops-warden; every repo contributing a catalog entry"
created: "2026-06-20"
updated: "2026-08-18"
last_reviewed: "2026-08-18"
review_interval: 6m
enforced_by: tests/test_routing.py
supersedes: ""
successor: ""
---
# ADR-0001 — The routing catalog is a pointer layer, never a second copy
## Status
Accepted. Decided during WARDEN-WP-0010 (access routing charter), enforced in code
since WARDEN-WP-0011. Restated here because it binds repos other than ops-warden
and had, until now, no address they could cite.
## Context
`registry/routing/catalog.yaml` tells a worker which subsystem owns a credential
need and where the authoritative procedure lives. The obvious temptation, every
time someone uses it, is to add the procedure itself: the reader is already here,
the steps are short, and one more copy seems cheaper than a second lookup.
That temptation is the failure mode. A copied procedure is correct on the day it
is written and silently wrong afterwards, because the owner changes theirs without
knowing ours exists. The estate has already paid for this once, between an ADR and
its published page — fixed by generating the page from the markdown rather than
maintaining both.
The catalog is consulted precisely when someone is about to touch a credential.
Being confidently wrong there is worse than being absent.
## Decision
**For any subsystem ops-warden does not own, a catalog entry carries identifiers
and pointers only** — `owner_repo`, `subsystem`, `wiki_ref`, `canon_ref`,
`need_keywords`, and the secret-free handoff metadata `warden access` needs.
**Authored procedure is permitted only where `warden_executes: true`.** A `steps:`
block and a `cert_command:` may exist on the SSH certificate lane and nowhere else,
because that is the one lane ops-warden actually owns. Rotation `steps:` are the
narrow exception and describe what the *owner* does, recorded because rotation
guidance had no other home; they are still pointers in spirit and must not grow
into a runnable substitute for the owner's tooling.
**No secret material in this file, ever.**
This is enforced, not merely documented. `tests/test_routing.py` fails any non-SSH
entry carrying a `steps` block, and checks that every `wiki_ref` anchor resolves to
a real section. A rule that is only written down is a rule that erodes.
## Consequences
**Accepted cost.** Two lookups instead of one. A worker who wants the procedure
follows the pointer. We consider a correct second hop cheaper than a stale first
one.
**Anchors must resolve.** Because the entry is only a pointer, a broken pointer is
a total failure rather than a cosmetic one. Hence the anchor test — which has
already caught a real break (`ADHOC-2026-08-11-T01`, a stale
`rapp-qonto-keycape-client` anchor).
**Other repos are bound by this.** When another repo asks us to add or rename a
lane, we add the pointer and decline to absorb the procedure. That has been
exercised: on 2026-08-11 railiance-platform asked ops-warden to rename an active
lane, and the answer was to cross-reference the id from their CCR rather than have
this repo carry a second identity for the same thing.
**It constrains what this repo may usefully become.** ops-warden cannot grow into
a documentation site for other people's credential procedures, however often that
is asked for. The value of the catalog is that a reader knows it points at truth
rather than at a copy of truth.
## Related
- `registry/routing/catalog.yaml` — the file this governs, header comment
- `wiki/AccessRouting.md` — the issue-vs-route role and boundary
- `ADR-0005` — the narrower charter this follows from