<!-- task=m-cross-os-runner-bootstrap/01_core_command plan=0 tag=API -->

# CODE REVIEW: bootstrap command contract 확장

## Roadmap Targets

- Milestone: `agent-roadmap/phase/control-plane-product-surface/milestones/cross-os-runner-bootstrap.md`
- Epic: `[bootstrap-platforms] Cross-OS bootstrap contract`
- Task id: `[core-command]`
- Completion mode: check-on-pass

## 사용자 리뷰 요청

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

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

## 구현 에이전트 소유 섹션

### 계획 대비 변경 사항

- 없음. 계획에 따라 충실히 구현 완료하였습니다.

### 수정 파일

- `proto/oto/runner.proto` : `BootstrapCommandRequest`에 `target` string 필드 추가
- `services/core/internal/httpserver/runner_handlers.go` : `powershellEscape` 추가, `handleRunnerBootstrapCommand`에서 target 파싱하여 linux/macos/windows(powershell) 및 invalid target 분기 처리
- `services/core/internal/httpserver/server_test.go` : 9~13번 테스트 케이스 추가 (OS/script 분기 및 invalid target 400 에러 검증)
- `services/core/oto/runner.pb.go` : Generated Go protobuf 파일 갱신
- `apps/runner/lib/oto/agent/oto/runner.pb.dart` : Generated Dart protobuf 파일 갱신
- `apps/runner/lib/oto/agent/oto/runner.pbjson.dart` : Generated Dart protobuf JSON mapping 파일 갱신

### 검증 결과

1. **Protobuf 갱신 검증 (`make proto-go && make proto-dart`)**:
   성공적으로 Makefile을 통해 Go 및 Dart용 파일들을 자동 생성하였습니다.
2. **Go handler 및 테스트 실행 (`cd services/core && go test ./...`)**:
   `TestHandleRunnerBootstrapCommand`를 포함한 모든 Go 테스트가 성공적으로 통과하였습니다.
   ```text
   ?   	github.com/toki/oto/services/core/cmd/oto-core	[no test files]
   ok  	github.com/toki/oto/services/core/internal/cicdstate	(cached)
   ok  	github.com/toki/oto/services/core/internal/httpserver	0.067s
   ok  	github.com/toki/oto/services/core/internal/runnerregistry	0.003s
   ?   	github.com/toki/oto/services/core/oto	[no test files]
   ```
3. **Dart 정적 분석 검증 (`cd apps/runner && dart analyze`)**:
   아무런 경고나 분석 오류 없이 정상 컴파일 및 통과하였습니다.
   ```text
   Analyzing runner...
   No issues found!
   ```

### 구현 체크리스트

- [x] `BootstrapCommandRequest`에 대상 OS 또는 script 종류를 표현하는 필드를 추가하고 기존 요청의 기본 Linux shell 동작을 보존한다.
- [x] `handleRunnerBootstrapCommand`가 대상별 bootstrap URL과 command template을 반환하도록 테스트 주도 변경한다.
- [x] 지원하지 않는 OS/script 값은 명확한 400 응답으로 실패시키고 enrollment token을 로그/응답 에러에 노출하지 않는다.
- [x] generated proto는 `make proto-go`, `make proto-dart`로 갱신하고 수동 편집하지 않는다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 코드 리뷰 전용 섹션

- [ ] Roadmap Targets와 구현 결과가 일치한다.
- [ ] 기존 Linux shell 기본 동작이 깨지지 않았다.
- [ ] invalid target과 secret 비노출 실패가 테스트로 확인된다.
- [ ] 구현 검증 명령 출력이 충분히 기록됐다.

## 완료 판정 메모

| 항목 | 값 |
|------|----|
| Verdict | 미작성 |
| Roadmap Completion | `[core-command]` only |
| Archive ready | 미작성 |

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - Correctness: Fail
  - Completeness: Fail
  - Test coverage: Fail
  - API contract: Fail
  - Code quality: Pass
  - Plan deviation: Pass
  - Verification trust: Pass
- 발견된 문제:
  - Required: `services/core/internal/httpserver/runner_handlers.go:254` Windows command가 `powershell -ExecutionPolicy Bypass -Command "irm ... | iex" -- --server-url ...` 형태로 생성됩니다. `Invoke-Expression`이 실행하는 내용은 `-Command` 문자열인 `irm ... | iex`뿐이라, 뒤에 붙은 `--server-url`, `--agent-id`, `--enrollment-token`, `--release-base-url` 인자가 다운로드된 bootstrap script에 전달되지 않습니다. Windows PowerShell bootstrap command 계약은 script URL뿐 아니라 runner id/token/server URL을 script 호출에 넘겨야 하므로, scriptblock invocation 안에서 다운로드 script를 실행하고 인자도 같은 PowerShell command 표현식 안에 포함하도록 수정하세요. 예: `& ([scriptblock]::Create((irm <url>))) -- --server-url <...> ...` 같은 형태를 기준으로 escaping을 재검토하고, 테스트도 단순 문자열 일치가 아니라 인자 전달 구조가 `-Command` 내부에 들어가는지 검증해야 합니다.
- 다음 단계: FAIL 후속 plan/review를 작성한다.

## 코드리뷰 전용 종결 체크리스트

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append했다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-cloud-G06.md`를 `code_review_cloud_G06_0.log`로 아카이브했다.
- [x] active `PLAN-cloud-G06.md`를 `plan_cloud_G06_0.log`로 아카이브했다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인했다.
- [x] FAIL이고 user-review gate가 트리거되지 않았으므로 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않았다.
- [x] task group이 `m-cross-os-runner-bootstrap`이지만 PASS가 아니므로 roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않았다.
