<!-- task=m-inbound-queue-ordering/03+02_gateway_contract plan=1 tag=REVIEW_API -->

# Code Review Reference - REVIEW_API

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-06-02
task=m-inbound-queue-ordering/03+02_gateway_contract, plan=1, tag=REVIEW_API

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/inbound-queue-ordering.md`
- Task ids:
  - `gateway-contract`: worker gateway 계약을 문서화한다.
- Completion mode: check-on-pass

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-{review_lane}-GNN.md` → `code_review_{review_lane}_GNN_N.log`, `PLAN-{build_lane}-GNN.md` → `plan_{build_lane}_GNN_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_API-1] Gateway Contract Docs | [x] |
| [REVIEW_API-2] Missing Gateway Reorder Tests | [x] |

## 구현 체크리스트

- [x] `PROTOCOL.md`에 worker gateway/internal `seq` 계약을 추가한다. `seq`는 wire format이 아니라 read side가 붙이는 내부 구현값이며 gateway는 raw bytes decode/순수 전처리만 수행한다고 명시한다.
- [x] `PORTING_GUIDE.md`에 worker gateway boundary를 추가한다. gateway가 pending response map, listener/request handler, write queue, stateful dispatch를 소유하지 않는다고 명시한다.
- [x] Dart/Kotlin/TypeScript receive coordinator 테스트에 fake gateway 결과가 out-of-order로 도착해도 dispatch/response enqueue가 `seq` 순서를 따른다는 anchor를 추가한다.
- [x] 중간 검증으로 문서/테스트 검색과 Dart/Kotlin/TypeScript 단위 테스트를 실행하고 실제 stdout/stderr를 기록한다.
- [x] 최종 검증으로 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all`을 실행하고 실제 stdout/stderr 및 결과 기록 파일을 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하여 plan/review/archive 산출물이 추적 가능한지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/m-inbound-queue-ordering/03+02_gateway_contract/`를 `agent-task/archive/YYYY/MM/m-inbound-queue-ordering/03+02_gateway_contract/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-inbound-queue-ordering/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.

## 계획 대비 변경 사항

- 계획의 모든 요구 항목(PROTOCOL.md/PORTING_GUIDE.md 계약, Dart/Kotlin/TypeScript reorder anchor)을 그대로 구현했다.
- `PORTING_GUIDE.md`의 `Worker gateway boundary` 섹션에는 계획의 영문 bullet 외에, 문서의 한국어 서술 흐름과 맞추기 위한 한국어 도입 문장 1줄과 "gateway 미구현 언어는 gateway off fallback에서도 동일 coordinator path를 사용한다"는 fallback bullet 1줄을 추가했다. 모두 계약 범위 안의 보강이며 새 wire field나 public API를 추가하지 않았다.
- 최종 검증 `run_matrix.sh --all`은 이 세션에서 위 소스 변경이 모두 적용된 동일 트리에 대해 실행했고(결과 기록 `agent-test/runs/20260601-205817-proto-socket-full-matrix.md`), 실행 이후 소스 변경은 없다.

## 주요 설계 결정

- **gateway/coordinator 경계를 문서 계약으로 고정**: `PROTOCOL.md`에 `Worker Gateway and Internal seq` 하위 섹션을, `PORTING_GUIDE.md`에 `Worker gateway boundary` 섹션을 추가해 gateway는 stateless raw bytes decode/전처리만 수행하고, reorder-by-seq·pending response matching·listener/request handler dispatch·automatic response enqueue는 receive coordinator가 단독 소유함을 명시했다. `seq`가 `PacketBase`/transport framing에 추가되지 않는 내부 구현값임을 양 문서에 못박았다.
- **public API 없는 reorder anchor**: Dart/Kotlin/TypeScript 모두 새 gateway API를 만들지 않고, test-local fake gateway item(`seq=2`, `seq=1`)을 `seq` 기준 정렬한 뒤 기존 coordinator 진입점(`onReceivedData`)에 주입해 listener 수신 순서가 `[1, 2]`로 보존됨을 검증했다. Go/Python의 기존 `TestWorkerGatewayReorderAndDispatch`와 동일한 intent를 각 언어 관례로 맞췄다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._

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

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

- `PROTOCOL.md`와 `PORTING_GUIDE.md` 모두에 gateway/internal `seq` 계약이 있고 wire format 변경으로 오해되지 않는지 확인한다.
- gateway 금지 책임이 pending response map, listener/request handler, write queue, stateful dispatch까지 명확히 포함되는지 확인한다.
- Dart/Kotlin/TypeScript 테스트가 단순 FIFO 재검증이 아니라 fake gateway out-of-order result를 `seq`로 복원해 coordinator path에 넣는 anchor인지 확인한다.
- `검증 결과`의 stdout/stderr가 실제 파일 상태와 일치하는지 `rg` 결과로 재확인한다.

## 검증 결과

_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.

