<!-- task=m-multi-edge-operations/02+01_edge_fleet_ops plan=2 tag=REVIEW_REVIEW_API -->

# Plan - REVIEW_REVIEW_API Agent Command Coverage

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

`CODE_REVIEW-cloud-G06.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 단계다. 코드 변경, 테스트 실행, 실제 stdout/stderr 기록을 끝낸 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다.

구현 중 사용자만 결정할 수 있는 scope 변경, 사용자 소유 외부 환경/secret, 또는 자동 후속으로 해결할 수 없는 차단이 생기면 `CODE_REVIEW-cloud-G06.md`의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 채우고 중단한다. 명령 재실행이나 증거 수집으로 닫을 수 있는 공백은 사용자 리뷰 요청이 아니라 구현/검증 항목으로 처리한다.

## 배경

G06 구현은 `agent.command` fake success를 제거했지만, 실제 supported command branch의 성공과 downstream node error 전파를 직접 검증하지 않는다. 이 follow-up은 `apps/edge/internal/service` 테스트만 보강해 `agent.command`가 실제 `NodeCommandRequest`를 보내는지, node error를 `EdgeCommandResponse`와 event로 반영하는지 확인한다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. code-review가 그 요청을 검증하고 필요할 때만 `USER_REVIEW.md`를 작성한다.

## 분석 결과

### 읽은 파일

- `agent-task/m-multi-edge-operations/02+01_edge_fleet_ops/plan_cloud_G06_1.log`
- `agent-task/m-multi-edge-operations/02+01_edge_fleet_ops/code_review_cloud_G06_1.log`
- `apps/edge/internal/service/service.go`
- `apps/edge/internal/service/service_test.go`
- `apps/edge/internal/controlplane/connector.go`
- `apps/edge/internal/controlplane/connector_test.go`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`

### 테스트 환경 규칙

- test_env: `local`
- matched profile: `agent-test/local/edge-smoke.md`
- applied commands: service package fresh test, edge package fresh test, `git diff --check`
- no external secret, Docker, Flutter, or remote runner is required for this follow-up.

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

- Missing: connected-node `agent.command` + `parameters.command=capabilities` success path sends a real `NodeCommandRequest`.
- Missing: supported command downstream `NodeCommandResponse.Error` becomes `EdgeCommandResponse.Status="error"` plus failed event.
- Already covered: nil client no longer fakes success, lifecycle summary states, status config non-leak, command relay parser.

### 심볼 참조

- Renamed/removed symbols: none.

### 분할 판단

- Existing split subtask remains `m-multi-edge-operations/02+01_edge_fleet_ops`.
- No additional split: this is one test-coverage repair inside `apps/edge/internal/service`.

### 범위 결정 근거

- Do not change proto schema, Control Plane API, or client UI.
- Do not add broad E2E harness. A package-level fake proto-socket node or injectable test helper is enough.
- Production code changes are allowed only if needed to make the command path testable without weakening behavior.

### 빌드 등급

- build=`cloud-G06`, review=`cloud-G06`: this is protocol/transport-path coverage for a prior Required issue, and the same cloud route remains appropriate.

## 구현 체크리스트

- [ ] [REVIEW_REVIEW_API-1] `agent.command` capabilities success path가 실제 `NodeCommandRequest`를 보내고 completed response/event를 반환하는 테스트를 추가한다.
- [ ] [REVIEW_REVIEW_API-2] `agent.command` capabilities downstream node error가 error response와 failed event로 전파되는 테스트를 추가한다.
- [ ] [REVIEW_REVIEW_API-3] fresh service/edge tests와 `git diff --check`를 실행하고 결과를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_API-1] Supported Command Success Test

문제:

`apps/edge/internal/service/service.go:770`의 `agent.command` capabilities branch는 code상 `s.Capabilities`를 호출하지만, 현재 `apps/edge/internal/service/service_test.go:522`는 nil client error만 검증한다.

해결 방법:

`service_test`에 fake proto-socket node client를 구성하거나, 기존 service 구조에 맞는 최소 test helper를 만든다. `ExecuteCommand`에 `Operation: "agent.command"`, `TargetSelector: "deployer"`, `Parameters: {"command":"capabilities","adapter":"cli","target":"codex"}`를 보내고 fake node가 받은 `NodeCommandRequest.Type == NODE_COMMAND_TYPE_CAPABILITIES`를 assert한다. fake node가 `Result`를 반환하면 response는 `Status: "completed"`이고 event sequence는 `started`, `completed`여야 한다.

수정 파일 및 체크리스트:

- [ ] `apps/edge/internal/service/service_test.go`: fake node command transport/helper 추가.
- [ ] `apps/edge/internal/service/service_test.go`: success test 추가.
- [ ] 요청의 adapter/target/session 값이 `NodeCommandRequest`로 전달되는지 검증.

테스트 작성:

- Add `TestServiceExecuteCommandAgentCommandCapabilitiesSuccess`.

중간 검증:

```bash
go test -count=1 ./apps/edge/internal/service
```

### [REVIEW_REVIEW_API-2] Downstream Error Test

문제:

`apps/edge/internal/service/service.go:639`는 downstream error를 `EdgeCommandResponse{Status:"error"}`로 변환하지만, `agent.command` 경유 node error fixture가 없다.

해결 방법:

success test의 fake node를 재사용해 `NodeCommandResponse{Error:"boom"}`를 반환하게 한다. `ExecuteCommand` 결과가 `Status: "error"`, `Error`에 `node reported error: boom`을 포함하고 마지막 event가 `Phase: "failed"`인지 확인한다.

수정 파일 및 체크리스트:

- [ ] `apps/edge/internal/service/service_test.go`: node error variant 추가.
- [ ] response error와 failed event summary를 함께 검증.

테스트 작성:

- Add `TestServiceExecuteCommandAgentCommandCapabilitiesNodeError`.

중간 검증:

```bash
go test -count=1 ./apps/edge/internal/service
```

### [REVIEW_REVIEW_API-3] Verification

문제:

이 follow-up은 테스트 신뢰 회복 작업이므로 fresh output이 필요하다.

해결 방법:

대상 package, edge 전체 package, diff cleanliness를 fresh run으로 확인한다.

수정 파일 및 체크리스트:

- [ ] `go test -count=1 ./apps/edge/internal/service`
- [ ] `go test -count=1 ./apps/edge/...`
- [ ] `git diff --check`

테스트 작성:

- 별도 테스트 없음. 위 명령 결과가 검증이다.

중간 검증:

```bash
git diff --check
```

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/edge/internal/service/service_test.go` | REVIEW_REVIEW_API-1, REVIEW_REVIEW_API-2, REVIEW_REVIEW_API-3 |
| `apps/edge/internal/service/service.go` | REVIEW_REVIEW_API-1, REVIEW_REVIEW_API-2 only if testability requires a small helper |

## 최종 검증

```bash
go test -count=1 ./apps/edge/internal/service
go test -count=1 ./apps/edge/...
git diff --check
```

예상 결과: 모든 명령 exit code 0. `go test` cache output은 완료 증거로 쓰지 말고 `-count=1` fresh output을 기록한다.

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