<!-- task=oto_agent_registration/02+01_edge_registration_runtime plan=0 tag=AGENT_REG -->

# Code Review Reference - AGENT_REG

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-05-24
task=oto_agent_registration/02+01_edge_registration_runtime, plan=0, tag=AGENT_REG

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G07.md` → `code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md` → `plan_cloud_G07_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/oto_agent_registration/02+01_edge_registration_runtime/`로 이동한다. WARN/FAIL이면 다음 active plan/review 파일을 즉시 작성한다.
4. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [AGENT_REG-1] production iop runtime message import 경계 | [x] |
| [AGENT_REG-2] Edge registration client와 result model | [x] |
| [AGENT_REG-3] CommandAgent default runner 연결 | [x] |
| [AGENT_REG-4] Production client 기준 smoke | [x] |

## 구현 체크리스트

- [x] AGENT_REG-1 production iop runtime message import 경계를 만든다.
- [x] AGENT_REG-2 Edge registration client와 registration result 모델을 추가한다.
- [x] AGENT_REG-3 `CommandAgent` default runner를 registration runtime에 연결한다.
- [x] AGENT_REG-4 registration unit/smoke 테스트를 추가하거나 기존 smoke를 production client 기준으로 갱신한다.
- [x] 모든 중간 검증과 최종 검증을 실행하고 실제 stdout/stderr를 `CODE_REVIEW-cloud-G07.md`에 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G07_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_M.log`로 아카이브한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/oto_agent_registration/02+01_edge_registration_runtime/`를 `agent-task/archive/YYYY/MM/oto_agent_registration/02+01_edge_registration_runtime/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/oto_agent_registration/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다.

## 계획 대비 변경 사항

- `RegisterResponse`의 비수락(rejected) 오류 원인 필드가 계획상의 `rejectReason`이 아닌 proto 생성 모델의 `reason`으로 되어 있어 이를 실제 프로토콜 규격에 맞게 연동했습니다.
- `DefaultAgentRunner` 및 `AgentRunner` 인터페이스를 `lib/oto/agent/agent_runner.dart` 파일로 일괄 정의하고 재수정하여, `CommandAgent`의 CLI parsing과 핵심 Runner 비즈니스 계층을 이상적으로 격리했습니다.

## 주요 설계 결정

- **주입식 설계(Dependency Injection)**: `DefaultAgentRunner`가 `EdgeRegistrationClient`를 주입받을 수 있도록 생성자에 DI 구조를 마련하고, 테스트 단계에서 `FakeEdgeRegistrationClient`를 자유롭게 주입하여 소켓/네트워크 대역 모킹 상태를 정교하게 연동 및 검증할 수 있도록 개선했습니다.
- **예외 격리 및 사용자 친화적 에러 출력**: 등록 수락 거절(rejected) 및 소켓 연결 예외 발생 시 `RegistrationException`을 통해 예외 의미를 명확히 가공하고, CLI 레벨에서 전체 도움말(Help Menu)이 출력되는 중복 노이즈를 피하고자 `Error: <reason>`만을 직관적으로 출력하고 프로세스 `exitCode = 10`을 설정하도록 구성했습니다.

## 리뷰어를 위한 체크포인트

- production code가 `test/support/**`를 import하지 않는가.
- `RegisterRequest.token` 값이 config의 `agent.enrollment_token`에서만 오고 stdout/stderr에 노출되지 않는가.
- registration accepted/rejected/connection failure가 exit code와 result model에서 구분되는가.
- iop Edge smoke가 production registration client 또는 runner를 사용하도록 갱신되었는가.

## 검증 결과

### AGENT_REG-1 중간 검증
```
$ dart pub get
Resolving dependencies...
Got dependencies!

$ dart analyze
Analyzing oto...
   info - lib/oto/agent/google/protobuf/struct.pb.dart:15:8 - Import of a
          library in the 'lib/src' directory of another package. Try importing a
          public library that exports this library, or removing the import. -
          implementation_imports

1 issue found.
```

### AGENT_REG-2 중간 검증
```
$ dart test test/oto_agent_registration_test.dart
00:00 +0: loading test/oto_agent_registration_test.dart
00:00 +0: EdgeEndpoint EdgeEndpoint parses host and port from config edge url
00:00 +1: EdgeEndpoint EdgeEndpoint parses host and port from config edge url
00:00 +1: AgentRunner AgentRunner maps config token to register request
00:00 +2: AgentRunner AgentRunner maps config token to register request
00:00 +2: AgentRunner AgentRunner reports rejected registration
00:00 +3: AgentRunner AgentRunner reports rejected registration
00:00 +3: All tests passed!
```

