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

# PLAN: bootstrap command contract 확장

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

이 계획은 현 마일스톤의 `bootstrap-platforms` 에픽 중 `[core-command]`만 완료 대상으로 삼는다. 구현 중 사용자 결정이 필요하면 채팅으로 질문하지 말고 동반 `CODE_REVIEW-cloud-G06.md`의 `사용자 리뷰 요청` 섹션을 실제 내용으로 채운 뒤 중단한다.

## 배경

현재 Core는 `/api/v1/runners/bootstrap-command`에서 Linux shell command만 반환한다. 요청 protobuf도 `runner_id`, `enrollment_token`만 있어 대상 OS 또는 script 종류를 표현하지 못한다. 이 작업은 OS/script 선택 계약을 먼저 고정해 후속 Unix/Windows bootstrap 구현이 같은 API 위에서 진행되게 한다.

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

## 분석 결과

### 읽은 파일

- `proto/oto/runner.proto`
- `services/core/internal/httpserver/runner_handlers.go`
- `services/core/internal/httpserver/routes.go`
- `services/core/internal/httpserver/bootstrap_provider.go`
- `services/core/internal/httpserver/server.go`
- `services/core/internal/httpserver/server_test.go`
- `services/core/oto/runner.pb.go`
- `apps/runner/lib/oto/agent/oto/runner.pb.dart`
- `apps/runner/lib/oto/agent/oto/runner.pbjson.dart`
- `apps/runner/test/oto_server_connection_smoke_test.dart`
- `agent-test/local/rules.md`
- `agent-test/local/agent-smoke.md`

### 테스트 환경 규칙

기본 환경은 local이다. 원격 runner checkout은 `/Users/toki/agent-work/oto`이고 SSH는 확인됐지만, 이 계획 작성 시점의 변경분은 현재 workspace에 있으므로 구현 검증은 변경분이 있는 checkout에서 실행해야 한다.

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

현재 Go 테스트는 기본 Linux shell command와 release URL validation은 다루지만 OS/script 선택 요청을 다루지 않는다. Dart smoke는 기존 필드 호환성 위주라 신규 proto 필드 기본값 호환 검증이 필요하다.

### 심볼 참조

`BootstrapCommandRequest`, `BootstrapCommandResponse`, `handleRunnerBootstrapCommand`, `/api/v1/runners/bootstrap-command`가 직접 참조점이다. generated proto 파일은 수동 편집하지 말고 `make proto-go`, `make proto-dart`로 갱신한다.

### 분할 판단

공유 task group은 `agent-task/m-cross-os-runner-bootstrap/`이다. 이 작업은 API/foundation이므로 `01_core_command`로 독립 실행한다. `03+01_windows_bootstrap`과 `05+01,02,03_node_connect`는 이 작업의 완료를 전제로 삼는다.

### 범위 결정 근거

이 계획은 API 요청/응답과 Core handler/test까지만 다룬다. shell/PowerShell script 구현, binary version check, agent 연결 smoke는 후속 split에서 다룬다.

### 빌드 등급

`cloud-G06`: protobuf 계약과 Go/Dart generated code를 포함하지만 변경 범위가 endpoint와 테스트에 한정되어 있다.

## 구현 체크리스트

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

### [API-1] bootstrap command 요청 계약 확장

문제: 현재 요청에는 OS/script 선택 필드가 없다.

해결 방법: proto에 enum 또는 string 기반 target 필드를 추가하되 기존 필드 번호를 보존한다. 기본값은 현재 Linux shell command와 동일해야 한다.

수정 파일 및 체크리스트:

- `proto/oto/runner.proto`
- `services/core/oto/runner.pb.go`
- `apps/runner/lib/oto/agent/oto/runner.pb.dart`
- `apps/runner/lib/oto/agent/oto/runner.pbjson.dart`

테스트 작성: generated code 갱신 후 기존 Dart smoke가 컴파일되는지 확인한다.

중간 검증: `make proto-go`, `make proto-dart`

### [API-2] Core handler OS/script 분기

문제: handler가 항상 `/bootstrap/oto-agent.sh`를 반환한다.

해결 방법: request target에 따라 shell 또는 powershell URL과 command wrapper를 선택한다. Linux/macOS는 shell 경로를 공유할 수 있고 Windows는 PowerShell script URL을 반환할 계약만 먼저 고정한다.

수정 파일 및 체크리스트:

- `services/core/internal/httpserver/runner_handlers.go`
- `services/core/internal/httpserver/server_test.go`

테스트 작성: Linux 기본값, macOS shell, Windows PowerShell, invalid target, HTTPS release URL validation 케이스를 추가한다.

중간 검증: `cd services/core && go test ./...`

## 수정 파일 요약

| 경로 | 목적 |
|------|------|
| `proto/oto/runner.proto` | bootstrap command 요청 계약 확장 |
| `services/core/internal/httpserver/runner_handlers.go` | OS/script별 command 반환 |
| `services/core/internal/httpserver/server_test.go` | command contract 회귀 테스트 |
| generated proto files | Go/Dart 컴파일 계약 갱신 |

## 최종 검증

- `make proto-go`
- `make proto-dart`
- `cd services/core && go test ./...`
- `cd apps/runner && dart analyze`

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