Architecture Decision Records¶
The Design Invariants document captures what is true about Heddle's architecture and how it fails when violated. These ADRs capture the why — what alternatives were considered, what they would have cost, and why we rejected them.
ADRs are written once at decision time and not revised. If a decision changes, write a new ADR that supersedes the old one rather than editing the old text. This preserves the historical record of how the architecture evolved.
Format¶
Each ADR follows this skeleton:
- Status — Accepted (the default for everything here), Superseded by ADR-NNN, or Deprecated.
- Context — what problem the decision solves and what constraints shape it.
- Decision — the chosen approach, stated as a single declarative sentence.
- Alternatives considered — each option that was on the table, with the reason it lost.
- Consequences — what this decision enables and what it costs.
Index¶
| ID | Title | Pairs with |
|---|---|---|
| ADR-001 | Stateless workers, no process-local cache | Invariant 1 |
| ADR-002 | Deterministic router, no LLM in routing path | Invariant 2 |
| ADR-003 | Shallow JSON Schema for I/O contracts | Invariant 5 |
| ADR-004 | Skip-and-log on malformed messages, not crash | Invariant 8 |
| ADR-005 | Subscribe before publish for request-reply | Invariant 17 |
| ADR-006 | Tri-state synthesizer partition (succeeded / failed / in_flight) | commit 15a9af4 |
| ADR-007 | Council synthesis budget and 5s per-turn floor | council-howto |
| ADR-008 | Council execution paths share one budget helper | ADR-007 |
| ADR-009 | Per-goal state isolation, lockless concurrency | Invariant 7 |
| ADR-010 | Condition-evaluation defaults — fail-closed by default, env-gated legacy | Invariant 10 |
| ADR-011 | Pipeline parallel levels use FIRST_COMPLETED, not gather | Invariant 16 |
| ADR-012 | Drop message-level retry fields | Invariant 1 |
| ADR-013 | NATS auth model — multi-user, single account | runbook: nats-acl-configuration |
When to write a new ADR¶
Add an ADR when a design decision:
- Was non-obvious — a reasonable person could have picked differently.
- Will be revisited — future contributors will ask "why didn't we just X?" and need to find a real answer.
- Touches a load-bearing invariant — something that, if reversed, would break the framework's value proposition.
Don't write ADRs for matters of style, library choice that could go either way, or implementation details below the invariant level. Those belong in code comments or the Coding Guide.