<!-- task=typescript_impl plan=0 tag=API -->

# Code Review Reference - API

## 개요

date=2026-04-24
task=typescript_impl, plan=0, tag=API

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

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료 후 반드시 아래 순서로 아카이브하세요.

1. `CODE_REVIEW.md` → `code_review_0.log` (N = 기존 code_review_*.log 수)
2. `PLAN.md` → `plan_0.log` (M = 기존 plan_*.log 수)
3. PASS인 경우 `complete.log` 작성 후 종료. WARN/FAIL인 경우 새 `PLAN.md` + `CODE_REVIEW.md` 스텁 작성.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [API-1] 패키지 스캐폴드 및 Protobuf 바인딩 생성 | [x] |
| [API-2] Communicator 구현 | [x] |
| [API-3] BaseClient 구현 (하트비트 + disconnect 리스너) | [x] |
| [API-4] TcpClient 구현 (Node.js) | [x] |
| [API-5] TcpServer 구현 (Node.js) | [x] |
| [API-6] WsClient 구현 (Node.js / Browser) | [x] |
| [API-7] WsServer 구현 (Node.js) | [x] |
| [API-8] 크로스테스트 추가 (Go 서버 / TypeScript 클라이언트) | [x] |

## 계획 대비 변경 사항

- `tsconfig.json`의 `rootDir`를 `src` 대신 `.`으로 두었다. 계획서의 핵심 옵션은 유지하되, `test/`와 `crosstest/`까지 `npx tsc --noEmit` 한 번으로 함께 검사하려면 `rootDir=src`로는 TS6059 오류가 발생하기 때문이다.
- protobuf-es v2 생성 코드는 메시지 인스턴스 메서드(`toBinary()`, `fromBinary()`)가 아니라 스키마(`GenMessage`) 기반 직렬화/파싱을 사용한다. 그래서 `ParserMap`에 `parserFromSchema()` 헬퍼를 추가하고, `Communicator` 내부에 `typeName -> schema` 레지스트리를 함께 유지하는 방식으로 구현했다.
- `WsClient`는 계획서의 “Node.js / Browser” 표현과 달리 이번 범위에서는 `ws` 패키지 기반 Node.js 런타임만 직접 제공한다. 브라우저 호환성은 코어 계층(`Communicator`, generated types)이 유지하는 수준으로 제한했고, README에 TLS/WSS 및 browser transport wrapper 미지원으로 명시했다.
- `API-8` 구현 파일과 실행 경로는 추가했지만, 이 환경에는 `go` 바이너리가 없어 `go run ./crosstest/go_typescript.go`를 실제로 수행하지 못했다. 따라서 cross-language run은 코드 추가 완료 상태이며 실행 검증은 환경 의존 caveat로 남긴다.

## 주요 설계 결정

- protobuf-es v2 generated schema를 그대로 체크인하고, 런타임은 `create()/toBinary()/fromBinary()`를 사용했다.
- `Communicator`의 write path는 Go/Python의 channel/queue를 배열 기반 직렬 큐(`writeQueue` + `runWriteQueue()`)로 옮겨, 동시 `send()`/`sendRequest()`에서도 nonce 순서와 byte write 순서를 보장했다.
- `BaseClient.close()`는 멱등성을 위해 `closePromise`를 사용하고, `doClose()`가 실패하더라도 disconnect listener는 항상 호출되도록 `notifyDisconnected()`를 분리했다.
- TCP/WS 서버는 실제 테스트에서 ephemeral port(`0`)를 사용할 수 있게 `port` getter를 노출했다.
- Go 오케스트레이터는 기존 `go_python.go` 패턴을 복제해 `npx tsx crosstest/go_typescript_client.ts`를 subprocess로 실행하도록 했다.

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

- protobuf-es의 `typeName`이 `"TestData"`, `"HeartBeat"`, `"PacketBase"` (단순 이름)인지 확인. `INFO typeName ts=...` 로그 출력 확인.
- `addListener`/`addRequestListener` 상호 배타 위반 시 `Error`가 throw되는지 확인.
- `Communicator.shutdown()` 호출 시 모든 `pendingRequests`가 `NotConnectedError`로 reject되는지 확인.
- `TcpClient.onData()`에서 불완전한 패킷(버퍼 부족)이 왔을 때 다음 `data` 이벤트까지 기다리는지 확인.
- `BaseClient.close()` 멱등성: `isClosed` 플래그로 중복 실행을 막는지 확인.
- `writeQueue` 배열 기반 큐: 여러 `await queuePacket()` 동시 호출 시 순서가 보장되는지 확인.
- 크로스테스트 `go_typescript.go`에서 TypeScript 실행 명령이 환경에 맞게 경로 해결되는지 확인 (`tsx` 또는 `node dist/...`).
- TLS/WSS는 이번 범위 밖이므로 README에 미지원임을 명시했는지 확인.

## 검증 결과

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

### API-1 중간 검증
```
$ cd typescript && npm install && npx tsc --noEmit

added 1 package, and audited 65 packages in 2s

17 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

### API-2 중간 검증
```
$ cd typescript && npx tsc --noEmit && npx vitest run test/communicator.test.ts

 RUN  v3.2.4 /config/workspace/toki_socket/typescript

 ✓ test/communicator.test.ts (7 tests) 29ms

 Test Files  1 passed (1)
      Tests  7 passed (7)
   Start at  04:08:52
   Duration  1.83s (transform 232ms, setup 0ms, collect 385ms, tests 29ms, environment 0ms, prepare 454ms)
