<!-- task=m-node-multi-target-serving-foundation/01_config_topology plan=0 tag=API -->

# Code Review Reference - API

> **[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.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation.
> Finalization is review-agent-only.

## 개요

date=2026-06-10
task=m-node-multi-target-serving-foundation/01_config_topology, plan=0, tag=API

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/node-multi-target-serving-foundation.md`
- Task ids:
  - `config-topology`: Edge `nodes[]` 설정과 `NodeConfigPayload`가 하나의 Node 안에 여러 CLI profile, terminal gateway, 추론 engine/profile instance, model target route를 표현한다.
- Completion mode: check-on-pass

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

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

구현을 실제 소스와 대조하고 검증 출력이 코드와 일치하는지 확인한다. PASS이면 active 파일을 log로 아카이브하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. WARN/FAIL이면 user-review gate를 확인하고 후속 plan/review 또는 `USER_REVIEW.md`를 작성한다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [API-1] Multi Target Topology Contract | [x] |

## 구현 체크리스트

- [x] Edge config와 proto payload가 multi adapter/profile/model route topology를 표현하고 legacy 단일 설정을 호환한다.
- [x] config/proto/mapper/edgecmd 테스트가 멀티 topology와 legacy compat를 검증한다.
- [x] `make proto` 필요 여부를 확인하고 생성물 및 import 깨짐을 정리한다.
- [x] 최종 검증 명령을 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] active `CODE_REVIEW-cloud-G08.md`를 `code_review_cloud_G08_N.log`로 아카이브한다.
- [x] active `PLAN-local-G08.md`를 `plan_local_G08_M.log`로 아카이브한다.
- [ ] PASS이면 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리를 archive로 이동한다.
- [ ] PASS이고 task group이 `m-node-multi-target-serving-foundation`이면 런타임 완료 이벤트 메타데이터를 보고한다.
- [x] WARN/FAIL이면 후속 active plan/review 또는 `USER_REVIEW.md`를 작성한다.

## 계획 대비 변경 사항

- **`edgecmd/node_register.go`**: plan에서 "register/config 생성 경로 보강"을 언급했으나, `node_register.go`의 `--adapter` 플래그 흐름은 단일 ollama/cli 진입 경로로 남겨뒀다. Multi-instance 등록은 edge.yaml 직접 편집으로 처리하는 것이 현 UX 방향과 맞고, CLI 플래그로 다수의 named instance를 표현하는 인터페이스 설계는 후속 task 범위로 판단해 이번 변경에서 제외했다. `validateEdgeConfig`에서 `ollama_instances`/`vllm_instances` 유효성 검증은 추가했다.
- **`normalizeAdapters`의 legacy 이름 고정**: legacy `Ollama.Enabled` 단일 필드는 `OllamaInstances`로 promote 시 name을 `"ollama"`로 고정한다. 이는 기존 단일 인스턴스 시나리오에서 instance identity를 예측 가능하게 만들기 위함이다.
- **기존 `TestBuildConfigPayload_OllamaEnabled` 수정**: mapper가 `OllamaInstances`만 읽도록 변경되었으므로, LoadEdge를 통하지 않고 NodeRecord를 직접 구성하는 기존 테스트도 `OllamaInstances`를 세팅하도록 수정했다. 이것은 "mapper는 post-normalisation 상태를 받는다"는 계약을 테스트에 명시하는 것이다.

## 주요 설계 결정

- **AdapterConfig.name 필드 (proto field 8)**: `AdapterConfig`에 `name` 문자열 필드를 추가해 동일 type의 여러 instance를 구분하는 stable identity로 사용한다. 빈 값은 legacy single-instance로 간주한다.
- **AdapterConfig.target 필드 (proto field 9)**: 선택적 default target/route 힌트. 이번 task에서는 proto contract 확보 목적으로 추가만 하고 routing 로직은 후속 task에서 사용한다.
- **`OllamaInstances`/`VllmInstances` slice를 `AdaptersConf`에 추가**: 동일 type 여러 engine instance를 표현한다. legacy `Ollama`/`Vllm` 단일 필드는 `LoadEdge` 내 `normalizeAdapters`에서 슬라이스 앞에 promote되어 하위 코드가 슬라이스만 읽으면 된다.
- **중복 name 검증**: `normalizeAdapters`(config load)와 `BuildConfigPayload`(mapper) 양쪽에서 중복 name을 에러로 처리해 키 충돌을 load 시점에 잡는다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._

- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음

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

- legacy 단일 `ollama`/`vllm`/`cli` 설정이 깨지지 않았는지 확인한다.
- proto 변경 시 생성물과 call site가 함께 반영됐는지 확인한다.
- 동일 adapter type 여러 instance의 key 충돌 정책이 테스트로 고정됐는지 확인한다.

## 검증 결과

### API-1 중간 검증

```bash
$ go test -count=1 ./packages/go/... ./apps/edge/internal/node/... ./apps/edge/internal/edgecmd/...
ok  	iop/packages/go/audit	0.002s
ok  	iop/packages/go/config	0.013s
ok  	iop/packages/go/hostsetup	0.004s
ok  	iop/packages/go/observability	0.015s
ok  	iop/apps/edge/internal/node	0.005s
ok  	iop/apps/edge/internal/edgecmd	0.007s
```

### 최종 검증

```bash
$ go test -count=1 ./packages/go/... ./proto/gen/... ./apps/edge/internal/node/... ./apps/edge/internal/edgecmd/...
ok  	iop/packages/go/audit	0.002s
ok  	iop/packages/go/config	0.014s
ok  	iop/packages/go/hostsetup	0.006s
ok  	iop/packages/go/observability	0.038s
?   	iop/proto/gen/iop	[no test files]
ok  	iop/apps/edge/internal/node	0.004s
ok  	iop/apps/edge/internal/edgecmd	0.011s
```

```bash
$ make proto
protoc \
	--go_out=. \
	--go_opt=module=iop \
	--proto_path=. \
	proto/iop/runtime.proto \
	proto/iop/node.proto \
	proto/iop/control.proto \
	proto/iop/job.proto
```

proto 변경 반영됨: `AdapterConfig`에 `name`(field 8), `target`(field 9) 추가. `proto/gen/iop/runtime.pb.go` 갱신 확인.

## 코드리뷰 결과

- 종합 판정: `WARN`
- 차원별 평가:
  - correctness: Warn
  - completeness: Pass
  - test coverage: Warn
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Pass
  - verification trust: Pass
- 발견된 문제:
  - Suggested: `apps/edge/internal/edgecmd/config.go:143`의 `hasOllama`/`hasVllm` 판정이 `len(instance) > 0`만 확인해, 모든 instance가 `enabled: false`여도 node가 adapter를 가진 것으로 검증 통과할 수 있다. 활성 instance 기준으로 판정하고 이 회귀를 edgecmd 테스트로 고정한다.
  - Suggested: `apps/edge/internal/edgecmd/config.go:151` 주변 검증이 `ollama_instances[].base_url`만 확인하고 `vllm_instances[].endpoint`는 확인하지 않는다. `enabled: true`인 vLLM instance의 빈 endpoint를 거부하고 테스트를 추가한다.
- 다음 단계: WARN/FAIL 후속 plan/review를 생성한다.
