<!-- task=m-high-performance-parallel-operations/07+06_gateway_cleanup plan=0 tag=GATEWAY_CLEANUP -->

# Plan - GATEWAY_CLEANUP

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

`CODE_REVIEW-cloud-G06.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 구현의 필수 마지막 단계다. 구현 후 검증을 실행하고, 실제 stdout/stderr를 review stub에 기록한 뒤 active 파일을 유지한 채 리뷰 준비를 보고한다. 구현 중 사용자 결정, 사용자 소유 외부 환경, 또는 범위 충돌이 없이는 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 증거를 남기고 중단한다. 명령 재실행이나 산출물 수집으로 해소 가능한 증거 공백은 사용자 리뷰 요청이 아니다.

## 배경

gateway policy는 default off로 선언됐지만, default on/adaptive 후보를 판단하려면 close/cancel/drain이 숫자로 보여야 한다. 현재 gateway lifecycle tests는 stale result가 sink/onError로 전달되지 않는지만 검증하고, queued jobs, reorder pending, worker pool pending, repeated run memory/backlog는 결과 row에 남기지 않는다. 이 작업은 gateway cleanup 진단을 추가하고 stress 결과에 close 후 상태를 기록한다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active `CODE_REVIEW-cloud-G06.md`의 `사용자 리뷰 요청` 섹션에 기록한다. code-review만 해당 요청을 검증하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/high-performance-parallel-operations.md`
- Task ids:
  - `gateway-cleanup`: gateway worker close/cancel/drain 계측을 추가한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/milestones/high-performance-parallel-operations.md`
- `agent-test/local/rules.md`
- `agent-test/local/proto-socket-full-matrix.md`
- `agent-test/local/typescript-smoke.md`
- `typescript/bench/stress.ts`
- `typescript/src/communicator.ts`
- `typescript/src/inbound_gateway.ts`
- `typescript/src/node_inbound_gateway.ts`
- `typescript/src/base_client.ts`
- `typescript/src/tcp_client.ts`
- `typescript/src/tcp_server.ts`
- `typescript/src/node_ws_client.ts`
- `typescript/src/node_ws_server.ts`
- `typescript/test/communicator.test.ts`
- `typescript/test/tcp.test.ts`
- `typescript/test/ws.test.ts`
- `typescript/test/base_client.test.ts`
- `typescript/package.json`

### 테스트 환경 규칙

- test_env: `local`.
- `agent-test/local/rules.md`는 존재하며 읽었다.
- TypeScript gateway lifecycle 변경이므로 `agent-test/local/typescript-smoke.md`를 적용한다: `cd typescript && npm run check && npm test`.
- public exported gateway interface 또는 communicator diagnostics를 확장하면 `agent-test/local/proto-socket-full-matrix.md`도 적용한다: `bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_matrix.sh --all`.
- gateway cleanup evidence는 stress runner 보조 검증으로 남긴다.
- `<확인 필요>` 값은 없었다.

### 테스트 커버리지 공백

- 기존 `typescript/test/communicator.test.ts:688` 이후는 close 후 pending decode resolve/reject가 sink/onError로 전달되지 않는지 검증한다.
- `WorkerGateway`의 queued jobs, active workers, reorder pending, sink delivery backlog를 숫자로 관측하는 test가 없다.
- `Node` worker pool의 pending decode 수와 close 후 pending clear/terminate 상태를 검증하는 test가 없다.
- `typescript/bench/stress.ts` gateway row는 `gatewayBacklog`를 항상 0으로 남겨 cleanup/drain 판단 근거가 부족하다.

### 심볼 참조

- rename/remove 예정 symbol 없음.
- `InboundGateway` interface: `typescript/src/inbound_gateway.ts:37`, `typescript/src/communicator.ts:198`, `typescript/src/node_inbound_gateway.ts:142`, `typescript/bench/stress.ts:815`, `typescript/test/communicator.test.ts:617`.
- `WorkerGateway.close`: `typescript/src/inbound_gateway.ts:152`, tests at `typescript/test/communicator.test.ts:705`, `typescript/test/communicator.test.ts:729`.
- Node worker pool close: `typescript/src/node_inbound_gateway.ts:64`, wrapper close at `typescript/src/node_inbound_gateway.ts:163`.

### 분할 판단

- split policy를 plan 작성 전에 평가했다.
- shared task group: `agent-task/m-high-performance-parallel-operations/`.
- 이 subtask path는 `07+06_gateway_cleanup`이며 predecessor index는 `06`이다.
- predecessor: active sibling `agent-task/m-high-performance-parallel-operations/06_gateway_real_path/PLAN-cloud-G07.md`가 생성되어 있으나 아직 `complete.log`는 없다. 구현은 `06_gateway_real_path` PASS 이후 시작해야 한다.
- dependency reason: cleanup row/backlog naming은 actual transport gateway baseline의 row schema와 맞춰야 한다.

### 범위 결정 근거

- gateway default on/adaptive 전환은 하지 않는다.
- browser Web Worker 구현은 제외한다.
- `WorkerGateway`/Node worker gateway의 진단 API와 TypeScript stress/test 범위로 제한한다.
- wire format, proto schema, nonce semantics는 변경하지 않는다.

### 빌드 등급

- build lane: `cloud-G06`. concurrency lifecycle와 worker termination 진단이 중심이지만 범위는 TypeScript gateway internals와 tests로 제한된다.
- review lane: `cloud-G06`. stats가 실제 cleanup 상태를 나타내는지, close 후 stale delivery가 없는지 확인이 필요하다.

## 구현 체크리스트

- [ ] [GATEWAY_CLEANUP-1] gateway stats/diagnostics 계약을 추가해 queued, active, reorder pending, sink pending, worker pending, closed 상태를 관측한다.
- [ ] [GATEWAY_CLEANUP-2] close/cancel/drain tests를 추가해 close 후 stats가 비고 stale sink/onError delivery가 없는지 검증한다.
- [ ] [GATEWAY_CLEANUP-3] stress gateway rows에 cleanup/backlog evidence를 기록하고 repeated quick run에서 memory/backlog가 누적되지 않음을 결과 파일로 남긴다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 의존 관계 및 구현 순서

이 plan은 `07+06_gateway_cleanup`이므로 implementation은 같은 task group의 `06_gateway_real_path`가 `complete.log`를 만든 뒤 시작한다. predecessor가 아직 완료되지 않았다면 구현하지 말고 review stub의 사용자 리뷰 요청이 아니라 "predecessor incomplete" 상태로 보고한다.

## [GATEWAY_CLEANUP-1] Gateway Diagnostics Contract

### 문제

`InboundGateway`는 `submit`과 `close`만 제공한다.

```ts
37 export interface InboundGateway {
39   submit(frame: InboundFrame): void;
41   close(): void;
42 }
```

`WorkerGateway` 내부에는 관측해야 할 상태가 있지만 모두 private이다.

```ts
127  private readonly reorder = new FrameReorderBuffer();
128  private readonly jobs: InboundFrame[] = [];
129  private activeWorkers = 0;
130  private closed = false;
131  private sinkChain: Promise<void> = Promise.resolve();
```

Node worker pool도 pending count가 private이다.

```ts
33 class WorkerThreadDecodePool {
35   private readonly pending = new Map<number, PendingDecode>();
38   private closed = false;
```

### 해결 방법

- `InboundGatewayStats` type을 추가한다.
- `InboundGateway`에 optional `stats?(): InboundGatewayStats`를 추가해 기존 custom gateway compatibility를 유지한다.
- `FrameReorderBuffer`에 `size` 또는 `pendingCount()`를 추가한다.
- `WorkerGateway.stats()`가 queued jobs, active workers, reorder pending, sink pending, closed를 반환하게 한다.
- `WorkerThreadDecodePool.stats()`와 `createNodeWorkerGateway(...).stats()` wrapper를 추가한다.

예상 shape:

```ts
export interface InboundGatewayStats {
  queued: number;
  active: number;
  reorderPending: number;
  sinkPending: number;
  workerPending: number;
  closed: boolean;
}
```

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

- [ ] `typescript/src/inbound_gateway.ts`: stats type과 optional interface method를 추가한다.
- [ ] `typescript/src/inbound_gateway.ts`: `FrameReorderBuffer` pending count accessor를 추가한다.
- [ ] `typescript/src/inbound_gateway.ts`: `WorkerGateway.stats()`를 구현한다.
- [ ] `typescript/src/node_inbound_gateway.ts`: pool stats와 wrapper stats를 구현한다.
- [ ] `typescript/src/communicator.ts`: 필요한 경우 attached gateway stats를 읽는 helper를 추가하되, public surface를 최소화한다.

### 테스트 작성

- 작성한다. cleanup 계측은 stats 값 자체가 검증 대상이다.

### 중간 검증

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

예상 결과: exit code 0.

## [GATEWAY_CLEANUP-2] Close/Cancel/Drain Tests

### 문제

현재 lifecycle tests는 stale delivery 금지만 확인한다.

```ts
688 describe("WorkerGateway lifecycle", () => {
689   test("close() 이후 pending decode result는 sink로 전달되지 않는다", async () => {
705     gateway.close();
709     expect(delivered).toEqual([]);
```

close 후 jobs/reorder/pool pending이 실제로 비었는지는 검증하지 않는다.

### 해결 방법

- `WorkerGateway`에 queued job이 남은 상태, in-flight decode가 pending인 상태, reorder pending이 있는 상태를 각각 만든다.
- `close()` 후 `stats()`가 zero backlog와 `closed=true`를 반환하는지 검증한다.
- Node worker gateway도 pending decode가 있는 상태에서 close 후 `workerPending=0`을 검증한다.

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

- [ ] `typescript/test/communicator.test.ts`: `WorkerGateway.stats()` unit tests를 추가한다.
- [ ] `typescript/test/communicator.test.ts`: Node worker gateway close stats test를 추가한다.
- [ ] `typescript/test/communicator.test.ts`: 기존 stale result tests가 새 stats contract와 함께 유지되는지 확인한다.

### 테스트 작성

- 작성한다. concurrency cleanup logic이므로 regression tests가 필요하다.

### 중간 검증

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

예상 결과: exit code 0.

## [GATEWAY_CLEANUP-3] Stress Cleanup Evidence

### 문제

현재 stress row는 `gatewayBacklog`를 기록할 수 있지만 gateway profile에서는 실측값이 없다.

```ts
89  queueBacklog: number;
90  gatewayBacklog: number;
```

```ts
836      emitThroughputRow("gateway", `frames=${count}`, count, elapsed, stability, gatewayOn ? "on" : "off", memMb(), {
```

### 해결 방법

- gateway profile에서 close 전/후 stats를 수집한다.
- row의 `gatewayBacklog`는 close 전 peak backlog 또는 close 후 잔여 backlog 중 더 위험한 값을 기록한다.
- close 후 잔여 backlog가 0이 아니면 `pendingLeak`을 증가시킨다.
- repeated quick run 명령을 계획 검증에 포함해 memory/backlog 누적 여부를 결과 파일로 남긴다.

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

- [ ] `typescript/bench/stress.ts`: gateway stats helper를 추가한다.
- [ ] `typescript/bench/stress.ts`: gateway row에 close/drain 후 `gatewayBacklog`를 반영한다.
- [ ] `typescript/bench/stress.ts`: close 후 non-zero backlog를 stability violation으로 기록한다.
- [ ] `agent-test/runs/`: focused stress 결과 파일을 생성한다.

### 테스트 작성

- 별도 unit test는 `GATEWAY_CLEANUP-2`에서 작성한다. 이 항목은 stress evidence 생성이다.

### 중간 검증

```bash
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --quick --lang typescript --transport tcp,ws --profile gateway
```

예상 결과: PASS, `gatewayBacklog`가 실제 stats 기반 값으로 기록되고 close 후 leak이면 FAIL한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `typescript/src/inbound_gateway.ts` | GATEWAY_CLEANUP-1 |
| `typescript/src/node_inbound_gateway.ts` | GATEWAY_CLEANUP-1 |
| `typescript/src/communicator.ts` | GATEWAY_CLEANUP-1 |
| `typescript/test/communicator.test.ts` | GATEWAY_CLEANUP-2 |
| `typescript/bench/stress.ts` | GATEWAY_CLEANUP-3 |
| `CODE_REVIEW-cloud-G06.md` | GATEWAY_CLEANUP-3 |

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

- stats API가 기존 custom `InboundGateway` 구현을 깨지 않도록 optional인지 확인한다.
- close 후 queued/reorder/worker pending이 0으로 관측되는지 확인한다.
- stale result/onError suppression이 기존 tests와 함께 유지되는지 확인한다.
- stress row의 `gatewayBacklog`가 하드코딩 0이 아니라 실제 stats 기반인지 확인한다.

## 최종 검증

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

```bash
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --quick --lang typescript --transport tcp,ws --profile gateway
```

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

모든 명령은 exit code 0이어야 한다. Go test cache 관련 없음. stress/matrix runner가 생성한 `agent-test/runs/*.md` 경로를 review stub에 기록한다.

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