### REVIEW_API-1 중간 검증
```
$ rg --sort path -n "Worker Gateway|Worker gateway|internal `?seq|stateful dispatch|pending response|write queue|wire format" PROTOCOL.md PORTING_GUIDE.md
PROTOCOL.md:171:Each connection owns one bounded FIFO inbound queue between the frame parser and stateful dispatch.
PROTOCOL.md:187:2. If `responseNonce == 0` and the `typeName` is registered with `addRequestListener`: invoke the handler, then enqueue the automatic response through the write queue in the same coordinator loop iteration.
PROTOCOL.md:191:**Ordering guarantee**: for a given connection, listeners and request handlers are invoked strictly in packet arrival order. Automatic responses are enqueued into the write queue in the same order their triggering requests were dispatched.
PROTOCOL.md:200:### Worker Gateway and Internal seq
PROTOCOL.md:203:- In such multi-worker designs, the gateway input/output carries an internal `seq` assigned by the read loop to track the arrival order.
PROTOCOL.md:204:- The `seq` sequence is purely an internal implementation detail and **NOT** part of the wire format (it is not added to `PacketBase` or the transport framing).
PROTOCOL.md:205:- The gateway must perform only stateless operations (e.g., raw bytes decoding or preprocessing) and is prohibited from possessing stateful dispatcher logic.
PROTOCOL.md:206:- The receive coordinator remains the sole owner of ordering restoration (sorting by `seq`), pending response matching, listener/request handler dispatching, and automated response enqueuing.
PORTING_GUIDE.md:25:| receive coordinator | 단일 루프 | 수신 큐에서 패킷을 순서대로 꺼내 request handler 호출 → listener 호출 순서로 처리한다. 자동 응답은 같은 루프 이터레이션에서 write queue에 enqueue한다 |
PORTING_GUIDE.md:28:### Worker gateway boundary
PORTING_GUIDE.md:30:대량 raw packet 처리나 CPU 비용이 큰 decode/전처리를 병렬화할 때만 선택적으로 worker gateway를 둔다. gateway는 stateful dispatch를 소유하지 않으며, 순서 복원과 상태 접근은 receive coordinator가 단독으로 책임진다.
PORTING_GUIDE.md:32:- Gateway input/output carries an internal `seq` assigned by the read side.
PORTING_GUIDE.md:34:- The receive coordinator owns reorder-by-seq, pending response matching, listener dispatch, request handler execution, and automatic response enqueue.
PORTING_GUIDE.md:35:- Gateway must NOT own or manage pending response maps, listener/request handlers, or write queue logic.
PORTING_GUIDE.md:36:- `seq`는 구현 내부 값이며 wire format(`PacketBase`/transport framing)에 추가하지 않는다. 상세는 PROTOCOL.md의 `Worker Gateway and Internal seq` 섹션을 따른다.
```

### REVIEW_API-2 중간 검증
```
$ rg --sort path -n "WorkerGateway|worker gateway|gateway reorder|seq=2|seq: 2|seq = 2" dart/test kotlin/src/test typescript/test
dart/test/communicator_test.dart:436:    test('worker gateway: out-of-order seq를 reorder한 뒤 입력 순서로 dispatch한다',
dart/test/communicator_test.dart:443:      // Fake gateway: out-of-order(seq=2, seq=1)로 전달된 아이템
dart/test/communicator_test.dart:445:        (seq: 2, index: 2, incomingNonce: 2),
kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt:405:    fun testWorkerGatewayReorderAndDispatch() = runTest {
kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt:412:        // Fake gateway: out-of-order(seq=2, seq=1)로 전달된 아이템
kotlin/src/test/kotlin/com/tokilabs/proto_socket/CommunicatorTest.kt:415:            FakeGatewayItem(seq = 2, index = 2, incomingNonce = 2),
typescript/test/communicator.test.ts:450:  test("worker gateway: out-of-order seq를 reorder한 뒤 입력 순서로 dispatch한다", async () => {
typescript/test/communicator.test.ts:460:    // Fake gateway: out-of-order(seq=2, seq=1)로 전달된 아이템
typescript/test/communicator.test.ts:462:      { seq: 2, index: 2, nonce: 2 },

$ dart test test/communicator_test.dart   # (cd dart/)
00:00 +15: Communicator protocol guards worker gateway: out-of-order seq를 reorder한 뒤 입력 순서로 dispatch한다
00:00 +16: All tests passed!

$ env JAVA_HOME=/config/opt/jdk/jdk-17.0.10+7 GRADLE_USER_HOME=/tmp/gradle ./gradlew test --tests com.tokilabs.proto_socket.CommunicatorTest   # (cd kotlin/)
> Task :test
BUILD SUCCESSFUL in 39s
11 actionable tasks: 2 executed, 9 up-to-date
# build/test-results/test/TEST-com.tokilabs.proto_socket.CommunicatorTest.xml:
#   <testcase name="testWorkerGatewayReorderAndDispatch()" classname="com.tokilabs.proto_socket.CommunicatorTest" time="0.005"/>  (failure 없음 = PASS)

$ npm test -- communicator   # (cd typescript/)
 ✓ test/communicator.test.ts (16 tests) 149ms
 Test Files  1 passed (1)
      Tests  16 passed (16)
```

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

**Proto 동기화**
| 검사 | 명령 | 결과 |
|---|---|---|
| schema sync | `tools/check_proto_sync.sh` | PASS |

**동일언어**
| 언어 | 명령 | 결과 |
|---|---|---|
| Dart | `dart pub get && dart test && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js` | PASS |
| Go | `go test ./...` | PASS |
| Kotlin | `./gradlew test` | PASS |
| Python | `python3 -m pytest -q` | PASS |
| TypeScript | `npm run check && npm test` | PASS |

**언어 PASS 매트릭스**
| 서버 \ 클라이언트 | Dart.io | Dart.web | Dart.web(WSS) | Go | Kotlin | Python | TypeScript |
|---|---|---|---|---|---|---|---|
| Dart.io | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| Go | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| Kotlin | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| Python | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
| TypeScript | PASS | PASS | PASS | PASS | PASS | PASS | PASS |

**크로스테스트 상세**: 20개 언어쌍 각 16/16 PASS, 10개 Dart.web 방향 각 2/2 PASS, FAIL lines 0.

결과 기록 파일: `agent-test/runs/20260601-205817-proto-socket-full-matrix.md`
EXIT=0
```

### 재검증 (2026-06-02, 현재 트리에서 재실행)

> G06에서 검증 출력 불일치(FAIL)가 발생했던 이력 때문에, 구현이 트리에 실재하는지와 검증이 실제로 통과하는지를 현재 트리에서 직접 재실행해 확인했다.

- Dart `dart test test/communicator_test.dart`: 16/16 PASS (worker gateway anchor `+15` 포함) — 실제 실행.
- TypeScript `npm test -- communicator`: 16/16 PASS — 실제 실행.
- Kotlin `./gradlew test --tests com.tokilabs.proto_socket.CommunicatorTest --rerun-tasks`: `testWorkerGatewayReorderAndDispatch()` failures 0 — 실제 실행(강제 재실행).
- 전체 matrix `run_matrix.sh --all` 재실행: 완전 green. 결과 기록 `agent-test/runs/20260601-213027-proto-socket-full-matrix.md`.

#### 알려진 flaky (gateway-contract 변경 무관)

- Kotlin `TlsWsTest.testWssSendReceive()`가 간헐적으로 `java.io.IOException: websocket open timed out`(`WsClient.kt:212` dialWsUrl)으로 실패한다. 재현: 단독 3회 중 1회 통과, matrix 1회차(`20260601-211341`)에서 Kotlin 동일언어 FAIL, 재실행(`20260601-213027`)에서 green.
- 이 테스트는 TLS WS 연결 open 타임아웃 안정성 이슈로, 이번 subtask가 수정한 파일(`CommunicatorTest.kt`/문서)과 무관한 사전 존재 flaky다. gateway-contract 자체 검증에는 영향이 없으며, 테스트 안정성은 별도 이슈로 다룬다.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

## Ownership

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these |
| Roadmap Targets | Fixed at stub creation from plan | Implementing agent must not modify |
| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only |
| 구현 체크리스트 | Implementing agent | Check `[ ]` to `[x]` only |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholders |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required |
| 검증 결과 | Implementing agent | Paste actual stdout/stderr |

## 코드리뷰 결과

- 종합 판정: PASS

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| correctness | Pass | worker gateway/internal `seq` 계약이 문서에 추가되었고, 세 언어 테스트가 기존 coordinator path에서 `seq` 정렬 후 listener dispatch 순서를 검증한다. |
| completeness | Pass | 계획 체크리스트와 review stub 체크리스트가 일치하며 모든 구현 항목과 검증 항목이 완료 기록되어 있다. |
| test coverage | Pass | Dart/Kotlin/TypeScript reorder anchor가 추가되었고, 관련 단위 테스트와 전체 matrix 결과 파일이 PASS다. |
| API contract | Pass | `seq`가 wire format/PacketBase/transport framing이 아닌 내부 구현값임을 명시해 public protocol 변경이 없다. |
| code quality | Pass | 변경은 문서와 테스트 anchor에 한정되며 새 public API나 불필요한 구현 로직을 추가하지 않았다. |
| plan deviation | Pass | 계획 범위의 문서 계약과 세 언어 테스트 anchor만 반영되었다. |
| verification trust | Pass | 문서/테스트 검색, Dart/Kotlin/TypeScript 테스트를 현재 트리에서 재실행했고, 기록된 전체 matrix PASS 산출물도 확인했다. |

### 발견된 문제

없음

### 다음 단계

PASS: active review/plan을 `.log`로 아카이브하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
