<!-- task=m-cross-os-runner-bootstrap/05+01,02,03_node_connect plan=1 tag=REVIEW_CONNECT -->

# PLAN: node-connect 리뷰 후속

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

이 계획은 이전 리뷰 `code_review_cloud_G07_0.log`의 Required 이슈만 해결한다. 사용자에게 직접 질문하거나 선택지를 제시하지 말고, 사용자 소유 결정이나 외부 환경 차단이 있으면 `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 남긴 뒤 멈춘다.

## 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: `[node-connect]`
- Completion mode: check-on-pass

## 리뷰 판정 요약

- 이전 plan: `plan_cloud_G07_0.log`
- 이전 review: `code_review_cloud_G07_0.log`
- 이전 verdict: FAIL
- Required:
  - `apps/runner/test/oto_agent_registration_test.dart:745`의 기대값이 `RegistrationResult.fromOtoJson()`의 기존 `reject_reason` 우선 계약과 맞지 않아 Dart agent smoke가 실패했다.
  - 구현 리뷰 파일에 필수 검증이 실제 stdout/stderr 없이 후속 수집 대상으로 남았고, 원격 runner checkout은 현재 workspace와 다른 HEAD라 이 변경의 검증 증거로 사용할 수 없었다.

## 범위 결정 근거

bootstrap config fixture 자체와 기존 Core registry 상태/heartbeat smoke는 리뷰 중 코드와 테스트를 대조했을 때 큰 구조 변경 없이 판단 가능했다. 후속은 실패한 token rejection 계약과 같은 소스 기준 검증 증거 회수로 제한한다.

## 구현 체크리스트

- [ ] `RegistrationResult.fromOtoJson` rejection contract and token rejection test expectation/fixture를 같은 계약으로 맞춘다.
- [ ] 현재 변경이 적용된 같은 소스 기준으로 필수 Dart/Go 검증을 실행하고 실제 stdout/stderr를 `CODE_REVIEW-cloud-G07.md`에 기록한다.
- [ ] `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_CONNECT-1] rejection contract 정합화

문제: 새 테스트는 fake server 응답에 `reject_reason: enrollment_token_invalid`와 `error.message: invalid or expired enrollment token`을 함께 넣고 `error.message`가 `result.rejectReason`이 되기를 기대한다. 하지만 현재 parser는 `reject_reason`을 우선한다.

해결 방법: 의도한 계약을 하나로 고정한다. 기존 JSON 계약을 유지한다면 테스트 기대값을 `enrollment_token_invalid`로 맞추고 token 원문 미포함 assertion을 유지한다. 메시지 우선 계약이 필요하다면 `RegistrationResult.fromOtoJson()`과 기존 rejection tests를 함께 갱신해 모든 call site가 같은 의미를 보게 한다.

수정 파일 및 체크리스트:

- `apps/runner/test/oto_agent_registration_test.dart`
- 필요 시 `apps/runner/lib/oto/agent/registration_client.dart`

중간 검증:

- `cd apps/runner && dart test test/oto_agent_registration_test.dart -p vm --plain-name 'OtoServerRegistrationClient registration rejects enrollment_token_invalid without exposing token value'`

### [REVIEW_CONNECT-2] 검증 증거 회수

문제: 이전 리뷰 파일은 원격 runner에서 필수 검증을 실행하지 않았고, 리뷰 중 확인한 원격 checkout도 현재 workspace와 다른 HEAD였다.

해결 방법: 현재 변경이 적용된 같은 소스 기준에서 필수 명령을 실행하고, 실제 stdout/stderr를 `CODE_REVIEW-cloud-G07.md`에 붙인다. 원격 runner를 사용한다면 먼저 해당 checkout이 이 변경을 포함하는지 `git rev-parse HEAD`, `git diff --stat` 또는 동등한 근거로 확인하고, 기준이 다르면 그 출력을 PASS 증거로 쓰지 않는다.

수정 파일 및 체크리스트:

- `CODE_REVIEW-cloud-G07.md`
- 필요 시 테스트 수정 파일

중간 검증:

- `cd apps/runner && dart format --output=none --set-exit-if-changed test/oto_agent_bootstrap_script_test.dart test/oto_agent_registration_test.dart`
- `cd apps/runner && dart analyze`
- `cd apps/runner && dart test test/oto_agent_bootstrap_script_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart`
- `cd services/core && go test ./...`

## 최종 검증

- `git diff --check`
- `cd apps/runner && dart format --output=none --set-exit-if-changed test/oto_agent_bootstrap_script_test.dart test/oto_agent_registration_test.dart`
- `cd apps/runner && dart analyze`
- `cd apps/runner && dart test test/oto_agent_bootstrap_script_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart`
- `cd services/core && go test ./...`

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