<!-- task=ai_first_improvements plan=0 tag=AI_FIRST -->

# Code Review Reference — AI_FIRST

## 개요

task=ai_first_improvements, plan=0, tag=AI_FIRST

## 구현 항목별 완료 여부

| 항목 | 완료 | 비고 |
|------|------|------|
| [AI_FIRST-1] Dart 전송 계층을 Go 기준으로 정렬 | [x] | `Transport` 추가, TCP/WS adapter 주입, TCP max packet guard 및 회귀 테스트 추가 |
| [AI_FIRST-2] Proto sync와 codegen 검증 도구 추가 | [x] | `tools/check_proto_sync.sh`, `tools/generate_proto.sh` 추가 및 README 갱신 |
| [AI_FIRST-3] 프로토콜/패키지 버전 정책 문서화 | [x] | `VERSIONING.md` 추가, `PROTOCOL.md`/README에 protocol version과 breaking 후보 명시 |
| [AI_FIRST-4] 새 언어 구현 scaffolding과 검증 체크리스트 추가 | [x] | `templates/language/` 3개 템플릿 추가, 포팅 절차 문서화 |

## 계획 대비 변경 사항

- 계획서대로 구현.
- Dart `Communicator.transmitPacket`은 즉시 제거하지 않고 deprecated fallback으로 유지했다. 기존 `initialize(parserMap)`만 호출하는 subclass 호환을 보존하면서 새 구현은 `Transport` 주입 경로를 사용한다.
- `tools/check_proto_sync.sh`는 `option go_package`뿐 아니라 빈 줄 차이도 정규화한다. schema drift 검사가 목적이라 포맷 공백만으로 실패하지 않게 했다.

## 주요 설계 결정

- Dart 전송 계층은 `dart/lib/src/transport.dart`의 최소 `Transport.writePacket`/`Transport.close` 인터페이스로 분리했다.
- TCP/WS client public 생성자는 유지하고 내부에서 `_TcpSocketTransport`, `_WebSocketTransport`를 만들어 `Communicator.initialize(..., transport: ...)`에 주입한다.
- TCP parser는 Go의 `MaxPacketSize = 64 << 20`와 맞춰 `maxPacketSize`를 추가했고, 음수 또는 초과 length를 받으면 `close()`를 예약한다.
- Proto sync 검사는 Dart canonical proto와 Go proto copy를 비교하되 Go 전용 `option go_package`는 허용한다.
- 새 언어 템플릿은 실제 코드를 생성하지 않고 README, 구현 체크리스트, crosstest 체크리스트만 제공한다.

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

- `dart/lib/src/communicator.dart`: `initialize`의 `transport` 선택 인자, deprecated fallback, `queuePacket`의 serialized write 경로.
- `dart/lib/src/protobuf_client.dart`: TCP transport adapter write/close 분리와 oversized/negative packet length close 처리.
- `dart/lib/src/ws_protobuf_client.dart`: WebSocket binary write/close adapter 분리.
- `tools/check_proto_sync.sh`: Go 전용 proto option 허용 범위와 diff 출력.
- `templates/language/`: 새 언어 구현에 과한 코드 구조를 강제하지 않고 필수 검증 조건만 담았는지 확인.

## 검증 결과

