ADR-018: The README’s badges are counts derived from the record
Status Active · Version 2 · Filed 2026-08-03
Context
The README carried five badges. Three report something real that changes on its own — CI status, Python version, licence. Two did not:
[]
[]
Those are assertions that can never be false, which makes them furniture. A badge earns its place by telling a reader something they would otherwise have to clone the repository to learn, and by being capable of turning a colour they don’t like.
This repository has exactly two such numbers, and both are already computed — they are the two standing reports (ADR-007) that nobody reads because they live behind a command.
Decision
The badges are the two counts, derived from frontmatter and regenerated by
luria index.
| badge | counts | why a reader cares |
|---|---|---|
| needs decision | documents whose status is Proposed or Deferred, in every scheme | an open question stated is fine; an open question nobody can see is how a decision gets made in code and never written down |
| cited but retired | documents no longer in force that current docs or code still cite without an acknowledgement | a reference reads as “this is why things are the way they are”, and that claim expires |
Zero is green, non-zero is amber, never red. Neither number is a failure —
ADR-007 is explicit that citing a Rejected decision is often
right and a decision can be legitimately open for months. The badge says look
at this, not you broke it.
Derived, and guarded
The numbers are baked into static shields URLs inside a marked region:
<!-- luria:badges -->
…
<!-- /luria:badges -->
luria index rewrites the region; luria lint fails when it is stale. That is
rung 1 of DP-3 — the projection is derived, so
it cannot drift — with the staleness check as the thing that makes “derived”
enforceable rather than aspirational. Adding a Proposed decision and
regenerating updates the badge in the same commit.
A project with no region is left alone. Not everyone wants badges, and a tool that edits a README nobody asked it to edit is a tool people stop running.
All schemes, and only local ones
“Needs decision” counts every configured scheme, which meant generalizing
luria pending — it had only ever looked at decisions. A Proposed principle
is an open question in exactly the same way, and a report that covers one
scheme goes quietly blind the day a project configures a second, which is the
failure ADR-006 exists to prevent.
Remote schemes are not counted, and can’t be. A remote’s status is not
knowable from a URL; finding out would mean fetching and parsing every foreign
document, which makes a badge on a documentation page depend on someone else’s
uptime — the argument that already keeps luria remotes --check out of the
lint (ADR-016).
Alternatives considered
-
A shields
endpointbadge reading a committed JSON file. The standard trick, and closer than version 1 of this decision claimed. It costs a second artifact and a job to write it, and it needs a bot commit onmain— but a bot commit is not automatically the hazard ADR-002 names. That hazard is specific:CHANGELOG.mdis appended to at a marker and its entries carry assigned numbers, so a bot commit forces in-flight branches to rebase into a conflict exactly where their own content goes, and a mis-resolution silently drops somebody’s entry. A badge file has neither property — it is a wholesale rewrite of a derived value, and a conflict in it is resolved by regenerating.What actually decides it is where the number lives. A baked-in URL is correct per commit: open a pull request that adds a
Proposeddecision and that branch’s README already says so, in the diff, where a reviewer is looking. An endpoint badge always reportsmain— so the one moment the number is most worth seeing, while deciding whether to merge the thing that moves it, is the moment it cannot show it. Needing no CI, no second file and no bot is the smaller half of the argument. -
Query it live. Nothing outside this repository can compute either number: both require reading frontmatter across the corpus and scanning every reference. There is no service to ask.
-
A GitHub Action writing to a gist. Works, needs a token, and puts the README’s truth in an account nobody else can audit.
-
Keep the decorative badges and add these. Seven badges is a wall nobody reads, and the two being replaced were the two that could never say anything.
-
Count
cited but retiredincluding acknowledged citations. A bigger, more alarming number that goes up when someone does the right thing. The acknowledgement exists precisely so the considered ones stop being noise; counting them would undo it.
Consequences
- Two numbers on the front page that can go amber, and one command
(
luria index) keeps them honest. The staleness check was fired both ways before being trusted: aProposedprinciple moved needs decision to 1, an unacknowledged citation of ADR-015 moved cited but retired to 1, and hand-editing a count to a wrong number producedREADME.md: badge counts are stale. luria pending’s output is now keyed by code rather than ADR number, since its rows can come from any scheme. The reports and their tests moved with it.- An adopting project gets this by adding the region to its own README; nothing is scaffolded, because a badge asserting a number about a record that does not exist yet is worse than no badge.