<!-- task=m-inbound-queue-ordering/08_typescript_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.

## 개요

date=2026-06-02
task=m-inbound-queue-ordering/08_typescript_gateway, plan=1, tag=REVIEW_API

## Roadmap Targets

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

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

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

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_API-1] WorkerGateway close lifecycle | [x] |

## 구현 체크리스트

- [x] `WorkerGateway.close()`가 close 이후 queued/in-flight decode 결과와 error를 sink/onError로 전달하지 않도록 lifecycle guard를 추가한다.
- [x] close 시 queued jobs와 reorder pending 상태를 정리해 stale result가 contiguous release를 유발하지 않게 한다.
- [x] `Communicator.attachInboundGateway()` 또는 재초기화 경계에서 이전 gateway의 늦은 결과가 현재 communicator로 들어오지 않는 테스트를 추가한다.
- [x] TypeScript tests에 `WorkerGateway.close()` 이후 pending decode result/error가 전달되지 않는 검증을 추가한다.
- [x] 중간 검증으로 `cd typescript && npm run check && npm test -- communicator`를 실행한다.
- [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 산출물이 추적 가능한지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 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로 이동한다.

## 계획 대비 변경 사항

- `code_review_cloud_G08_0.log`의 Required issue(`InboundGateway.close()` 계약 위반)만 해소했다. Node worker pool 구조, public export, transport 경로, wire schema는 변경하지 않았다.
- 수정 파일: `typescript/src/inbound_gateway.ts`(close lifecycle), `typescript/test/communicator.test.ts`(lifecycle 테스트 3건 추가). 계획의 `수정 파일 요약`과 일치한다.
- `FrameReorderBuffer`에 `clear()`를 추가해 close 시 reorder pending을 비울 수 있게 했다(계획의 "reorder pending 상태 정리" 항목 충족).

## 주요 설계 결정

- **per-instance closed guard로 stale delivery 차단**: `WorkerGateway.close()`는 `closed = true` 설정에 더해 `jobs.length = 0`과 `reorder.clear()`로 queued/buffered 상태를 비운다. in-flight decode는 `workerLoop()`이 `await this.decode()` 직후 `this.closed`를 확인해 close된 경우 collect 없이 종료하고, `collect()`와 `sinkChain` 콜백 진입부에서도 `closed`를 재확인한다. 따라서 close 이후 완료/실패하는 decode는 sink·onError로 전달되지 않는다.
- **세대 토큰이 아닌 인스턴스 guard 선택 근거**: communicator가 `attachInboundGateway()`/`initialize()`로 gateway를 교체할 때 이전 gateway 인스턴스는 `closeGateway()`로 close된다. sink는 해당 인스턴스 생성 시점에 바인딩된 클로저이므로, 인스턴스별 `closed` guard만으로 이전 gateway의 늦은 결과가 현재 communicator(`enqueueInbound`)로 유입되는 것을 막는다. 별도 cross-instance 세대 토큰은 불필요하다.
- **close 이후 in-flight sink의 잔여 frame 중단**: `sinkChain` 콜백은 각 ready frame 전달 전에 `closed`를 확인해, 스케줄 이후 close되면 남은 batch 전달을 멈춘다. 이미 await 중인 단일 sink 호출은 완주하되 그 이후 frame은 전달되지 않는다.
- 기존 reorder/fallback/Node worker/decode-error 동작과 그 테스트는 모두 그대로 유지된다(회귀 없음).

## 사용자 리뷰 요청

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

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

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

- `WorkerGateway.close()` 이후 pending result/error가 sink/onError로 전달되지 않는지 확인한다.
- reattach/reinitialize 경계에서 이전 gateway의 늦은 결과가 현재 communicator 상태로 들어오지 않는지 확인한다.
- 기존 Node worker gateway, fallback, out-of-order reorder 테스트가 유지되는지 확인한다.

## 검증 결과

### Required issue 재현 → 해소 확인
```
$ cd typescript && node --import tsx --input-type=module <<'EOF'
import { WorkerGateway } from './src/inbound_gateway.ts';
let resolveDecode;
const delivered = [];
const gw = new WorkerGateway({
  workers: 1,
  decode: () => new Promise((resolve) => { resolveDecode = resolve; }),
  sink: (frame) => { delivered.push(frame.seq); },
});
gw.submit({ seq: 1, bytes: new Uint8Array([1]) });
gw.close();
resolveDecode({ typeName: 't', data: new Uint8Array(), incomingNonce: 0, responseNonce: 0 });
await new Promise((r) => setTimeout(r, 0));
console.log("delivered:", JSON.stringify(delivered));
EOF
delivered: []      # 수정 전 [1] → 수정 후 [] (기대값)
```

### REVIEW_API-1 중간 검증
```
$ cd typescript && npm run check && npm test -- communicator
> proto-socket@1.0.5 check
> tsc --noEmit
(에러 없음)

> proto-socket@1.0.5 test
> vitest run communicator

 RUN  v3.2.4 /config/workspace/proto-socket/typescript
 ✓ test/communicator.test.ts (24 tests) 409ms
   ✓ WorkerGateway lifecycle > close() 이후 pending decode result는 sink로 전달되지 않는다
   ✓ WorkerGateway lifecycle > close() 이후 pending decode reject는 onError로 전달되지 않는다
   ✓ Communicator inbound gateway > attachInboundGateway 경계: 닫힌 이전 gateway의 늦은 결과가 현재 communicator로 들어오지 않는다

 Test Files  1 passed (1)
      Tests  24 passed (24)
```
(기존 21건 + lifecycle 3건 = 24건 PASS)

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

**Proto 동기화**: schema sync PASS
**동일언어**: Dart / Go / Kotlin / Python / TypeScript 모두 PASS
**언어 PASS 매트릭스**: 5 서버 × (Dart.io/Dart.web/Dart.web(WSS)/Go/Kotlin/Python/TypeScript) 전부 PASS
**크로스테스트 상세**: 일반 언어간 20방향 16/16, Dart.web/Dart.web(WSS) 10방향 2/2, FAIL lines 0

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

## 코드리뷰 결과

- 종합 판정: PASS

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| correctness | Pass | close 이후 pending decode result/error가 sink/onError로 전달되지 않도록 `WorkerGateway` guard가 적용됐다. |
| completeness | Pass | 계획의 close lifecycle 항목, queued/reorder 정리, attach 경계 테스트, lifecycle 테스트가 모두 충족됐다. |
| test coverage | Pass | WorkerGateway close result/reject, Communicator attach stale result, 기존 gateway reorder/fallback/Node worker 테스트가 포함됐다. |
| API contract | Pass | `InboundGateway.close()`의 "추가 전달 중단" 계약과 구현이 일치한다. |
| code quality | Pass | close guard가 submit, decode await 이후, collect, sinkChain 내부 전달 직전에 적용되어 async 경계가 명확하다. |
| plan deviation | Pass | 후속 계획 범위인 lifecycle 수정과 테스트만 수행했다. |
| verification trust | Pass | 재현 스크립트, TypeScript check/test, 전체 로컬 매트릭스를 리뷰에서 직접 재실행해 PASS를 확인했다. |

### 발견된 문제

- 없음

### 리뷰 검증

```bash
$ cd typescript && node --import tsx --input-type=module
delivered: []
```

```bash
$ cd typescript && npm run check && npm test -- communicator
> proto-socket@1.0.5 check
> tsc --noEmit

> proto-socket@1.0.5 test
> vitest run communicator

 RUN  v3.2.4 /config/workspace/proto-socket/typescript
 ✓ test/communicator.test.ts (24 tests) 417ms
 Test Files  1 passed (1)
      Tests  24 passed (24)
```

```bash
$ bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all
(종료 코드 0)

Proto 동기화: schema sync PASS
동일언어: Dart / Go / Kotlin / Python / TypeScript 모두 PASS
언어 PASS 매트릭스: 5 서버 x 7 클라이언트 전부 PASS
크로스테스트 상세: 일반 언어간 20방향 16/16, Dart.web/Dart.web(WSS) 10방향 2/2, FAIL lines 0
결과 기록 파일: agent-test/runs/20260602-074418-proto-socket-full-matrix.md
```

### 다음 단계

- PASS: active 파일을 archive하고 `complete.log`를 작성한 뒤 task directory를 `agent-task/archive/2026/06/m-inbound-queue-ordering/08_typescript_gateway/`로 이동한다. Runtime은 Milestone PASS completion metadata를 사용해 roadmap 갱신 여부를 판단한다.
