<!-- task=m-edge-model-group-queue-scheduling/02+01_surface_snapshot_contract plan=2 tag=REVIEW_REVIEW_REFACTOR -->

# Plan - REVIEW_REVIEW_REFACTOR Console Zero-Key Test Follow-up

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

`code_review_cloud_G06_1.log`의 Required 이슈만 해결한다. 구현 후 검증 명령을 실행하고 실제 stdout/stderr, 구현 메모, 계획 대비 변경 사항을 `CODE_REVIEW-cloud-G06.md`에 채운 뒤 active 파일을 남긴 채 리뷰 준비 상태로 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review-skill 전용이다.

구현 중 사용자만 결정할 수 있는 범위 변경, 외부 환경/secret, 또는 scope conflict가 생기면 chat에서 묻지 말고 review stub의 `사용자 리뷰 요청` 섹션에 근거와 재개 조건을 남긴다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백은 사용자 리뷰 요청 사유가 아니다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/edge-model-group-queue-scheduling.md`
- Task ids:
  - `snapshot-contract`: Edge-visible capacity/in-flight/queued snapshot이 Edge-owned model group 상태를 기준으로 표현되고 Node capability snapshot과 충돌하지 않는다.
  - `surface-coverage`: OpenAI Chat Completions/Responses 실행 경로가 `model` 값 기반 Edge-owned queue를 우회하지 않고, A2A/console 경로는 별도 model group key 없이 같은 Edge dispatch primitive와 충돌하지 않는다.
- Completion mode: check-on-pass

## 배경

두 번째 리뷰는 snapshot canonical mapping은 통과로 보았지만, console zero-key 테스트가 아직 `ModelGroupKey` 회귀를 잡지 못한다고 판정했다. 현재 테스트는 `edgeservice.New(reg, nil)`로 service를 만들어 queue가 비활성화되어 있으므로, `SendRun()`이 실수로 non-empty `ModelGroupKey`를 채워도 direct path로 전송되어 테스트가 통과한다.

## 이전 리뷰 근거

- Archived plan: `agent-task/m-edge-model-group-queue-scheduling/02+01_surface_snapshot_contract/plan_cloud_G06_1.log`
- Archived review: `agent-task/m-edge-model-group-queue-scheduling/02+01_surface_snapshot_contract/code_review_cloud_G06_1.log`
- Verdict: FAIL

## 구현 체크리스트

- [ ] Console `SendRun` 테스트가 queue 활성 service에서 non-empty `ModelGroupKey` 회귀를 실패로 잡도록 보강한다.
- [ ] `go test -count=1 ./apps/edge/internal/opsconsole -run TestSendRun_SubmitRunRequest_MetadataSource`가 통과한다.
- [ ] `go test -count=1 ./apps/edge/internal/openai ./apps/edge/internal/input/a2a ./apps/edge/internal/opsconsole ./apps/edge/internal/controlplane ./apps/edge/internal/service`가 통과한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REFACTOR-1] Queue-Active Console Zero-Key Guard

#### 문제

`apps/edge/internal/opsconsole/console_test.go:180`의 테스트 service는 event bus 없이 생성되어 queue가 nil이다. `SubmitRun()`은 `s.queue == nil`이면 `ModelGroupKey`를 무시하고 direct path를 타므로, 테스트가 `ModelGroupKey == ""` 계약을 실제로 보호하지 않는다.

#### 해결 방법

테스트 service를 `edgeevents.NewBus()`와 함께 생성해 queue를 활성화한다. 그리고 `SetNodeStore()`로 같은 node ID의 `NodeRecord`를 추가하되, non-empty queue path가 `adapter="cli", target="codex"`를 통과하지 못하도록 CLI config를 명시적으로 disabled/present 상태로 둔다. 예를 들어 `CLI.Enabled=false`이고 `Profiles`에 `codex`를 넣으면 queued path는 `resolveAdapterForNode()`에서 unsupported가 된다. 이 상태에서 현재 production `SendRun()`이 성공하고 node가 `RunRequest`를 받으면, console이 empty `ModelGroupKey` direct path를 유지했다는 회귀 증거가 된다.

#### 수정 파일 및 체크리스트

- [ ] `apps/edge/internal/opsconsole/console_test.go`: `TestSendRun_SubmitRunRequest_MetadataSource`를 queue-active service + restrictive node store로 보강한다.
- [ ] 테스트 코멘트는 “왜 non-empty ModelGroupKey면 실패하는지”를 실제 service 조건과 맞게 정정한다.

#### 중간 검증

```bash
go test -count=1 ./apps/edge/internal/opsconsole -run TestSendRun_SubmitRunRequest_MetadataSource
```

## 최종 검증

```bash
go test -count=1 ./apps/edge/internal/openai ./apps/edge/internal/input/a2a ./apps/edge/internal/opsconsole ./apps/edge/internal/controlplane ./apps/edge/internal/service
```

기대 결과: 통과. Go test cache는 허용하지 않는다.
