Decision index¶
Architecture decision records: the choices that are not obvious from the code, and the alternatives that were rejected.
Each one states what was decided, what else was considered, and what the decision costs. They are written to be read by someone who is about to change the thing they describe — including the author, months later, who no longer remembers why it is like that.
An ADR is immutable once accepted. A decision that turns out to be wrong gets a new record that supersedes the old one; the original stays, because the reasoning that led to a mistake is part of the history. ADR 0000 describes the process itself.
The records¶
| # | Decision | Status | Date |
|---|---|---|---|
| 0000 | ADR process | accepted | 2026-09-01 |
| 0001 | Project name: evalstand |
accepted | 2026-09-01 |
| 0002 | Design scope | accepted | 2026-09-01 |
| 0003 | No variants in v1 | accepted | 2026-09-01 |
| 0004 | evaluate() registers, it does not execute |
accepted | 2026-09-01 |
| 0005 | The database is project-local | accepted | 2026-09-01 |
| 0006 | Trace parenting via a reset ContextVar |
accepted | 2026-09-01 |
| 0007 | LiteLLM rather than provider SDKs | accepted | 2026-09-01 |
| 0008 | The plugin collects and reports; the runner executes | accepted | 2026-09-03 |
| 0009 | The web UI is optional, and read-only over history | accepted | 2026-09-14 |
By what they answer¶
"Why does this project exist, and what is it not?" 0001 on the name, 0002 on what is adopted from the TypeScript implementation that proved the idea, what is done differently, and what is added. 0003 records the one significant capability deliberately waived rather than missing.
"Why is the code structured this way?"
0004 on why evaluate() performs no I/O,
and 0008 on why the pytest
plugin executes nothing. Together these two explain the central seam:
collection and execution are separate, because pytest runs items one at a time
and concurrency has to live somewhere else.
"Why does my data live there?" 0005 on the project-local SQLite database — and therefore on why CI starts every build with no history.
"Why does it do that at runtime?"
0006 on the single ContextVar rule that makes trace
trees survive asyncio.gather and mid-call exceptions.
0007 on reaching every provider through
one library, including what that costs.
Writing a new one¶
Copy the shape of an existing record: a title line, a status, a date, then context, the decision, and the consequences — including the ones you would rather not write down. Number it sequentially, add it to the nav and to the table above.
A test enforces that every ADR on disk appears in the nav, so a decision written and never linked will fail the suite rather than quietly become unfindable.