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:

[![Decisions](…/badge/decisions-generated%20index-informational)]
[![Principles](…/badge/principles-versioned-informational)]

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.

badgecountswhy a reader cares
needs decisiondocuments whose status is Proposed or Deferred, in every schemean 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 retireddocuments no longer in force that current docs or code still cite without an acknowledgementa 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 endpoint badge 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 on main — but a bot commit is not automatically the hazard ADR-002 names. That hazard is specific: CHANGELOG.md is 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 Proposed decision and that branch’s README already says so, in the diff, where a reviewer is looking. An endpoint badge always reports main — 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 retired including 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: a Proposed principle 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 produced README.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.