Files
rdbms-playground/docs/adr/0000-record-architecture-decisions.md
T
claude@clouddev1 b5c848efcb
ci / gate (push) Successful in 2m5s
ci / manifests (push) Successful in 4s
ci / gate (pull_request) Successful in 2m5s
ci / manifests (pull_request) Successful in 4s
chore(workflow): branch-and-PR working method + ADR-number reservation (ADR-0059)
Adopt a trackable working method now the repo is public:
- PRs onto a protected main; --no-ff merge commits; one worktree per branch.
- Reserve-first ADR numbering: scripts/adr-reserve.sh claims the next number
  atomically against main (push = compare-and-swap; ledger
  docs/adr/RESERVATIONS.log), so a number is stable from creation.
- Worktree helpers scripts/wt-new.sh + wt-clean.sh.
- Local-origin test harnesses (reserve 10/10, worktrees 7/7, shellcheck clean).

Record the decision in ADR-0059, supersede ADR-0000's placeholder-until-merge
numbering default, and add the lean CONTRIBUTING.md sections + CLAUDE.md
operational rules.
2026-06-23 20:41:42 +00:00

5.1 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:

Reserve the number up front, via scripts/adr-reserve.sh (ADR-0059, which superseded the earlier placeholder-until-merge default). The moment you know an ADR is needed — at branch start or mid-branch — run scripts/adr-reserve.sh <slug> "<title>". It atomically claims the next free number against main (the remote ref is the registry; a git push is the compare-and-swap, retried on contention) and records it in the append-only ledger docs/adr/RESERVATIONS.log. The number is then stable from creation, so it is safe to cite in commit messages (immutable under the no-rewrite rule), in other ADRs, and in the PR from the first commit. Create the ADR as docs/adr/<NNNN>-<slug>.md and add its README index row as part of the branch's normal work.

A number is "taken" once its ledger line (or NNNN-*.md file) is on main; the script reads both to compute the next free number — never compute "next" by hand from a feature branch. The full rationale (why reserve-first beats number-on-merge, issue-number ids, or an allocator bot) is in ADR-0059.

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.md stays trustworthy because keeping it current is part of every ADR change, not an afterthought.