ADR-0007 — Tests are part of every change
Every change ships tests for its happy path and its obvious failure paths, and a bug fix starts with a test that fails for the bug's reason.
- Status: Approved
- Date: 2026-10-31
- Deciders: @puncoz
- Approved by: @puncoz
- Approved on: 2026-11-01
- Supersedes: —
- Superseded by: —
- Design documents:
AGENTS.md§3, §5, §11
Context
Most of this site is content, but the code around it decides what is published and where: the
content loader, the Markdown and llms.txt routes, the search records and their sync, and —
once private documentation exists — whatever keeps private pages off public surfaces. Errors
there are silent: a page goes missing from search, or a private page appears in it.
No test runner is installed. Bun is the package manager and has a built-in test runner; the choice of runner is left to its own ADR so it can be weighed against what the site's code needs.
Decision
- Every change ships tests for its happy path and its obvious failure paths — empty or missing input, the boundary and the first value past it, the wrong shape or an unknown value, and the rejection the code exists to perform (a private page refused, a malformed frontmatter rejected). Part of being done, not a follow-up.
- A bug fix starts with a test that fails for the bug's reason.
- A test must have been seen to fail (written first, or checked by breaking the code) before it counts.
- The runner is chosen by its own ADR, before the first code change that needs tests.
Until then, a change is verified with
bun run lint,bun run types:checkandbunx next build, and the ADR's implementation notes say what was verified instead. - Unit tests are pure: no live search index, network or real private content. Fixtures are invented.
- Content is verified by the build.
bunx next buildfails on invalid MDX or frontmatter; link and example checks, if wanted, are decided by their own ADR. - Exempt from unit tests: config modules, pure layout and styling. Anything that needs a browser says so in the ADR's implementation notes, with what was verified instead.
Options considered
| Option | Pros | Cons | Verdict |
|---|---|---|---|
| A — Tests with every change; runner chosen by its own ADR | The rule holds from now; the runner is a deliberate choice | No runner until that ADR lands | Chosen |
| B — Pick a runner in this ADR | Tests can start immediately | Decides tooling before there is code that needs it | Rejected |
| C — Tests optional for small changes | Faster small changes | Publishing bugs hide in small changes | Rejected |
Consequences
Positive
- The code that decides what is published has a safety net from its first line.
Negative / accepted trade-offs
- Every change takes longer. Accepted.
Content invariants
Guards §6.1 (private stays private) and §6.5 (every page readable as Markdown) through tests on the code that serves them.
Security considerations
Tests must never contain a real secret, a real search key, or private project content. Visibility code is tested for refusals, not only for success.
Implementation notes
- A test-runner ADR before the first code change that needs tests: ADR-0021, proposed 2026-11-01. ADR-0018 and ADR-0019 shipped with hand checks only; their checks become the first tests once ADR-0021 is approved.
- Tests: not applicable (process only).
Docs to update on implementation
-
AGENTS.md§5 — the runner and its command, once its ADR is approved. -
README.mdscripts — the test command. -
content/docs/maintain/adr/index.mdx— status.
ADR-0006 — Agent skills are advisory; this repository's documentation is binding
Use agent skills freely, but this repository's working agreement and documents are binding, and no skill grants a permission they withhold.
ADR-0008 — A UI change ships an app flow, drawn in Mermaid
Any decision that changes what a person sees ships an app flow, with entry points, the flow, a wireframe per screen and each screen's states.