# 클래스 자바독과 목록 선언 (93 줄)
  GrpcCompletionReconciler.java:8 
  GrpcCompletionReconciler.java:9 /**
  GrpcCompletionReconciler.java:10  * Turns an unknown completion into a decision, or hands it on.
  GrpcCompletionReconciler.java:11  *
  GrpcCompletionReconciler.java:12  * <p>Two sources, consulted in a fixed order: the ledger first, then — only when the ledger has
  GrpcCompletionReconciler.java:13  * nothing and the method offers one — a business-resource probe. The order matters because they
  GrpcCompletionReconciler.java:14  * answer different questions. The ledger knows whether this exact operation was claimed; the
  GrpcCompletionReconciler.java:15  * resource only knows whether something that looks like the result exists, which is a weaker
  GrpcCompletionReconciler.java:16  * statement and can be satisfied by a different caller's write.
  GrpcCompletionReconciler.java:17  *
  GrpcCompletionReconciler.java:18  * <p>When neither is conclusive, the resolution stays UNKNOWN and the case is queued. Guessing is
  GrpcCompletionReconciler.java:19  * the failure mode this class exists to make impossible: a reconciler that resolves an ambiguous
  GrpcCompletionReconciler.java:20  * case by re-issuing has converted an unknown into a duplicate.
  GrpcCompletionReconciler.java:21  */
  GrpcCompletionReconciler.java:22 public final class GrpcCompletionReconciler {
  GrpcCompletionReconciler.java:23 
  GrpcCompletionReconciler.java:24   private final GrpcOperationStatusQuery statusQuery;
  GrpcCompletionReconciler.java:25   private final List<PendingCase> pending = new ArrayList<>();
  GrpcCompletionReconciler.java:26 

# pending 이 나오는 줄 전부
  GrpcCompletionReconciler.java:25  private final List<PendingCase> pending = new ArrayList<>();
  GrpcCompletionReconciler.java:34  throw new IllegalArgumentException("a pending case identifies its operation");
  GrpcCompletionReconciler.java:37  throw new IllegalArgumentException("a pending case says why it is pending");
  GrpcCompletionReconciler.java:79  pending.add(new PendingCase(method, callerFingerprint, idempotencyKey, fromLedger.reason()));
  GrpcCompletionReconciler.java:85  public List<PendingCase> pendingCases() {
  GrpcCompletionReconciler.java:86  return List.copyOf(pending);
  GrpcCompletionReconciler.java:91  pending.remove(resolved);

# 동기화 표시자 — 같은 검색을 같은 리프의 짝에도 건다
    표시자          이 파일 짝 파일 리프 전체
    synchronized                0          5          3
    volatile                    0          0          0
    java.util.concurrent          0          0         10
    ReentrantLock               0          0          0
    CopyOnWrite                 0          0          0
    not thread                  0          0          1
    single-threaded             0          0          0
  같은 검색을 리프 전체에 걸어 파일별로 :
    GrpcContextBinder.java                 2 건
    GrpcCancellationCoordinator.java       5 건
    GrpcOutcomeReplay.java                 2 건
    GrpcRetryBudget.java                   1 건
    GrpcCredentialRotationManager.java     1 건
    GrpcSerializedStreamWriter.java        9 건
    GrpcStreamAdmission.java               3 건
    GrpcStreamSequence.java                1 건
    리프 전체 62 파일

# pending.add 가 실행되는 조건
  GrpcCompletionReconciler.java:62     GrpcCompletionResolution fromLedger =
  GrpcCompletionReconciler.java:63         statusQuery.resolve(method, callerFingerprint, idempotencyKey);
  GrpcCompletionReconciler.java:64     if (fromLedger.status() == GrpcOperationStatus.COMMITTED
  GrpcCompletionReconciler.java:65         || fromLedger.status() == GrpcOperationStatus.FAILED_TERMINAL) {
  GrpcCompletionReconciler.java:66       return fromLedger;
  GrpcCompletionReconciler.java:67     }
  GrpcCompletionReconciler.java:68     if (fromLedger.status() == GrpcOperationStatus.NOT_FOUND && businessProbe != null) {
  GrpcCompletionReconciler.java:69       Optional<String> observed = businessProbe.apply(method);
  GrpcCompletionReconciler.java:70       if (observed.isPresent()) {
  GrpcCompletionReconciler.java:71         return GrpcCompletionResolution.of(
  GrpcCompletionReconciler.java:72             GrpcOperationStatus.COMMITTED,
  GrpcCompletionReconciler.java:73             observed,
  GrpcCompletionReconciler.java:74             "no ledger claim, but the business resource shows the effect");
  GrpcCompletionReconciler.java:75       }
  GrpcCompletionReconciler.java:76       return fromLedger;
  GrpcCompletionReconciler.java:77     }
  GrpcCompletionReconciler.java:78     if (fromLedger.requiresReconciliation()) {
  GrpcCompletionReconciler.java:79       pending.add(new PendingCase(method, callerFingerprint, idempotencyKey, fromLedger.reason()));
  GrpcCompletionReconciler.java:80     }
  GrpcCompletionReconciler.java:81     return fromLedger;
  GrpcCompletionReconciler.java:82   }
  GrpcCompletionResolution.java:46   }
  GrpcCompletionResolution.java:47 
  GrpcCompletionResolution.java:48   /** Whether this must be handed to a reconciliation job rather than answered now. */
  GrpcCompletionResolution.java:49   public boolean requiresReconciliation() {
  GrpcCompletionResolution.java:50     return status == GrpcOperationStatus.UNKNOWN || status == GrpcOperationStatus.IN_PROGRESS;
  GrpcCompletionResolution.java:51   }
  GrpcCompletionResolution.java:52 }

