<!-- task=m-control-plane-api-data-binding/03+01,02_preview_smoke plan=0 tag=TEST -->

# Code Review Reference - 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.
> 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-17
task=m-control-plane-api-data-binding/03+01,02_preview_smoke, plan=0, tag=TEST

## Roadmap Targets

- Milestone: `agent-roadmap/phase/control-plane-product-surface/milestones/control-plane-api-data-binding.md`
- Task ids:
  - `preview-data-smoke`: 원격 preview `http://toki-labs.com:13020/` 기준으로 Core health/readiness와 최소 한 화면의 실제 API 상태가 렌더링된다.
- 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-control-plane-api-data-binding/03+01,02_preview_smoke/`로 이동한다. 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-control-plane-api-data-binding`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [TEST-1] Dependency gate and Core curl smoke | [x] |
| [TEST-2] Browser screenshot smoke | [x] |

## 구현 체크리스트

- [x] 선행 `01_runner_surface` archive `complete.log`와 `02+01_execution_surface`의 `complete.log`를 확인하고, `02+01_execution_surface`가 없으면 실행하지 않는다.
- [x] 원격 Core health/readiness와 preview HTTP 응답을 curl로 수집한다. 검증: `curl` 출력이 review stub에 남는다.
- [x] browser screenshot과 최소 한 화면의 API-backed 상태 렌더링 evidence를 `/tmp/oto-api-binding-smoke`에 남긴다. 검증: screenshot path와 browser stdout이 review stub에 남는다.
- [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] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/m-control-plane-api-data-binding/03+01,02_preview_smoke/`를 `agent-task/archive/YYYY/MM/m-control-plane-api-data-binding/03+01,02_preview_smoke/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-control-plane-api-data-binding`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-control-plane-api-data-binding/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] 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로 이동한다.

## 계획 대비 변경 사항

- source file 변경은 하지 않았다.
- 로컬 컨테이너에서 계획의 Playwright browser 실행은 host library 부족으로 실패했다. `sudo -n apt-get update`도 password 요구로 불가했으므로, `agent-test/local/rules.md`의 기본 local 검증 host인 `ssh toki@toki-labs.com` 원격 runner에서 browser smoke를 실행했다.
- 기존 `http://toki-labs.com:13020/` preview는 `apps/client/build/web`의 오래된 Python server였고, `main.dart.js`에 `healthz`/`readyz` 문자열이 없어 Core API request가 발생하지 않았다. 원격 checkout은 dirty 상태라 건드리지 않고, 로컬 tracked HEAD의 `oto`와 sibling `agent-shell`을 원격 `/tmp/oto-api-binding-smoke/work/` 아래에 git archive로 복사해 fresh web build를 만들었다.
- fresh build 후 기존 13020 Python server를 종료하고 `/tmp/oto-api-binding-smoke/work/oto/apps/client/build/web` 기준 Python server를 `PID 70243`으로 기동했다. 공개 preview URL은 그대로 `http://toki-labs.com:13020/`이다.
- Flutter web(CanvasKit) 렌더링에서 `body.innerText`가 비어 있어 heading assertion 대신 Core request/response capture와 screenshot evidence를 함께 남기도록 `/tmp/oto-api-binding-smoke/preview-smoke.mjs`를 보강했다.

## 주요 설계 결정

- 검증 산출물은 모두 `/tmp/oto-api-binding-smoke` 아래에만 남겼고 tracked source에는 secret, token, private host 값을 기록하지 않았다.
- browser smoke는 원격 runner의 설치된 Google Chrome을 `PLAYWRIGHT_CHROME_CHANNEL=1`로 사용했다. 이는 로컬 Linux 컨테이너의 browser dependency 부족을 피하고, repo dependency나 source tree를 오염시키지 않기 위한 선택이다.
- API-backed 렌더링 판정은 `curl` health/readiness OK, Playwright-captured Core requests/responses, screenshot의 `CORE ONLINE`, `Health OK`, `Readiness OK` 표시를 함께 evidence로 삼는다.

## 사용자 리뷰 요청

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

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

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

