<!-- task=m-inbound-queue-ordering/06_kotlin_gateway plan=0 tag=API -->

# Code Review Reference - API

> **[IMPLEMENTING AGENT — READ FIRST]** 구현 후 이 파일을 채우고 active 파일을 그대로 둔 채 리뷰를 요청한다. 최종화는 code-review 전용이다.

## 개요

date=2026-06-02
task=m-inbound-queue-ordering/06_kotlin_gateway, plan=0, tag=API

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/inbound-queue-ordering.md`
- Task ids:
  - `kotlin-gateway`: Kotlin coroutine worker gateway 후보를 적용한다.
- Completion mode: check-on-pass

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [API-1] Kotlin coroutine gateway | [x] |

## 구현 체크리스트

- [x] Kotlin gateway input/output에 내부 `seq`를 포함하고 coroutine worker pool 또는 제한 dispatcher를 추가한다.
- [x] gateway는 decode/전처리만 수행하고 pending/listener/request/write queue 상태를 소유하지 않는다.
- [x] 결과 collector가 `seq` 순서로 receive coordinator에 전달한다.
- [x] Kotlin tests에 out-of-order worker completion, 대량 packet 순서, close/cancel anchor를 추가한다.
- [x] 중간 검증으로 `cd kotlin && env JAVA_HOME=/config/opt/jdk/jdk-17.0.10+7 GRADLE_USER_HOME=/tmp/gradle ./gradlew test --tests com.tokilabs.proto_socket.CommunicatorTest --rerun-tasks`를 실행한다.
- [x] 최종 검증으로 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all`을 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드리뷰 전용 체크리스트

- [x] verdict append, log archive, FAIL follow-up PLAN/CODE_REVIEW 작성을 수행했다.

## 계획 대비 변경 사항

- `Communicator.kt`에 coroutine worker-pool gateway를 추가했다(`InboundFrame`, `DecodedFrame`, `InboundGateway`, `CoroutineWorkerGateway`, 내부 `GatewayResult`/`FrameReorderBuffer`). Go의 `go/inbound_gateway.go` 설계를 coroutine 모델로 대응시켰다. 계획의 "수정 파일 요약"대로 신규 파일을 만들지 않고 기존 `Communicator.kt`에 추가했다.
- `CommunicatorTest.kt`에 gateway 테스트 5개를 추가했다(reorder buffer, out-of-order worker completion, decode error 전파, communicator 통합 대량 순서, close 멱등/전달 중단).
- **계획 범위 외 변경(사용자 승인)**: 계획은 "OkHttp WS staging 정책"을 범위 제외로 명시했다. staging 정책 코드(`WsClient.kt`)는 건드리지 않았으나, 기존 flaky 테스트 `testWsInboundStagingOverflowDisconnects`가 베이스라인에서도 5회 중 4회 실패하여 전체 검증 게이트를 막았다. 사용자 결정에 따라 해당 테스트의 대기 방식만 안정화했다(가상 시간 `delay(100)` → 실제 시간 폴링). 프로덕션 staging 정책은 변경하지 않았다.

## 주요 설계 결정

- **gateway 책임 경계**: gateway는 순수 `PacketBase` decode/전처리만 수행한다. `pendingRequests`, listener, request handler, write queue 상태는 소유하지 않고 receive coordinator(`Communicator.enqueueInbound`)에 남긴다. sink를 호출하는 coroutine이 단일 collector뿐이므로 dispatch 호출은 직렬화되고 입력 순서가 보존된다.
- **seq 기반 reorder**: `seq`는 수신 측이 gateway 제출 전에 부여하는 내부 단조 증가 시퀀스로, wire format/공개 프로토콜 필드에는 노출하지 않는다. `FrameReorderBuffer`가 out-of-order 결과를 버퍼해 연속 prefix가 완성될 때만 순서대로 release한다. decode 실패 프레임도 seq를 진행시켜 reorder window를 막지 않으며, 오류는 sink가 아니라 `onError`로 seq 순서에 맞춰 보고한다(transport 종료 결정은 호출자 몫).
- **backpressure / 수명주기**: bounded jobs `Channel`이 backpressure를 제공한다(가득 차면 `submit` suspend). `close()`는 jobs 채널을 닫아 worker가 잔여 프레임을 drain한 뒤 종료하게 하며 멱등이다. 모든 worker가 종료하면 results 채널을 닫아 collector도 정상 종료시킨다. close 이후 `submit`은 drop한다.
- **테스트 결정성**: out-of-order 완료를 결정적으로 재현하기 위해 `decode`를 suspend로 두고 `runTest` 가상 시간 `delay`로 worker 완료 순서를 제어했다(Go의 sleep 기반 테스트에 대응).

