Files
clean-architecture-backend-…/docs/2026-08-13-grpc-advanced-capabilities-expansion-plan.md
T

79 KiB
Raw Blame History

타입 안전 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 153과 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 153
→ Advanced Task 118

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 13 Feature isolation and schema evaluation lanes
Streaming 47 Client/Bidi session, checkpoint and manual flow control
Resilience·Discovery 811 Hedging, custom resolver/LB and xDS
Compatibility Bridges 1216 gRPC-Web, Servlet, Integration, Reactor, Kotlin
Diagnostics·Promotion 1718 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 45 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 117의 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"