3.0 KiB
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.