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

# Plan - API

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

`CODE_REVIEW-cloud-G08.md`의 구현 에이전트 소유 섹션 작성까지가 구현의 일부다. 코드 변경 후 검증을 실행하고 실제 변경 내용, 검증 출력, 계획 대비 변경 사항을 채운 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, 또는 범위 충돌 없이는 진행할 수 없으면 review stub의 `사용자 리뷰 요청`에 근거를 남기고 중단한다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`, `USER_REVIEW.md`, archive log, `complete.log`를 만들지 않는다.

## 배경

현재 Edge `nodes[]`와 `NodeConfigPayload`는 adapter type별 단일 endpoint를 표현하는 구조다. 하나의 Node 연결에서 여러 CLI profile, terminal gateway, 여러 inference engine/profile, model route를 함께 쓰려면 config와 proto payload가 먼저 멀티 타겟 topology를 표현해야 한다.

## 사용자 리뷰 요청 흐름

구현 중 blocker는 active `CODE_REVIEW-cloud-G08.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 직접 사용자 프롬프트를 만들지 않으며, code-review가 요청 타당성과 실제 `USER_REVIEW.md` 작성 여부를 판단한다.

## 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

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/node-smoke.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `packages/go/config/config.go`
- `packages/go/config/config_test.go`
- `proto/iop/runtime.proto`
- `configs/edge.yaml`
- `apps/edge/internal/node/mapper.go`
- `apps/edge/internal/node/mapper_test.go`
- `apps/edge/internal/edgecmd/config.go`
- `apps/edge/internal/edgecmd/node_register.go`
- `agent-roadmap/phase/inference-provider-extension/milestones/node-multi-target-serving-foundation.md`

### 테스트 환경 규칙

- test_env: `local`
- local rules/profile을 읽었다. 적용 명령은 `go test ./packages/go/... ./proto/gen/...`, `go test ./apps/edge/internal/node/...`, `go test ./apps/edge/internal/edgecmd/...`이며 proto schema 변경 시 `make proto` 후 생성물 차이를 확인한다.
- `platform-common-smoke`, `edge-smoke`, `node-smoke` 기준상 사용자 실행 경로가 바뀌면 최소 edge/node config round-trip smoke 증거를 남겨야 한다.

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

- `EdgeConfig.Nodes[].Adapters`가 단일 `OllamaConf`/`VllmConf`만 갖는 구조는 `config_test.go`의 단일 context size 테스트로만 덮인다. 멀티 engine/profile decode 테스트가 없다.
- `NodeConfigPayload`는 typed oneof가 단일 adapter instance를 전송하는 테스트만 있다. 동일 type 여러 instance와 route/profile id 전달 테스트가 없다.
- `edgecmd node register`는 단일 ollama/cli 플래그 중심이라 여러 profile/engine 입력 테스트가 없다.

### 심볼 참조

- 변경 전 rename/remove 예정 심볼: 없음. 새 config/proto 필드를 추가하고 legacy 필드는 compat path로 유지한다.
- 관련 참조: `AdaptersConf`, `OllamaConf`, `VllmConf`, `CLIConf`, `BuildConfigPayload`, `NodeConfigPayload`, `AdapterConfig`.

### 분할 판단

- split 정책을 적용했다. 공유 API/proto/config foundation이 먼저 필요하므로 task group은 `m-node-multi-target-serving-foundation`이고 이 작업은 `01_config_topology` 독립 선행 작업이다.
- sibling 작업: `02+01_adapter_registry`, `03+01_route_catalog`, `04+01,02_engine_profiles`, `05+03,04_edge_owned_options`, `06+02,04_commands_caps`, `07+02_runtime_concurrency`, `08+03,04,05,06,07_field_smoke`.
- predecessor: 없음.

### 범위 결정 근거

- Edge OpenAI route 해석, Node adapter registry, provider 실행 구현은 후속 sibling task로 분리한다.
- SGLang 완성 구현, cloud fallback, RAG/tool policy는 milestone 범위 제외에 남긴다.

### 빌드 등급

- build: `local-G08`, review: `cloud-G08`. 프로토콜/schema와 config/call-site가 함께 움직이지만 범위가 foundation 파일로 제한된다.

## 구현 체크리스트

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

### [API-1] Multi Target Topology Contract

- 문제: `AdaptersConf`는 `Ollama`, `Vllm`, `CLI` 단일 필드만 제공해 동일 adapter type 여러 engine/profile instance를 표현하지 못한다 (`packages/go/config/config.go:168`). `NodeConfigPayload`와 `AdapterConfig`도 instance identity나 route metadata 없이 `type` 중심이다 (`proto/iop/runtime.proto:147`, `proto/iop/runtime.proto:153`). `BuildConfigPayload`는 ollama/vllm을 각각 한 번만 append한다 (`apps/edge/internal/node/mapper.go:24`, `apps/edge/internal/node/mapper.go:36`).
- 해결 방법: `NodeConf`/`AdaptersConf`에 typed profile collection을 추가하고 기존 단일 필드는 legacy alias로 유지한다. `AdapterConfig`에는 stable `name` 또는 `id`, optional target route/profile metadata를 추가한다. Mapper는 legacy 단일 필드와 신규 collection을 모두 payload로 변환하되 중복 key는 명확한 에러로 처리한다.
- 수정 파일 및 체크리스트:
  - [ ] `packages/go/config/config.go`: multi profile structs와 defaults/legacy normalization 추가.
  - [ ] `proto/iop/runtime.proto`: adapter instance identity와 route/profile payload 필드 추가.
  - [ ] `apps/edge/internal/node/mapper.go`: 신규 topology를 `NodeConfigPayload`로 변환.
  - [ ] `apps/edge/internal/edgecmd/node_register.go`: register/config 생성 경로가 신규 topology를 만들 수 있게 보강.
  - [ ] `configs/edge.yaml`: 사람용 예시를 multi target 기준으로 갱신.
- 테스트 작성: 추가한다. `packages/go/config/config_test.go`에 멀티 Ollama/vLLM/CLI profile decode와 legacy 단일 decode 테스트, `apps/edge/internal/node/mapper_test.go`에 동일 adapter type 여러 instance payload 테스트, `apps/edge/internal/edgecmd` 테스트에 register 출력 topology 테스트를 추가한다.
- 중간 검증:
  - `go test -count=1 ./packages/go/... ./apps/edge/internal/node/... ./apps/edge/internal/edgecmd/...`
  - proto 변경 시 `make proto && go test -count=1 ./proto/gen/...`

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/go/config/config.go` | API-1 |
| `packages/go/config/config_test.go` | API-1 |
| `proto/iop/runtime.proto` | API-1 |
| `proto/gen/**` | API-1 |
| `apps/edge/internal/node/mapper.go` | API-1 |
| `apps/edge/internal/node/mapper_test.go` | API-1 |
| `apps/edge/internal/edgecmd/config.go` | API-1 |
| `apps/edge/internal/edgecmd/node_register.go` | API-1 |
| `configs/edge.yaml` | API-1 |

## 최종 검증

```bash
go test -count=1 ./packages/go/... ./proto/gen/... ./apps/edge/internal/node/... ./apps/edge/internal/edgecmd/...
```

proto 파일을 수정했으면 아래도 실행한다.

```bash
make proto
git diff -- proto/gen
```

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