<!-- task=m-performance-hotspot-optimization/11+10_dart_isolate_transport_path plan=0 tag=REFACTOR -->

# Code Review Reference - REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> Do not implement until predecessor `10` has `complete.log`.

## 개요

date=2026-06-06
task=m-performance-hotspot-optimization/11+10_dart_isolate_transport_path, plan=0, tag=REFACTOR

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/performance-hotspot-optimization.md`
- Task ids:
  - `dart-isolate-real-path`: 실제 TCP/WS transport 수신 경로 hardening 연결
- Completion mode: check-on-pass

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

> **[REVIEW AGENT ONLY]** 종결 절차는 코드리뷰 에이전트 전용이다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REFACTOR-1] TCP transport receive path | [x] |
| [REFACTOR-2] WS IO/web receive path | [x] |
| [REFACTOR-3] Performance row inclusion | [x] |

## 구현 체크리스트

- [x] predecessor `10_dart_isolate_gateway_contract` complete.log 존재를 확인한다. (archive: `agent-task/archive/2026/06/m-performance-hotspot-optimization/10_dart_isolate_gateway_contract/complete.log` 존재 + git `9082c0c`에서 archive 확인. 의존성 충족.)
- [x] `ProtobufClient`가 decoded inline path 대신 hardened gateway-backed `onReceivedFrame`을 사용하게 한다. (`_parsing()`이 `onReceivedFrame(packetBytes)` 호출, 생성자에서 `IsolateInboundGateway` attach+start.)
- [x] `WsProtobufClient` IO/web이 같은 receive coordinator path를 사용하고 web은 `SyncInboundGateway` fallback을 유지한다. (IO는 `inbound_gateway_io.dart`의 `IsolateInboundGateway`, web은 `inbound_gateway_web.dart`의 `SyncInboundGateway` 기반 `IsolateInboundGateway`. 둘 다 `_dispatch`가 `onReceivedFrame(bytes)`만 수행.)
- [x] 내부 단일 수신 경로로 동작하며 public on/off 옵션을 추가하지 않는다. (gateway는 각 transport 생성자 내부에서만 attach. public API/생성자 시그니처 변경 없음.)
- [x] TCP/WS FIFO, nonce matching, close cleanup regression tests와 focused stress 결과를 기록한다. (`dart test` 67 통과, focused stress dart 12 rows violations=0. 아래 검증 결과 참조.)
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

- [x] 판정을 append한다.
- [x] PASS이면 complete/archive 절차와 런타임 완료 이벤트를 처리한다.

## 계획 대비 변경 사항

- 계획 범위(REFACTOR-1/2)는 transport 3종을 `onReceivedFrame`으로 전환하는 것이었으나, 전환 후 기존 회귀 테스트 `TCP inbound backpressure pauses subscription on heavy load`가 실패했다. 원인은 transport swap 자체가 아니라 predecessor `10`의 gateway wiring이 **decode in-flight**(gateway capacity)로만 backpressure를 측정하는데, 실제 병목은 **dispatch**(stalled handler)라는 점이다. decode는 병목이 아니므로 handler가 막혀도 socket이 멈추지 않고 decoded frame이 unbounded로 쌓여 기존 64-bound 회귀가 발생했다.
- 이를 plan의 "심볼 참조"가 명시한 변경 후보(`Communicator.attachInboundGateway`, `onReceivedFrame`) 범위 안에서 `dart/lib/src/communicator.dart`를 추가 수정해 해결했다. 계획의 "수정 파일 요약" 표에는 communicator.dart가 없었으나, 같은 plan 본문이 두 심볼을 변경 후보로 적시했으므로 범위 내로 판단했고 사용자 리뷰 요청으로 올리지 않았다.
- web `IsolateInboundGateway`는 `SyncInboundGateway`를 상속한 conditional-export 구현이라, 계획 체크리스트의 "web `SyncInboundGateway` fallback 유지"를 그대로 만족한다(별도 분기 코드 불필요).

## 주요 설계 결정

- **gateway 경로 전용 backlog 카운터로 dispatch backpressure를 transport read loop에 전파.** `_gatewayBacklog`는 "gateway에 submit했지만 아직 dispatch 완료되지 않은 frame 수"다. `onReceivedFrame`(gateway branch)이 submit 전에 `_gatewayBacklog >= _inboundQueueCapacity`(64)면 대기하고, 통과 시 `_gatewayBacklog++` 후 submit한다. backlog는 frame이 실제로 handle된 시점(데이터/요청은 dispatch 체인 `whenComplete`, 응답은 pending 완료 직후, error는 즉시)에만 `_releaseGatewayBacklog()`로 감소한다. 따라서 stalled handler 하에서 backlog가 64까지 차면 read loop가 멈춰 inline 경로와 동일한 outstanding-frame bound를 회복한다.
- **gateway 경로를 `onReceivedData`의 큐 회계와 분리.** `onReceivedData`(+`_inboundQueueLength`/`_awaitInboundCapacity`)는 inline 경로와 직접 호출 테스트가 계속 쓰므로 그대로 두고, gateway listener는 decoded frame을 `_onGatewayResult`에서 직접 dispatch 체인에 태운다. 이렇게 하면 큐 슬롯을 enqueue 시점이 아니라 submit 시점에 예약(backlog)하게 되어, submit→decode→enqueue 사이 비동기 지연으로 read loop가 앞서 달리던 문제를 제거한다(단일 카운터로 두 회계를 섞지 않는다).
- **응답 immediacy 보존.** gateway 경로에서도 `responseNonce > 0` frame은 dispatch 체인을 거치지 않고 pending request를 즉시 완료한다 — inline `onReceivedData`와 동일한 out-of-band 처리.
- **decode pipeline 깊이는 gateway capacity(1024)가, dispatch bound는 backlog(64)가 담당**하도록 두 backpressure 축을 분리해, 병렬 decode 이점과 메모리 bound를 동시에 유지한다.
- **gateway start()는 await하지 않는다.** async 함수는 첫 await 전까지 동기 실행되어 `_ready` completer가 생성자 동기 구간에 설정되므로, isolate spawn 완료 전 도착한 첫 frame도 `submit`이 readiness를 기다려 drop되지 않는다.
- **teardown 안전.** `close()`/`shutdown()`에 `_drainGatewayBacklog()`를 추가해 backlog를 0으로 리셋하고 대기 중인 `onReceivedFrame`을 깨워, gateway 경로가 read loop를 strand하지 않게 한다.

## 사용자 리뷰 요청

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

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

- `10` predecessor가 실제 PASS인지 확인한다.
- TCP/WS/web 모두 inline decode bypass 없이 단일 receive coordinator를 쓰는지 확인한다.
- public gateway on/off 옵션이 생기지 않았는지 확인한다.

## 검증 결과

### REFACTOR-1/2 중간 검증
```text
$ cd dart && dart analyze lib/src/protobuf_client.dart lib/src/ws_protobuf_client_io.dart lib/src/ws_protobuf_client_web.dart lib/src/communicator.dart
No issues found!

