The website subproject drew ADR numbers from the same global integer pool
as main, so every merge risked a collision — this already happened twice
(drafted 0042, bumped to 0044, both landing on numbers main had taken; main
has now used 0044 for relationship visualization). Give the website its own
ADR namespace so the two never compete again.
- docs/adr/0044-public-website-...md
-> docs/website/adr/20260604-adr-website-001.md (id: ADR-website-001)
- docs/plans/20260604-adr-0044-website.md
-> docs/website/plans/20260604-website-implementation-plan.md
- new docs/website/adr/README.md index (dated <date>-adr-website-<NNN> seq)
- docs/adr/README.md: drop the 0044 entry, add a namespace pointer in the
intro (keeps the list tail == merge-base, so main's 0044 merges cleanly)
- ADR-0000: record the subproject-ADR-namespace convention
- update references in STYLE.md, astro.config.mjs, the plan body
Handoff files left untouched as point-in-time history.
4.7 KiB
ADR-0000: Record architecture decisions
Status
Accepted
Context
The RDBMS Playground project will accumulate design decisions as it grows. We want those decisions to be traceable, reviewable, and easy to challenge later when context has changed.
Decision
Record significant architecture and product decisions as Architecture
Decision Records (ADRs) in docs/adr/, using the Michael Nygard
format (Status, Context, Decision, Consequences). Files are numbered
sequentially with a four-digit prefix and a kebab-case slug, e.g.
0001-language-and-tui-framework.md.
Each ADR captures one decision. Superseding a decision means adding a new ADR that references the old one and marking the old one as "Superseded by ADR-NNNN".
ADRs document decisions, not speculation. An idea under discussion belongs in conversation, an issue, or a design note — not an ADR. An ADR is written once a decision has actually been made.
Index discipline
docs/adr/README.md contains the canonical index of all ADRs.
Whenever an ADR is added, renamed, or has its status changed (e.g.
"Superseded by ADR-NNNN"), the index MUST be updated in the same
change. An ADR change without a corresponding index update is
incomplete.
The index lists ADRs in numerical order. Each entry shows the number, title, and — where relevant — status annotations such as "Superseded by ADR-NNNN" or "Deprecated".
Numbering discipline
ADR numbers are a single global sequence, so two branches can each grab
"the next number" independently and collide on merge. (This happened when
the website branch's ADR-0042 met main's ADR-0042, resolved by
renumbering the former to ADR-0044.) To prevent it:
Assign an ADR's number at merge-to-main, not at creation. While the
work lives on a non-main branch, draft the ADR under a placeholder — an
ADR-XXXX title and a draft-<slug>.md filename — and reference it that
way from any plan or notes. Give it the next free number only when the
branch merges to main, renaming the file and updating its references in
the same step.
A number is "taken" only once it appears in main's docs/adr/README.md,
which is the single source of truth for the next free number — never
compute "next" from a feature branch. A branch that genuinely needs a real
number up front may instead reserve one by landing a stub index entry on
main first, but placeholder-until-merge is the default.
Subproject ADR namespaces
A long-lived subproject developed on its own branch can escape the shared
integer pool entirely by keeping its decision records in a separate
namespace, rather than fighting collisions on every merge. The website
(docs/website/adr/) is the first: its ADRs use a dated sequence —
<date>-adr-website-<NNN>.md, referenced in prose as ADR-website-NNN —
and are indexed by their own docs/website/adr/README.md. Because the
date-plus-subproject prefix is disjoint from main's integer sequence, a
website ADR and a main ADR can never claim "the same number" again. (This
namespace was created on 2026-06-10 after the website's ADR collided with
main's on consecutive numbers — drafted 0042, bumped to 0044, both times
landing on a number main had taken; the move retired it from the pool as
ADR-website-001.) The main docs/adr/ index carries a pointer to each
such namespace. Use this for a new subproject only when it is genuinely
self-contained and branch-isolated; one-off cross-cutting decisions stay in
the global sequence.
Out-of-scope discipline
ADRs (and the plans they spawn) lean heavily on "out of scope" language. The phrase carries two very different meanings, and conflating them misleads a later reader:
- Deferred — out of scope for this plan / phase / step, but a reasonable thing to do later. A sequencing decision, effectively a tracked TODO. Where possible, point at where it will be picked up.
- Rejected — considered and deliberately not done, on principle. Durable. State the reason.
When writing an out-of-scope item, say which kind it is — e.g.
OOS (deferred) / OOS (rejected: <reason>), or the equivalent in prose
— so a future reader can tell a standing decision from a not-yet. A bare
"out of scope" is ambiguous and tends to read, wrongly, as permanent.
(Motivating example: ADR-0030 §13 OOS-2 was a deferred scope exclusion
that read as a permanent rejection until ADR-0039 lifted it.)
Consequences
- New significant decisions require an ADR before or alongside the implementation that depends on them.
- Old decisions remain visible even after they are superseded.
- Reviewers can audit the rationale chain by reading
docs/adr/in order. - The index in
README.mdstays trustworthy because keeping it current is part of every ADR change, not an afterthought.