79 KiB
타입 안전 gRPC Advanced Capability Expansion Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Stable Unary·Server Streaming 플랫폼을 변경하지 않고 Edition 2024/2026, Client/Bidirectional Streaming, Manual Flow Control, Hedging, Custom Resolver·Load Balancer, xDS, gRPC-Web, Servlet, Spring Integration, Reactor·Kotlin과 Channel Diagnostics를 독립적으로 검증·승격할 수 있는 Advanced capability 계층을 구축한다.
Architecture: 모든 Advanced 기능은 modules/grpc-advanced에 격리하고 명시적 feature flag를 요구한다. Stable method policy, deadline, execution evidence, security, status, metadata, observability와 streaming guardrail을 그대로 소비하며 raw gRPC escape hatch를 제공하지 않는다. 각 capability는 자체 Compatibility·Security·Fault·Performance·Soak gate를 통과한 뒤에만 Advanced Stable로 승격된다.
Tech Stack: Java 21, Spring Boot 4.1 BOM, Boot-managed gRPC Java/Protobuf, Protobuf Editions, grpc-xds, grpc-web proxy/Envoy, Servlet HTTP/2, Spring Integration 7.1, Project Reactor, Kotlin coroutines/Flow, Channelz/CSDS, JUnit 5, AssertJ, Testcontainers, Toxiproxy.
Global Constraints
- Stable Task 1–53과 Stable Release Gate가 먼저 완료돼야 한다.
- Advanced module root는
modules/grpc-advanced이다. - Root package는
io.backend.skeleton.grpc.advanced이다. - 모든 capability는
backend.grpc.advanced.*아래의 명시적 feature flag를 요구한다. - Stable starter는 Advanced module에 compile/runtime dependency를 갖지 않는다.
- Edition 2024는 opt-in이고 Edition 2026은 Watch/Experimental이다.
- Client Streaming과 Bidirectional Streaming은 session·sequence·dedup·resume 계약 없이 활성화하지 않는다.
- Manual Flow Control이 raw StreamObserver를 application에 직접 반환해서는 안 된다.
- Hedging은 READ_ONLY Unary만 허용한다.
- Custom Resolver와 Load Balancer는 Stable channel security·retry owner·observability를 우회하지 않는다.
- xDS는 proxyless GR3 Experimental로 유지한다.
- gRPC-Web은 Unary와 Server Streaming만 지원한다.
- Client Streaming·Bidirectional Streaming의 gRPC-Web 지원을 선언하지 않는다.
- Servlet transport는 Netty certification을 대체하지 않는다.
- Spring Integration bridge는 Generated Stub·Service 타입 안전 계약을 대체하지 않는다.
- Reactor와 Kotlin adapter는 Stable Core 타입과 execution evidence를 유지한다.
- Channelz·CSDS는 관리자 전용이며 credential·metadata·payload를 노출하지 않는다.
- 각 capability는 독립 승격이 가능해야 한다.
- 모든 task는 red-green TDD와 독립 commit으로 끝난다.
Execution Baseline
Stable Task 1–53
→ Advanced Task 1–18
Advanced Module Map
modules/grpc-advanced/
├── grpc-advanced-bootstrap
├── grpc-edition-2024
├── grpc-edition-2026-experimental
├── grpc-client-streaming
├── grpc-bidi-streaming
├── grpc-manual-flow-control
├── grpc-hedging
├── grpc-custom-resolver
├── grpc-custom-load-balancer
├── grpc-xds
├── grpc-web
├── grpc-servlet-compat
├── grpc-integration-bridge
├── grpc-reactor
├── grpc-kotlin
└── grpc-channel-diagnostics
Capability Classification
| Capability | Initial grade | Stable default |
|---|---|---|
| Edition 2024 | Advanced opt-in | No |
| Edition 2026 | Watch/Experimental | No |
| Client Streaming | Advanced | No |
| Bidirectional Streaming | Advanced | No |
| Manual Flow Control | Advanced | No |
| Hedging | Experimental | No |
| Custom Resolver | Advanced | No |
| Custom Load Balancer | Experimental | No |
| xDS | Experimental | No |
| gRPC-Web | Advanced compatibility | No |
| Servlet HTTP/2 | Compatibility | No |
| Spring Integration bridge | Optional | No |
| Reactor adapter | Optional Advanced | No |
| Kotlin adapter | Optional Advanced | No |
| Channelz/CSDS diagnostics | Admin Advanced | No |
Delivery Phases
| Phase | Tasks | Result |
|---|---|---|
| Boundary·Edition | 1–3 | Feature isolation and schema evaluation lanes |
| Streaming | 4–7 | Client/Bidi session, checkpoint and manual flow control |
| Resilience·Discovery | 8–11 | Hedging, custom resolver/LB and xDS |
| Compatibility Bridges | 12–16 | gRPC-Web, Servlet, Integration, Reactor, Kotlin |
| Diagnostics·Promotion | 17–18 | Admin diagnostics, infrastructure testkit and promotion gate |
Task 1: Advanced Module Boundary와 Feature Flag
Files:
- Modify:
settings.gradle.kts - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedCapability.java - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedFeatureFlags.java - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedModuleGuard.java - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedCapabilityDisabledException.java - Create:
modules/grpc-advanced/build.gradle.kts - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/build.gradle.kts - Test:
modules/grpc-advanced/grpc-advanced-bootstrap/src/test/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedModuleGuardTest.java
Interfaces:
- Consumes: Stable Task 53 release evidence와 Spring Boot environment.
- Produces: Advanced·Experimental capability가 Stable starter에 자동 유입되지 않도록 하는 dependency·feature flag 경계.
Implementation requirements:
-
모든 capability는
backend.grpc.advanced.*아래의 명시적 flag를 요구한다. -
Stable starter는 Advanced module에 compile/runtime dependency를 갖지 않는다.
-
capability grade는
ADVANCED_STABLE,EXPERIMENTAL,WATCH,DISABLED로 구분한다. -
production에서 Experimental capability는 별도 승인 profile 없이는 시작되지 않는다.
-
Advanced module은 Stable public types를 소비하지만 Stable guardrail을 우회하지 않는다.
-
Step 1: Write the failing test
class GrpcAdvancedModuleGuardTest {
@org.junit.jupiter.api.Test
void disabledCapabilityCannotStart() {
var guard = new GrpcAdvancedModuleGuard(
GrpcAdvancedFeatureFlags.disabled());
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> guard.requireEnabled(
GrpcAdvancedCapability.XDS))
.isInstanceOf(
GrpcAdvancedCapabilityDisabledException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-advanced-bootstrap:test --tests 'io.backend.skeleton.grpc.advanced.bootstrap.GrpcAdvancedModuleGuardTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public enum GrpcAdvancedCapability {
EDITION_2024, EDITION_2026,
CLIENT_STREAMING, BIDI_STREAMING,
MANUAL_FLOW_CONTROL, HEDGING,
CUSTOM_RESOLVER, CUSTOM_LOAD_BALANCER,
XDS, GRPC_WEB, SERVLET_COMPAT,
SPRING_INTEGRATION, REACTOR, KOTLIN,
CHANNEL_DIAGNOSTICS
}
public record GrpcAdvancedFeatureFlags(
java.util.Set<GrpcAdvancedCapability> enabled) {
public static GrpcAdvancedFeatureFlags disabled() {
return new GrpcAdvancedFeatureFlags(java.util.Set.of());
}
public boolean isEnabled(GrpcAdvancedCapability capability) {
return enabled.contains(capability);
}
}
public final class GrpcAdvancedModuleGuard {
private final GrpcAdvancedFeatureFlags flags;
public GrpcAdvancedModuleGuard(
GrpcAdvancedFeatureFlags flags) {
this.flags = flags;
}
public void requireEnabled(
GrpcAdvancedCapability capability) {
if (!flags.isEnabled(capability)) {
throw new GrpcAdvancedCapabilityDisabledException(
capability.name());
}
}
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-advanced-bootstrap:test --tests 'io.backend.skeleton.grpc.advanced.bootstrap.GrpcAdvancedModuleGuardTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedCapability.java' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedFeatureFlags.java' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedModuleGuard.java' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedCapabilityDisabledException.java' 'modules/grpc-advanced/build.gradle.kts' 'modules/grpc-advanced/grpc-advanced-bootstrap/build.gradle.kts' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/test/java/io/backend/skeleton/grpc/advanced/bootstrap/GrpcAdvancedModuleGuardTest.java' 'settings.gradle.kts'
git commit -m "build: isolate grpc advanced modules"
Task 2: Protobuf Edition 2024 Opt-in Lane
Files:
- Create:
modules/grpc-advanced/grpc-edition-2024/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2024Policy.java - Create:
modules/grpc-advanced/grpc-edition-2024/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEditionCompatibilityReport.java - Create:
modules/grpc-advanced/grpc-edition-2024/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2024Gate.java - Create:
modules/grpc-advanced/grpc-edition-2024/src/main/proto/edition2024/compatibility.proto - Create:
modules/grpc-advanced/grpc-edition-2024/buf.yaml - Test:
modules/grpc-advanced/grpc-edition-2024/src/test/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2024GateTest.java
Interfaces:
- Consumes: Stable proto3+optional descriptor, consumer language/toolchain fixtures와 Buf gate.
- Produces: Edition 2024 schema를 Stable 기본값과 분리하여 검증·비교하는 Advanced lane.
Implementation requirements:
-
Edition 2024는 module-level opt-in으로만 사용한다.
-
Java뿐 아니라 지원 consumer language/toolchain compile evidence를 요구한다.
-
proto3+optional과 wire/source/JSON behavior를 비교한다.
-
public service를 Edition 2024로 이동하려면 승격 ADR과 consumer migration이 필요하다.
-
Edition 2024 failure가 Stable proto3 release를 차단하지 않되 promotion을 차단한다.
-
Step 1: Write the failing test
class GrpcEdition2024GateTest {
@org.junit.jupiter.api.Test
void missingConsumerEvidenceBlocksPromotion() {
var gate = new GrpcEdition2024Gate();
org.assertj.core.api.Assertions.assertThat(
gate.promotable(new GrpcEditionCompatibilityReport(
true, false, true))).isFalse();
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-edition-2024:test --tests 'io.backend.skeleton.grpc.advanced.edition.GrpcEdition2024GateTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcEditionCompatibilityReport(
boolean javaCompatible,
boolean consumerLanguagesCompatible,
boolean jsonCompatible) {}
public final class GrpcEdition2024Gate {
public boolean promotable(
GrpcEditionCompatibilityReport report) {
return report.javaCompatible()
&& report.consumerLanguagesCompatible()
&& report.jsonCompatible();
}
}
public record GrpcEdition2024Policy(
boolean explicitOptIn,
boolean stableDefault) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-edition-2024:test --tests 'io.backend.skeleton.grpc.advanced.edition.GrpcEdition2024GateTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-edition-2024/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2024Policy.java' 'modules/grpc-advanced/grpc-edition-2024/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEditionCompatibilityReport.java' 'modules/grpc-advanced/grpc-edition-2024/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2024Gate.java' 'modules/grpc-advanced/grpc-edition-2024/src/main/proto/edition2024/compatibility.proto' 'modules/grpc-advanced/grpc-edition-2024/buf.yaml' 'modules/grpc-advanced/grpc-edition-2024/src/test/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2024GateTest.java'
git commit -m "test: add protobuf edition 2024 lane"
Task 3: Protobuf Edition 2026 Watch Lane
Files:
- Create:
modules/grpc-advanced/grpc-edition-2026-experimental/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026Status.java - Create:
modules/grpc-advanced/grpc-edition-2026-experimental/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026WatchReport.java - Create:
modules/grpc-advanced/grpc-edition-2026-experimental/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026Guard.java - Test:
modules/grpc-advanced/grpc-edition-2026-experimental/src/test/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026GuardTest.java
Interfaces:
- Consumes: Task 2 Edition 2024 report와 current Protobuf toolchain metadata.
- Produces: released-edition 상태와 toolchain support가 확정되기 전 Stable 사용을 차단하는 Watch lane.
Implementation requirements:
-
Edition 2026은
WATCH또는EXPERIMENTAL상태만 가진다. -
official release status, protoc support, Buf support, Java/runtime support를 분리 기록한다.
-
Stable public contract source로 사용하지 않는다.
-
CI failure는 watch report를 생성하지만 Stable build와 분리한다.
-
승격은 별도 ADR와 complete cross-language evidence를 요구한다.
-
Step 1: Write the failing test
class GrpcEdition2026GuardTest {
@org.junit.jupiter.api.Test
void edition2026CannotBeStable() {
var guard = new GrpcEdition2026Guard();
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> guard.requireStable(
GrpcEdition2026Status.WATCH))
.isInstanceOf(IllegalStateException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-edition-2026-experimental:test --tests 'io.backend.skeleton.grpc.advanced.edition.GrpcEdition2026GuardTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public enum GrpcEdition2026Status {
WATCH, EXPERIMENTAL
}
public final class GrpcEdition2026Guard {
public void requireStable(
GrpcEdition2026Status status) {
throw new IllegalStateException(
"Edition 2026 is not a Stable contract");
}
}
public record GrpcEdition2026WatchReport(
boolean officiallyReleased,
boolean protocSupported,
boolean bufSupported,
boolean javaSupported) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-edition-2026-experimental:test --tests 'io.backend.skeleton.grpc.advanced.edition.GrpcEdition2026GuardTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-edition-2026-experimental/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026Status.java' 'modules/grpc-advanced/grpc-edition-2026-experimental/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026WatchReport.java' 'modules/grpc-advanced/grpc-edition-2026-experimental/src/main/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026Guard.java' 'modules/grpc-advanced/grpc-edition-2026-experimental/src/test/java/io/backend/skeleton/grpc/advanced/edition/GrpcEdition2026GuardTest.java'
git commit -m "test: track protobuf edition 2026"
Task 4: Client Streaming Session·Sequence Contract
Files:
- Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamSessionId.java - Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamMessage.java - Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamPolicy.java - Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamState.java - Test:
modules/grpc-advanced/grpc-client-streaming/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamPolicyTest.java
Interfaces:
- Consumes: Stable method policy, deadline, metadata, execution evidence와 generated client-streaming RPC.
- Produces: session ID, client sequence, half-close, server result를 명시하는 client-streaming contract.
Implementation requirements:
-
각 stream message는 session generation과 monotonic client sequence를 가진다.
-
half-close 이후 새 message를 거부한다.
-
전체 stream을 transparent retry하지 않는다.
-
server final response 전에 일부 message가 적용됐을 수 있음을 evidence로 보존한다.
-
stream max duration, idle timeout, message rate와 in-flight limit을 요구한다.
-
Step 1: Write the failing test
class GrpcClientStreamPolicyTest {
@org.junit.jupiter.api.Test
void duplicateOrDecreasingSequenceIsRejected() {
var policy = new GrpcClientStreamPolicy();
policy.accept(1);
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> policy.accept(1))
.isInstanceOf(IllegalArgumentException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-client-streaming:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcClientStreamPolicyTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcClientStreamSessionId(String value) {}
public record GrpcClientStreamMessage<T>(
GrpcClientStreamSessionId sessionId,
long sequence,
T payload) {}
public final class GrpcClientStreamPolicy {
private long last;
public void accept(long sequence) {
if (sequence <= last) {
throw new IllegalArgumentException(
"client stream sequence must increase");
}
last = sequence;
}
}
public enum GrpcClientStreamState {
OPEN, HALF_CLOSED, COMPLETED, CANCELLED, UNKNOWN
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-client-streaming:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcClientStreamPolicyTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamSessionId.java' 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamMessage.java' 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamPolicy.java' 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamState.java' 'modules/grpc-advanced/grpc-client-streaming/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamPolicyTest.java'
git commit -m "feat: define grpc client streaming sessions"
Task 5: Client Streaming Dedup·Checkpoint·Resume
Files:
- Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamCheckpoint.java - Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientMessageDeduplicator.java - Create:
modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamResumeDecision.java - Test:
modules/grpc-advanced/grpc-client-streaming/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientMessageDeduplicatorTest.java
Interfaces:
- Consumes: Task 4 client stream session and application checkpoint storage.
- Produces: 재연결 시 client message 중복을 제거하고 last applied sequence에서 resume하는 contract.
Implementation requirements:
-
dedup identity는 stream session + sequence다.
-
checkpoint는 application side effect와 가능한 한 같은 transaction에 저장한다.
-
checkpoint 이전 duplicate는 replay 결과를 반환하거나 무시한다.
-
history·session이 만료되면 새 stream/full resync를 요구한다.
-
transport ACK와 application applied checkpoint를 구분한다.
-
Step 1: Write the failing test
class GrpcClientMessageDeduplicatorTest {
@org.junit.jupiter.api.Test
void alreadyAppliedSequenceIsDuplicate() {
var deduplicator = new GrpcClientMessageDeduplicator(10);
org.assertj.core.api.Assertions.assertThat(
deduplicator.accept(9)).isFalse();
org.assertj.core.api.Assertions.assertThat(
deduplicator.accept(11)).isTrue();
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-client-streaming:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcClientMessageDeduplicatorTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcClientStreamCheckpoint(
String sessionId,
long lastAppliedSequence,
String businessRevision) {}
public final class GrpcClientMessageDeduplicator {
private long lastApplied;
public GrpcClientMessageDeduplicator(long lastApplied) {
this.lastApplied = lastApplied;
}
public boolean accept(long sequence) {
if (sequence <= lastApplied) {
return false;
}
lastApplied = sequence;
return true;
}
}
public enum GrpcClientStreamResumeDecision {
RESUME, START_NEW, FULL_RESYNC_REQUIRED
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-client-streaming:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcClientMessageDeduplicatorTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamCheckpoint.java' 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientMessageDeduplicator.java' 'modules/grpc-advanced/grpc-client-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientStreamResumeDecision.java' 'modules/grpc-advanced/grpc-client-streaming/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcClientMessageDeduplicatorTest.java'
git commit -m "feat: add grpc client stream resume"
Task 6: Bidirectional Streaming Dual Sequence·Lifecycle
Files:
- Create:
modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiSession.java - Create:
modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiDirectionState.java - Create:
modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiSequenceTracker.java - Create:
modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiResumeState.java - Test:
modules/grpc-advanced/grpc-bidi-streaming/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiSequenceTrackerTest.java
Interfaces:
- Consumes: Tasks 4–5 client stream contract와 Stable server stream envelope.
- Produces: client→server와 server→client sequence·flow-control·resume를 독립적으로 관리하는 bidi session.
Implementation requirements:
-
양 방향 sequence를 하나의 counter로 합치지 않는다.
-
각 방향의 half-close와 cancellation을 독립적으로 기록한다.
-
양 방향 bounded queue와 single writer를 사용한다.
-
resume token은 client applied/server applied sequence를 모두 보존한다.
-
session generation mismatch는 full session restart를 요구한다.
-
Step 1: Write the failing test
class GrpcBidiSequenceTrackerTest {
@org.junit.jupiter.api.Test
void directionsAdvanceIndependently() {
var tracker = new GrpcBidiSequenceTracker();
tracker.acceptClient(1);
tracker.acceptServer(1);
tracker.acceptServer(2);
org.assertj.core.api.Assertions.assertThat(
tracker.clientSequence()).isEqualTo(1);
org.assertj.core.api.Assertions.assertThat(
tracker.serverSequence()).isEqualTo(2);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-bidi-streaming:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcBidiSequenceTrackerTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public final class GrpcBidiSequenceTracker {
private long client;
private long server;
public void acceptClient(long sequence) {
if (sequence <= client) {
throw new IllegalArgumentException("client sequence");
}
client = sequence;
}
public void acceptServer(long sequence) {
if (sequence <= server) {
throw new IllegalArgumentException("server sequence");
}
server = sequence;
}
public long clientSequence() { return client; }
public long serverSequence() { return server; }
}
public record GrpcBidiResumeState(
long lastClientApplied,
long lastServerApplied,
long generation) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-bidi-streaming:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcBidiSequenceTrackerTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiSession.java' 'modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiDirectionState.java' 'modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiSequenceTracker.java' 'modules/grpc-advanced/grpc-bidi-streaming/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiResumeState.java' 'modules/grpc-advanced/grpc-bidi-streaming/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcBidiSequenceTrackerTest.java'
git commit -m "feat: define grpc bidi stream lifecycle"
Task 7: Manual Flow Control 승인 API
Files:
- Create:
modules/grpc-advanced/grpc-manual-flow-control/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcManualFlowControlPolicy.java - Create:
modules/grpc-advanced/grpc-manual-flow-control/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcDemandController.java - Create:
modules/grpc-advanced/grpc-manual-flow-control/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcDemandDecision.java - Test:
modules/grpc-advanced/grpc-manual-flow-control/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcDemandControllerTest.java
Interfaces:
- Consumes: Stable bounded flow-control policy와 gRPC readiness/request APIs.
- Produces: 승인된 streaming method가 수신 demand와 outbound readiness를 직접 제어하는 GR2 API.
Implementation requirements:
-
manual inbound request 수와 outstanding demand를 제한한다.
-
application code에 raw observer를 직접 반환하지 않는다.
-
read와 write 양쪽이 서로 기다리는 deadlock을 탐지하는 watchdog을 둔다.
-
demand와 queue high-watermark를 metric으로 기록한다.
-
manual mode가 없는 method에는 자동 flow control을 유지한다.
-
Step 1: Write the failing test
class GrpcDemandControllerTest {
@org.junit.jupiter.api.Test
void demandCannotExceedConfiguredWindow() {
var controller = new GrpcDemandController(4);
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> controller.request(5))
.isInstanceOf(IllegalArgumentException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-manual-flow-control:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcDemandControllerTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public final class GrpcDemandController {
private final int maxOutstanding;
private int outstanding;
public GrpcDemandController(int maxOutstanding) {
this.maxOutstanding = maxOutstanding;
}
public void request(int count) {
if (count <= 0
|| outstanding + count > maxOutstanding) {
throw new IllegalArgumentException(
"manual flow-control window exceeded");
}
outstanding += count;
}
}
public record GrpcManualFlowControlPolicy(
int maxOutstanding,
java.time.Duration deadlockWatchdog) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-manual-flow-control:test --tests 'io.backend.skeleton.grpc.advanced.streaming.GrpcDemandControllerTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-manual-flow-control/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcManualFlowControlPolicy.java' 'modules/grpc-advanced/grpc-manual-flow-control/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcDemandController.java' 'modules/grpc-advanced/grpc-manual-flow-control/src/main/java/io/backend/skeleton/grpc/advanced/streaming/GrpcDemandDecision.java' 'modules/grpc-advanced/grpc-manual-flow-control/src/test/java/io/backend/skeleton/grpc/advanced/streaming/GrpcDemandControllerTest.java'
git commit -m "feat: add approved grpc manual flow control"
Task 8: Read-only Unary Hedging
Files:
- Create:
modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingPolicy.java - Create:
modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingEligibility.java - Create:
modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingBudget.java - Create:
modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingResult.java - Test:
modules/grpc-advanced/grpc-hedging/src/test/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingEligibilityTest.java
Interfaces:
- Consumes: Stable method policy, deadline, retry owner와 Service Config.
- Produces: READ_ONLY Unary에만 제한된 duplicate attempt와 first-success 정책.
Implementation requirements:
-
READ_ONLY + UNARY만 hedging 대상이다.
-
mutation, streaming, idempotency-key write에는 hedging을 금지한다.
-
maximum attempts는 초기 2로 제한한다.
-
hedging delay와 total deadline·attempt budget을 함께 검증한다.
-
duplicate backend load와 cancelled loser result를 metric으로 기록한다.
-
Step 1: Write the failing test
class GrpcHedgingEligibilityTest {
@org.junit.jupiter.api.Test
void mutationCannotHedge() {
var eligibility = new GrpcHedgingEligibility();
org.assertj.core.api.Assertions.assertThat(
eligibility.allowed(
RpcIdempotencyProfile.NON_IDEMPOTENT,
RpcType.UNARY)).isFalse();
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-hedging:test --tests 'io.backend.skeleton.grpc.advanced.resilience.GrpcHedgingEligibilityTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcHedgingPolicy(
int maxAttempts,
java.time.Duration hedgingDelay) {
public GrpcHedgingPolicy {
if (maxAttempts < 2 || maxAttempts > 2) {
throw new IllegalArgumentException(
"initial hedging supports exactly two attempts");
}
}
}
public final class GrpcHedgingEligibility {
public boolean allowed(
RpcIdempotencyProfile profile,
RpcType type) {
return profile == RpcIdempotencyProfile.READ_ONLY
&& type == RpcType.UNARY;
}
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-hedging:test --tests 'io.backend.skeleton.grpc.advanced.resilience.GrpcHedgingEligibilityTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingPolicy.java' 'modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingEligibility.java' 'modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingBudget.java' 'modules/grpc-advanced/grpc-hedging/src/main/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingResult.java' 'modules/grpc-advanced/grpc-hedging/src/test/java/io/backend/skeleton/grpc/advanced/resilience/GrpcHedgingEligibilityTest.java'
git commit -m "feat: add read only grpc hedging"
Task 9: Custom Name Resolver SPI
Files:
- Create:
modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcEndpointSnapshot.java - Create:
modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcResolverUpdate.java - Create:
modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcCustomResolver.java - Create:
modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcResolverSafetyPolicy.java - Test:
modules/grpc-advanced/grpc-custom-resolver/src/test/java/io/backend/skeleton/grpc/advanced/discovery/GrpcResolverSafetyPolicyTest.java
Interfaces:
- Consumes: Stable Named Channel Profile and custom discovery event source.
- Produces: backend address와 Service Config update를 versioned snapshot으로 전달하는 승인된 resolver SPI.
Implementation requirements:
-
resolver update는 monotonic revision과 endpoint set을 가진다.
-
빈 endpoint update, stale revision, invalid authority를 거부한다.
-
resolver는 credential·business metadata를 제공하지 않는다.
-
Service Config를 함께 제공할 경우 retry owner·LB policy 검증을 통과해야 한다.
-
resolver close 후 update를 수신하지 않는다.
-
Step 1: Write the failing test
class GrpcResolverSafetyPolicyTest {
@org.junit.jupiter.api.Test
void staleRevisionIsRejected() {
var policy = new GrpcResolverSafetyPolicy();
policy.accept(new GrpcEndpointSnapshot(2,
java.util.Set.of("10.0.0.2:9090")));
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> policy.accept(new GrpcEndpointSnapshot(
1, java.util.Set.of("10.0.0.1:9090"))))
.isInstanceOf(IllegalArgumentException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-custom-resolver:test --tests 'io.backend.skeleton.grpc.advanced.discovery.GrpcResolverSafetyPolicyTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcEndpointSnapshot(
long revision,
java.util.Set<String> endpoints) {}
public final class GrpcResolverSafetyPolicy {
private long revision = -1;
public void accept(GrpcEndpointSnapshot snapshot) {
if (snapshot.endpoints().isEmpty()
|| snapshot.revision() <= revision) {
throw new IllegalArgumentException(
"invalid resolver update");
}
revision = snapshot.revision();
}
}
public interface GrpcCustomResolver
extends AutoCloseable {
void start(
java.util.function.Consumer<GrpcResolverUpdate> listener);
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-custom-resolver:test --tests 'io.backend.skeleton.grpc.advanced.discovery.GrpcResolverSafetyPolicyTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcEndpointSnapshot.java' 'modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcResolverUpdate.java' 'modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcCustomResolver.java' 'modules/grpc-advanced/grpc-custom-resolver/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcResolverSafetyPolicy.java' 'modules/grpc-advanced/grpc-custom-resolver/src/test/java/io/backend/skeleton/grpc/advanced/discovery/GrpcResolverSafetyPolicyTest.java'
git commit -m "feat: add grpc custom resolver spi"
Task 10: Custom Load Balancer SPI
Files:
- Create:
modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcEndpointCandidate.java - Create:
modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerPicker.java - Create:
modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerDecision.java - Create:
modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerSafetyPolicy.java - Test:
modules/grpc-advanced/grpc-custom-load-balancer/src/test/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerSafetyPolicyTest.java
Interfaces:
- Consumes: Task 9 custom resolver snapshot and Stable channel profile.
- Produces: bounded endpoint candidate에서 picker가 결정을 내리고 unsafe policy를 차단하는 GR3 SPI.
Implementation requirements:
-
picker는 resolver가 제공한 endpoint만 선택할 수 있다.
-
endpoint health, connectivity, weight와 ejection state를 bounded metadata로 사용한다.
-
business request body·tenant ID를 routing input으로 사용하지 않는다.
-
custom picker failure는 deterministic fallback 또는 call failure로 드러난다.
-
load-aware/weighted policy는 performance·fairness·failover evidence를 요구한다.
-
Step 1: Write the failing test
class GrpcLoadBalancerSafetyPolicyTest {
@org.junit.jupiter.api.Test
void pickerCannotChooseUnknownEndpoint() {
var policy = new GrpcLoadBalancerSafetyPolicy(
java.util.Set.of("a:9090"));
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> policy.validate("b:9090"))
.isInstanceOf(IllegalArgumentException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-custom-load-balancer:test --tests 'io.backend.skeleton.grpc.advanced.discovery.GrpcLoadBalancerSafetyPolicyTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcEndpointCandidate(
String authority,
int weight,
boolean ready) {}
public final class GrpcLoadBalancerSafetyPolicy {
private final java.util.Set<String> endpoints;
public GrpcLoadBalancerSafetyPolicy(
java.util.Set<String> endpoints) {
this.endpoints = java.util.Set.copyOf(endpoints);
}
public void validate(String selected) {
if (!endpoints.contains(selected)) {
throw new IllegalArgumentException(
"picker selected unknown endpoint");
}
}
}
public interface GrpcLoadBalancerPicker {
GrpcLoadBalancerDecision pick(
java.util.List<GrpcEndpointCandidate> candidates);
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-custom-load-balancer:test --tests 'io.backend.skeleton.grpc.advanced.discovery.GrpcLoadBalancerSafetyPolicyTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcEndpointCandidate.java' 'modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerPicker.java' 'modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerDecision.java' 'modules/grpc-advanced/grpc-custom-load-balancer/src/main/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerSafetyPolicy.java' 'modules/grpc-advanced/grpc-custom-load-balancer/src/test/java/io/backend/skeleton/grpc/advanced/discovery/GrpcLoadBalancerSafetyPolicyTest.java'
git commit -m "feat: add grpc custom load balancer spi"
Task 11: xDS Proxyless Experimental Profile
Files:
- Create:
modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsProfile.java - Create:
modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsResourceSnapshot.java - Create:
modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsStartupGuard.java - Create:
modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsFailurePolicy.java - Create:
modules/grpc-advanced/grpc-xds/src/test/resources/xds/bootstrap.json - Test:
modules/grpc-advanced/grpc-xds/src/test/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsStartupGuardTest.java
Interfaces:
- Consumes: Stable channel/security policy, xDS bootstrap and control-plane resources.
- Produces: xds target, resource discovery, traffic policy, mTLS와 fallback을 별도 Experimental profile로 검증.
Implementation requirements:
-
xds:///target만 explicit xDS profile에서 허용한다. -
bootstrap·control-plane credential·resource namespace를 검증한다.
-
application YAML과 xDS에 retry/LB owner를 중복 정의하지 않는다.
-
resource not found, stale resource, control-plane outage와 last-known-good policy를 명시한다.
-
xDS 기능을 Stable DNS/LB support로 광고하지 않는다.
-
Step 1: Write the failing test
class GrpcXdsStartupGuardTest {
@org.junit.jupiter.api.Test
void xdsRequiresExplicitFeatureFlagAndBootstrap() {
var guard = new GrpcXdsStartupGuard(false);
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> guard.validate(
new GrpcXdsProfile(
"xds:///document-service", "")))
.isInstanceOf(IllegalStateException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-xds:test --tests 'io.backend.skeleton.grpc.advanced.xds.GrpcXdsStartupGuardTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcXdsProfile(
String target,
String bootstrapResource) {}
public final class GrpcXdsStartupGuard {
private final boolean enabled;
public GrpcXdsStartupGuard(boolean enabled) {
this.enabled = enabled;
}
public void validate(GrpcXdsProfile profile) {
if (!enabled
|| !profile.target().startsWith("xds:///")
|| profile.bootstrapResource().isBlank()) {
throw new IllegalStateException(
"valid xDS experimental profile is required");
}
}
}
public record GrpcXdsResourceSnapshot(
String version,
java.util.Set<String> clusters,
java.time.Instant receivedAt) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-xds:test --tests 'io.backend.skeleton.grpc.advanced.xds.GrpcXdsStartupGuardTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsProfile.java' 'modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsResourceSnapshot.java' 'modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsStartupGuard.java' 'modules/grpc-advanced/grpc-xds/src/main/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsFailurePolicy.java' 'modules/grpc-advanced/grpc-xds/src/test/resources/xds/bootstrap.json' 'modules/grpc-advanced/grpc-xds/src/test/java/io/backend/skeleton/grpc/advanced/xds/GrpcXdsStartupGuardTest.java'
git commit -m "feat: add experimental grpc xds profile"
Task 12: gRPC-Web Unary·Server Streaming Bridge
Files:
- Create:
modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebRpcSupport.java - Create:
modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebProfile.java - Create:
modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebProxyContract.java - Create:
modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebCompatibilityGate.java - Create:
modules/grpc-advanced/grpc-web/src/test/resources/envoy/envoy.yaml - Test:
modules/grpc-advanced/grpc-web/src/test/java/io/backend/skeleton/grpc/advanced/web/GrpcWebCompatibilityGateTest.java
Interfaces:
- Consumes: Stable proto contract, Envoy/proxy profile and browser gRPC-Web client contract.
- Produces: 브라우저에서 Unary와 grpcwebtext Server Streaming만 지원하고 Client/Bidi를 명시적으로 차단하는 bridge.
Implementation requirements:
-
지원 RPC는 Unary와 Server Streaming이다.
-
Client Streaming과 Bidirectional Streaming을 지원한다고 선언하지 않는다.
-
Envoy 또는 승인된 proxy의 CORS, TLS, metadata/header mapping을 검증한다.
-
browser credential·cookie·bearer profile과 CSRF/CORS 정책을 분리한다.
-
native gRPC와 gRPC-Web compatibility suite를 같은 schema에 실행한다.
-
Step 1: Write the failing test
class GrpcWebCompatibilityGateTest {
@org.junit.jupiter.api.Test
void bidiStreamingIsUnsupported() {
var gate = GrpcWebCompatibilityGate.standard();
org.assertj.core.api.Assertions.assertThat(
gate.supports(RpcType.BIDI_STREAMING)).isFalse();
org.assertj.core.api.Assertions.assertThat(
gate.supports(RpcType.UNARY)).isTrue();
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-web:test --tests 'io.backend.skeleton.grpc.advanced.web.GrpcWebCompatibilityGateTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public enum GrpcWebRpcSupport {
UNARY, SERVER_STREAMING
}
public final class GrpcWebCompatibilityGate {
public static GrpcWebCompatibilityGate standard() {
return new GrpcWebCompatibilityGate();
}
public boolean supports(RpcType type) {
return type == RpcType.UNARY
|| type == RpcType.SERVER_STREAMING;
}
}
public record GrpcWebProfile(
String proxy,
boolean tlsRequired,
java.util.Set<String> allowedOrigins) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-web:test --tests 'io.backend.skeleton.grpc.advanced.web.GrpcWebCompatibilityGateTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebRpcSupport.java' 'modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebProfile.java' 'modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebProxyContract.java' 'modules/grpc-advanced/grpc-web/src/main/java/io/backend/skeleton/grpc/advanced/web/GrpcWebCompatibilityGate.java' 'modules/grpc-advanced/grpc-web/src/test/resources/envoy/envoy.yaml' 'modules/grpc-advanced/grpc-web/src/test/java/io/backend/skeleton/grpc/advanced/web/GrpcWebCompatibilityGateTest.java'
git commit -m "feat: add grpc web compatibility bridge"
Task 13: Servlet HTTP/2 Compatibility Profile
Files:
- Create:
modules/grpc-advanced/grpc-servlet-compat/src/main/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletCompatibilityProfile.java - Create:
modules/grpc-advanced/grpc-servlet-compat/src/main/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletCapabilityMatrix.java - Create:
modules/grpc-advanced/grpc-servlet-compat/src/main/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletStartupValidator.java - Test:
modules/grpc-advanced/grpc-servlet-compat/src/test/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletStartupValidatorTest.java
Interfaces:
- Consumes: Stable server profile and Spring Servlet container HTTP/2 integration.
- Produces: 동일 web server/port를 사용하는 Servlet transport의 지원·비지원 기능을 명시하는 compatibility module.
Implementation requirements:
-
Servlet transport는 Stable Netty certification을 대체하지 않는다.
-
container가 network layer를 소유하므로 native Netty-only 설정을 요청하면 실패한다.
-
HTTP/2, TLS, message/metadata limits, health, reflection, drain을 실제 container에서 검증한다.
-
keepalive·connection age·flow-control capability 차이를 matrix에 기록한다.
-
Servlet profile은 명시적 feature flag와 compatibility release gate를 요구한다.
-
Step 1: Write the failing test
class GrpcServletStartupValidatorTest {
@org.junit.jupiter.api.Test
void nativeOnlyFlowControlSettingIsRejected() {
var validator = new GrpcServletStartupValidator();
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> validator.validate(
new GrpcServletCompatibilityProfile(true)))
.isInstanceOf(IllegalArgumentException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-servlet-compat:test --tests 'io.backend.skeleton.grpc.advanced.servlet.GrpcServletStartupValidatorTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcServletCompatibilityProfile(
boolean requestsNativeNettyFlowControl) {}
public final class GrpcServletStartupValidator {
public void validate(
GrpcServletCompatibilityProfile profile) {
if (profile.requestsNativeNettyFlowControl()) {
throw new IllegalArgumentException(
"Servlet transport cannot promise Netty-only policy");
}
}
}
public record GrpcServletCapabilityMatrix(
boolean http2,
boolean tls,
boolean health,
boolean reflection,
boolean nettyFlowControl) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-servlet-compat:test --tests 'io.backend.skeleton.grpc.advanced.servlet.GrpcServletStartupValidatorTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-servlet-compat/src/main/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletCompatibilityProfile.java' 'modules/grpc-advanced/grpc-servlet-compat/src/main/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletCapabilityMatrix.java' 'modules/grpc-advanced/grpc-servlet-compat/src/main/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletStartupValidator.java' 'modules/grpc-advanced/grpc-servlet-compat/src/test/java/io/backend/skeleton/grpc/advanced/servlet/GrpcServletStartupValidatorTest.java'
git commit -m "feat: add grpc servlet compatibility profile"
Task 14: Spring Integration gRPC Bridge
Files:
- Create:
modules/grpc-advanced/grpc-integration-bridge/src/main/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationInboundGateway.java - Create:
modules/grpc-advanced/grpc-integration-bridge/src/main/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationOutboundGateway.java - Create:
modules/grpc-advanced/grpc-integration-bridge/src/main/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationBridgePolicy.java - Test:
modules/grpc-advanced/grpc-integration-bridge/src/test/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationBridgePolicyTest.java
Interfaces:
- Consumes: Stable Generated service/stub, Spring Integration Message flow and method policy.
- Produces: Spring
Message기반 Integration Flow를 typed RPC 계약과 분리해 연결하는 선택 bridge.
Implementation requirements:
-
bridge가 일반 Generated Stub/Service API를 대체한다고 설명하지 않는다.
-
message header를 gRPC metadata로 무제한 복사하지 않는다.
-
deadline, security, status, error, observability Stable policy를 그대로 적용한다.
-
payload type은 registered converter를 통해 Proto message와 변환한다.
-
broker-style ACK·durability semantics를 bridge에 추가하지 않는다.
-
Step 1: Write the failing test
class GrpcIntegrationBridgePolicyTest {
@org.junit.jupiter.api.Test
void arbitraryHeadersAreNotForwarded() {
var policy = GrpcIntegrationBridgePolicy.standard();
org.assertj.core.api.Assertions.assertThat(
policy.forwardedHeaders())
.containsExactlyInAnyOrder(
"correlation-id", "traceparent");
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-integration-bridge:test --tests 'io.backend.skeleton.grpc.advanced.integration.GrpcIntegrationBridgePolicyTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcIntegrationBridgePolicy(
java.util.Set<String> forwardedHeaders) {
public static GrpcIntegrationBridgePolicy standard() {
return new GrpcIntegrationBridgePolicy(
java.util.Set.of(
"correlation-id", "traceparent"));
}
}
public interface GrpcIntegrationInboundGateway {}
public interface GrpcIntegrationOutboundGateway {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-integration-bridge:test --tests 'io.backend.skeleton.grpc.advanced.integration.GrpcIntegrationBridgePolicyTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-integration-bridge/src/main/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationInboundGateway.java' 'modules/grpc-advanced/grpc-integration-bridge/src/main/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationOutboundGateway.java' 'modules/grpc-advanced/grpc-integration-bridge/src/main/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationBridgePolicy.java' 'modules/grpc-advanced/grpc-integration-bridge/src/test/java/io/backend/skeleton/grpc/advanced/integration/GrpcIntegrationBridgePolicyTest.java'
git commit -m "feat: add spring integration grpc bridge"
Task 15: Reactor gRPC Adapter
Files:
- Create:
modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/ReactiveGrpcClient.java - Create:
modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/ReactiveGrpcServerAdapter.java - Create:
modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/GrpcReactorContextBridge.java - Create:
modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/GrpcReactorCancellationBridge.java - Test:
modules/grpc-advanced/grpc-reactor/src/test/java/io/backend/skeleton/grpc/advanced/reactor/GrpcReactorContextBridgeTest.java
Interfaces:
- Consumes: Stable typed stub/service adapter, Reactor Context and cancellation contracts.
- Produces: Unary·Server Streaming을 Mono/Flux로 노출하면서 context·deadline·cancel·backpressure를 유지하는 adapter.
Implementation requirements:
-
Core public contract를 Reactor에 종속시키지 않는다.
-
Mono/Flux cancellation을 gRPC call cancellation으로 전파한다.
-
gRPC Context와 Reactor Context의 Actor·Tenant·Trace·Deadline을 bridge한다.
-
blocking JPA/SDK 호출을 event loop에서 실행하지 않는다.
-
server stream Flux가 Stable bounded flow-control contract를 우회하지 않는다.
-
Step 1: Write the failing test
class GrpcReactorContextBridgeTest {
@org.junit.jupiter.api.Test
void missingActorContextFailsClosed() {
var bridge = new GrpcReactorContextBridge();
org.assertj.core.api.Assertions.assertThatThrownBy(
() -> bridge.requireContext(java.util.Map.of()))
.isInstanceOf(IllegalStateException.class);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-reactor:test --tests 'io.backend.skeleton.grpc.advanced.reactor.GrpcReactorContextBridgeTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public final class GrpcReactorContextBridge {
public GrpcRequestContext requireContext(
java.util.Map<String, Object> context) {
var value = context.get("grpcRequestContext");
if (!(value instanceof GrpcRequestContext requestContext)) {
throw new IllegalStateException(
"gRPC request context is required");
}
return requestContext;
}
}
public interface ReactiveGrpcClient {}
public interface ReactiveGrpcServerAdapter {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-reactor:test --tests 'io.backend.skeleton.grpc.advanced.reactor.GrpcReactorContextBridgeTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/ReactiveGrpcClient.java' 'modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/ReactiveGrpcServerAdapter.java' 'modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/GrpcReactorContextBridge.java' 'modules/grpc-advanced/grpc-reactor/src/main/java/io/backend/skeleton/grpc/advanced/reactor/GrpcReactorCancellationBridge.java' 'modules/grpc-advanced/grpc-reactor/src/test/java/io/backend/skeleton/grpc/advanced/reactor/GrpcReactorContextBridgeTest.java'
git commit -m "feat: add reactor grpc adapter"
Task 16: Kotlin Coroutine·Flow Adapter
Files:
- Create:
modules/grpc-advanced/grpc-kotlin/src/main/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcKotlinProfile.java - Create:
modules/grpc-advanced/grpc-kotlin/src/main/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcCoroutineContextBridge.java - Create:
modules/grpc-advanced/grpc-kotlin/src/main/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcKotlinCompatibilityGate.java - Create:
modules/grpc-advanced/grpc-kotlin/src/main/kotlin/io/backend/skeleton/grpc/advanced/kotlin/GrpcCoroutineAdapter.kt - Test:
modules/grpc-advanced/grpc-kotlin/src/test/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcKotlinCompatibilityGateTest.java
Interfaces:
- Consumes: Stable schema artifact, Kotlin generated code and coroutine/Flow runtime.
- Produces: Kotlin coroutine unary와 Flow streaming을 Stable method policy·evidence와 연결하는 optional adapter.
Implementation requirements:
-
Java generated contract와 Kotlin generated contract의 schema source를 하나로 유지한다.
-
Coroutine cancellation을 gRPC cancellation으로 전파한다.
-
Flow backpressure가 Stable stream buffer limit을 우회하지 않는다.
-
Kotlin adapter가 Java Core의 evidence·status·deadline types를 보존한다.
-
Kotlin toolchain compatibility를 별도 release lane에서 검증한다.
-
Step 1: Write the failing test
class GrpcKotlinCompatibilityGateTest {
@org.junit.jupiter.api.Test
void schemaDigestMustMatchJavaLane() {
var gate = new GrpcKotlinCompatibilityGate();
org.assertj.core.api.Assertions.assertThat(
gate.compatible("sha256:a", "sha256:b"))
.isFalse();
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-kotlin:test --tests 'io.backend.skeleton.grpc.advanced.kotlin.GrpcKotlinCompatibilityGateTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public final class GrpcKotlinCompatibilityGate {
public boolean compatible(
String javaSchemaDigest,
String kotlinSchemaDigest) {
return javaSchemaDigest.equals(kotlinSchemaDigest);
}
}
public record GrpcKotlinProfile(
String kotlinVersion,
String grpcKotlinVersion,
boolean coroutineCancellationEnabled) {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-kotlin:test --tests 'io.backend.skeleton.grpc.advanced.kotlin.GrpcKotlinCompatibilityGateTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-kotlin/src/main/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcKotlinProfile.java' 'modules/grpc-advanced/grpc-kotlin/src/main/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcCoroutineContextBridge.java' 'modules/grpc-advanced/grpc-kotlin/src/main/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcKotlinCompatibilityGate.java' 'modules/grpc-advanced/grpc-kotlin/src/main/kotlin/io/backend/skeleton/grpc/advanced/kotlin/GrpcCoroutineAdapter.kt' 'modules/grpc-advanced/grpc-kotlin/src/test/java/io/backend/skeleton/grpc/advanced/kotlin/GrpcKotlinCompatibilityGateTest.java'
git commit -m "feat: add kotlin grpc adapter"
Task 17: Channelz·CSDS 진단과 Advanced Testkit
Files:
- Create:
modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcChannelDiagnosticsSnapshot.java - Create:
modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcChannelDiagnosticsPolicy.java - Create:
modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcAdvancedInfrastructureTestkit.java - Create:
modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcDiagnosticsRedactor.java - Create:
modules/grpc-advanced/grpc-channel-diagnostics/src/test/resources/xds/control-plane-snapshot.json - Create:
modules/grpc-advanced/grpc-channel-diagnostics/src/test/resources/grpc-web/envoy.yaml - Test:
modules/grpc-advanced/grpc-channel-diagnostics/src/test/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcChannelDiagnosticsPolicyTest.java
Interfaces:
- Consumes: Channel runtime, xDS profile, server state and admin authorization.
- Produces: Channelz/CSDS 기반 channel·subchannel·socket·xDS 상태를 관리자에게 제한적으로 제공하는 진단 계층.
Implementation requirements:
-
diagnostics endpoint는 admin network·role을 요구한다.
-
socket address·authority는 정책에 따라 마스킹한다.
-
token, certificate private material, metadata와 payload를 노출하지 않는다.
-
xDS CSDS는 xDS feature가 활성화된 경우에만 등록한다.
-
testkit은 gRPC-Web proxy, Servlet container, xDS control-plane failure를 검증한다.
-
Step 1: Write the failing test
class GrpcChannelDiagnosticsPolicyTest {
@org.junit.jupiter.api.Test
void anonymousAccessIsDenied() {
var policy = GrpcChannelDiagnosticsPolicy.adminOnly();
org.assertj.core.api.Assertions.assertThat(
policy.allowed(java.util.Set.of())).isFalse();
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-channel-diagnostics:test --tests 'io.backend.skeleton.grpc.advanced.diagnostics.GrpcChannelDiagnosticsPolicyTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public record GrpcChannelDiagnosticsPolicy(
java.util.Set<String> requiredRoles) {
public static GrpcChannelDiagnosticsPolicy adminOnly() {
return new GrpcChannelDiagnosticsPolicy(
java.util.Set.of("GRPC_ADMIN"));
}
public boolean allowed(java.util.Set<String> roles) {
return roles.containsAll(requiredRoles);
}
}
public record GrpcChannelDiagnosticsSnapshot(
String channelProfile,
String connectivityState,
int subchannels,
int sockets,
java.time.Instant capturedAt) {}
public interface GrpcAdvancedInfrastructureTestkit {}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-channel-diagnostics:test --tests 'io.backend.skeleton.grpc.advanced.diagnostics.GrpcChannelDiagnosticsPolicyTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcChannelDiagnosticsSnapshot.java' 'modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcChannelDiagnosticsPolicy.java' 'modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcAdvancedInfrastructureTestkit.java' 'modules/grpc-advanced/grpc-channel-diagnostics/src/main/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcDiagnosticsRedactor.java' 'modules/grpc-advanced/grpc-channel-diagnostics/src/test/resources/xds/control-plane-snapshot.json' 'modules/grpc-advanced/grpc-channel-diagnostics/src/test/resources/grpc-web/envoy.yaml' 'modules/grpc-advanced/grpc-channel-diagnostics/src/test/java/io/backend/skeleton/grpc/advanced/diagnostics/GrpcChannelDiagnosticsPolicyTest.java'
git commit -m "feat: add grpc channel diagnostics and testkit"
Task 18: Advanced Capability Promotion Gate
Files:
- Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionEvidence.java - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionDecision.java - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionGate.java - Create:
modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedSupportMatrix.java - Create:
docs/compatibility/grpc-advanced-support-matrix.md - Create:
docs/runbooks/grpc-advanced-capabilities.md - Create:
docs/adr/ADR-065-grpc-advanced-capability-promotion.md - Test:
modules/grpc-advanced/grpc-advanced-bootstrap/src/test/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionGateTest.java
Interfaces:
- Consumes: Tasks 1–17의 capability-specific compatibility, security, fault, performance, soak evidence.
- Produces: 각 Advanced/Experimental capability를 독립적으로 승격·차단하고 Stable starter 유입을 관리하는 release gate.
Implementation requirements:
-
capability별 required evidence를 분리한다.
-
Edition, streaming, xDS, gRPC-Web, Servlet, language adapter가 서로의 승격을 묶지 않는다.
-
Experimental에서 Advanced Stable로 승격하려면 ADR, runbook, actual environment test와 soak evidence가 필요하다.
-
Stable default로 승격하려면 dependency·security·operational cost 재검토가 필요하다.
-
미승격 capability는 feature flag와 별도 module로 유지한다.
-
Step 1: Write the failing test
class GrpcAdvancedPromotionGateTest {
@org.junit.jupiter.api.Test
void xdsWithoutControlPlaneSoakIsBlocked() {
var evidence = new GrpcAdvancedPromotionEvidence(
GrpcAdvancedCapability.XDS,
java.util.Set.of(
"compatibility", "security", "fault", "adr"));
var gate = new GrpcAdvancedPromotionGate();
org.assertj.core.api.Assertions.assertThat(
gate.decide(evidence))
.isEqualTo(GrpcAdvancedPromotionDecision.BLOCKED);
}
}
- Step 2: Run the focused test and verify the failure
Run:
./gradlew :modules:grpc-advanced:grpc-advanced-bootstrap:test --tests 'io.backend.skeleton.grpc.advanced.release.GrpcAdvancedPromotionGateTest'
Expected: FAIL because the Advanced production contract does not exist or the capability bypasses the Stable guardrail.
- Step 3: Implement the smallest complete production contract
public enum GrpcAdvancedPromotionDecision {
ADVANCED_STABLE, EXPERIMENTAL, BLOCKED
}
public record GrpcAdvancedPromotionEvidence(
GrpcAdvancedCapability capability,
java.util.Set<String> passed) {}
public final class GrpcAdvancedPromotionGate {
public GrpcAdvancedPromotionDecision decide(
GrpcAdvancedPromotionEvidence evidence) {
var required = java.util.Set.of(
"compatibility", "security", "fault",
"performance", "soak", "adr", "runbook");
return evidence.passed().containsAll(required)
? GrpcAdvancedPromotionDecision.ADVANCED_STABLE
: GrpcAdvancedPromotionDecision.BLOCKED;
}
}
Implement every listed production file with the exact names and invariants above. Preserve the Stable method policy, security, deadline, evidence, error and observability contracts; an Advanced capability is not a raw escape hatch.
- Step 4: Run the focused test and Advanced aggregate suite
Run:
./gradlew :modules:grpc-advanced:grpc-advanced-bootstrap:test --tests 'io.backend.skeleton.grpc.advanced.release.GrpcAdvancedPromotionGateTest'
./gradlew grpcAdvancedTest
Expected: PASS for the focused test and Advanced aggregate suite.
- Step 5: Commit the independently reviewable change
git add 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionEvidence.java' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionDecision.java' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionGate.java' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/main/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedSupportMatrix.java' 'docs/compatibility/grpc-advanced-support-matrix.md' 'docs/runbooks/grpc-advanced-capabilities.md' 'docs/adr/ADR-065-grpc-advanced-capability-promotion.md' 'modules/grpc-advanced/grpc-advanced-bootstrap/src/test/java/io/backend/skeleton/grpc/advanced/release/GrpcAdvancedPromotionGateTest.java'
git commit -m "docs: complete grpc advanced promotion gate"