<!-- task=dart_web_e2e/01_browser_harness plan=1 tag=REVIEW_TEST -->

# Code Review Reference - REVIEW_TEST

> **[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.
> 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-05-24
task=dart_web_e2e/01_browser_harness, plan=1, tag=REVIEW_TEST

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

> **[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/dart_web_e2e/01_browser_harness/`로 이동한다. WARN/FAIL이면 다음 active plan/review 파일을 즉시 작성한다.
4. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_TEST-1] 브라우저 Origin host/port 패턴을 허용한다. | [x] |
| [REVIEW_TEST-2] Go 오케스트레이터가 전체 browser suite를 한 번만 실행하도록 서버 기능을 합친다. | [x] |
| [REVIEW_TEST-3] repo-local Go 빌드 산출물을 제거하고 재생성을 막는다. | [x] |
| [REVIEW_TEST-4] 로컬 정적 검증과 `ssh toki@toki-labs.com` 원격 Chrome E2E를 실행한다. | [x] |

## 구현 체크리스트

- [x] [REVIEW_TEST-1] 브라우저 Origin host/port 패턴을 허용한다.
- [x] [REVIEW_TEST-2] Go 오케스트레이터가 전체 browser suite를 한 번만 실행하도록 서버 기능을 합친다.
- [x] [REVIEW_TEST-3] repo-local Go 빌드 산출물을 제거하고 재생성을 막는다.
- [x] [REVIEW_TEST-4] 로컬 정적 검증과 `ssh toki@toki-labs.com` 원격 Chrome E2E를 실행한다.
- [x] 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_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_M.log`로 아카이브한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/dart_web_e2e/01_browser_harness/`를 `agent-task/archive/YYYY/MM/dart_web_e2e/01_browser_harness/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/dart_web_e2e/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다.

## 계획 대비 변경 사항

- REVIEW_TEST-2: 계획은 `OnClientConnected`에서 `AddListenerTyped[*packets.TestData]`(send-push)와 `AddRequestListenerTyped[*packets.TestData, *packets.TestData]`(request)를 함께 등록하도록 지시했지만, Go `Communicator`는 같은 `typeName`에 두 종류를 동시에 등록하면 패닉으로 막는다(`go/communicator.go:230,246`). 같은 TestData type을 send-push와 request 두 패턴에 모두 쓰는 테스트 구조라 listener 두 개 등록이 원천적으로 불가능했다. 이를 해결하기 위해 단일 `AddRequestListenerTyped` 핸들러로 통합하고, 페이로드가 send-push 시그니처(index=101, message=`fire from dart web client`)인 경우에만 추가로 `client.Send`로 push를 보내고 모든 입력에 echo 응답을 반환하도록 변경했다. send-push 테스트의 클라이언트는 pending request가 없어 echo 응답은 자동 폐기되고, push 메시지만 `addListener`로 전달되므로 계약은 그대로 유지된다.

## 주요 설계 결정

- 동일한 proto type(`TestData`)으로 send-push와 request 두 패턴을 한 서버에서 모두 처리해야 하는 제약 때문에, request listener 하나로 통합하고 페이로드 기반 분기를 사용했다. 다른 대안으로는 (a) Go 프레임워크 API 확장(`Communicator.NextNonce` 노출 등), (b) protocol에 새 proto type 추가가 있었으나, 계획의 "Dart public API와 protocol schema도 변경하지 않는다" 제약 안에서 가장 침습이 적은 선택이다.
- `runDartBrowserTest()`는 `dart test -p chrome test/browser_ws_runtime_test.dart` 한 번만 호출해 send-push/single request/concurrent requests 세 테스트를 동일 서버에서 처리한다. `received` 채널은 버퍼 1, select+default로 송신해 send-push 첫 매칭만 기록하고 이후 요청은 자연스럽게 통과한다.
- 검증 산출물은 모두 `/tmp/proto-socket-go-dart-web-review`, `/tmp/proto-socket-go-dart-web-darwin-arm64`로 생성해 `go/go_dart_web` 재생성을 방지했다.
- 원격 검증은 로컬에서 cross-build한 darwin/arm64 바이너리와 dart 패키지(`tar --exclude='dart/.dart_tool'` 등)를 `/Users/toki/tmp/proto-socket-review-<timestamp>`에 업로드하고, `/Users/toki/SDK/flutter/bin/dart`를 PATH에 추가해 실행한 뒤 임시 디렉터리를 cleanup했다.

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

- OriginPatterns가 `localhost:<port>`와 `127.0.0.1:<port>`를 허용하고 `InsecureSkipVerify`를 쓰지 않는지 확인한다.
- Go server가 send-push listener와 request listener를 같은 browser suite 실행에서 제공하는지 확인한다.
- `go/go_dart_web` 같은 repo-local build artifact가 남지 않았는지 확인한다.
- `ssh toki@toki-labs.com` 원격 Chrome E2E 출력이 실제 stdout/stderr로 기록됐고 마지막 PASS line이 있는지 확인한다.

## 검증 결과

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

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.

### REVIEW_TEST-1 중간 검증
```
$ cd go && go build -o /tmp/proto-socket-go-dart-web-review ./crosstest/go_dart_web.go
exit=0
```

### REVIEW_TEST-2 중간 검증
```
$ cd go && go build -o /tmp/proto-socket-go-dart-web-review ./crosstest/go_dart_web.go
exit=0
```

### REVIEW_TEST-3 중간 검증
```
$ test ! -e go/go_dart_web
exit=0
```

### REVIEW_TEST-4 중간 검증
```
$ ssh -o BatchMode=yes -o ConnectTimeout=10 toki@toki-labs.com 'printf "remote-ok\n"; test -d "/Applications/Google Chrome.app"; /Users/toki/SDK/flutter/bin/dart --version'
remote-ok
Dart SDK version: 3.10.0-290.4.beta (beta) (Thu Oct 30 11:12:42 2025 -0700) on "macos_arm64"
exit=0
```

### 최종 검증
```
$ cd dart && dart analyze test/browser_ws_runtime_test.dart
Analyzing browser_ws_runtime_test.dart...
No issues found!
exit=0

$ cd go && go build -o /tmp/proto-socket-go-dart-web-review ./crosstest/go_dart_web.go
exit=0

$ test ! -e go/go_dart_web
exit=0

$ ssh -o BatchMode=yes -o ConnectTimeout=10 toki@toki-labs.com 'printf "remote-ok\n"; test -d "/Applications/Google Chrome.app"; /Users/toki/SDK/flutter/bin/dart --version'
remote-ok
Dart SDK version: 3.10.0-290.4.beta (beta) (Thu Oct 30 11:12:42 2025 -0700) on "macos_arm64"
exit=0

$ GOOS=darwin GOARCH=arm64 go build -o /tmp/proto-socket-go-dart-web-darwin-arm64 ./go/crosstest/go_dart_web.go
# 실제 실행은 working dir 차이로 `GOOS=darwin GOARCH=arm64 go -C go build -o /tmp/proto-socket-go-dart-web-darwin-arm64 ./crosstest/go_dart_web.go`로 동치 실행
exit=0
ls -la /tmp/proto-socket-go-dart-web-darwin-arm64
-rwxr-xr-x 1 abc abc 13028498 May 24 22:57 /tmp/proto-socket-go-dart-web-darwin-arm64

$ remote_dir="/Users/toki/tmp/proto-socket-review-$(date +%Y%m%d%H%M%S)" && \
  ssh -o BatchMode=yes toki@toki-labs.com "mkdir -p '$remote_dir'/go '$remote_dir'/dart" && \
  tar --exclude='dart/.dart_tool' --exclude='dart/build' --exclude='dart/.packages' --exclude='dart/.git' -cf - dart | ssh -o BatchMode=yes toki@toki-labs.com "cd '$remote_dir' && tar -xf -" && \
  scp -q /tmp/proto-socket-go-dart-web-darwin-arm64 "toki@toki-labs.com:$remote_dir/go/go_dart_web" && \
  ssh -o BatchMode=yes toki@toki-labs.com "chmod +x '$remote_dir/go/go_dart_web'; zsh -lc 'export PATH=/Users/toki/SDK/flutter/bin:\$PATH; cd '$remote_dir'/dart && dart pub get && cd '$remote_dir'/go && ./go_dart_web'" ; \
  status=$?; ssh -o BatchMode=yes toki@toki-labs.com "rm -rf '$remote_dir'"; exit $status
Resolving dependencies...
Downloading packages...
< _fe_analyzer_shared 99.0.0 (was 100.0.0) (100.0.0 available)
< analyzer 12.1.0 (was 13.0.0) (13.0.0 available)
  lints 3.0.0 (6.1.0 available)
< matcher 0.12.19 (was 0.12.20) (0.12.20 available)
  protobuf 3.1.0 (6.0.0 available)
< test 1.31.0 (was 1.31.1) (1.31.1 available)
< test_api 0.7.11 (was 0.7.12) (0.7.12 available)
< test_core 0.6.17 (was 0.6.18) (0.6.18 available)
Changed 6 dependencies!
8 packages have newer versions incompatible with dependency constraints.
Try `dart pub outdated` for more information.
INFO typeName go=TestData
00:00 +0: loading test/browser_ws_runtime_test.dart
Compiled 11,805,491 input bytes (6,809,996 characters source) to 1,424,064 characters JavaScript in 2.60 seconds

00:00 +0: Dart Web WsProtobufClient talks to Go WS server send-push: fire-and-forget and receive push
SERVER_RECEIVED index=101 message=fire from dart web client
00:00 +1: Dart Web WsProtobufClient talks to Go WS server sendRequest: single request-response
SERVER_RECEIVED index=21 message=single request from dart web
00:00 +2: Dart Web WsProtobufClient talks to Go WS server sendRequest: concurrent requests
SERVER_RECEIVED index=30 message=multi request 0 from dart web
SERVER_RECEIVED index=31 message=multi request 1 from dart web
SERVER_RECEIVED index=32 message=multi request 2 from dart web
SERVER_RECEIVED index=34 message=multi request 4 from dart web
SERVER_RECEIVED index=33 message=multi request 3 from dart web
00:00 +3: All tests passed!
PASS all go-server/dart-web-client crosstests passed
FINAL_STATUS=0
```

---

> **[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.

## Ownership

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these |
| 구현 항목별 완료 여부 | Implementing agent | Check only after implementation |
| 구현 체크리스트 | Implementing agent | Final checkbox is mandatory |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text |
| 검증 결과 | Implementing agent | Paste actual stdout/stderr |

## 코드리뷰 결과

### 종합 판정

PASS

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| correctness | Pass | Origin host/port 허용과 단일 suite 서버 구성이 실제 원격 Chrome E2E에서 통과했다. |
| completeness | Pass | REVIEW_TEST-1~4와 최종 CODE_REVIEW 작성 항목이 모두 완료됐다. |
| test coverage | Pass | Dart browser runtime 테스트가 send-push, 단일 request, concurrent request를 실제 Chrome에서 검증한다. |
| API contract | Pass | public API/protocol 변경 없이 crosstest harness 내부만 수정했다. |
| code quality | Pass | `gofmt -d` 출력 없음, repo-local `go/go_dart_web` 산출물 없음. |
| plan deviation | Pass | 동일 type listener/request-listener 동시 등록 불가에 따른 request listener 통합이 기록됐고 범위 안의 변경이다. |
| verification trust | Pass | 로컬 analyze/build와 `ssh toki@toki-labs.com` 원격 Chrome E2E를 리뷰어가 재실행해 PASS를 확인했다. |

### 발견된 문제

없음

### 다음 단계

PASS: `complete.log`를 작성하고 task 디렉터리를 `agent-task/archive/2026/05/dart_web_e2e/01_browser_harness/`로 이동한다.
