<!-- task=m-performance-hotspot-optimization/16_perf_regression plan=2 tag=REVIEW_REVIEW_TEST -->

# Plan - REVIEW_REVIEW_TEST

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

이 작업은 full performance regression에서 발견된 hard-gate 실패를 해소하는 follow-up이다. Dart WS burst 수신 누락을 먼저 수정하고, TypeScript TCP parallel 1024는 idle-focused rerun으로 환경성 여부를 다시 확인한다. 구현 후 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션에 실제 stdout/stderr, 결과 파일 경로, regression summary, 남은 WARN/FAIL row 분류를 채우고 active 파일을 그대로 둔 채 리뷰를 요청한다. 사용자 소유 idle host, 외부 환경, scope conflict 때문에 진행할 수 없으면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거를 기록하고 멈춘다. 구현 중 사용자에게 직접 질문하거나 `request_user_input`, `USER_REVIEW.md`, `complete.log`, archive 로그를 만들지 않는다. 명령 재실행이나 결과 수집으로 해소 가능한 증거 공백은 사용자 리뷰 요청이 아니라 검증 결과/계획 대비 변경 사항에 남긴다.

## 배경

plan=1은 누락된 full performance evidence를 회수했다. 결과는 `agent-test/runs/20260606-200122-proto-socket-performance-full.md`의 `overall_result=FAIL`, `regression_result=WARN`, hard-gate FAIL 2건이었다. Dart WS burst 100000은 focused rerun에서도 56060/100000 수신과 `Timeout=1`, `PendLeak=1`을 재현했으므로 제품 수신 경로 회귀로 보고 수정해야 한다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 프롬프트는 금지이며, code-review가 요청 타당성을 검증하고 실제 `USER_REVIEW.md` 작성을 소유한다. 명령 재실행이나 결과 수집으로 해소 가능한 증거 공백은 사용자 리뷰 요청이 아니라 검증 결과/계획 대비 변경 사항에 남긴다.

## Roadmap Targets

