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

# Plan - Preview Data Smoke

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

구현 완료의 마지막 단계는 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 검증 출력과 evidence path로 채우는 것이다. 이 작업은 코드 변경보다 원격 preview/browser evidence 수집이 중심이다. 검증을 실행하고, 실제 출력과 스크린샷 경로를 기록한 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 종결 처리, log rename, `complete.log` 작성, archive 이동은 code-review 스킬 전용이다. 구현 중 사용자만 결정할 항목, 사용자 소유 외부 환경, 범위 충돌이 발견되면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 근거를 남기고 멈춘다. 구현 중 채팅으로 직접 질문하거나 `request_user_input`을 호출하지 않는다.

## 배경

`preview-data-smoke`는 Core health/readiness와 실제 preview 화면 증거가 함께 있어야 닫을 수 있다. 2026-06-17 preflight에서 `http://toki-labs.com:18020/healthz`, `readyz`는 `OK`였고 `http://toki-labs.com:13020/`은 HTTP 200을 반환했다. 그러나 이 Task는 runner/execution surface가 구현된 후 최소 한 화면의 API-backed 상태가 렌더링되는지 확인해야 하므로 선행 split 완료가 필요하다.

## 사용자 리뷰 요청 흐름

구현 중 차단 사항은 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 해당 섹션은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식을 따른다. 직접 사용자 프롬프트는 금지되며, code-review가 요청 타당성을 검토하고 실제 `USER_REVIEW.md` 작성 여부를 결정한다.

## 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

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`
- `agent-roadmap/phase/control-plane-product-surface/PHASE.md`
- `agent-roadmap/phase/control-plane-product-surface/milestones/control-plane-api-data-binding.md`
- `agent-test/local/rules.md`
- `apps/client/lib/src/app/core_connection_client.dart`
- `apps/client/lib/src/app/oto_client_app.dart`
- `apps/client/test/widget_test.dart`
- `packages/flutter/oto_console/lib/oto_console.dart`
- `packages/flutter/oto_console/lib/src/oto_console_contract.dart`
- `packages/flutter/oto_console/lib/src/oto_console_shell.dart`
- `packages/flutter/oto_console/test/oto_console_test.dart`
- `services/core/internal/httpserver/routes.go`
- `services/core/internal/httpserver/dto.go`
- `services/core/internal/httpserver/runner_handlers.go`
- `services/core/internal/httpserver/job_handlers.go`
- `services/core/internal/httpserver/execution_handlers.go`

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`를 읽었다.
- matched agent-test profile: 없음. 이 작업은 원격 preview smoke evidence 수집이며 전용 profile이 없다.
- 적용할 fallback source: `agent-test/local/rules.md`의 Workspace 포트/환경 체크리스트와 Monorepo Targets.
- 도구 확인: `command -v curl`, `command -v npx`, `command -v node`, `command -v flutter` 성공.
- 현재 preflight: `curl -fsS --max-time 10 http://toki-labs.com:18020/healthz` -> `OK`, `readyz` -> `OK`, `curl -fsSI --max-time 10 http://toki-labs.com:13020/` -> HTTP 200.

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

- unit/widget test는 remote preview 배포 상태와 browser rendering을 검증하지 않는다.
- screenshot evidence와 curl output을 `CODE_REVIEW-cloud-G07.md`에 실제 출력으로 남겨야 한다.

### 심볼 참조

- renamed/removed symbols: none.

### 분할 판단

- split decision policy를 먼저 평가했다.
- current subtask: `03+01,02_preview_smoke`.
- predecessor `01`: satisfied via `agent-task/archive/2026/06/m-control-plane-api-data-binding/01_runner_surface/complete.log`.
- predecessor `02`: satisfied via `agent-task/archive/2026/06/m-control-plane-api-data-binding/02+01_execution_surface/complete.log`.
- 이 smoke는 `01_runner_surface`와 `02+01_execution_surface` PASS 이후만 실행한다.

### 범위 결정 근거

- source code 변경은 기본 범위가 아니다. smoke 중 명백한 preview wiring bug가 발견되면 이 task에서 고치지 말고 review stub에 evidence를 남기고 후속 plan으로 분리한다.
- private token, credential, private release host 원문은 어떤 tracked 파일에도 남기지 않는다.
- Playwright/npm cache와 screenshot은 `/tmp/oto-api-binding-smoke` 아래에만 둔다.

### 빌드 등급

- build: `cloud-G07`, review: `cloud-G07`. 원격 preview, browser screenshot, 외부 API 상태 증거가 성공 조건의 중심이라 local deterministic review만으로 충분하지 않다.

## 의존 관계 및 구현 순서

1. `01_runner_surface`는 PASS되어 `agent-task/archive/2026/06/m-control-plane-api-data-binding/01_runner_surface/complete.log`를 남겼다.
2. `02+01_execution_surface`는 PASS되어 `agent-task/archive/2026/06/m-control-plane-api-data-binding/02+01_execution_surface/complete.log`를 남겼다.
3. 선행 충족 후 원격 Core curl evidence를 수집한다.
4. browser screenshot과 body text evidence를 수집한다.
5. 모든 실제 stdout/stderr와 screenshot path를 review stub에 붙인다.

