Superseded by 0117: public types live in a types-only
./contracts entry per package and shared primitives in @stackra/contracts; there are no separate <domain>-contracts packages. Decisions 1, 3, 4 and 5 carry forward there.Context
A “shared types” folder becomes a dumping ground where every type two packages happen to use ends up. A contract is different: it is what another independently released component must know to talk to this one.Decision
- Membership test. A type belongs in a contracts package only if another independently deployed or released component needs it to communicate with this one. Two packages importing the same type is not the test; that is a shared utility.
-
Two kinds of boundary, two names.
- Protocol contracts carry request and response, event, error and envelope shapes, organised by contract category, with no behaviour and no runtime dependencies.
- Events are versioned. A breaking change is a new event type or version, published beside the old one until every consumer has moved.
- Services and apps depend on contracts, never on each other’s source (0003, 0010).
Consequences
- Wire compatibility is a property of one small package that reviewers can read.
- A type used by two packages but not crossing a boundary stays in its owner or in a utility.
Enforcement
Planned: a validator check that a*-contracts package has no runtime dependencies and no imports from a service or an app; guardian review of every new contracts package until then. The tier rule (0003) already stops a contracts package from importing a service.
Supersedes and sources
Supersedes: none. Sources: basaltadr/0035-contract-packages, std/contract-packages.