57 lines
3.1 KiB
Markdown
57 lines
3.1 KiB
Markdown
# ADR-WS-001: The WebSocket platform ships as packages in one leaf, with machine-checked boundaries
|
|
|
|
- Status: accepted
|
|
- Date: 2026-08-25
|
|
- Scope: `:adapter:inbound:websocket`
|
|
|
|
## Context
|
|
|
|
The realtime connection platform design models itself as eighteen Gradle modules under
|
|
`modules/websocket`, each with a declared purity grade and a declared set of allowed dependencies.
|
|
This repository's `src/config/architecture/modules.json` is a fail-closed registry that owns the
|
|
leaf list; adding eighteen leaves is a registry change of a size that needs its own decision, and
|
|
HARD-STOP #5 forbids doing it implicitly.
|
|
|
|
Three earlier platforms in this repository — JPA, GraphQL, and the HTTP platform — met the same
|
|
situation and resolved it the same way.
|
|
|
|
## Decision
|
|
|
|
The eighteen design modules ship as packages inside the single registered leaf. `WebSocketStableModule`
|
|
declares each one's package, purity grade and exact allowed edges, and `WebSocketModuleBoundaryTest`
|
|
scans the production tree and fails when the declaration and the tree disagree in either direction.
|
|
|
|
Three deviations from the design's module map were forced by the check and are recorded in
|
|
`docs/websocket/repository-adaptation.md`: `WebSocketSubprotocolName` moved to `core` and the codec
|
|
moved to its own FRAMEWORK_BOUND module, both to avoid cycles the design's placement created here;
|
|
and the `budget -> core` edge was inverted because `budget` imports nothing from `core`.
|
|
|
|
## Consequences
|
|
|
|
**The boundary is enforced, not documented.** Six violations were caught during implementation that
|
|
a document would not have: two would-be cycles, a duplicate module declaration where two ids claimed
|
|
one package, and three undeclared edges. The duplicate is the instructive one — with two ids on one
|
|
package, ownership depends on iteration order and one module's rules silently apply to nothing. A
|
|
guard against it is now part of the boundary test.
|
|
|
|
**The detector had a hole.** Its framework-import list named `com.fasterxml` (Jackson 2) and not
|
|
`tools.jackson` (Jackson 3), which is what Spring 7 actually uses — so a CORE module could have
|
|
imported a mapper unnoticed. Fixed here and in the HTTP platform, which shared the list.
|
|
|
|
**Promotion stays cheap.** Each enum constant is already shaped like a leaf specification, so
|
|
splitting one out later is a registry edit rather than an archaeology exercise.
|
|
|
|
**The design's own rules were kept where they cost something.** `core` names no framework, so the
|
|
same decisions serve both runtimes and are testable without a server; no Java class name reaches the
|
|
wire; the payload is an encoded string rather than a map; and handlers are given no way to write,
|
|
which is what makes ordering and backpressure guarantees rather than conventions.
|
|
|
|
## Alternatives considered
|
|
|
|
**Register eighteen leaves.** Faithful to the design and a large change to a fail-closed registry
|
|
for a platform that ships as one artifact either way. Rejected as disproportionate; the boundary
|
|
test provides the property the modules were for.
|
|
|
|
**Ship the modules as packages with no enforcement.** Cheapest, and it makes the boundary a claim.
|
|
The six violations found during implementation are the argument against it.
|