```
$ tools/check_proto_sync.sh
Proto schemas are in sync.

$ cd dart && dart analyze
Analyzing dart...
No issues found!

$ cd dart && dart test
00:15 +42: All tests passed!

$ cd go && PATH=/config/go-sdk/go/bin:/config/go/bin:$PATH GOCACHE=/tmp/go-build GOMODCACHE=/tmp/go-mod go test ./...
?   	toki-labs.com/toki_socket/go	[no test files]
?   	toki-labs.com/toki_socket/go/crosstest	[no test files]
?   	toki-labs.com/toki_socket/go/crosstest/dart_go_client	[no test files]
?   	toki-labs.com/toki_socket/go/examples/tcp_echo	[no test files]
?   	toki-labs.com/toki_socket/go/examples/ws_echo	[no test files]
?   	toki-labs.com/toki_socket/go/packets	[no test files]
ok  	toki-labs.com/toki_socket/go/test	(cached)

$ find templates/language -maxdepth 1 -type f
templates/language/IMPLEMENTATION_CHECKLIST.md
templates/language/CROSSTEST_CHECKLIST.md
templates/language/README.md

$ cd dart && PATH=/config/go-sdk/go/bin:/config/go/bin:$PATH dart run crosstest/dart_go.dart
INFO typeName dart=TestData
INFO typeName go=TestData
PASS scenario=1 detail=fire-and-forget sent
PASS scenario=2 detail=received push from dart server
PASS scenario=3 detail=single request response matched
PASS scenario=4 detail=concurrent request responses matched
PASS scenario=1 detail=fire-and-forget sent
PASS scenario=2 detail=received push from dart server
PASS scenario=3 detail=single request response matched
PASS scenario=4 detail=concurrent request responses matched
PASS all dart-server/go-client crosstests passed

$ cd go && PATH=/config/go-sdk/go/bin:/config/go/bin:$PATH GOCACHE=/tmp/go-build GOMODCACHE=/tmp/go-mod go run ./crosstest
INFO typeName go=TestData
INFO typeName dart=TestData
PASS scenario=1 detail=fire-and-forget sent
PASS scenario=2 detail=received push from go server
PASS scenario=3 detail=single request response matched
PASS scenario=4 detail=concurrent request responses matched
PASS scenario=1 detail=fire-and-forget sent
PASS scenario=2 detail=received push from go server
PASS scenario=3 detail=single request response matched
PASS scenario=4 detail=concurrent request responses matched
PASS all go-server/dart-client crosstests passed
```

참고: crosstest는 기본 sandbox에서 SDK cache 쓰기 또는 localhost bind가 차단되어 승인된 외부 실행으로 재시도했다.

---

## 코드리뷰 결과

### 종합 판정

**PASS**

> 4개 항목 모두 계획대로 구현됐고, 테스트 수(42개)와 검증 출력이 실제 코드와 일치한다. 전송 계층 분리, proto sync 도구, 버전 정책 문서, 언어 추가 템플릿 모두 품질 이슈 없음.

### 차원별 평가

| 차원 | 판정 | 비고 |
|------|------|------|
| 정확성 (Correctness) | Pass | maxPacketSize 가드, queuePacket 에러 전파, _LegacyCommunicatorTransport 위임 경로 모두 정확 |
| 완성도 (Completeness) | Pass | 계획서의 모든 체크리스트 항목 구현 확인 |
| 테스트 커버리지 | Pass | `queuePacket uses injected transport`(에러 전파 포함), `TCP closes on oversized packet length` 두 신규 테스트 모두 의미 있는 assertion |
| API 계약 | Pass | `toki_socket.dart`에 `transport.dart` export 추가, 기존 `ProtobufClient`/`WsProtobufClient` public 생성자 유지 |
| 코드 품질 | Pass | 디버그 출력·dead import·leftover TODO 없음 |
| 계획 대비 이탈 | Pass | `transmitPacket` deprecated 유지 결정이 CODE_REVIEW.md에 명시됨 |
| 검증 신뢰도 | Pass | 보고된 출력(42개 통과, crosstest PASS)이 실제 코드 로직과 일치 |

### 발견된 문제

- **[Nit]** `dart/lib/src/communicator.dart:59` — `if (transport == null)` 분기는 `initialize()` 호출 후에는 실행되지 않는 방어 코드다. `initialize()` 가 항상 non-null 값을 `_transport`에 할당하므로 실질적으로 dead branch다. 제거하거나 `assert(false, 'queuePacket called before initialize')` 로 교체 가능하지만 동작에 영향 없음.

### 다음 단계

**[PASS]** 추가 작업 불필요. 아카이브 완료.
