<!-- task=m-inbound-queue-ordering/05_go_gateway 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/05_go_gateway, plan=1, tag=REVIEW_API

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/inbound-queue-ordering.md`
- Task ids:
  - `go-gateway`: Go goroutine worker pool 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`를 작성한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_API-1] 실제 transport read path gateway 연결 | [x] |

## 구현 체크리스트

- [x] TCP/WS read loop가 gateway 부착 시 raw frame을 gateway 경로로 전달하고, gateway 미부착 시 기존 inline decode 동작을 유지한다.
- [x] raw frame decode 실패 시 기존 TCP/WS parse error disconnect semantics가 유지되도록 error 처리 경계를 보완한다.
- [x] 실제 TCP 또는 WS read path에서 `EnableInboundGateway`가 dispatch 순서를 보존하는 테스트를 추가한다.
- [x] gateway read path 테스트가 `OnReceivedFrame` 직접 호출만으로 통과하지 않고 transport read loop 연결 누락을 잡을 수 있게 구성한다.
- [x] 중간 검증으로 `cd go && go test -count=1 ./... && go test -race ./...`를 실행하고 실제 stdout/stderr를 기록한다.
- [x] 최종 검증으로 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all`을 실행하고 결과 기록 파일을 남긴다.
- [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 산출물이 추적 가능한지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] 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로 이동한다.

## 계획 대비 변경 사항

- `code_review_cloud_G08_0.log`의 Required 2건만 해결했다. gateway worker pool 자체(plan=0 산출물)는 유지하고, 실제 transport read loop 연결 누락만 보완했다.
- `Communicator.OnReceivedFrame`의 시그니처를 `(raw []byte)` → `(raw []byte) error`로 바꿨다. inline decode 실패 시 error를 반환해 transport가 기존 parse-error disconnect를 그대로 적용하게 했다. gateway 부착 시에는 비동기 decode이므로 항상 nil을 반환하고, 디코드 실패 프레임은 gateway worker가 drop한다(연결을 끊지 않음).
- `go/tcp_client.go`, `go/ws_client.go`의 read loop가 직접 `proto.Unmarshal` + `OnReceivedData` 하던 부분을 `c.OnReceivedFrame(raw)` 호출로 교체했다. inline 모드 동작과 disconnect reason(`DisconnectReasonTCPPacketParse`/`DisconnectReasonWSPacketParse`)은 동일하게 보존된다.
- `go/test/communicator_test.go`에 실제 `TcpClient.readLoop`(`net.Pipe` 기반) 테스트 3종을 추가했다. plan=0의 `TestInboundGatewayPreservesDispatchOrder`(직접 `OnReceivedFrame` 호출)는 gateway+coordinator 통합 단위 테스트로 유지했다.
- `go/inbound_gateway.go`는 plan에 후보 파일로 적혔으나 이번 Required 해결에는 추가 변경이 필요 없어 수정하지 않았다.

## 주요 설계 결정

- **read loop는 raw-frame 진입점 하나로 단일화.** `OnReceivedFrame`이 gateway 부착 여부를 내부에서 분기하므로, TCP/WS read loop는 동일한 한 줄로 두 모드를 모두 처리한다. gateway 부착 → worker pool submit, 미부착 → inline decode 후 coordinator 전달.
- **parse-error disconnect 경계는 inline 경로에 보존.** `OnReceivedFrame`이 inline decode 실패 시 error를 반환하고 read loop가 기존 reason으로 `onDisconnected`를 호출한다. gateway 부착 시 malformed 프레임은 worker가 비동기로 drop한다 — gateway는 순수 decode만 하고 transport teardown/dispatch를 소유하지 않는다는 계약을 깨지 않기 위한 의도된 trade-off다. disconnect 의미 검증 테스트는 기본(미부착) 경로에서 수행한다.
- **wiring 누락을 잡는 테스트.** `TestTcpReadLoopRoutesThroughGateway`는 `AttachInboundGateway`로 submit 횟수를 세는 test gateway를 붙인다. read loop가 gateway를 우회해 inline decode하면 submit 수가 0이 되어 실패하므로, 이전 리뷰가 지적한 연결 누락을 회귀로 잡는다. 단순 순서 보존 테스트는 read loop가 순차적이라 우회해도 통과하므로 wiring 검증에 불충분하다는 점을 반영했다.
- **heartbeat 무소음 테스트 환경.** `intervalSec=0`이면 `baseClient.sendHeartBeat`가 즉시 반환하므로 `net.Pipe` 위 client가 파이프에 아무것도 쓰지 않아 테스트가 deadlock 없이 read path만 검증한다.

## 사용자 리뷰 요청

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

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

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

- TCP/WS 실제 read loop가 gateway 부착 시 raw frame을 gateway로 전달하는지 확인한다.
- gateway 미부착 시 기존 inline decode와 parse failure disconnect semantics가 유지되는지 확인한다.
- 신규 테스트가 `OnReceivedFrame` 직접 호출만으로 통과하지 않는지 확인한다.

## 검증 결과

### REVIEW_API-1 중간 검증
```
$ cd go && go test -count=1 ./...
ok  	git.toki-labs.com/toki/proto-socket/go	0.043s
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/dart_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/kotlin_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/python_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/typescript_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/examples/tcp_echo	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/examples/ws_echo	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/packets	[no test files]
ok  	git.toki-labs.com/toki/proto-socket/go/test	8.203s