- Milestone: `agent-roadmap/milestones/performance-hotspot-optimization.md`
- Task ids:
  - `perf-regression`: 개선 후 `run_performance.sh --full --baseline <baseline>`을 실행해 throughput 20% 이상 하락 또는 p99 25% 이상 악화 WARN 후보를 확인한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/code-review/SKILL.md`
- `agent-test/local/dart-smoke.md`
- `agent-test/local/proto-socket-performance-baseline.md`
- `agent-ops/rules/project/domain/dart/rules.md`
- `agent-task/m-performance-hotspot-optimization/16_perf_regression/plan_cloud_G07_1.log`
- `agent-task/m-performance-hotspot-optimization/16_perf_regression/code_review_cloud_G07_1.log`
- `agent-test/runs/20260606-200122-proto-socket-performance-full.md`
- `agent-test/runs/20260607-021802-proto-socket-stress-full.md`
- `agent-test/runs/20260607-021929-proto-socket-stress-full.md`
- `dart/lib/src/ws_protobuf_client_io.dart`
- `dart/lib/src/ws_protobuf_client_web.dart`
- `dart/lib/src/protobuf_client.dart`
- `dart/lib/src/inbound_gateway.dart`
- `dart/lib/src/inbound_gateway_io.dart`
- `dart/test/socket_test.dart`

### 테스트 환경 규칙

`test_env=local`이다. Dart 변경이므로 `agent-test/local/dart-smoke.md`의 `cd dart && dart pub get && dart test && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js`를 적용한다. 성능 회귀 확인이므로 `agent-test/local/proto-socket-performance-baseline.md`의 focused `run_stress.sh` 보조 검증과 baseline 지정 `run_performance.sh --full --baseline ...` 최종 검증을 적용한다. stability hard gate는 timeout, nonce mismatch, response type mismatch, per-connection FIFO violation, pending leak, queue/gateway backlog leak가 모두 0이어야 PASS다.

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

Dart WS IO 수신 경로의 burst 100000 frame drop 회귀를 잡는 단위/통합 테스트가 없다. `dart/test/socket_test.dart`에는 일반 WS 송수신 테스트가 있지만, async `onReceivedFrame` 중 연속 WS frame이 도착해도 drop-free로 drain되는지를 검증하지 않는다. Dart web implementation에도 같은 `_isDispatching` early return 패턴이 있어 compile smoke와 함께 조건부 구현을 같이 보정해야 한다.

### 심볼 참조

renamed/removed symbol 없음. 관련 receive symbols는 `_onMessage`, `_dispatch`, `_isDispatching`, `_subscription`, `onReceivedFrame`, `sendHeartBeat`다.

### 분할 판단

이 작업은 기존 split subtask `16_perf_regression`의 두 번째 follow-up이며 새 split을 만들지 않는다. Dart WS hard-gate 수정과 TypeScript idle-focused evidence는 같은 full performance PASS 여부를 결정하는 직접 후속이므로 한 plan에서 처리한다. sibling `17+16_compat_matrix`는 16번 완료 뒤 실행되는 별도 full-cycle compatibility 검증이므로 이 plan의 구현 범위에 포함하지 않는다.

### 범위 결정 근거

wire format, protobuf schema, `PacketBase` nonce/responseNonce 의미는 변경하지 않는다. TypeScript source는 이번 plan에서 수정하지 않는다. TypeScript TCP parallel 1024는 focused idle evidence만 회수하고, 낮은 host load에서도 재현되면 다음 review가 별도 TypeScript fix plan으로 라우팅하도록 기록한다. Dart 변경은 `dart/lib/src/ws_protobuf_client_io.dart`, 같은 conditional API의 web fallback인 `dart/lib/src/ws_protobuf_client_web.dart`, 그리고 Dart WS regression test로 제한한다.

### 빌드 등급

`cloud-G07`: terminal benchmark-style regression 결과 해석, Dart async stream backpressure, conditional IO/Web implementation, full performance evidence 회수가 함께 필요하므로 cloud route를 유지한다.

## 구현 체크리스트

- [ ] Dart IO/Web WS `_onMessage`가 `_isDispatching` 중 도착한 frame을 버리지 않도록 drop-free 직렬 drain queue로 수정한다.
- [ ] Dart WS burst 수신 누락 regression test를 추가하고 Dart smoke를 실행한다.
- [ ] Dart WS burst focused stress가 stability violation 0 PASS인지 확인한다.
- [ ] TypeScript TCP parallel focused rerun을 낮은 host load에서 실행해 환경성 여부를 기록한다.
- [ ] full performance regression 비교 명령을 실행하고 결과 파일 경로, 전체 결과값, regression 결과값, compared/warning rows와 남은 WARN/FAIL 분류를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_TEST-1] Dart WS Drop-Free Receive Queue

문제: `agent-test/runs/20260607-021802-proto-socket-stress-full.md`의 `burst / count=100000 / Dart / ws` focused rerun이 100000건 중 56060건만 수신하고 `Timeout=1`, `PendLeak=1`로 FAIL했다. `dart/lib/src/ws_protobuf_client_io.dart:60`-`:69`와 `dart/lib/src/ws_protobuf_client_web.dart:85`-`:110`은 `_isDispatching` 중 reentrant message가 들어오면 `return`으로 버린다. baseline `agent-test/runs/20260605-025842-proto-socket-performance-full.md`의 Dart WS burst 100000은 stability 0 PASS였으므로, 현재 수신 coordinator는 burst 상황에서 frame을 drop할 수 있다.

해결 방법: IO와 web WS client 모두에서 `_isDispatching` early return을 제거하고, 도착한 frame을 queue에 넣은 뒤 하나의 drain loop가 순서대로 `_dispatch`하도록 바꾼다. subscription pause/resume은 source backpressure 용도로 유지하되, pause가 적용되기 전 이미 전달된 event도 queue에 남아야 한다. IO는 raw `dynamic data` 또는 normalized `List<int>` queue를 사용할 수 있고, web은 `MessageEvent`의 `ByteBuffer`/`Uint8List`/`List<int>`/`Blob` 변환을 drop 없이 drain path에서 처리한다. `sendHeartBeat()` 호출은 기존처럼 frame dispatch 완료 후 1회 유지한다.

수정 파일 및 체크리스트:

- [ ] `dart/lib/src/ws_protobuf_client_io.dart`: `_isDispatching` reentrant drop guard를 drop-free queue/drain 구조로 교체한다.
- [ ] `dart/lib/src/ws_protobuf_client_web.dart`: IO와 같은 의미의 drop-free queue/drain 구조로 교체하고 browser import compile이 유지되게 한다.
- [ ] `dart/test/socket_test.dart`: plain WS group에 server->client 또는 client->server burst regression test를 추가해 연속 WS frame이 모두 수신되고 pending leak 없이 완료되는지 검증한다. 테스트 규모는 로컬 unit 안정성을 위해 full stress 100000보다 작게 잡되, 기존 early return이면 실패할 만큼 연속 dispatch를 유발해야 한다.

테스트 작성: 필요. Bug fix이며, 기존 unit/integration test가 burst frame drop을 잡지 못했다.

중간 검증:

```bash
cd dart && dart test test/socket_test.dart -r expanded
```

기대 결과: 추가된 WS burst regression test를 포함해 socket tests가 PASS한다.

### [REVIEW_REVIEW_TEST-2] Performance Hard Gate Recheck

문제: `agent-task/m-performance-hotspot-optimization/16_perf_regression/code_review_cloud_G07_1.log`의 최종 검증은 `overall_result=FAIL`, `regression_result=WARN`, compared rows 336, warning rows 83이었다. Dart WS burst는 REVIEW_REVIEW_TEST-1로 수정해야 하고, TypeScript TCP parallel 1024는 focused rerun에서도 timeout 56건을 남겨 환경성이라고 단정하기 어렵다.

해결 방법: Dart fix 이후 focused stress와 full performance baseline 비교를 다시 실행한다. TypeScript TCP parallel 1024는 실행 전 `uptime`을 기록하고, host load가 계속 높으면 결과 해석에 그 값을 포함한다. 낮은 host load에서 TypeScript timeout이 0으로 떨어지면 환경성 watchlist로 분류한다. 낮은 host load에서도 timeout이 남으면 TypeScript source 변경은 하지 말고 별도 Required로 기록한다.

수정 파일 및 체크리스트:

- [ ] `CODE_REVIEW-cloud-G07.md`: Dart focused stress 결과 파일, TypeScript focused rerun 결과 파일, full performance 결과 파일, hard-gate rows, regression summary, WARN 분류를 실제 stdout/stderr와 함께 기록.
- [ ] 소스 수정은 REVIEW_REVIEW_TEST-1의 Dart 파일로 제한한다.

테스트 작성: 별도 test file 작성 없음. 이 항목은 performance evidence 회수다.

중간 검증:

```bash
uptime
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --lang dart --transport ws --profile burst
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_stress.sh --full --lang typescript --transport tcp --profile parallel
```

기대 결과: Dart WS burst는 `overall_result: PASS`와 stability violations 0을 기록한다. TypeScript TCP parallel은 load와 timeout 결과를 함께 기록하고, timeout이 남으면 후속 TypeScript fix 후보로 분리한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `dart/lib/src/ws_protobuf_client_io.dart` | REVIEW_REVIEW_TEST-1 |
| `dart/lib/src/ws_protobuf_client_web.dart` | REVIEW_REVIEW_TEST-1 |
| `dart/test/socket_test.dart` | REVIEW_REVIEW_TEST-1 |
| `agent-test/runs/YYYYMMDD-HHMMSS-proto-socket-stress-full.md` | REVIEW_REVIEW_TEST-2 |
| `agent-test/runs/YYYYMMDD-HHMMSS-proto-socket-performance-full.md` | REVIEW_REVIEW_TEST-2 |
| `CODE_REVIEW-cloud-G07.md` | REVIEW_REVIEW_TEST-1, REVIEW_REVIEW_TEST-2 |

## 최종 검증

```bash
cd dart && dart pub get && dart test && dart compile js test/browser_ws_import_compile.dart -o /tmp/proto_socket_browser_ws_import_compile.js
bash agent-ops/skills/project/run-proto-socket-test-matrix/scripts/run_performance.sh --full --baseline agent-test/runs/20260605-025842-proto-socket-performance-full.md --throughput-drop-pct 20 --p99-worse-pct 25
```

기대 결과: Dart smoke가 PASS하고 browser import compile 산출물이 생성된다. full performance 결과 파일이 생성되고 stability hard gate 위반이 없어야 한다. `regression_result`가 PASS이면 `perf-regression` 완료 evidence로 기록한다. `regression_result`가 WARN이면 warning rows를 모두 분류하고, 남은 WARN의 원인과 후속 처리가 기록되어야 한다. hard-gate FAIL이 남으면 이 task는 PASS가 아니다.

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