```

### API-3 중간 검증
```
$ cd typescript && npx tsc --noEmit && npx vitest run test/base_client.test.ts

 RUN  v3.2.4 /config/workspace/toki_socket/typescript

 ✓ test/base_client.test.ts (5 tests) 17ms

 Test Files  1 passed (1)
      Tests  5 passed (5)
   Start at  04:08:52
   Duration  1.83s (transform 223ms, setup 0ms, collect 395ms, tests 17ms, environment 0ms, prepare 447ms)
```

### API-4 중간 검증
```
$ cd typescript && npx tsc --noEmit && npx vitest run test/tcp.test.ts

 RUN  v3.2.4 /config/workspace/toki_socket/typescript

 ✓ test/tcp.test.ts (2 tests) 13ms

 Test Files  1 passed (1)
      Tests  2 passed (2)
   Start at  04:08:51
   Duration  1.96s (transform 280ms, setup 0ms, collect 468ms, tests 13ms, environment 0ms, prepare 778ms)
```

### API-5 중간 검증
```
$ cd typescript && npx tsc --noEmit

(no output, exit 0)
```

### API-6 중간 검증
```
$ cd typescript && npx tsc --noEmit && npx vitest run test/ws.test.ts

 RUN  v3.2.4 /config/workspace/toki_socket/typescript

 ✓ test/ws.test.ts (2 tests) 94ms

 Test Files  1 passed (1)
      Tests  2 passed (2)
   Start at  04:08:51
   Duration  2.23s (transform 307ms, setup 0ms, collect 582ms, tests 94ms, environment 0ms, prepare 767ms)
```

### API-7 중간 검증
```
$ cd typescript && npx tsc --noEmit

(no output, exit 0)
```

### API-8 중간 검증
```
$ cd go && go run ./crosstest/go_typescript.go

bash: line 1: go: command not found
```

### 최종 검증
```
$ cd typescript && npx tsc --noEmit && npx vitest run

 RUN  v3.2.4 /config/workspace/toki_socket/typescript

 ✓ test/base_client.test.ts (5 tests) 9ms
 ✓ test/communicator.test.ts (7 tests) 19ms
 ✓ test/tcp.test.ts (2 tests) 35ms
 ✓ test/ws.test.ts (2 tests) 35ms

 Test Files  4 passed (4)
      Tests  16 passed (16)
   Start at  04:08:51
   Duration  2.17s (transform 611ms, setup 0ms, collect 2.27s, tests 97ms, environment 0ms, prepare 3.78s)
$ cd go && go run ./crosstest/go_typescript.go

bash: line 1: go: command not found
```

---

## 코드리뷰 결과

### 종합 판정

**WARN**

### 차원별 평가

| 차원 | 평가 | 비고 |
|------|------|------|
| 정확성 (Correctness) | Pass | 프로토콜 준수, 상태 관리, nonce 단조 증가, 경쟁 조건 없음 |
| 완료도 (Completeness) | Pass | 계획 8개 항목 전부 구현됨 |
| 테스트 커버리지 (Test coverage) | Pass | 16개 테스트 전부 PASS. 계획 명세 항목 모두 존재 |
| API 계약 (API contract) | Warn | `ws`가 devDependencies에 있어 런타임 배포 시 누락 가능 |
| 코드 품질 (Code quality) | Pass | debug print, dead code, TODO 없음 |
| 계획 이탈 (Plan deviation) | Pass | 3가지 이탈 모두 이유가 타당하고 문서화됨 |
| 검증 신뢰도 (Verification trust) | Pass | 검증 출력이 실제 코드와 일치. `go` 실행 불가 caveat 명시됨 |

### 발견된 문제

**Suggested — 1건**

- `typescript/package.json:17`: `ws`가 `devDependencies`에 있으나 런타임 의존성이다. `ws_client.ts`와 `ws_server.ts` 모두 `ws`를 런타임 import한다. `npm install --omit=dev` 또는 프로덕션 설치 시 실패한다. `dependencies`로 이동할 것.
  ```diff
  -  "devDependencies": {
  -    ...
  -    "ws": "^8.18.1"
  -  }
  +  "dependencies": {
  +    "@bufbuild/protobuf": "^2.2.5",
  +    "ws": "^8.18.1"
  +  }
  ```

**Nit — 3건**

- `typescript/src/communicator.ts:334`: `encodeMessage()`는 `schemaMap`에 스키마가 등록된 타입만 직렬화할 수 있다. `parserFromSchema()` 없이 직접 파서를 등록하면 `send()` 시 `"protobuf schema is not registered"` 에러가 발생하는 제약이 문서화되지 않았다. API 주석 한 줄로 명시 권장.
- `typescript/src/ws_client.ts:85-86`: `Array.isArray(data)` 분기에서 각 chunk를 `Buffer.from(chunk)`로 감싼 후 concat한다. `ws` 패키지는 `Buffer[]`를 방출하므로 `Buffer.concat(data as Buffer[])` 가 더 직접적이다.
- `typescript/README.md:3` + `PROTOCOL.md:183`: 상태가 각각 `"planned"`, `"Planned"`로 남아 있다. `go` 환경에서 크로스테스트가 통과하면 `"Available"`로 갱신해야 한다. 현재는 환경 제약으로 인한 정당한 보류이므로 별도 액션 불필요.

### 다음 단계

WARN이므로 Suggested 항목(`ws` dependencies 이동)을 수정하는 새 PLAN.md + CODE_REVIEW.md 스텁을 작성한다.
