Enforce Architecture Decision Records
Require every ADR to carry a single status, real context, a decision, and consequences.
A decision record with an empty Consequences section is a decision nobody finished thinking about.
Architecture Decision Records are only useful when they're complete and honest: one clear status, the forces that drove the call, the decision itself, and what it costs. A contract beside the template keeps half-written ADRs out of the log.
The contract
<!-- mdv: document strict -->
<!-- mdv: choice required oneChecked -->
## Status
- [ ] Proposed
- [ ] Accepted
- [ ] Superseded
<!-- mdv: endchoice -->
<!-- mdv: block required minWords=15 noPlaceholder -->
## Context
What forces a decision, and what constraints bound it.
<!-- mdv: endblock -->
<!-- mdv: block required minWords=10 noPlaceholder -->
## Decision
What we are doing.
<!-- mdv: endblock -->
<!-- mdv: block required minWords=10 noPlaceholder -->
## Consequences
What becomes easier or harder as a result.
<!-- mdv: endblock -->document strict locks the section set and their order — exactly Status, Context, Decision, Consequences, nothing else. The choice oneChecked makes Status a single-select: precisely one of Proposed / Accepted / Superseded. Each prose section needs real substance (minWords) and no leftover template text (noPlaceholder).
What it catches
An ADR that's half-filled and out of shape:
## Status
- [ ] Proposed
- [ ] Accepted
- [ ] Superseded
## Context
We need to pick a logging approach soon.
## Decision
We will adopt structured JSON logging.
## Consequences
Dashboards get simpler over time.
## Notes
randomadr-0007.md:19 error [unexpected-section] The "Notes" section is not one the schema declares here.
adr-0007.md:3 error [need-exactly-one] The "Status" section needs exactly one box checked (found 0).
adr-0007.md:11 error [too-few-words] The "Context" section is too short (8 words).
adr-0007.md:17 error [too-few-words] The "Decision" section is too short (6 words).
adr-0007.md:23 error [too-few-words] The "Consequences" section is too short (5 words).No status chosen, three thin sections, and a stray Notes heading — five errors, exit 1. Fill it in honestly and it passes.
Run it in CI
Keep the contract as docs/adr/template.mdv.md and validate new records explicitly, or let the zero-config scan pair each NNNN-title.md with a sibling contract:
npx mediva check docs/adr/0007-structured-logging.md --schema docs/adr/template.mdv.mdVariations
- If your team writes ADRs in a fixed order but sometimes adds an optional
## Alternatives Considered, swapdocument strictfordocument noExtraSections(no order constraint) and declare the optional section withblock optional. - Add a
frontblock for machine-readable metadata —front date date=isoandfront id pattern=/^ADR-\d{4}$/— when an index generator reads the records. See Frontmatter. - To require the decision to cite a driving issue, add
issueKeyword=Refsto the Decision block — it checks the prose carries aRefs #NNreference and needs no--context. AddissueState=open(and pass--context) only if you also want CI to verify the issue is actually open.