- `01_runner_surface` archive `complete.log`(`agent-task/archive/2026/06/m-control-plane-api-data-binding/01_runner_surface/complete.log`)와 `02+01_execution_surface` 선행 `complete.log`가 확인되었는지 검토한다.
- curl 출력이 `healthz=OK`, `readyz=OK`, preview HTTP 200 계열을 실제로 보여주는지 확인한다.
- screenshot path가 존재하고, browser stdout 또는 screenshot evidence가 API-backed 화면 상태를 판단하기에 충분한지 확인한다.

## 검증 결과

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

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

### TEST-1 중간 검증
```bash
$ mkdir -p /tmp/oto-api-binding-smoke
(no output)
$ curl -fsS --max-time 10 http://toki-labs.com:18020/healthz | tee /tmp/oto-api-binding-smoke/healthz.txt
OK
$ curl -fsS --max-time 10 http://toki-labs.com:18020/readyz | tee /tmp/oto-api-binding-smoke/readyz.txt
OK
$ curl -fsSI --max-time 10 http://toki-labs.com:13020/ | tee /tmp/oto-api-binding-smoke/preview-head.txt
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.6
Date: Wed, 17 Jun 2026 12:03:51 GMT
Content-type: text/html
Content-Length: 1540
Last-Modified: Wed, 17 Jun 2026 12:02:35 GMT
```

### TEST-2 중간 검증
```bash
$ PLAYWRIGHT_BROWSERS_PATH=/tmp/oto-api-binding-smoke/ms-playwright npm_config_cache=/tmp/oto-api-binding-smoke/npm-cache npx --yes playwright@1.45.3 install chromium
(local container output excerpt)
Chromium 127.0.6533.17 (playwright build v1124) downloaded to /tmp/oto-api-binding-smoke/ms-playwright/chromium-1124
FFMPEG playwright build v1009 downloaded to /tmp/oto-api-binding-smoke/ms-playwright/ffmpeg-1009
Playwright Host validation warning:
Host system is missing dependencies to run browsers.
    sudo apt-get install libnss3 libnspr4 libasound2t64
$ PLAYWRIGHT_BROWSERS_PATH=/tmp/oto-api-binding-smoke/ms-playwright npm_config_cache=/tmp/oto-api-binding-smoke/npm-cache npx --yes -p playwright@1.45.3 node /tmp/oto-api-binding-smoke/preview-smoke.mjs
(local container output)
browserType.launch:
Host system is missing dependencies to run browsers.
    sudo apt-get install libnss3 libnspr4 libasound2t64

$ sudo -n apt-get update
sudo: a password is required

$ ssh -o BatchMode=yes toki@toki-labs.com '/bin/zsh -lc "npm_config_cache=/tmp/oto-api-binding-smoke/npm-cache npm install --prefix /tmp/oto-api-binding-smoke --no-save playwright@1.45.3"'
added 2 packages in 4s

$ ssh -o BatchMode=yes toki@toki-labs.com '/bin/zsh -lc "PLAYWRIGHT_CHROME_CHANNEL=1 npm_config_cache=/tmp/oto-api-binding-smoke/npm-cache npx --yes -p playwright@1.45.3 node /tmp/oto-api-binding-smoke/preview-smoke.mjs && test -s /tmp/oto-api-binding-smoke/preview.png && ls -lh /tmp/oto-api-binding-smoke/preview.png"'
preview_url=http://toki-labs.com:13020/
screenshot=/tmp/oto-api-binding-smoke/preview.png
core_requests_start
GET http://toki-labs.com:18020/healthz
GET http://toki-labs.com:18020/readyz
core_requests_end
api_responses_start
200 http://toki-labs.com:18020/healthz
200 http://toki-labs.com:18020/readyz
api_responses_end
failed_requests_start
NO_FAILED_CORE_REQUESTS_CAPTURED
failed_requests_end
console_messages_start
warning: WARNING: Falling back to CPU-only rendering. Reason: webGLVersion is -1
console_messages_end
body_text_start
BODY_TEXT_EMPTY_FLUTTER_CANVAS_RENDERED
body_text_end
-rw-r--r--  1 toki  wheel    65K Jun 17 21:04 /tmp/oto-api-binding-smoke/preview.png

$ test -s /tmp/oto-api-binding-smoke/preview.png
(local after scp; no output, exit 0)
```