## 사용자 리뷰 요청

- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

## 리뷰어를 위한 체크포인트

- gateway가 actor/coordinator state ownership을 침범하지 않는지 확인한다.

## 검증 결과

### API-1 중간 검증
```
$ cd kotlin && env JAVA_HOME=/config/opt/jdk/jdk-17.0.10+7 GRADLE_USER_HOME=/tmp/gradle ./gradlew test --tests com.tokilabs.proto_socket.CommunicatorTest --rerun-tasks
# 안정성 확인을 위해 5회 반복 실행
=== run 1 === BUILD SUCCESSFUL in 7s
=== run 2 === BUILD SUCCESSFUL in 6s
=== run 3 === BUILD SUCCESSFUL in 6s
=== run 4 === BUILD SUCCESSFUL in 5s
=== run 5 === BUILD SUCCESSFUL in 5s
# 신규 gateway 테스트 5개 단독 실행도 3/3 안정 통과:
#   testFrameReorderBufferReleasesInOrder
#   testWorkerGatewayReordersOutOfOrderCompletion
#   testWorkerGatewayReportsDecodeErrorAndAdvances
#   testWorkerGatewayDispatchesThroughCommunicatorInOrder
#   testWorkerGatewayCloseIsIdempotentAndStopsDelivery
```

flaky 안정화 근거: 동일 명령을 변경 전 베이스라인에서 5회 실행 시 `testWsInboundStagingOverflowDisconnects`가 4회 FAIL(가상 시간 vs Dispatchers.IO 실제 코루틴 레이스). 테스트 대기를 실제 시간 폴링으로 바꾼 뒤 5/5 PASS.

### 최종 검증
```
$ bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all

**Proto 동기화**: schema sync PASS
**동일언어**: Dart PASS / Go PASS / Kotlin PASS / Python PASS / TypeScript PASS
**언어 PASS 매트릭스**: 모든 서버×클라이언트 조합 PASS (Dart.io/Go/Kotlin/Python/TypeScript × Dart.io/Dart.web/Dart.web(WSS)/Go/Kotlin/Python/TypeScript)
**크로스테스트 상세**: 전 방향 PASS (언어간 16/16, Dart.web 방향 2/2), FAIL lines 0

결과 기록 파일: agent-test/runs/20260602-033833-proto-socket-full-matrix.md
```

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Fail
  - API contract: Fail
  - code quality: Pass
  - plan deviation: Fail
  - verification trust: Pass
- 발견된 문제:
  - Required: [kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt:437](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/Communicator.kt:437) 새 `CoroutineWorkerGateway`가 생성되었지만 `Communicator`에 gateway를 attach/enable하거나 raw frame을 gateway로 제출하는 API가 없습니다. 현재 실제 ingress는 [TcpClient.kt:71](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/TcpClient.kt:71)와 [WsClient.kt:64](/config/workspace/proto-socket/kotlin/src/main/kotlin/com/tokilabs/proto_socket/WsClient.kt:64)에서 여전히 `PacketBase.parseFrom` 후 `enqueueInbound`를 직접 호출하므로 gateway worker pool이 production TCP/WS 수신 경로에 적용되지 않습니다. `Communicator`에 `enableInboundGateway`/`attachInboundGateway`/`onReceivedFrame`와 내부 frame seq, gateway decode error handler를 추가하고, TCP/WS read loop가 raw bytes를 `onReceivedFrame`으로 전달하게 수정하세요.
  - Required: [kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt:533](/config/workspace/proto-socket/kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt:533) gateway 테스트가 gateway 인스턴스를 수동 생성한 뒤 sink에서 `communicator.enqueueInbound`를 직접 호출하는 단위 검증에 머물러 있어, 실제 read loop가 gateway를 우회해도 실패하지 않습니다. custom counting gateway를 communicator에 attach한 뒤 TCP/WS ingress가 raw frame을 gateway에 submit하는지 검증하고, gateway decode error가 transport disconnect/error path로 이어지는 테스트를 추가하세요.
- 다음 단계: FAIL이므로 user-review gate 없이 후속 `PLAN-cloud-G08.md`와 `CODE_REVIEW-cloud-G08.md`를 작성한다.