## 구현 체크리스트

- [ ] 선행 `01_runner_surface`와 `02+01_execution_surface` archive `complete.log`를 확인한다.
- [ ] 원격 Core health/readiness와 preview HTTP 응답을 curl로 수집한다. 검증: `curl` 출력이 review stub에 남는다.
- [ ] browser screenshot과 최소 한 화면의 API-backed 상태 렌더링 evidence를 `/tmp/oto-api-binding-smoke`에 남긴다. 검증: screenshot path와 browser stdout이 review stub에 남는다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [TEST-1] Dependency gate and Core curl smoke

문제: 이 smoke는 UI surface 구현 완료 전에는 의미 있는 completion evidence가 될 수 없다.

해결 방법: 선행 `complete.log`를 확인한 뒤 curl evidence를 수집한다.

수정 파일 및 체크리스트:

- [ ] source file 변경 없음.
- [ ] `agent-task/archive/2026/06/m-control-plane-api-data-binding/01_runner_surface/complete.log` 확인.
- [ ] `agent-task/archive/2026/06/m-control-plane-api-data-binding/02+01_execution_surface/complete.log` 확인.
- [ ] `/tmp/oto-api-binding-smoke`에 curl output 저장.

테스트 작성: 생략. 이 항목은 원격 smoke evidence 수집이다.

중간 검증:

```bash
mkdir -p /tmp/oto-api-binding-smoke
curl -fsS --max-time 10 http://toki-labs.com:18020/healthz | tee /tmp/oto-api-binding-smoke/healthz.txt
curl -fsS --max-time 10 http://toki-labs.com:18020/readyz | tee /tmp/oto-api-binding-smoke/readyz.txt
curl -fsSI --max-time 10 http://toki-labs.com:13020/ | tee /tmp/oto-api-binding-smoke/preview-head.txt
```

기대 결과: `healthz.txt`와 `readyz.txt`에 `OK`, `preview-head.txt` 첫 줄에 HTTP 200 계열 상태가 남는다.

### [TEST-2] Browser screenshot smoke

문제: curl만으로는 Flutter preview가 API-backed 상태를 실제 화면에 렌더링했는지 확인할 수 없다.

해결 방법: Playwright를 `/tmp` cache로만 사용해 screenshot과 body text evidence를 남긴다. Browser setup 또는 rendering이 실패하면 stdout/stderr를 그대로 review stub에 남긴다.

수정 파일 및 체크리스트:

- [ ] source file 변경 없음.
- [ ] `/tmp/oto-api-binding-smoke/preview-smoke.mjs` 작성.
- [ ] `/tmp/oto-api-binding-smoke/preview.png` 생성.
- [ ] browser stdout에 preview URL, screenshot path, body text excerpt 또는 capture 불가 사유 기록.

테스트 작성: 생략. screenshot smoke evidence가 검증 산출물이다.

중간 검증:

```bash
mkdir -p /tmp/oto-api-binding-smoke
cat >/tmp/oto-api-binding-smoke/preview-smoke.mjs <<'NODE'
import { chromium } from 'playwright';

const screenshotPath = '/tmp/oto-api-binding-smoke/preview.png';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
await page.goto('http://toki-labs.com:13020/', {
  waitUntil: 'networkidle',
  timeout: 60000,
});
await page.screenshot({ path: screenshotPath, fullPage: true });
const bodyText = await page.locator('body').innerText({ timeout: 5000 }).catch((error) => {
  return `BODY_TEXT_UNAVAILABLE: ${error.message}`;
});
console.log(`preview_url=http://toki-labs.com:13020/`);
console.log(`screenshot=${screenshotPath}`);
console.log('body_text_start');
console.log(bodyText.slice(0, 2000));
console.log('body_text_end');
await browser.close();

if (!bodyText.includes('Build Operations Overview') && !bodyText.includes('BODY_TEXT_UNAVAILABLE')) {
  throw new Error('preview body text did not include the overview heading');
}
NODE
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
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
test -s /tmp/oto-api-binding-smoke/preview.png
```

기대 결과: `preview.png`가 생성되고 stdout에 preview URL, screenshot path, body text excerpt 또는 body text unavailable 사유가 남는다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| source 변경 없음 | TEST-1, TEST-2 |
| `/tmp/oto-api-binding-smoke/*` | TEST-1, TEST-2 |
| `agent-task/m-control-plane-api-data-binding/03+01,02_preview_smoke/CODE_REVIEW-cloud-G07.md` | TEST-1, TEST-2 |

## 최종 검증

```bash
mkdir -p /tmp/oto-api-binding-smoke
curl -fsS --max-time 10 http://toki-labs.com:18020/healthz | tee /tmp/oto-api-binding-smoke/healthz.txt
curl -fsS --max-time 10 http://toki-labs.com:18020/readyz | tee /tmp/oto-api-binding-smoke/readyz.txt
curl -fsSI --max-time 10 http://toki-labs.com:13020/ | tee /tmp/oto-api-binding-smoke/preview-head.txt
test -s /tmp/oto-api-binding-smoke/preview.png
```

기대 결과: health/readiness OK, preview HTTP 200 계열, screenshot file exists. Browser stdout과 screenshot path는 반드시 review stub에 붙인다.

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