### AGENT_REG-3 중간 검증
```
$ dart test test/oto_agent_cli_test.dart test/oto_agent_registration_test.dart
00:00 +0: loading test/oto_agent_cli_test.dart
00:00 +0: CommandAgent parses run config and calls runner
00:00 +1: CommandAgent parses run config and calls runner
00:00 +1: CommandAgent parses run config with equals option and calls runner
00:00 +2: CommandAgent parses run config with equals option and calls runner
00:00 +2: CommandAgent rejects unknown subcommand
00:00 +3: CommandAgent rejects unknown subcommand
00:00 +3: CommandAgent rejects missing config parameter
00:00 +4: CommandAgent rejects missing config parameter
00:00 +4: CommandAgent sets exit code zero on accepted registration
00:00 +5: CommandAgent sets exit code zero on accepted registration
00:00 +5: CommandAgent sets exit code ten on rejected registration
00:00 +6: CommandAgent sets exit code ten on rejected registration
00:00 +6: actual bin agent help lists run usage
00:01 +6: actual bin agent help lists run usage
00:02 +6: actual bin agent help lists run usage
00:03 +6: actual bin agent help lists run usage
00:03 +7: actual bin agent help lists run usage
00:03 +7: actual bin agent run help works
00:04 +7: actual bin agent run help works
00:05 +7: actual bin agent run help works
00:05 +8: actual bin agent run help works
00:05 +8: actual bin agent with no parameters shows root help
00:06 +8: actual bin agent with no parameters shows root help
00:07 +8: actual bin agent with no parameters shows root help
00:08 +8: actual bin agent with no parameters shows root help
00:08 +9: actual bin agent with no parameters shows root help
00:08 +9: All tests passed!
```

### AGENT_REG-4 중간 검증
```
$ dart test test/oto_iop_connection_smoke_test.dart
00:00 +0: loading test/oto_iop_connection_smoke_test.dart
00:00 +0: OTO Dart proto-socket client registers with iop Edge
00:01 +0: OTO Dart proto-socket client registers with iop Edge
00:02 +0: OTO Dart proto-socket client registers with iop Edge
00:03 +0: OTO Dart proto-socket client registers with iop Edge
00:04 +0: OTO Dart proto-socket client registers with iop Edge
00:05 +0: OTO Dart proto-socket client registers with iop Edge
00:06 +0: OTO Dart proto-socket client registers with iop Edge
00:07 +0: OTO Dart proto-socket client registers with iop Edge
00:08 +0: OTO Dart proto-socket client registers with iop Edge
00:09 +0: OTO Dart proto-socket client registers with iop Edge
00:10 +0: OTO Dart proto-socket client registers with iop Edge
00:11 +0: OTO Dart proto-socket client registers with iop Edge
00:12 +0: OTO Dart proto-socket client registers with iop Edge
00:12 +1: OTO Dart proto-socket client registers with iop Edge
00:12 +1: All tests passed!
```

### 최종 검증
```
$ dart pub get
Resolving dependencies...
Got dependencies!

$ dart analyze
Analyzing oto...
   info - lib/oto/agent/google/protobuf/struct.pb.dart:15:8 - Import of a
          library in the 'lib/src' directory of another package. Try importing a
          public library that exports this library, or removing the import. -
          implementation_imports

1 issue found.

$ dart test test/oto_agent_config_test.dart test/oto_agent_cli_test.dart test/oto_agent_registration_test.dart
All tests passed!

$ dart test test/oto_iop_connection_smoke_test.dart
All tests passed!
```

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

## 코드리뷰 결과

### 종합 판정

WARN

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| correctness | Pass | production `EdgeRegistrationClient`가 config token을 iop `RegisterRequest`로 보내고 accepted/rejected를 구분한다. |
| completeness | Pass | 계획된 runtime import 경계, runner 연결, production-client smoke 갱신, 구현-owned 리뷰 섹션 작성이 완료되어 있다. |
| test coverage | Pass | agent config/CLI/registration unit test와 iop Edge smoke가 실제로 통과한다. |
| API contract | Pass | `CommandAgent`는 default runner를 registration runtime에 연결하고 registration/config 예외를 exit code 10으로 매핑한다. |
| code quality | Warn | 새 Dart 파일들이 `dart format --output=none --set-exit-if-changed ...`에서 변경 필요로 보고되고, production generated WKT 파일의 analyzer info가 남아 있다. |
| plan deviation | Pass | heartbeat/daemon loop 제외 등 계획상 범위 밖 구현을 확장하지 않았다. |
| verification trust | Pass | 기록된 `dart pub get`, `dart analyze`, unit test, iop smoke를 재실행했고 출력이 현재 상태와 일치한다. |

### 발견된 문제

- Suggested: `lib/oto/agent/edge_registration_client.dart:75`, `lib/oto/agent/agent_config.dart:57`, `test/oto_iop_connection_smoke_test.dart:72` 등 새 Dart 파일 7개가 `dart format --output=none --set-exit-if-changed ...`에서 `Changed ...`로 보고된다. `dart format`을 적용한 뒤 같은 format check가 exit 0이 되게 한다.
- Suggested: `lib/oto/agent/google/protobuf/struct.pb.dart:15`에서 `dart analyze`가 generated production protobuf의 `implementation_imports` info를 계속 보고한다. generated 파일 직접 수정 대신 scoped analyzer exclude 또는 재생성/의존성 경계를 통해 `dart analyze`가 `No issues found!`가 되게 한다.

### 다음 단계

WARN: Suggested 이슈를 처리하는 follow-up `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성한다.
