ㄹ<!-- task=m-node-provider-first-config-surface/03+01_legacy_compat plan=0 tag=COMPAT code-review -->

# CODE_REVIEW - COMPAT (G05)

## 구현 에이전트 기록

### 변경 파일 요약

| 파일 | 변경 내용 |
|------|----------|
| `packages/go/config/config.go` | `checkProviderLegacyConflict` 함수 및 `legacyAdapterRef` 타입 추가. `LoadEdge`에서 호출. |
| `packages/go/config/config_test.go` | `TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed`, `TestLoadEdge_ProviderFirstLegacyConflictRejected`, `TestLoadEdge_LegacyOnlyConfigRegression` 추가. |
| `apps/edge/internal/edgevalidate/validate_test.go` | 기존 테스트 유지. `ValidateEdgeConfig`는 `LoadEdge`가 아닌 별도 검증 경로. |

### 구현 내용

1. **`checkProviderLegacyConflict` 함수 추가** (`config.go`)
   - enabled legacy adapter instances (`ollama`, `vllm`, `openai_compat`, `cli` profiles)의 이름/키를 맵으로 수집
   - 각 `providers[].id`가 enabled adapter instance 이름과 일치하면 타입별 일치 검증 수행
   - 필드 불일치 시 `nodes[N].providers[M] "ID" conflicts with adapters.TYPE instance "NAME": field mismatch` 형식 error 반환
   - 일치하면 compat accepted (silent precedence 방지)

2. **`legacyAdapterRef` 구조체 추가**
   - legacy adapter instance의 핵심 필드를 저장하는 lightweight 구조체

3. **`LoadEdge` 검증 flow 수정**
   - 기존 provider ID 고유성 검증 loop 종료 후 `checkProviderLegacyConflict`를 모든 노드에 대해 호출

4. **테스트 3개 추가** (`config_test.go`)
   - `TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed`: identical fields일 때 통과
   - `TestLoadEdge_ProviderFirstLegacyConflictRejected`: conflicting field 값일 때 에러
   - `TestLoadEdge_LegacyOnlyConfigRegression`: legacy-only config 회귀 테스트

### 검증 출력

```
=== RUN   TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed
--- PASS: TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed (0.00s)
=== RUN   TestLoadEdge_ProviderFirstLegacyConflictRejected
--- PASS: TestLoadEdge_ProviderFirstLegacyConflictRejected (0.00s)
=== RUN   TestLoadEdge_LegacyOnlyConfigRegression
--- PASS: TestLoadEdge_LegacyOnlyConfigRegression (0.00s)
ok  	iop/packages/go/config	0.051s
ok  	iop/apps/edge/internal/edgevalidate	0.008s
```

`go test ./...` 전체 테스트도 통과.

### 검증 범위

- `go test ./packages/go/config ./apps/edge/internal/edgevalidate` — 통과
- `go test ./...` — 통과
- 기존 테스트 전체 회귀 없음

### 검증 밖 항목

- runtime dispatch/precedence behavior — 이 PR 대상 아님
- `ValidateEdgeConfig` 직접 호출 path의 충돌 검증 — `LoadEdge` 경로에서만 검증. `ValidateEdgeConfig`는 별도 검증 흐름.
- migration command — 이 PR 대상 아님

## 사용자 리뷰

Milestone lock 여부:

- [ ] Milestone lock

리뷰 의견:

(사용자가 작성)

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Fail
  - API contract: Fail
  - code quality: Pass
  - implementation deviation: Fail
  - verification trust: Pass
  - spec conformance: Fail
- 발견된 문제:
  - Required: `packages/go/config/config.go:882`의 capacity 충돌 검증이 `p.Capacity != 0 && p.Capacity != legacy.Capacity`로 작성되어 provider-first provider가 동일 key legacy adapter와 섞였을 때 `capacity: 0` 또는 capacity 생략 상태를 legacy `capacity > 0`과 다른 값으로 보지 않습니다. 이 계약에서 provider capacity 0은 not-dispatchable 의미가 있으므로, SDD S03과 plan의 “endpoint/capacity mismatch는 silent precedence 대신 validation error” 조건을 만족하지 못합니다. `capacity`는 동일 key mixed config에서 legacy 값과 직접 비교하고, `LoadEdge`와 `ValidateEdgeConfig` 경로 모두에서 legacy capacity와 provider capacity가 다른 mixed config를 거부하는 테스트를 추가하세요.
- 다음 단계: FAIL follow-up plan/review를 생성한다.

## 코드리뷰 전용 체크리스트 최종 상태

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append했다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-local-G05.md`를 `code_review_local_G05_0.log`로 아카이브했다.
- [x] active `PLAN-local-G05.md`를 `plan_local_G05_0.log`로 아카이브했다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인했다.
- [ ] PASS 전용 `complete.log` 작성은 해당 없음.
- [ ] PASS 전용 task directory archive 이동은 해당 없음.
- [ ] PASS 전용 `m-<milestone-slug>` 완료 이벤트 메타데이터 보고는 해당 없음.
- [ ] PASS split parent 정리는 해당 없음.
- [x] FAIL이고 user-review gate가 트리거되지 않았으므로 다음 active `PLAN-local-G04.md`와 `CODE_REVIEW-local-G04.md`를 작성했고 `complete.log`를 작성하지 않았다.
- [ ] USER_REVIEW 작성은 해당 없음.
- [ ] USER_REVIEW 해소 처리는 해당 없음.
