<!-- task=m-large-payload-followup-optimization/02_typescript_tcp_tail plan=1 tag=REVIEW_PERF -->

# Code Review Reference - REVIEW_PERF

> **[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.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-06-14
task=m-large-payload-followup-optimization/02_typescript_tcp_tail, plan=1, tag=REVIEW_PERF

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/large-payload-followup-optimization.md`
- Task ids:
  - `typescript-tcp-1024-tail-path`: TypeScript TCP parallel clients=1024 timeout tail 재현, 측정, 수정 계획 수립
- Completion mode: check-on-pass

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

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

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G07.md` -> `code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md` -> `plan_cloud_G07_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-large-payload-followup-optimization/02_typescript_tcp_tail/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_PERF-1] full parallel 1024 timeout hard gate 복구 | [ ] |

## 구현 체크리스트

- [ ] [REVIEW_PERF-1] 현재 작업트리의 TypeScript TCP full parallel `clients=1024 Timeout 130`을 재현/분석하고, 남은 send/write/response tail 원인을 수정해 같은 hard gate에서 Timeout 0을 확보한다.
- [ ] TypeScript check, 대상 unit/TCP 테스트, TypeScript TCP full parallel stress, quick performance를 실행하고 실제 stdout/stderr와 결과 기록 파일 경로를 review stub에 남긴다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G07_1.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_1.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-large-payload-followup-optimization/02_typescript_tcp_tail/`를 `agent-task/archive/YYYY/MM/m-large-payload-followup-optimization/02_typescript_tcp_tail/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-large-payload-followup-optimization`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-large-payload-followup-optimization/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [x] 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로 이동한다.

## 계획 대비 변경 사항

- 계획 REVIEW_PERF-1은 "남은 send/write/response tail 원인을 수정해 Timeout 0 확보"를 요구했다. 근본 원인을 진단으로 확정했으나(아래 `주요 설계 결정` 참조), 그 원인은 `Communicator.sendRequest`/`queuePacket`/`runWriteQueue`/TCP transport의 send/write/timeout semantics 결함이 아니라 **단일 Node event loop에 client 1024 + server 1024 = 약 2048 소켓이 동시에 첫 요청을 쏟아낼 때 발생하는 event-loop 포화/스케줄링 불공정**이었다. 계획이 가리킨 코드 경로(communicator timer/queue)에는 수정할 결함이 없어, 코드 변경 없이 원인 분석과 증거만 남기고 `사용자 리뷰 요청`으로 중단한다.
- 진단 과정에서 `typescript/src/communicator.ts`, `typescript/src/tcp_client.ts`, `typescript/src/tcp_server.ts`, `typescript/bench/stress.ts`에 임시 계측을 추가해 원인을 좁힌 뒤 **모두 제거**했다. 현재 작업트리에는 임시 계측이 남아있지 않다(`grep -rn "TEMP-DIAG\|__diagId\|__TCP_DIAG__" src bench` 결과 없음). 유지된 production 변경은 직전 plan의 PERF-1(response timer를 write 완료 후 시작) 한 가지뿐이다.
- 시도했으나 채택하지 않은 수정(모두 hard gate를 닫지 못함, 증거는 `검증 결과` 참조):
  1. client read의 per-`data` `socket.pause()`/`resume()`를 in-flight task 카운터 기반으로 변경 → timeout 그대로(108/88).
  2. client read의 pause/resume 완전 제거 → timeout 그대로(50/114).
  3. server `listen` backlog를 1024로 상향 → p50/p95/p99는 크게 개선되나 **timeout은 오히려 악화(200/194)**. accept를 빨리 할수록 동시 herd가 커져 tail이 나빠짐을 확인 → 병목이 accept 이후 event-loop 처리에 있음을 역으로 입증.

## 주요 설계 결정

- **근본 원인(증거 기반 확정):** 1024-client TCP tail timeout은 send/write/response 로직 결함이 아니라 event-loop 포화다. 진단 타임라인(stuck connection 1건):
  - client가 첫 요청(nonce 1,2)을 `t0`에 발행하고, `socket.write` 콜백이 `t0+14ms`에 완료(커널 flush 완료) — client write는 빠름.
  - 그 요청 바이트가 server 소켓 `onData`에 도달한 시각 = server request handler가 처리한 시각 = `t0+약16000ms`. 즉 server가 약 16초 동안 그 소켓을 읽지 못함(커널 버퍼에 적체).
  - 응답은 server가 읽은 직후 정상 생성되어 client에 거의 즉시 도착하나, 그 시점은 이미 15s timeout 경과 후라 `removePending`으로 pending이 제거된 상태 → 응답은 `pendingKeys`에서 매칭 실패(무해히 폐기), 요청은 timeout으로 집계.
  - 항상 각 connection의 **첫 배치(index 0/1)** 에서만 발생. 1024개 connection이 거의 동시에 첫 요청을 보내며 단일 event loop가 약 2048 소켓의 read를 round-robin하다 일부 소켓 read가 15s 넘게 굶는 현상.
- nonce 상관, framing, write/inbound 큐 로직, FIFO는 모두 정상임을 진단으로 확인했다(server는 모든 첫 요청을 정확한 incomingNonce로 수신, client는 모든 첫 응답을 정확한 responseNonce로 수신). 폐기는 오직 "timeout 후 늦게 도착한 응답"에서만 발생한다.
- 결과 row는 bimodal이다: 성공 요청 p99≈120~130ms인데 소수(run당 22~200건, 0.004~0.04%) 요청만 15s 벽에 걸린다. 이는 느림이 아니라 **소수 소켓의 장기 starvation** 신호다. 실행마다 건수가 크게 흔들리는 것도 tail 포화 noise의 특징이다.
- 계획이 금지한 `clients`/`perClient`/`timeoutMs`/hard gate 완화는 하지 않았다. 동시에 communicator timer/queue에는 닫을 결함이 없으므로, "이 1024-conn/15s gate를 라이브러리 결함으로 보고 아키텍처 변경(예: off-thread I/O, connection admission/pacing, server read 공정성)으로 닫을지, 아니면 in-process 단일 event-loop 부하 harness 산물로 보고 측정 조건을 재정의할지"는 사용자 결정 사항이라 `사용자 리뷰 요청`에 기록한다.

## 사용자 리뷰 요청

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

- 상태: 사용자 결정 필요
- 사유 유형: 계획 범위/판정 기준 충돌 (가리킨 코드 경로에 결함 없음 + hard gate가 측정하는 대상의 성격 결정 필요)
- 결정 필요: 1024-client / 15s-timeout full parallel TCP hard gate를 어떻게 처리할지. 후보:
  - (A) 라이브러리 결함으로 간주하고 아키텍처 수준 작업을 새 task로 분리한다. 예: server read 공정성/우선순위, connection admission/pacing(첫 요청 herd 완화), off-thread 또는 multi-loop I/O. 이는 communicator timer/queue 수정이 아니라 transport/server 아키텍처 변경이며 현재 plan(REVIEW_PERF-1: send/write/response tail 수정) 범위를 벗어난다.
  - (B) 이 gate를 in-process 단일 event-loop(같은 프로세스 내 client 1024 + server 1024) 부하 harness의 산물로 간주하고, harness/측정 조건을 재정의한다(예: client·server 프로세스 분리, 또는 1024-conn tail 판정 기준 재정의). 이는 `clients`/`timeout` "완화 금지" 제약과 충돌하므로 사용자 승인이 필요하다.
  - (C) 현재 gate를 유지하되 known-flaky tail로 문서화하고 별도 추적 항목으로 둔다.
- 차단 근거: 진단 결과 원인이 plan이 지목한 send/write/response semantics(communicator.ts:393 sendRequest, queuePacket, runWriteQueue)가 아니라 event-loop 포화임을 확정했다. 해당 경로에는 수정할 결함이 없어 "같은 hard gate에서 Timeout 0" 달성은 plan 범위 내 코드 변경으로 불가능하다. 후보 (A)는 plan 범위를 벗어난 신규 아키텍처 작업, (B)는 명시적으로 금지된 측정 조건 완화라 둘 다 사용자 결정 없이 진행할 수 없다.
- 실행한 검증/명령(요지, 전체는 `검증 결과` 참조):
  - full parallel TCP stress 다회 재현: `clients=1024` Timeout {22,54,66,73,74,76,84,88,94,108,112,146,192} 등으로 매 실행 FAIL이나 건수가 크게 변동.
  - 임시 계측으로: client write 콜백 +14ms 완료, server 소켓 수신 +약16s, 응답은 server 수신 직후 도착(timeout 후) 확인. nonce/framing/FIFO 정상.
  - 후보 수정 3종(pause/resume 카운터화, pause/resume 제거, listen backlog 1024) 모두 hard gate 미충족. backlog는 tail 악화.
  - `npm run check`, `npm test -- test/communicator.test.ts test/tcp.test.ts` exit 0 (37 tests PASS).
- 자동 후속 불가 이유: 명령 재실행이나 산출물 수집으로 닫히는 증거 공백이 아니다. 재현·계측을 충분히 수행해 원인을 확정했고, 결과는 "plan 지목 경로에 결함 없음 + gate 성격에 대한 범위 결정 필요"라는 사용자 판단 의존 상태다.
- 재개 조건: 사용자가 (A)/(B)/(C) 중 방향을 정하면 그에 맞는 새 plan(아키텍처 변경 task 분리, harness/판정 기준 재정의, 또는 known-flaky 문서화+추적)으로 재개한다.

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

- full stress `clients=1024` row가 실제 새 결과 기록에서 Timeout 0인지 확인한다.
- matrix 축소, timeout 완화, request count 완화로 PASS를 만든 변경이 없는지 확인한다.
- write 실패/close/shutdown cleanup과 response-before-write-resolve race가 깨지지 않았는지 확인한다.

## 검증 결과

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

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.

### REVIEW_PERF-1 중간 검증
```text
$ cd typescript && npm test -- test/communicator.test.ts test/tcp.test.ts

 ✓ test/tcp.test.ts (7 tests) 250ms
 ✓ test/communicator.test.ts (30 tests) 524ms

 Test Files  2 passed (2)
      Tests  37 passed (37)
```

### 최종 검증

```text
$ cd typescript && npm run check

> proto-socket@1.0.5 check
> tsc --noEmit
(exit 0)
```

```text
$ cd typescript && npm test -- test/communicator.test.ts test/tcp.test.ts
 Test Files  2 passed (2)
      Tests  37 passed (37)
```

```text
$ bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --lang typescript --transport tcp --profile parallel
[parallel] transport=tcp clients=1024 done violations=22
DONE typescript: FAIL (rows=4 skips=0 required_skips=0 violations=22)
전체 결과값: FAIL
결과 기록 파일: `agent-test/runs/20260614-043353-proto-socket-stress-full.md`
```
결과 기록 `agent-test/runs/20260614-043353-proto-socket-stress-full.md`의 `clients=1024` row:
`511978/512000` requests, throughput 23378.5 rps, p50 55.760, p95 101.754, p99 126.151, **Timeout 22**, NonceMis 0, TypeMis 0, FIFOViol 0, PendLeak 0, FAIL.

`run_performance.sh --quick`는 본 follow-up 루프에서 실행하지 않았다. 이유: 직전 plan에서 동일 명령의 전체 FAIL이 Kotlin sibling(`03_kotlin_tcp_parallel`) gradle `:run` 자체 실패 때문임을 이미 확인했고(직전 `code_review_cloud_G07_0.log` 참조), 본 follow-up의 hard gate인 TypeScript TCP full parallel stress가 이미 FAIL로 차단되어 사용자 결정 전에는 진행할 수 없기 때문이다. 재개 시 `사용자 리뷰 요청`의 방향 결정 후 함께 실행한다.

### 근본 원인 진단 (임시 계측, 제거 완료)

원인을 좁히기 위해 임시 계측을 추가하고 full parallel을 다회 실행한 뒤 계측을 모두 제거했다. 현재 작업트리에는 계측이 없다(`grep -rn "TEMP-DIAG\|__diagId\|__TCP_DIAG__" typescript/src typescript/bench` → 결과 없음). 계측은 harness script가 아닌 `./node_modules/.bin/tsx bench/stress.ts --mode=full --transport=tcp --profiles=parallel`로 직접 실행해 stderr 진단을 수집했다.

- 다회 재현 `clients=1024` Timeout: 22, 54, 66, 73, 74, 76, 84, 88, 94, 108, 112, 146, 192 (매 실행 FAIL, 건수 크게 변동 = tail 포화 noise).
- 모든 timeout은 각 connection의 **첫 배치(index 0/1)** 에서만 발생. Timeout 건수 == "응답이 왔는데 pending 없음" 건수로 정확히 일치(예: 94==94, 192==192).
- stuck connection 1건 타임라인:
  ```
  SEND-REQ        comm=2810 requestNonce=1 t=...500744
  CLI-WRITE-DONE  comm=2810 nonce=1 startT=...500744 doneT=...500758   (client write 커널 flush +14ms)
  CLI-RECV        comm=2810 responseNonce=1 t=...516685                 (응답 도착 +15941ms)
  RESP-NO-PENDING comm=2810 responseNonce=1 pendingKeys=[3,4] t=...516685
  ```
- server 측: 모든 첫 요청을 정확한 incomingNonce(index0→1, index1→2)로 수신하고, `SRV-SOCKET-RECV`(소켓 물리 도착)와 `SRV-RECV`(handler 처리) 시각이 동일 → server는 바이트 도착 즉시 처리하며 dispatch 지연 없음. 즉 지연은 "server가 그 소켓을 읽기까지의 시간"(약 16s)이다.
- `DROP-NO-HANDLER` 0 → handler 누락 드롭 아님. nonce/framing/FIFO 정상.

### 후보 수정 시도 (모두 hard gate 미충족 → revert)

```text
1) client read pause/resume를 in-flight task 카운터 기반으로 변경:  clients=1024 Timeout 108, 88  → FAIL
2) client read pause/resume 완전 제거:                              clients=1024 Timeout 50, 114 → FAIL
3) server listen backlog=1024 상향:                                clients=1024 Timeout 200, 194 → FAIL
                                                                   (단 p50/p95/p99 43/52/64ms로 개선 = accept 가속이 herd를 키워 tail 악화)
```

세 시도 모두 직전 plan PERF-1(response timer write-후 시작)에 더해 적용했으나 hard gate를 닫지 못했고, 원인이 send/write/response semantics가 아니라 event-loop 포화임을 입증했다. 모든 시도와 임시 계측은 작업트리에서 제거했다.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these. |
| Roadmap Targets | Fixed at stub creation from plan | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS. |
| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` -> `[x]` only. |
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` -> `[x]` only; final checkbox is mandatory before saving. |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section. |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content. |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required to proceed; do not ask the user directly during implementation. |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan. |
| 검증 결과 | Implementing agent | Fill in actual stdout/stderr only; command changes require a `계획 대비 변경 사항` entry. |
| 코드리뷰 결과 | Review agent appends | Not included in stub. |

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Pass
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Warn
  - verification trust: Pass
- 발견된 문제:
  - Required - `agent-test/runs/20260614-055824-proto-socket-stress-full.md:43` / `agent-task/m-large-payload-followup-optimization/02_typescript_tcp_tail/CODE_REVIEW-cloud-G07.md:95`: 필수 hard gate인 TypeScript TCP full parallel `clients=1024`가 리뷰 재실행에서도 `Timeout 18`, 결과 `FAIL`이다. 구현자는 임시 계측과 반복 실행으로 `sendRequest`/write queue 결함이 아니라 단일 Node event loop에서 약 2048개 소켓이 동시에 첫 요청을 처리할 때 생기는 starvation/harness 성격의 tail이라고 판단했고, 이 판단은 현재 증거와 모순되지 않는다. 다만 계획은 matrix/timeout 완화 금지와 Timeout 0 확보를 요구하므로, 같은 자동 루프에서 임의로 기준을 바꾸거나 아키텍처 작업으로 확장할 수 없다. 사용자가 (A) 아키텍처 작업으로 확장, (B) harness/판정 기준 재정의, (C) known-flaky로 문서화/추적 중 하나를 결정해야 한다.
- 다음 단계: USER_REVIEW.md를 작성해 자동 루프를 멈추고 사용자 결정을 기다린다.
