ADR-045: Worked configurations are executable examples, not prose

Status Active · Filed 2026-08-11 · Influenced by ADR-006 · ADR-044 · Influenced ADR-046 · ADR-047

Context

ADR-044 gave the docs a generated configuration reference, which fixed discoverability: every key is now listed and cannot go missing. It did not fix credibility. The reference and the new “Shaping the record to your project” section both describe configurations in prose, and this project’s founding observation is precisely that prose drifts — every documentation surface with an executable guard held; every surface governed by prose alone had not.

The gap was not hypothetical for long. Building four working projects out of the configurations that had just been documented falsified two of them immediately, and surfaced a third defect:

  • active = "Accepted" was offered as “whatever in force means for your RFCs”. The status vocabulary is closed and lint-enforced (ADR-003), so active selects from five statuses and cannot extend them. The example named a state no document could hold.
  • “Omit output and the view renders beside its sources” was true for a scheme a project invents and false for ADR — configuration merges over DEFAULTS, which carries output = "docs/decisions". The documented way to adopt without moving files silently relocated the index.
  • A render = "document" scheme with no README.stub emitted the heading # Design principles regardless of prefix, so a SPEC family rendered as a document was titled after this package’s own principles.

None of the three was visible to review. All three were visible in the first minute of running the configuration.

Decision

examples/ holds four complete projects, each demonstrating a different shape: rfcs-and-specs/, collocated/, many-journals/, external-citations/. tests/test_examples.py copies each into tmp_path, points LURIA_ROOT at it, runs luria index and the lint checks, and asserts the specific capability — that a document-rendered scheme emits its bodies and a stable anchor, that three journals produce month, year and day books, that ARXIV-2301.07041 becomes a real arXiv URL.

Two details carry weight.

Nothing generated is committed. The tests build in a temporary directory and examples/.gitignore keeps the views out of the repository. A committed view that no CI run regenerates is exactly the stale projection these examples exist to argue against, and it would be a particularly bad one — sitting in the directory a newcomer copies from.

The limits are asserted, not just described. Three tests pin things Luria cannot do: active cannot extend the vocabulary, the shipped ADR scheme cannot be removed, and omitting its output does not collocate it. A capability that regresses fails a feature test; a limit that goes undocumented, or a documented limit that quietly stops being true, has no guard at all unless someone writes one. examples/README.md states all three, and a document that states a limit has to be right about it.

Alternatives considered

  • Prose examples alone. The status quo. Now known to have been wrong in two places on the day it was written, which is the strongest argument available and was not available before this work.
  • Fixtures inside tests/ only. Cheaper and gets the same guard, but the audience is adopters deciding whether Luria fits a shape they have in mind. They will not read a test module, and they cannot copy one. Putting the projects where they can be browsed, and then executing them, is the same source serving both uses (DP-3).
  • Doctest-style snippets in the guide. Tests the snippet rather than a project. None of the three defects above would have been caught: each needed a real tree to render and lint end to end.
  • Committing the generated views so the examples look complete when browsed. Tempting, and it would put a stale view in the one directory people copy from.

Consequences

Four configurations are now claims CI defends, and the guide points at them rather than only describing them. The three defects found are fixed: the DEFAULT_DOCUMENT_STUB heading names its own scheme, and both wrong prose claims in docs/adopting.md are corrected and now have tests behind them.

Two ADR-scheme limits are documented rather than resolved, both from the same cause — configuration merges over DEFAULTS rather than replacing them. Making the shipped scheme removable, or its output genuinely unset by omission, is a change to merge semantics and belongs in its own decision. Until then the reference, the guide and examples/README.md all say so, and tests hold them to it.

The ongoing cost is real: a change to render output now breaks example tests as well as Luria’s own, and examples/** joins template/** in the site’s exclusions so a sample record is not published beside the real one (DP-9). That is the intended direction — the examples are meant to be load-bearing, and a guard that never fires was not worth adding.