Decision Records
Architecture decision records: what was decided, what the alternative was, and what it costs. Each one is short and each one names a trade-off — an ADR with no downside section is a press release, not a record.
These sixteen are the decisions that shape the structure of the library and would be
expensive to reverse. They are not the complete set: PLAN.md §7 holds sixty-four resolved
decisions, most of which are API details rather than architecture (whether a configuring
method returns void or self, how a particular exception factory is spelled). Each ADR
below cites the §7 numbers it comes from, so the fuller reasoning is one hop away.
| # | Decision | Shapes |
|---|---|---|
| 0001 | Decorate a PSR-18 client | The whole library |
| 0002 | JSON cassettes, YAML opt-in | On-disk format |
| 0003 | Recording allowed locally, refused on CI | Safety default |
| 0004 | Interactions are snapshots, not PSR-7 objects | Core data model |
| 0005 | Session lock behind an optional interface | Persistence contract |
| 0006 | Configuration freezes at the session | Lifecycle |
| 0007 | Redaction normalises both sides | Matching + redaction |
| 0008 | Redaction is one rule class with a target enum | Hook pipeline |
| 0009 | A session never replays what it just recorded | Recording semantics |
| 0010 | Scoping splits session and manager | Cassette identity |
| 0011 | Guzzle integrates through withInner() satellites | Bridges |
| 0012 | Strict mode verified in close(), never __destruct | Lifecycle |
| 0013 | Large bodies move to sidecar files | Storage |
| 0014 | Decompression applies to the recording run too | Record/replay parity |
| 0015 | Only PSR-18 exception interfaces are recorded | Transport errors |
| 0016 | Laravel bridge in its own repository | Packaging |
The thread running through them
Several of these are the same decision applied in different places. Record and replay must be indistinguishable from the caller’s side produces 0014 (decompress on both runs), 0004 (rebuild responses rather than hand back stored ones) and 0009 (the recording run makes the requests the code actually makes).
State belongs to the session, not the object produces 0006, 0010 and 0011 — all three fall out of the bridges needing to construct clients freely without fragmenting the run.
Optional capability goes in a second interface produces
0005 and the ExplainsMismatch
treatment of matcher diagnostics: the minimum contract stays implementable, and the extra is
detected with instanceof.
Writing a new one
New work is either a PLAN.md §8 idea being promoted — in which case write the decision in
§7 first — or a correction to something already here. If the change alters one of the
sixteen above, amend that ADR with a Superseded by line rather than editing the decision
out of history.