Decision Record Discipline
Every strange piece of code was once obvious. Someone knew why the retry count is
7, why this service does not call that one directly, why the check nobody
understands must run before the write. The knowledge existed for about six weeks
and then evaporated, and what remains is a line of code that looks removable.
The cost is paid by a stranger — often you, later — who must choose between two
bad options: delete it and find out why it was there, or keep it forever out of
superstition. software-archaeology is the discipline for surviving that
situation; this skill is the discipline that prevents creating it.
A decision record is not documentation of what the system does — the code says
that, and says it more accurately. It records what was true when the choice was
made, and what would make the choice wrong.
Composes with: software-archaeology and codebase-health-assessment (fossils
are undocumented decisions), abductive-engineering (a decision is a hypothesis
about the future), irreversible-action-gate (one-way vs two-way doors),
claim-provenance-discipline (that one preserves findings in transit; this one
preserves choices over time), daubert-defensible-writing (say what you knew,
not what you hoped).
Part 1 — The six fields, and why five of them get dropped
Almost every real-world "decision doc" records only the first field. The other
five are the ones with future value.
| Field |
What it captures |
What breaks without it |
| Decision |
What we are doing |
— (this is the one everyone writes) |
| Forces |
The constraints that were real at the time: scale, deadline, team size, what the platform supported, what we did not yet know |
The future reader judges a 2024 decision by 2027 conditions and concludes the author was incompetent |
| Alternatives rejected |
Each option considered, and the specific reason it lost |
The same debate is re-run every eighteen months, from scratch, by people who assume it was never had |
| Assumption |
The belief the decision depends on ("traffic stays single-region", "the vendor keeps this API") |
The assumption fails silently and nobody connects the outage to the choice that assumed it |
| Reversibility |
One-way door or two-way door, and the cost of undoing |
Cheap decisions get expensive deliberation; expensive ones get made in a standup |
| Revisit trigger |
The observable condition that should reopen this |
The decision becomes doctrine — permanent because it is old, not because it is right |
The rejected alternatives are the load-bearing part. They do double duty:
they stop re-litigation, and — more valuable — they tell a future reader whether
their new idea was already considered and under what conditions it lost. "We
rejected event sourcing because the team had no operational experience with it
and the deadline was eight weeks" ages into a reopenable decision. "We chose a
relational schema" ages into nothing.
Part 2 — Reversibility sets the ceremony
Not every choice deserves a document. Match the effort to how hard it is to undo
(the same axis as irreversible-action-gate, applied to design):
- Two-way door — changed in an afternoon, contained inside one module. Decide
fast, record in a code comment or the PR description, move on. Writing a formal
record here is waste that trains people to ignore records.
- One-way-ish — a data model, a public API shape, a persisted format, a
dependency that will spread. Undoing means a migration or a coordinated change
across consumers. This is where records earn their cost.
- One-way door — a protocol other parties implement against, an external
commitment, a data-retention or privacy choice, anything already shipped to
users or stored irreversibly. Record before deciding, and treat the record as
part of the deliverable.
A useful test: if this turns out wrong, who finds out and how? If the answer is
"a stranger, in an incident, in two years", write the record.
Part 3 — Record the non-decisions too
The hardest knowledge to reconstruct is why something doesn't exist. Nothing in
the codebase points at it, so it is invisible, and it gets proposed again every
year and sometimes built.
Worth recording as first-class decisions:
- "We deliberately did not build X" — and why. The absence of a caching layer
can be a considered choice or an oversight, and no reader can tell which.
- "We accepted this limitation" — the known-slow path, the case not handled,
the tradeoff taken on purpose. Otherwise it will be "fixed" by someone who
thinks they found a bug, and the reason it existed will resurface as a
regression.
- "We tried this and it failed" — the approach that seemed right and did not
work, with the evidence. This is the single most expensive knowledge in an
organization to regenerate, and the least likely to be written down, because
failed attempts feel like something to move past rather than a result.
Part 4 — Anchor the record to the code
A record nobody finds at the moment of danger has no effect. The moment of danger
is when someone is reading the line and deciding to delete it.
- Put a short pointer in the code, at the surprising line:
# retry=7 and the 400ms backoff: vendor rate limiter, see ADR-0031. Do not lower without a load test. The comment explains why, never what — a comment restating the code
rots and misleads; a comment carrying a reason cannot be derived from anywhere
else.
- Keep the record in the repository, versioned alongside the code it governs.
A decision in a wiki, a ticket, or a chat thread is a decision on a different
clock from the code — and chat is not a record, it is a transcript of a
conversation whose conclusion may never have been stated.
- Give it a stable ID, and reference that ID from the code, the PR, and any
later record that supersedes it.
- Supersede, never delete. A reversed decision keeps its record and gains a
pointer to the one replacing it — including what changed to justify the
reversal. That chain is how an organization learns instead of oscillating.
Part 5 — Write it at the moment, and write it honestly
Timing. The cheapest moment is while deciding; the context is free and
complete. A week later you will remember the conclusion and reconstruct the
reasoning — and reconstruction is where the record turns into an argument for
what you already did. A record written afterwards drops the alternatives that
were close calls and inflates the confidence of the winner.
Honesty. Two failure modes, both common:
- Rationalization — recording the justification rather than the reason. If the
real driver was a deadline, a team preference, or an existing contract, write
that. "We chose the boring option because the team ships it confidently" is a
legitimate, defensible reason, and it is far more useful to a future reader than
an invented technical narrative that does not survive scrutiny.
- False certainty — a record that reads as if the outcome were known. Say what
was uncertain and how you decided under it. The reader's most useful question is
"what did they not know", and a confident record answers it with silence.
Record the losing argument's best point. One line: the strongest thing the
rejected option had going for it. When conditions change, that is the sentence
that tells you the decision is worth reopening — and it is proof the alternative
was actually considered rather than dismissed.
Template
# ADR-00NN — <decision, stated as an action>
Date: <when> Status: proposed | accepted | superseded by ADR-00MM
Reversibility: two-way | one-way-ish (cost: <migration/coordination>) | one-way
## Forces at the time
<constraints that were real then: scale, deadline, team, platform, unknowns>
## Decision
<what we are doing, specifically enough to check compliance against it>
## Alternatives rejected
- **<option>** — rejected because <specific reason>. Best argument for it: <one line>.
- **<option>** — rejected because <specific reason>. Best argument for it: <one line>.
## Assumption this rests on
<the belief that must hold. If it fails, this decision is wrong, not just dated.>
## Consequences
Accepted now: <what gets worse on purpose>
Deferred: <what we are choosing to deal with later>
## Revisit trigger
<observable condition: "if p99 write latency exceeds X", "if we pass N tenants",
"if the vendor ships Y", "review by <date> if none of the above fired">
## Anchored at
<code paths carrying a pointer comment to this ADR>
Deliverable checklist
- Is the decision stated specifically enough that a reader could tell whether the code still complies with it?
- Are the forces described as they were then, including what was unknown?
- Does every rejected alternative carry a specific reason and its best argument?
- Is the load-bearing assumption named, so its failure is attributable?
- Is reversibility classified, and does the ceremony match it?
- Is there a revisit trigger that is observable, not "revisit someday"?
- Are the non-decisions recorded — what we chose not to build, what we accepted, what failed?
- Does the surprising code carry a pointer comment to the record?
- Is the record honest about the real driver, including non-technical ones?
How to respond when this skill is active
- When a decision is being made, ask for the forces, the alternatives, and the revisit trigger before drafting anything — those are the fields that will be missing later.
- Classify reversibility first and scale the ceremony to it; say explicitly when a choice is a two-way door that needs no document.
- Push to record the rejected options with their best arguments. A record listing only the winner is a press release.
- Record non-decisions and accepted limitations as first-class entries; they are invisible in code and get "fixed" by strangers.
- Add the pointer comment at the surprising line, explaining why and never what.
- Write it now, at the moment of deciding. Flag reconstruction risk when asked to write a record for a decision made weeks ago, and mark which parts are recalled rather than recorded.
- Supersede rather than delete, and state what changed to justify the reversal.
- When asked "why is this here?" and nobody knows, treat that as the trigger to create the record now — with the honest answer being "unknown; preserved pending evidence" (
software-archaeology).
1---2name: decision-record-discipline3description: Decision Record Discipline4---56# Decision Record Discipline78Every strange piece of code was once obvious. Someone knew why the retry count is97, why this service does not call that one directly, why the check nobody10understands must run before the write. The knowledge existed for about six weeks11and then evaporated, and what remains is a line of code that looks removable.1213The cost is paid by a stranger — often you, later — who must choose between two14bad options: delete it and find out why it was there, or keep it forever out of15superstition. `software-archaeology` is the discipline for surviving that16situation; **this skill is the discipline that prevents creating it**.1718A decision record is not documentation of *what* the system does — the code says19that, and says it more accurately. It records **what was true when the choice was20made, and what would make the choice wrong**.2122Composes with: `software-archaeology` and `codebase-health-assessment` (fossils23are undocumented decisions), `abductive-engineering` (a decision is a hypothesis24about the future), `irreversible-action-gate` (one-way vs two-way doors),25`claim-provenance-discipline` (that one preserves findings in transit; this one26preserves choices over time), `daubert-defensible-writing` (say what you knew,27not what you hoped).2829---3031## Part 1 — The six fields, and why five of them get dropped3233Almost every real-world "decision doc" records only the first field. The other34five are the ones with future value.3536| Field | What it captures | What breaks without it |37|---|---|---|38| **Decision** | What we are doing | — (this is the one everyone writes) |39| **Forces** | The constraints that were real *at the time*: scale, deadline, team size, what the platform supported, what we did not yet know | The future reader judges a 2024 decision by 2027 conditions and concludes the author was incompetent |40| **Alternatives rejected** | Each option considered, and the specific reason it lost | The same debate is re-run every eighteen months, from scratch, by people who assume it was never had |41| **Assumption** | The belief the decision depends on ("traffic stays single-region", "the vendor keeps this API") | The assumption fails silently and nobody connects the outage to the choice that assumed it |42| **Reversibility** | One-way door or two-way door, and the cost of undoing | Cheap decisions get expensive deliberation; expensive ones get made in a standup |43| **Revisit trigger** | The observable condition that should reopen this | The decision becomes doctrine — permanent because it is old, not because it is right |4445**The rejected alternatives are the load-bearing part.** They do double duty:46they stop re-litigation, and — more valuable — they tell a future reader whether47their new idea was already considered and under what conditions it lost. "We48rejected event sourcing because the team had no operational experience with it49and the deadline was eight weeks" ages into a *reopenable* decision. "We chose a50relational schema" ages into nothing.5152---5354## Part 2 — Reversibility sets the ceremony5556Not every choice deserves a document. Match the effort to how hard it is to undo57(the same axis as `irreversible-action-gate`, applied to design):5859- **Two-way door** — changed in an afternoon, contained inside one module. Decide60 fast, record in a code comment or the PR description, move on. Writing a formal61 record here is waste that trains people to ignore records.62- **One-way-ish** — a data model, a public API shape, a persisted format, a63 dependency that will spread. Undoing means a migration or a coordinated change64 across consumers. **This is where records earn their cost.**65- **One-way door** — a protocol other parties implement against, an external66 commitment, a data-retention or privacy choice, anything already shipped to67 users or stored irreversibly. Record before deciding, and treat the record as68 part of the deliverable.6970A useful test: *if this turns out wrong, who finds out and how?* If the answer is71"a stranger, in an incident, in two years", write the record.7273---7475## Part 3 — Record the non-decisions too7677The hardest knowledge to reconstruct is why something *doesn't* exist. Nothing in78the codebase points at it, so it is invisible, and it gets proposed again every79year and sometimes built.8081Worth recording as first-class decisions:8283- **"We deliberately did not build X"** — and why. The absence of a caching layer84 can be a considered choice or an oversight, and no reader can tell which.85- **"We accepted this limitation"** — the known-slow path, the case not handled,86 the tradeoff taken on purpose. Otherwise it will be "fixed" by someone who87 thinks they found a bug, and the reason it existed will resurface as a88 regression.89- **"We tried this and it failed"** — the approach that seemed right and did not90 work, with the evidence. This is the single most expensive knowledge in an91 organization to regenerate, and the least likely to be written down, because92 failed attempts feel like something to move past rather than a result.9394---9596## Part 4 — Anchor the record to the code9798A record nobody finds at the moment of danger has no effect. The moment of danger99is when someone is reading the line and deciding to delete it.100101- Put a short **pointer in the code**, at the surprising line: `# retry=7 and the102 400ms backoff: vendor rate limiter, see ADR-0031. Do not lower without a load103 test.` The comment explains *why*, never *what* — a comment restating the code104 rots and misleads; a comment carrying a reason cannot be derived from anywhere105 else.106- Keep the record **in the repository**, versioned alongside the code it governs.107 A decision in a wiki, a ticket, or a chat thread is a decision on a different108 clock from the code — and chat is not a record, it is a transcript of a109 conversation whose conclusion may never have been stated.110- Give it a **stable ID**, and reference that ID from the code, the PR, and any111 later record that supersedes it.112- **Supersede, never delete.** A reversed decision keeps its record and gains a113 pointer to the one replacing it — including *what changed* to justify the114 reversal. That chain is how an organization learns instead of oscillating.115116---117118## Part 5 — Write it at the moment, and write it honestly119120**Timing.** The cheapest moment is while deciding; the context is free and121complete. A week later you will remember the conclusion and reconstruct the122reasoning — and reconstruction is where the record turns into an argument for123what you already did. A record written afterwards drops the alternatives that124were close calls and inflates the confidence of the winner.125126**Honesty.** Two failure modes, both common:127128- *Rationalization* — recording the justification rather than the reason. If the129 real driver was a deadline, a team preference, or an existing contract, write130 that. "We chose the boring option because the team ships it confidently" is a131 legitimate, defensible reason, and it is far more useful to a future reader than132 an invented technical narrative that does not survive scrutiny.133- *False certainty* — a record that reads as if the outcome were known. Say what134 was uncertain and how you decided under it. The reader's most useful question is135 "what did they not know", and a confident record answers it with silence.136137**Record the losing argument's best point.** One line: the strongest thing the138rejected option had going for it. When conditions change, that is the sentence139that tells you the decision is worth reopening — and it is proof the alternative140was actually considered rather than dismissed.141142---143144## Template145146```markdown147# ADR-00NN — <decision, stated as an action>148Date: <when> Status: proposed | accepted | superseded by ADR-00MM149Reversibility: two-way | one-way-ish (cost: <migration/coordination>) | one-way150151## Forces at the time152<constraints that were real then: scale, deadline, team, platform, unknowns>153154## Decision155<what we are doing, specifically enough to check compliance against it>156157## Alternatives rejected158- **<option>** — rejected because <specific reason>. Best argument for it: <one line>.159- **<option>** — rejected because <specific reason>. Best argument for it: <one line>.160161## Assumption this rests on162<the belief that must hold. If it fails, this decision is wrong, not just dated.>163164## Consequences165Accepted now: <what gets worse on purpose>166Deferred: <what we are choosing to deal with later>167168## Revisit trigger169<observable condition: "if p99 write latency exceeds X", "if we pass N tenants",170"if the vendor ships Y", "review by <date> if none of the above fired">171172## Anchored at173<code paths carrying a pointer comment to this ADR>174```175176---177178## Deliverable checklist179180- Is the decision stated specifically enough that a reader could tell whether the code still complies with it?181- Are the forces described as they were *then*, including what was unknown?182- Does every rejected alternative carry a specific reason and its best argument?183- Is the load-bearing assumption named, so its failure is attributable?184- Is reversibility classified, and does the ceremony match it?185- Is there a revisit trigger that is observable, not "revisit someday"?186- Are the non-decisions recorded — what we chose not to build, what we accepted, what failed?187- Does the surprising code carry a pointer comment to the record?188- Is the record honest about the real driver, including non-technical ones?189190---191192## How to respond when this skill is active193194- When a decision is being made, ask for the forces, the alternatives, and the revisit trigger before drafting anything — those are the fields that will be missing later.195- Classify reversibility first and scale the ceremony to it; say explicitly when a choice is a two-way door that needs no document.196- Push to record the rejected options with their best arguments. A record listing only the winner is a press release.197- Record non-decisions and accepted limitations as first-class entries; they are invisible in code and get "fixed" by strangers.198- Add the pointer comment at the surprising line, explaining why and never what.199- Write it now, at the moment of deciding. Flag reconstruction risk when asked to write a record for a decision made weeks ago, and mark which parts are recalled rather than recorded.200- Supersede rather than delete, and state what changed to justify the reversal.201- When asked "why is this here?" and nobody knows, treat that as the trigger to create the record now — with the honest answer being "unknown; preserved pending evidence" (`software-archaeology`).