<!-- task=m-control-plane-separation-migration/04+02_bootstrap_command plan=2 tag=REVIEW_REVIEW_API -->

# Plan - REVIEW_REVIEW_API

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

이 plan은 code review FAIL 후속 루프다. 아래 Required 이슈만 좁게 수정한다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션만 채우고 active 파일을 그대로 둔다. 사용자에게 직접 질문하거나 선택지를 제시하지 않는다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/independent-control-plane/milestones/control-plane-separation-migration.md`
- Task ids:
  - `bootstrap-command`: OTO Server가 runner bootstrap command를 발급하고, bootstrap script가 `apps/runner` binary/config를 기준으로 runner를 실행하는 흐름이 정의된다.
- Completion mode: check-on-pass

## 범위 결정 근거

- 서버 command 렌더링과 bootstrap script 변경 자체는 유지한다.
- 이번 루프는 review에서 확인된 검증 공백만 다룬다.
- release artifact publishing, checksum signing, package hosting 구현은 계속 제외한다. 테스트에서는 fake `curl`/`tar` fixture로 외부 artifact 없이 script 성공 경로를 검증한다.
- legacy iop smoke는 현재 최종 검증 계약에 포함되어 있으므로, 조용히 제외하지 않는다. 외부 sibling repo 때문에 자동 후속이 불가능하면 review stub의 `사용자 리뷰 요청`으로 멈춘다.

## 구현 체크리스트

- [ ] [REVIEW_REVIEW_API-1] server-issued bootstrap command smoke가 fake `curl`/`tar` fixture로 실제 script download/extract/config 성공 경로를 통과하도록 고치고, script exitCode 0과 생성 config/installed binary를 assert한다.
- [ ] [REVIEW_REVIEW_API-2] 최종 Dart 검증 계약을 정확하게 충족하거나, legacy iop smoke 실패가 사용자 소유 외부 repo blocker라면 `사용자 리뷰 요청`에 실제 실패 출력과 재개 조건을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_REVIEW_API-1] Endpoint command smoke 강화

문제: `apps/runner/test/oto_server_connection_smoke_test.dart:202`는 endpoint command에서 인자를 추출해 script를 실행하지만 fake `curl`/`tar` 없이 `https://example.com/releases` 다운로드 실패를 허용한다. `apps/runner/test/oto_server_connection_smoke_test.dart:209`는 stderr에 HTTPS 검증 오류가 없는지만 확인하므로 script가 실제 성공 경로를 통과하지 않아도 테스트가 성공한다.

해결 방법:

- endpoint response의 bootstrap command를 shell 계약대로 안전하게 분해한다. 단순 regex가 shell escape를 잘못 해석할 수 있으면 `bash` 기반 fixture로 command 실행을 검증하거나, quote escape를 처리하는 작은 parser를 테스트 helper로 둔다.
- temp `PATH`에 fake `curl`을 주입해 requested `-o` 파일에 fake `oto-linux-*.tar.gz`를 복사하게 한다.
- fake archive에는 executable `oto`를 넣고 script를 `--config-path <temp>/config.yaml --install-dir <temp>/bin --workspace-root <temp>/workspace --log-dir <temp>/log --no-background`로 실행한다.
- assertion은 최소한 script exitCode 0, generated config의 `server.url`, `agent.id`, `agent.enrollment_token`, installed `oto` 존재/실행권한을 확인한다.
- `apps/runner/test/oto_server_connection_smoke_test.dart:184`의 trailing whitespace도 함께 제거한다.

수정 파일 및 체크리스트:

- [ ] `apps/runner/test/oto_server_connection_smoke_test.dart`
- [ ] 필요 시 `apps/runner/test/oto_agent_bootstrap_script_test.dart`

테스트 작성:

- OTO Server endpoint가 반환한 실제 command에서 나온 script 인자로 fake artifact 성공 경로를 실행한다.
- runner id/token에 shell metacharacter가 있는 경우에도 인자 값이 보존되고 추가 command가 실행되지 않는지 확인한다. Go unit string 비교만으로 충분하지 않으면 Dart smoke에 포함한다.

중간 검증:

```bash
cd apps/runner && dart test test/oto_server_connection_smoke_test.dart test/oto_agent_bootstrap_script_test.dart
```

## [REVIEW_REVIEW_API-2] 최종 검증 계약 정리

문제: `code_review_cloud_G07_1.log:155`의 최종 검증은 `test/oto_iop_connection_smoke_test.dart`를 포함하지만, 재실행 결과 해당 테스트가 sibling `../../../iop`의 Go compile error로 실패한다. 같은 로그 `:156`은 "user decision"으로 제외했다고 기록했지만 loop state에 사용자 결정 또는 `USER_REVIEW.md` 근거가 없다.

해결 방법:

- 먼저 exact final command를 재실행하고 실제 stdout/stderr를 review stub에 기록한다.
- 통과시키는 것이 repo 범위에서 가능하면 iop smoke 또는 관련 fixture를 수정하지 말고 필요한 설정/환경 근거를 정리해 exact final command를 통과시킨다.
- 외부 sibling `iop` checkout 문제라서 자동 후속이 안전하게 해결할 수 없으면 active review stub의 `사용자 리뷰 요청`에 다음을 채운다: 실행한 exact command, 실패 stdout/stderr 핵심, 왜 repository-owned follow-up으로 해소할 수 없는지, 사용자가 제공해야 할 결정 또는 외부 repo 상태, 재개 조건.
- "제외"가 실제 범위 결정이라면 조용히 생략하지 않는다. 관련 테스트 규칙 또는 plan 계약을 바꿔야 하며, 그 경우 작업 전 `agent-ops/skills/common/update-test/SKILL.md`를 읽고 근거와 변경된 정확한 최종 명령을 남긴다.

수정 파일 및 체크리스트:

- [ ] `agent-task/m-control-plane-separation-migration/04+02_bootstrap_command/CODE_REVIEW-cloud-G07.md`
- [ ] 필요 시 `agent-test/local/agent-smoke.md`
- [ ] 필요 시 `apps/runner/test/oto_iop_connection_smoke_test.dart`

테스트 작성:

- 별도 테스트 추가보다 최종 검증 계약의 실제 stdout/stderr 신뢰성을 우선한다.

중간 검증:

```bash
cd apps/runner && dart test test/oto_iop_connection_smoke_test.dart
```

## 최종 검증

```bash
cd services/core && go test ./...
cd apps/runner && dart analyze
cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_iop_connection_smoke_test.dart test/oto_server_connection_smoke_test.dart
```

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