<!-- task=m-node-multi-target-serving-foundation/08+03,04,05,06,07_field_smoke plan=2 tag=REVIEW_REVIEW_TEST -->

# Plan - REVIEW_REVIEW_TEST

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

이 작업은 직전 code review `FAIL`의 남은 Required 이슈만 고친다. 사용자에게 직접 질문하지 말고, 원격 field smoke가 여전히 사용자 소유 환경 때문에 불가능하면 `CODE_REVIEW-cloud-G07.md`의 `사용자 리뷰 요청`에 증거와 재개 조건을 남긴다.

## 배경

직전 후속 구현은 `NormalizeAdapters`의 same-name conflict에서 base URL, context size, endpoint mismatch는 잡았지만 `Enabled` mismatch를 비교하지 않았다. legacy field가 enabled인데 explicit same-name instance가 disabled이면 normalize는 통과하고, `BuildConfigPayload`는 disabled instance를 skip해 enabled legacy adapter가 payload에서 사라질 수 있다.

## 사용자 리뷰 요청 흐름

원격 runner, 연결된 Node, Node token, Ollama endpoint, CLI target 같은 사용자 소유 prerequisite이 없으면 진행할 수 없는 경우 active review stub의 `사용자 리뷰 요청`에 기록한다. code-review가 user-review stop 여부를 결정한다. repo-owned normalize correctness issue와 테스트 증거 공백은 사용자 리뷰 요청으로 넘기지 않는다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/node-multi-target-serving-foundation.md`
- Task ids:
  - `field-smoke`: split-host smoke에서 하나의 연결된 Node가 최소 두 개의 inference model target과 하나의 CLI target을 같은 Edge-Node 연결로 호출할 수 있음을 확인한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-task/m-node-multi-target-serving-foundation/08+03,04,05,06,07_field_smoke/plan_cloud_G07_1.log`
- `agent-task/m-node-multi-target-serving-foundation/08+03,04,05,06,07_field_smoke/code_review_cloud_G07_1.log`
- `packages/go/config/config.go`
- `packages/go/config/config_test.go`
- `apps/edge/internal/node/store_test.go`
- `apps/edge/internal/node/mapper.go`

### 리뷰 실패 요약

- Required: `NormalizeAdapters`가 same-name explicit instance의 `Enabled` mismatch를 conflict로 처리하지 않는다.
- 영향: raw config에 `ollama.enabled=true`와 `ollama_instances[].name="ollama", enabled=false`가 같은 URL/context로 함께 있으면 adapter가 payload에서 누락될 수 있다. Vllm도 동일하다.
- 기존 테스트는 다른 URL/endpoint만 검증하고 disabled same-name instance를 직접 검증하지 않는다.

### 범위 결정 근거

- 이번 후속 범위는 `Enabled` conflict handling과 disabled explicit instance 회귀 테스트로 제한한다.
- 이미 추가된 legacy payload 유지 테스트와 idempotence 테스트는 유지한다.
- field smoke 자체는 이 fix 후에도 원격 환경이 준비되어야 완료 가능하다.

### 빌드 등급

- build: `cloud-G07`, review: `cloud-G07`. repo-owned fix는 좁지만 이 subtask의 종료 판단은 원격 field smoke와 user-review gate가 함께 걸려 있다.

## 구현 체크리스트

- [ ] `NormalizeAdapters`가 legacy enabled config와 same-name explicit disabled instance를 Ollama/Vllm 각각 error로 거부하게 한다.
- [ ] disabled same-name explicit instance 회귀 테스트를 Ollama/Vllm 각각 추가한다.
- [ ] idempotent 재호출 테스트가 여전히 통과하도록 exact promoted legacy instance는 enabled 값까지 동일할 때만 허용한다.
- [ ] `go test -count=1 ./packages/go/config ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/edge/internal/edgecmd`, `go test -count=1 ./...`, `go build ./apps/edge/... ./apps/node/...`를 실행하고 실제 stdout/stderr를 기록한다.
- [ ] 원격 field 환경이 준비되어 있으면 `/healthz`, `/v1/models`, inference target 두 개 호출, CLI target 호출이 같은 connected Node id/alias를 쓰는 증거를 수집한다. 준비되어 있지 않으면 `사용자 리뷰 요청`에 user-owned blocker와 재개 조건을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_TEST-1] Enabled mismatch conflict

- 문제: same-name explicit instance가 disabled이면 enabled legacy adapter가 silently dropped될 수 있다.
- 해결 방법: `findOllamaInstance`/`findVllmInstance`로 찾은 explicit instance가 legacy promoted instance와 `Enabled`까지 정확히 일치하는지 비교한다. `Enabled`, `BaseURL`, `ContextSize`, `Endpoint` 중 하나라도 다르면 error를 반환한다.
- 수정 파일 및 체크리스트:
  - [ ] `packages/go/config/config.go`: same-name legacy/explicit conflict 비교에 `Enabled`를 포함한다.
  - [ ] `packages/go/config/config_test.go`: disabled explicit same-name Ollama/Vllm conflict 테스트를 추가한다.
  - [ ] 필요 시 `apps/edge/internal/node/store_test.go`의 payload 유지 테스트를 새 계약과 맞춰 보강한다.
- 테스트 작성: 필수. disabled same-name conflict가 이번 Required issue의 본체다.
- 중간 검증:
  - `go test -count=1 ./packages/go/config ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/edge/internal/edgecmd`

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/go/config/config.go` | REVIEW_REVIEW_TEST-1 |
| `packages/go/config/config_test.go` | REVIEW_REVIEW_TEST-1 |
| `agent-task/m-node-multi-target-serving-foundation/08+03,04,05,06,07_field_smoke/CODE_REVIEW-cloud-G07.md` | REVIEW_REVIEW_TEST-1 |

## 최종 검증

```bash
go test -count=1 ./packages/go/config ./apps/edge/internal/node ./apps/edge/internal/transport ./apps/edge/internal/edgecmd
go test -count=1 ./...
go build ./apps/edge/... ./apps/node/...
curl -fsS http://<edge-openai>/healthz
curl -fsS http://<edge-openai>/v1/models
curl -fsS http://<edge-openai>/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"<model-a>","messages":[{"role":"user","content":"ping"}]}'
curl -fsS http://<edge-openai>/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"<model-b>","messages":[{"role":"user","content":"ping"}]}'
```

CLI target 호출은 프로젝트의 최신 Edge command endpoint 또는 `iop-edge` command로 실행하고, 실제 명령과 출력을 `CODE_REVIEW-cloud-G07.md`에 기록한다. 원격 환경이 사용자 소유 prerequisite 때문에 불가하면 실행하지 못한 field smoke 명령과 정확한 blocker를 `사용자 리뷰 요청`에 기록한다.
