<!-- task=m-node-multi-target-serving-foundation/02+01_adapter_registry plan=0 tag=REFACTOR -->

# Code Review Reference - REFACTOR

> **[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.
> 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/02+01_adapter_registry, plan=0, tag=REFACTOR

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/node-multi-target-serving-foundation.md`
- Task ids:
  - `adapter-registry`: Node adapter registry가 동일 adapter type의 여러 engine/profile instance를 덮어쓰지 않고 라우팅 가능한 target namespace로 관리한다.
- Completion mode: check-on-pass

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

> **[REVIEW AGENT ONLY]** 종결 절차는 코드리뷰 에이전트 전용이다.

구현을 plan과 대조하고, registry/router namespace가 legacy 단일 요청과 multi instance 요청을 모두 안전하게 처리하는지 검토한다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REFACTOR-1] Registry Namespace | [x] |

## 구현 체크리스트

- [x] Registry가 adapter type과 instance key를 보존하고 동일 adapter type 여러 instance를 덮어쓰지 않는다.
- [x] Factory가 `NodeConfigPayload`의 multi adapter instance를 registry namespace로 등록한다.
- [x] Router가 request의 adapter/target을 새 namespace로 해석하고 legacy 단일 adapter 요청을 호환한다.
- [x] registry/factory/router/node 단위 테스트를 추가 또는 갱신한다.
- [x] 최종 검증 명령을 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-cloud-G07.md`를 `code_review_cloud_G07_N.log`로 아카이브한다.
- [x] active `PLAN-local-G08.md`를 `plan_local_G08_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `complete.log` 작성 후 archive 이동한다.
- [x] WARN/FAIL이면 후속 active plan/review 또는 `USER_REVIEW.md`를 작성한다.

## 계획 대비 변경 사항

- `runtime/types.go` 변경 없음: 계획에 "필요한 routing metadata 최소 추가"로 열려 있었으나, `ExecutionSpec.Adapter`가 instance key를 그대로 전달하는 구조로 충분하여 추가 필드 없이 구현. `Adapter` 필드의 의미가 type name → instance key로 전환됨.
- `node_test.go` 변경 없음: 기존 테스트가 `fixedRouter` stub을 사용하므로 registry namespace 변경과 무관하게 통과. node 계층 테스트 추가 불필요 판단.

## 주요 설계 결정

- **`entry` 내부 구조체**: `Registry`가 `map[string]entry`로 각 등록 항목의 `typeName`(adapter 타입)과 `adapter` 인스턴스를 함께 보존. key는 instance key(proto `AdapterConfig.name`이 있으면 그것, 없으면 type name).
- **`RegisterKeyed(key, typeName, adapter)` 추가**: Factory가 proto payload의 `name` 필드를 instance key로 명시 등록할 수 있도록 분리. 기존 `Register(a)`는 `a.Name()`을 key와 typeName 양쪽에 사용해 backward compat 유지.
- **`Lookup(name)` 추가, `Get(key)` 유지**: `Get`은 exact key lookup 전용. `Lookup`은 exact → legacy type-name 단일 후보 → ambiguous error 순서로 처리. Router는 `Lookup`으로 전환. `GetAdapter(adapterName)` 인터페이스 시그니처는 유지하되 내부적으로 `Lookup`을 사용하고 error를 `(nil, false)`로 flattening.
- **ambiguous error 메시지**: instance key 목록을 포함시켜 운영자가 올바른 key를 식별할 수 있도록 안내.

## 사용자 리뷰 요청

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

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

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

- 동일 adapter type 여러 instance가 등록되어도 overwrite가 없는지 확인한다.
- ambiguous legacy adapter 요청이 조용히 임의 target으로 가지 않는지 확인한다.
- lifecycle `Start`/`Stop` 순서와 `All()` 진단 출력이 새 key 기준으로 안정적인지 확인한다.

## 검증 결과

### REFACTOR-1 중간 검증

```bash
$ go test -count=1 ./apps/node/internal/adapters/... ./apps/node/internal/router/...
ok  	iop/apps/node/internal/adapters	0.006s
ok  	iop/apps/node/internal/adapters/cli	42.397s
?   	iop/apps/node/internal/adapters/cli/internal/testutil	[no test files]
ok  	iop/apps/node/internal/adapters/cli/status	39.900s
?   	iop/apps/node/internal/adapters/mock	[no test files]
ok  	iop/apps/node/internal/adapters/ollama	0.008s
ok  	iop/apps/node/internal/adapters/vllm	0.007s
ok  	iop/apps/node/internal/router	0.006s
```

### 최종 검증

```bash
$ go test -count=1 ./apps/node/...
ok  	iop/apps/node/cmd/node	0.012s
ok  	iop/apps/node/internal/adapters	0.008s
ok  	iop/apps/node/internal/adapters/cli	42.426s
?   	iop/apps/node/internal/adapters/cli/internal/testutil	[no test files]
ok  	iop/apps/node/internal/adapters/cli/status	39.849s
?   	iop/apps/node/internal/adapters/mock	[no test files]
ok  	iop/apps/node/internal/adapters/ollama	0.012s
ok  	iop/apps/node/internal/adapters/vllm	0.012s
ok  	iop/apps/node/internal/bootstrap	0.262s
ok  	iop/apps/node/internal/node	0.012s
ok  	iop/apps/node/internal/router	0.005s
?   	iop/apps/node/internal/runtime	[no test files]
ok  	iop/apps/node/internal/store	0.045s
ok  	iop/apps/node/internal/terminal	0.445s
ok  	iop/apps/node/internal/transport	5.137s
```

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - Correctness: Fail
  - Completeness: Fail
  - Test coverage: Fail
  - API contract: Fail
  - Code quality: Pass
  - Plan deviation: Warn
  - Verification trust: Fail
- 발견된 문제:
  - Required: `apps/node/internal/router/router.go:67`의 `GetAdapter`가 `Registry.Lookup`의 ambiguous error를 `(nil, false)`로 접으면서, `apps/node/internal/node/node.go:162`와 `apps/node/internal/node/node.go:209`의 cancel/command 경로가 multi instance legacy adapter 요청을 `"not found"`로만 보고합니다. 계획은 ambiguous legacy 요청에 명확한 error와 instance key 안내를 요구했고, `Registry.Lookup` 자체는 `apps/node/internal/adapters/registry.go:76`에서 그 정보를 만들고 있습니다. 해결: router 인터페이스에 error-returning adapter lookup을 추가하거나 기존 `GetAdapter` 계약을 바꿔 command/cancel 경로가 ambiguous 원인과 key 후보를 그대로 응답하게 만들고, node command/cancel 테스트를 추가하세요.
  - Required: 이 변경은 `apps/node/internal/adapters/**`와 `apps/node/internal/router/**`의 adapter registry/실행 요청 경로를 바꿉니다. Node domain rule은 해당 경로 변경 후 testing domain rule의 작업 후 검증 기준을 따르라고 하며, testing rule은 edge-node registry/input surface 변경이 사용자 실행 파이프라인에 닿으면 Go 테스트 외 repo 내부 edge-node 진단과 full-cycle 실제 구동 기준을 함께 요구합니다. 현재 review evidence는 `go test -count=1 ./apps/node/...`까지만 있어 필수 실행 검증이 비어 있습니다. 해결: `agent-test/local/node-smoke.md` 기준으로 보조 smoke 및 repo 내부 edge-node/full-cycle evidence를 수집하거나, 실행 불가 시 정확한 blocker를 기록하세요.
- 리뷰어 재검증:
  - `go test -count=1 ./apps/node/...` - PASS; reviewer rerun 완료.
- 다음 단계:
  - FAIL: 위 Required 항목을 해결하는 후속 `PLAN-*`/`CODE_REVIEW-*`를 작성한다.
