56 lines
3.0 KiB
Markdown
56 lines
3.0 KiB
Markdown
# ADR-GRPC-001: The gRPC platform ships as a registered family, not as one adapter leaf
|
|
|
|
- Status: accepted
|
|
- Date: 2026-08-30
|
|
- Scope: `:grpc:*`, `:grpc-advanced:*`, `src/config/architecture/modules.json`
|
|
|
|
## Context
|
|
|
|
The two source plans describe a type-safe gRPC execution platform with its own API, SPI, adapters and
|
|
composition root: fifteen Stable modules under `modules/grpc` and sixteen Advanced ones under
|
|
`modules/grpc-advanced`, on Gradle Kotlin DSL, in package `io.backend.skeleton.grpc`, against
|
|
Spring Boot 4.1.
|
|
|
|
None of that layout exists here. This repository uses Groovy DSL, a fail-closed module registry that
|
|
owns the leaf list, package root `dev.caskeleton`, and Spring Boot 4.0.8. The plans anticipate this:
|
|
their last Global Constraint says that when the repository structure differs, file paths are remapped
|
|
and the public contracts, invariants and test meanings are not changed.
|
|
|
|
Two shapes were available. Fold the platform into the existing `:adapter:inbound:grpc` leaf as
|
|
packages — which is what the JPA, GraphQL, WebSocket and HTTP platforms did here — or register it as
|
|
a family the way `messaging:*` is registered.
|
|
|
|
## Decision
|
|
|
|
Register it as a family: twelve Stable leaves under `src/grpc/` and six Advanced ones under
|
|
`src/grpc-advanced/`.
|
|
|
|
The deciding property is that this is not a layer of this application. Root `CLAUDE.md` already
|
|
describes `messaging:*` as "a vendored messaging platform: a product with its own API, SPI, adapters
|
|
and composition boundary, not a layer of this application", and the gRPC platform is the same shape
|
|
for the same reason — the application is meant to reach it the way it reaches a library, through an
|
|
application-owned port. The four platforms that became packages are all layers of this application;
|
|
this one is not.
|
|
|
|
The split between `src/grpc/` and `src/grpc-advanced/` is not organisational. The Stable plan
|
|
requires that the Stable starter's build fail if it reaches an Advanced module, and separate Gradle
|
|
path prefixes make that a `verifyCleanArchitectureDependencies` failure rather than a review note:
|
|
`grpc-spring-boot-starter`'s registry entry names no advanced id, and it cannot acquire one silently.
|
|
|
|
## Consequences
|
|
|
|
**The registry grew from 44 leaves to 62.** That is a large registry change, made deliberately and in
|
|
one place. Every new leaf is `runtime_memberships: []`, so nothing ships until a second, explicit
|
|
decision moves it.
|
|
|
|
**The advanced boundary is checked twice.** Once by the registry at build time, and once by
|
|
`GrpcStableBuildInvariant` at runtime, because a fat jar or a shaded artifact is assembled by
|
|
something the registry never sees.
|
|
|
|
**Four testkit modules became four test lanes.** The plan's split exists so in-process results cannot
|
|
be mistaken for network results; this repository expresses that with `ca.strict-test-lane`, whose
|
|
lanes fail when they discover nothing and never serve an up-to-date result. `GrpcEvidenceGrade` keeps
|
|
the same rule inside the code, so a report cannot cite a contract run as transport evidence.
|
|
|
|
**Codegen is not wired.** See ADR-GRPC-002.
|