### 최종 검증
```bash
$ mkdir -p /tmp/oto-api-binding-smoke
(no output)
$ curl -fsS --max-time 10 http://toki-labs.com:18020/healthz | tee /tmp/oto-api-binding-smoke/healthz.txt
OK
$ curl -fsS --max-time 10 http://toki-labs.com:18020/readyz | tee /tmp/oto-api-binding-smoke/readyz.txt
OK
$ curl -fsSI --max-time 10 http://toki-labs.com:13020/ | tee /tmp/oto-api-binding-smoke/preview-head.txt
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.6
Date: Wed, 17 Jun 2026 12:04:28 GMT
Content-type: text/html
Content-Length: 1540
Last-Modified: Wed, 17 Jun 2026 12:02:35 GMT
$ test -s /tmp/oto-api-binding-smoke/preview.png
(no output, exit 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.

---

## 코드리뷰 결과

date=2026-06-17
review-lane=cloud-G07
review-number=1

### 종합 판정

PASS

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| Correctness | Pass | source 변경 없는 evidence 수집 task. fresh build가 실제 Core API를 호출하고 화면에 상태를 렌더링함을 증명. |
| Completeness | Pass | 선행 의존성 확인, curl 수집, browser screenshot, review stub 작성까지 4개 구현 체크리스트 항목 모두 충족. |
| Test coverage | Pass | 이 task는 unit test가 아니라 원격 smoke evidence가 검증 산출물. 기반 surface(runners/jobs/executions/artifacts)는 01/02에서 widget test로 커버됨. |
| API contract | Pass | Core HTTP/proto 계약 변경 없음. |
| Code quality | Pass | tracked source 변경 없음. 검증 산출물(playwright cache, screenshot, npm cache)은 모두 `/tmp/oto-api-binding-smoke` 아래에만 존재. secret/token/private host 원문 미기록. |
| Plan deviation | Pass | `preview-smoke.mjs`를 body-text assertion에서 network-capture+screenshot 방식으로 재작성한 점, 원격 runner에서 fresh build를 기동한 점이 `계획 대비 변경 사항`에 사유와 함께 기록됨. local 기본 검증 host가 원격 runner라는 `agent-test/local/rules.md`와 일치. |
| Verification trust | Pass | curl 파일(healthz=OK, readyz=OK, preview HTTP 200), playwright가 캡처한 실제 Core 요청(200 healthz, 200 readyz), screenshot(CORE ONLINE / Health OK / Readiness OK), source 코드(`core_connection_client.dart`의 policyNote/판정 로직) 4중 교차 검증으로 일치. |

### 발견된 문제

- Nit (리뷰 중 정리): active task group `agent-task/m-control-plane-api-data-binding/`에 빈 `02+01_execution_surface/` 디렉터리가 잔존(02는 이미 archive PASS, complete.log 존재). 비어 있어 동작 영향 없음. 종결 정리 단계에서 제거함.
- Nit (정보): 공개 preview `http://toki-labs.com:13020/`가 이번 smoke에서 tracked HEAD fresh build로 재기동되었으나 `/tmp/oto-api-binding-smoke/work/...` 기반 ephemeral Python server로 서비스된다. durable preview 배포는 이 Milestone `범위 제외`(쓰기/persistence)라 smoke evidence 판정에는 영향 없음. 영구 13020 배포 파이프라인의 stale build 갱신은 후속 운영 작업 후보.

### 다음 단계

- PASS: `code_review_cloud_G07_0.log` / `plan_cloud_G07_0.log` 아카이브, `complete.log` 작성 후 task 디렉터리를 `agent-task/archive/2026/06/m-control-plane-api-data-binding/03+01,02_preview_smoke/`로 이동. task group이 `m-control-plane-api-data-binding`이므로 런타임용 완료 이벤트 메타데이터를 보고한다. roadmap 수정/`update-roadmap` 직접 호출은 하지 않는다.
