<!-- task=m-inbound-queue-ordering/08_typescript_gateway plan=1 tag=REVIEW_API -->

# TypeScript Worker Gateway Follow-up 계획

## 이 파일을 읽는 구현 에이전트에게

이 계획은 `code_review_cloud_G08_0.log`의 Required issue만 해소한다. 구현 후 `CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션에 실제 변경 내용과 검증 stdout/stderr를 채운 뒤 active 파일을 그대로 두고 리뷰를 요청한다. 최종화는 code-review 전용이다.

## 배경

초기 TypeScript gateway 구현은 Node worker/fallback/reorder 테스트를 통과했지만, `InboundGateway.close()`가 "추가 전달 중단" 계약을 지키지 않는다. pending decode가 close 이후 완료되면 stale result가 sink 또는 onError로 전달될 수 있고, `Communicator.attachInboundGateway()`/`initialize()`/`close()` 경계에서 이전 gateway 결과가 현재 communicator 상태에 섞일 수 있다.

## 사용자 리뷰 요청 흐름

구현 중 user-only blocker가 있으면 active review stub의 `사용자 리뷰 요청` 섹션을 채운다.

## Roadmap Targets

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

## 분석 결과

### 읽은 파일

- `agent-task/m-inbound-queue-ordering/08_typescript_gateway/code_review_cloud_G08_0.log`
- `agent-task/m-inbound-queue-ordering/08_typescript_gateway/plan_cloud_G08_0.log`
- `typescript/src/inbound_gateway.ts`
- `typescript/src/communicator.ts`
- `typescript/test/communicator.test.ts`

### 실패 재현

```bash
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(JSON.stringify(delivered));
EOF
```

현재 출력은 `[1]`이며, 기대 출력은 close 이후 전달 없음(`[]`)이다.

### 범위 결정 근거

- `WorkerGateway` lifecycle과 관련 테스트만 수정한다.
- Node worker pool 구조, public export, transport 경로, wire schema는 변경하지 않는다.
- `Roadmap Targets`는 동일 task completion을 계속 향하므로 유지한다.

### 빌드 등급

- build/review: `cloud-G08`. 이유: async worker lifecycle, close/cancel, stale delivery 차단은 gateway API contract와 concurrency 경계에 직접 영향을 준다.

## 구현 체크리스트

- [ ] `WorkerGateway.close()`가 close 이후 queued/in-flight decode 결과와 error를 sink/onError로 전달하지 않도록 lifecycle guard를 추가한다.
- [ ] close 시 queued jobs와 reorder pending 상태를 정리해 stale result가 contiguous release를 유발하지 않게 한다.
- [ ] `Communicator.attachInboundGateway()` 또는 재초기화 경계에서 이전 gateway의 늦은 결과가 현재 communicator로 들어오지 않는 테스트를 추가한다.
- [ ] TypeScript tests에 `WorkerGateway.close()` 이후 pending decode result/error가 전달되지 않는 검증을 추가한다.
- [ ] 중간 검증으로 `cd typescript && npm run check && npm test -- communicator`를 실행한다.
- [ ] 최종 검증으로 `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all`을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_API-1] WorkerGateway close lifecycle

#### 문제

- `WorkerGateway.close()`가 `closed = true`만 설정해 pending async decode 완료 후 `collect()`/`sinkChain` 경로가 계속 실행된다.

#### 해결 방법

- close generation 또는 closed guard를 `workerLoop()` 완료 후, `collect()`, `sinkChain` 내부 전달 직전에 적용한다.
- close 시 queued jobs와 reorder pending을 비우거나 교체해 이전 세대 결과가 release되지 않게 한다.
- `onError`도 close 이후에는 전달하지 않는다.

#### 수정 파일 및 체크리스트

- [ ] `typescript/src/inbound_gateway.ts`
- [ ] `typescript/test/communicator.test.ts`

#### 테스트 작성

- pending decode Promise를 close 이후 resolve했을 때 sink가 호출되지 않는지 검증한다.
- pending decode Promise를 close 이후 reject했을 때 onError가 호출되지 않는지 검증한다.
- 기존 communicator gateway reorder/fallback/Node worker tests가 계속 통과하는지 확인한다.

#### 중간 검증

```bash
cd typescript && npm run check && npm test -- communicator
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `typescript/src/inbound_gateway.ts` | REVIEW_API-1 |
| `typescript/test/communicator.test.ts` | REVIEW_API-1 |

## 최종 검증

```bash
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all
```

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