$ cd dart && dart test test/socket_test.dart test/communicator_test.dart -r expanded
00:15 +64: ... Request-Response (WS plain) TCP inbound backpressure pauses subscription on heavy load
00:16 +65: ... TCP fragmentation and large payload TCP receives fragmented large frame without reordering or truncation
00:16 +66: ... TCP fragmentation and large payload TCP 1MB payload roundtrip
00:17 +67: All tests passed!
```
- FIFO/fragmentation/1MB/request-response/close/broadcast 회귀 및 gateway 단위 테스트 모두 통과(67).
- backpressure 회귀 테스트는 transport swap 직후 FAIL이었고, communicator backlog gate 수정 후 PASS로 회복(계획 대비 변경 사항 참조).

### REFACTOR-3 중간 검증 (focused stress)
```text
$ bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --quick --lang dart --transport tcp,ws --profile roundtrip,payload
DONE dart: PASS (rows=12 skips=0 required_skips=0 violations=0)
| 언어 | 결과 | ROW | SKIP(전체) | SKIP(required) | stability_violations | 비고 |
| dart | PASS | 12 | 0 | 0 | 0 |  |
전체 결과값: PASS
결과 기록 파일: agent-test/runs/20260606-042547-proto-socket-stress-quick.md
```

### 최종 검증
```text
$ cd dart && dart test
00:17 +67: All tests passed!

$ cd dart && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js
Compiled 10,874,863 input bytes (5,876,091 characters source) to 11,692 characters JavaScript in 0.50 seconds

$ bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --quick
| 구성 | 결과 | exit code |
| same-language | PASS | 0 |  (Dart 18 rows, 모든 row stability_violations=0)
| cross-language | PASS | 0 |
| typescript-gateway | PASS | 0 |
전체 결과값: PASS
결과 기록 파일: agent-test/runs/20260606-042556-proto-socket-performance-quick.md
```
- same-language run의 Dart 실제 수신 경로(gateway-backed) rows: roundtrip(c1/16/64/256), burst, sustained, parallel, payload(1KB/64KB) × tcp/ws 전부 PASS, stability_violations 0.

## 코드리뷰 결과

- 종합 판정: PASS
- 차원별 평가:
  - correctness: Pass
  - completeness: Pass
  - test coverage: Pass
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Pass
  - verification trust: Pass
- 발견된 문제: 없음
- 다음 단계: PASS이므로 active plan/review를 `.log`로 아카이브하고 `complete.log` 작성 후 task 디렉터리를 archive로 이동한다.