$ cd go && go test -race ./...
ok  	git.toki-labs.com/toki/proto-socket/go	1.052s
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/dart_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/kotlin_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/python_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/crosstest/typescript_go_client	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/examples/tcp_echo	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/examples/ws_echo	[no test files]
?   	git.toki-labs.com/toki/proto-socket/go/packets	[no test files]
ok  	git.toki-labs.com/toki/proto-socket/go/test	9.222s
```

신규 transport read-path 테스트(실제 `TcpClient.readLoop`, `net.Pipe`):
```
$ go test -count=1 -v -run 'TestTcpReadLoop' ./test/
=== RUN   TestTcpReadLoopRoutesThroughGateway
--- PASS: TestTcpReadLoopRoutesThroughGateway (0.00s)
=== RUN   TestTcpReadLoopWorkerGatewayPreservesOrder
--- PASS: TestTcpReadLoopWorkerGatewayPreservesOrder (0.00s)
=== RUN   TestTcpReadLoopParseErrorDisconnects
--- PASS: TestTcpReadLoopParseErrorDisconnects (0.00s)
PASS
ok  	git.toki-labs.com/toki/proto-socket/go/test	0.010s
```

- `TestTcpReadLoopRoutesThroughGateway`: read loop가 gateway로 raw frame을 submit하는지(우회 시 submit=0으로 실패) + 순서 보존.
- `TestTcpReadLoopWorkerGatewayPreservesOrder`: 실제 `EnableInboundGateway`(worker pool)로 100개 burst의 dispatch 순서 보존.
- `TestTcpReadLoopParseErrorDisconnects`: gateway 미부착 시 malformed frame이 `DisconnectReasonTCPPacketParse`로 disconnect.

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

- 결과: 전 항목 PASS. Proto 동기화 PASS, 동일언어 5/5 PASS, 언어 PASS 매트릭스 5x7 전부 PASS, 크로스테스트 30방향 전부 expected 일치 PASS.
- 결과 기록 파일: `agent-test/runs/20260602-021055-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: `go/communicator.go:327`과 `go/inbound_gateway.go:157`에서 gateway 부착 시 malformed raw frame이 worker에서 decode error로 표시된 뒤 collector에서 조용히 drop된다. 이 경로에서는 `OnReceivedFrame`이 항상 nil을 반환하므로 `TcpClient.readLoop`/`WsClient.readLoop`가 기존 `DisconnectReasonTCPPacketParse`/`DisconnectReasonWSPacketParse` disconnect를 적용할 수 없다. follow-up 계획의 "raw frame decode 실패 시 기존 TCP/WS parse error disconnect semantics 유지" 체크리스트가 gateway 부착 경로에서는 충족되지 않는다. gateway decode error를 transport/communicator가 관찰해 동일한 parse-error disconnect를 실행하도록 error callback/result sink를 추가하거나, gateway submit 전에 parse validation을 분리해 기존 semantics를 보존해야 한다.
  - Required: `go/test/communicator_test.go:518`의 parse-error 회귀 테스트는 "with no gateway" 경로만 검증한다. 실제로 문제가 생기는 gateway 부착 read path에서 malformed frame이 parse-error disconnect를 유발하는 테스트가 없다. TCP gateway 부착 경로의 malformed frame 테스트와, 가능하면 WS gateway 부착 경로도 같은 semantics를 확인하는 테스트를 추가해야 한다.
- 다음 단계: WARN/FAIL follow-up으로 다음 active `PLAN-cloud-G08.md`와 `CODE_REVIEW-cloud-G08.md`를 작성한다.
