<!-- task=m-node-provider-first-config-surface/04+02,03_routing_status_refresh plan=2 tag=REVIEW_REVIEW_ROUTE -->

# Plan - REVIEW_REVIEW_ROUTE

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

구현 완료는 `CODE_REVIEW-local-G05.md` 작성 후 review-ready 보고까지다. review/finalization은 code-review 전용이다.

직접 사용자에게 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 구현 중 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 `CODE_REVIEW-local-G05.md`의 `사용자 리뷰 요청` 섹션을 증거와 함께 채우고 중단한다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니라 검증 결과 또는 후속 리뷰 이슈로 처리한다.

## 배경

이 후속 루프는 이전 리뷰의 남은 Required만 처리한다. provider-first 실행 필드 refresh 분류는 `classify.go`와 endpoint/header 테스트로 보강됐지만, 새 `providers[].enabled=false` 검증 경로가 unsupported provider type을 통과시키고, config refresh 계약 문서의 restart-required 목록이 실행 필드 분류와 불일치한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/node-provider-first-config-surface.md`
- Task ids:
  - `routing-status-refresh`: provider-first dispatch, status snapshot, config refresh
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- Archived plan: `agent-task/m-node-provider-first-config-surface/04+02,03_routing_status_refresh/plan_local_G07_1.log`
- Archived review: `agent-task/m-node-provider-first-config-surface/04+02,03_routing_status_refresh/code_review_local_G07_1.log`
- Verdict: FAIL
- Required summary:
  - `apps/edge/internal/edgevalidate/validate.go`의 disabled provider branch가 `p.Validate()`만 호출하고 supported provider type allowlist 검증을 건너뛰어 `enabled=false` + `type: unknown_provider`가 통과할 수 있다.
  - `agent-contract/inner/edge-config-runtime-refresh.md`의 restart-required 기준이 `classify.go`의 provider-first execution field restart-required 구현과 불일치한다.
- Affected files:
  - `apps/edge/internal/edgevalidate/validate.go`
  - `apps/edge/internal/edgevalidate/validate_test.go`
  - `agent-contract/inner/edge-config-runtime-refresh.md`
  - 필요한 경우 `apps/edge/internal/configrefresh/classify_test.go`
- Verification evidence from previous loop:
  - `go test ./apps/edge/internal/configrefresh ./apps/edge/internal/bootstrap`
  - `go test ./packages/go/config ./apps/edge/internal/edgevalidate ./apps/edge/internal/node ./apps/edge/internal/service ./apps/edge/internal/openai ./apps/edge/internal/configrefresh ./apps/edge/internal/bootstrap`
  - 두 명령 모두 현재 checkout에서 통과했다.
- Roadmap carryover:
  - Milestone task `routing-status-refresh`
  - SDD S04/S05, especially status/config refresh tests for `agent-task/m-node-provider-first-config-surface/04+02,03_routing_status_refresh`
- Narrow reread allowed:
  - `agent-task/m-node-provider-first-config-surface/04+02,03_routing_status_refresh/plan_local_G07_1.log`
  - `agent-task/m-node-provider-first-config-surface/04+02,03_routing_status_refresh/code_review_local_G07_1.log`

## 범위 결정 근거

새 schema나 dispatch/status semantics를 다시 설계하지 않는다. `enabled=false`는 adapter reference check만 skip해야 하며, provider id/type/category/models/numeric bounds 같은 구조 검증은 유지해야 한다. Contract 변경은 이미 구현된 refresh classification과 테스트 evidence를 문서 원문에 맞추는 작업이다.

## 구현 체크리스트

- [ ] `apps/edge/internal/edgevalidate/validate.go`에서 disabled provider도 enabled provider와 같은 supported type allowlist(`NormalizeProviderType` 결과 `openai_compat`, `ollama`, `cli`)를 통과하게 하고, adapter reference/type-specific execution field availability 검증만 skip한다.
- [ ] `apps/edge/internal/edgevalidate/validate_test.go`에 `enabled=false` provider가 unknown type이면 validation error를 내고, missing adapter reference만 skip한다는 회귀 테스트를 추가한다.
- [ ] `agent-contract/inner/edge-config-runtime-refresh.md`의 restart-required 기준에 provider-first 실행 필드(`provider`, `endpoint`, `base_url`, `headers`, `command`, `args`, `env`, `mode`, `resume_args`, `output_format`, `context_size`, `request_timeout_ms`) 변경을 명시한다.
- [ ] `go test ./apps/edge/internal/edgevalidate ./apps/edge/internal/configrefresh`를 실행한다.
- [ ] `go test ./packages/go/config ./apps/edge/internal/edgevalidate ./apps/edge/internal/node ./apps/edge/internal/service ./apps/edge/internal/openai ./apps/edge/internal/configrefresh ./apps/edge/internal/bootstrap`를 실행한다.
- [ ] `CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_ROUTE-1] Disabled Provider Structural Type Validation

#### 문제

`apps/edge/internal/edgevalidate/validate.go:82`는 disabled provider에서 `p.Validate()`만 실행하고 `continue`한다. `NodeProviderConf.Validate()`는 type이 비어 있는지만 확인하므로 unsupported provider type을 거부하지 않는다. 계약은 disabled provider의 adapter reference check만 skip하고 structural validation은 유지한다고 되어 있다.

#### 해결 방법

지원 provider type 검증을 disabled 여부보다 앞에서 공통으로 수행하거나, disabled branch 안에서 같은 allowlist 검증을 호출한다. 단, disabled provider의 missing adapter reference와 type-specific execution field availability는 계속 허용한다.

#### 테스트 작성

작성한다. `enabled=false`, `type: unknown_provider`, valid category/model/numeric fields를 가진 provider가 `unknown provider type` 계열 error를 내는지 확인한다. 기존 `TestValidateEdgeConfig_DisabledProviderSkipsAdapterRefCheck`는 missing adapter reference skip이 유지되는지 계속 통과해야 한다.

### [REVIEW_REVIEW_ROUTE-2] Config Refresh Contract Restart Field Alignment

#### 문제

`apps/edge/internal/configrefresh/classify.go`는 provider-first execution field 변경을 `restart_required`로 분류하지만, `agent-contract/inner/edge-config-runtime-refresh.md`의 restart-required 기준은 해당 필드를 명시하지 않는다.

#### 해결 방법

계약 문서의 restart-required 목록에 provider-first execution fields를 추가한다. 코드 동작 변경은 필요하지 않다.

#### 테스트 작성

별도 테스트는 필요 없다. 문서 정렬 변경이며, REVIEW_REVIEW_ROUTE-1의 edgevalidate 테스트와 기존 configrefresh 테스트를 함께 실행한다.

## 최종 검증

```bash
go test ./apps/edge/internal/edgevalidate ./apps/edge/internal/configrefresh
```

```bash
go test ./packages/go/config ./apps/edge/internal/edgevalidate ./apps/edge/internal/node ./apps/edge/internal/service ./apps/edge/internal/openai ./apps/edge/internal/configrefresh ./apps/edge/internal/bootstrap
```

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