# 같은 리프에서 같은 모양의 필드를 가진 클래스
    deadline/GrpcCancellationCoordinator.java:27:  private final Map<String, GrpcCancellableOperation> operations = new LinkedHashMap<>();
    validation/GrpcTransportValidator.java:104:    private final List<Rule<T>> rules = new ArrayList<>();
    validation/GrpcTransportValidator.java:105:    private final Set<String> seen = new LinkedHashSet<>();
    idempotency/GrpcCompletionReconciler.java:25:  private final List<PendingCase> pending = new ArrayList<>();
    streaming/GrpcSerializedStreamWriter.java:31:  private final Deque<GrpcStreamEnvelope<T>> queue = new ArrayDeque<>();
  그중 GrpcCancellationCoordinator 의 공개 메서드 :
    GrpcCancellationCoordinator.java:32  public GrpcCancellationCoordinator(GrpcCancellationToken token) {
    GrpcCancellationCoordinator.java:45  public synchronized void register(GrpcCancellableOperation operation) {
    GrpcCancellationCoordinator.java:69  public synchronized List<String> cancel(GrpcCancellationReason cancellationReason, Instant at) {
    GrpcCancellationCoordinator.java:90  public synchronized void markCommitBoundaryCrossed() {
    GrpcCancellationCoordinator.java:100  public synchronized boolean businessEffectAborted() {
    GrpcCancellationCoordinator.java:105  public boolean cancelled() {
    GrpcCancellationCoordinator.java:110  public synchronized Optional<GrpcCancellationReason> reason() {
    GrpcCancellationCoordinator.java:119  public void requireMayStartSideEffect(String operationName) {

# 이 타입을 참조하는 자리 — 경로 제한 없이, 절단 없이
  docs/2026-08-13-grpc-type-safe-rpc-platform-implementation-plan.md
  docs/adr/ADR-GRPC-003-three-axis-execution-evidence.md
  docs/runbooks/grpc-platform-operations.md
  src/grpc/grpc-policy/src/main/java/dev/caskeleton/grpc/idempotency/GrpcCompletionReconciler.java
  src/grpc/grpc-policy/src/test/java/dev/caskeleton/grpc/idempotency/GrpcCompletionReconcilerTest.java
  main · GrpcCompletionReconciler.java:22 public final class GrpcCompletionReconciler {
  main · GrpcCompletionReconciler.java:43   public GrpcCompletionReconciler(GrpcOperationStatusQuery statusQuery) {
  test · GrpcCompletionReconcilerTest.java:11 class GrpcCompletionReconcilerTest {
  test · GrpcCompletionReconcilerTest.java:96     GrpcCompletionReconciler reconciler = new GrpcCompletionReconciler(query);
  test · GrpcCompletionReconcilerTest.java:108     GrpcCompletionReconciler reconciler = new GrpcCompletionReconciler(query);
  test · GrpcCompletionReconcilerTest.java:121     GrpcCompletionReconciler reconciler = new GrpcCompletionReconciler(query);
  test · GrpcCompletionReconcilerTest.java:138     GrpcCompletionReconciler reconciler = new GrpcCompletionReconciler(query);
  자기 파일 밖 main 참조 : 0 개
  [대조] GrpcCancellationCoordinator : 2 개  (0 이 아니어야 정상)

# 운영 런북이 자기를 어떻게 규정하는가
  grpc-platform-operations.md:1 # Runbook: gRPC platform operations
  grpc-platform-operations.md:2 
  grpc-platform-operations.md:3 Scope: the `:grpc:*` family. All of it is build-only today — every leaf's `runtime_memberships` is
  grpc-platform-operations.md:4 empty — so nothing here fires in production yet. It is written now because the states it covers are
  grpc-platform-operations.md:5 the ones an on-call cannot work out from first principles at three in the morning, and shipping the
  grpc-platform-operations.md:6 behaviour before the runbook means the first person to meet one is doing that.
  grpc-platform-operations.md:7 
  grpc-platform-operations.md:8 Configuration lives under `ca-skeleton.grpc.platform.*` and is bound by `GrpcPlatformProperties`.
  grpc-platform-operations.md:9 The platform does not start unless `ca-skeleton.grpc.platform.enabled=true`.
  그 런북이 요구하는 스위치가 코드에 있는가 : 0 개 파일
  독립 문서의 같은 서술 :
    grpc-support-matrix.md:66  Not released. Every `:grpc:*` leaf is `runtime_memberships: []` in the module registry, so the
    grpc-support-matrix.md:67  platform is build-only: it compiles, its lanes run, and no deployed artifact carries it.

# 그 런북이 이 클래스에 기대하는 동작
  grpc-platform-operations.md:34 4. `NOT_FOUND` means the operation never started and is safe to re-issue. `FAILED_TERMINAL` means the
  grpc-platform-operations.md:35    same.
  grpc-platform-operations.md:36 5. `UNKNOWN` means the ledger could not be consulted. Nothing may be concluded. The case is queued by
  grpc-platform-operations.md:37    `GrpcCompletionReconciler` and retried later.
  grpc-platform-operations.md:38 6. If the method is not keyed, there is no ledger row. Resolve it against the business resource, or
  grpc-platform-operations.md:39    escalate to the service owner. This is the case the keyed profile exists to avoid.
  grpc-platform-operations.md:40 
  grpc-platform-operations.md:41 **Escalate when** the reconciler's pending list grows across passes. That means the ledger is
  grpc-platform-operations.md:42 unreachable rather than slow.
