<!-- task=m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission plan=1 tag=REVIEW_PROVIDER_POLICY_ADMISSION -->

# Provider-pool Queue Admission 리뷰 후속 계획

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

구현과 검증을 완료한 뒤 `CODE_REVIEW-local-G07.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 stdout/stderr로 채우고 active 파일을 그대로 둔 채 리뷰 준비 상태를 보고한다. 종결 판정, log rename, `complete.log`, archive 이동은 code-review 전용이다. 선택된 Milestone의 `구현 잠금 > 결정 필요`가 구현을 막을 때만 review stub의 `사용자 리뷰 요청`에 정확한 연결 근거를 기록하고 멈춘다. 직접 사용자 질문·선택지·`request_user_input`, `USER_REVIEW.md`, archive log, `complete.log` 작성은 금지한다. 환경/secret/service blocker, 일반 범위 조정, 후속 에이전트가 해소할 수 있는 evidence gap은 사용자 리뷰 요청이 아니다.

## 배경

첫 구현은 global provider-pool gate를 추가했지만 초기 `NewRuntime`이 root policy를 전달하지 않고 explicit zero timeout을 기본 30초로 되돌린다. 새 회귀 테스트도 실제 pending cap과 bootstrap handoff를 실행하지 않아 SDD S06 완료 evidence로 사용할 수 없다.

**현재 코드 확인 결과**:
- `apps/edge/internal/bootstrap/runtime.go:74`: 이미 `SetRuntimeConfig(nodeStore, cfg.Models, convertProviderPoolConf(cfg.ProviderPool))` 경로를 사용한다.
- `apps/edge/internal/service/model_queue_types.go:93`: `queueTimeoutSet: true`로 explicit zero 보존 완료.
- `apps/edge/internal/service/model_queue_admission.go:446-450`: `pendingProviderPoolCountLocked()` 기반 admission gate 구현됨.
- `apps/edge/internal/service/service.go:91-111`: `SetRuntimeConfig`가 queue lock 아래 `setProviderPoolPolicyLocked` 호출.

`go build ./apps/edge/...` (GOCACHE=/tmp/iop-go-cache-provider-policy-review-followup) PASS. 코드 수정은 이미 완료되었으므로, 이번 후속은 **S06 완료를 위한 deterministic regression 테스트 작성과 검증 신뢰도 복구**만 처리한다.

## 사용자 리뷰 요청 흐름

선택된 Milestone lock 결정만 active `CODE_REVIEW-local-G07.md`의 `사용자 리뷰 요청`에 기록한다. 이 섹션은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식을 사용한다. 구현 중 직접 사용자 prompt는 금지하며 code-review가 요청 검증과 실제 `USER_REVIEW.md` 작성을 소유한다.

## Archive Evidence Snapshot

- Prior task path: `agent-task/m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission`
- Prior plan: `agent-task/m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission/plan_local_G07_0.log`
- Prior review: `agent-task/m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission/code_review_local_G07_0.log`
- Verdict: FAIL
- Findings: Required 3, Suggested 1, Nit 0.
- Affected files: `apps/edge/internal/bootstrap/runtime.go`, `apps/edge/internal/service/model_queue_types.go`, `apps/edge/internal/service/service.go`, `apps/edge/internal/service/provider_pool_admission_test.go`, `apps/edge/internal/bootstrap/runtime_refresh_test.go`, `apps/edge/internal/service/service_internal_test.go`.
- Verification evidence:
  - global-cap test는 `-timeout=5s`에서 `provider_pool_admission_test.go:48` / `model_queue_admission.go:548` 대기로 timeout panic했다.
  - bootstrap `TestRefreshProviderPoolPolicy` 필터는 `[no tests to run]`이었다.
  - 나머지 focused 일부와 `go test -count=1 ./apps/edge/...`는 PASS했지만 service package가 잘못 구성된 30초 대기 테스트 때문에 `33.641s`가 걸렸다.
  - live preflight는 config check PASS 후 외부 `/models`와 Control Plane status endpoint 접근 불가로 rc=3이었다.
- Roadmap carryover: `queue-ownership`은 미완료이며 승인된 SDD S06의 global pending cap, common timeout, first-candidate/model-group non-owner evidence가 필요하다.
- 구현에 추가 세부가 필요할 때 위 prior plan/review 두 파일만 좁게 다시 읽는다. 다른 `agent-task/archive/**`를 탐색하지 않는다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md)
- Task ids:
  - `queue-ownership`: Edge 공통 provider-pool queue policy와 전체 pending 상한
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- 규칙/스킬: `AGENTS.md`, `agent-ops/rules/project/rules.md`, `agent-ops/rules/common/rules-roadmap.md`, `agent-ops/rules/common/rules-agent-spec.md`, `agent-ops/rules/project/domain/edge/rules.md`, `agent-ops/rules/project/domain/platform-common/rules.md`, `agent-ops/rules/project/domain/testing/rules.md`, `agent-ops/skills/common/router.md`, `agent-ops/skills/common/code-review/SKILL.md`, `agent-ops/skills/common/plan/SKILL.md`, `agent-ops/skills/common/finalize-task-routing/SKILL.md`
- 로드맵/SDD: `agent-roadmap/current.md`, `agent-roadmap/phase/operational-observability-provider-management/PHASE.md`, `agent-roadmap/phase/operational-observability-provider-management/milestones/provider-resource-admission-ownership-alignment.md`, `agent-roadmap/sdd/operational-observability-provider-management/provider-resource-admission-ownership-alignment/SDD.md`
- 구현 스펙/계약: `agent-spec/index.md`, `agent-spec/runtime/provider-pool-config-refresh.md`, `agent-spec/runtime/edge-node-execution.md`, `agent-contract/index.md`, `agent-contract/inner/edge-config-runtime-refresh.md`, `agent-contract/inner/edge-node-runtime-wire.md`
- 구현: `apps/edge/internal/bootstrap/runtime.go`, `apps/edge/internal/service/model_queue_types.go`, `apps/edge/internal/service/model_queue_admission.go`, `apps/edge/internal/service/service.go`
- 테스트: `apps/edge/internal/service/provider_pool_admission_test.go`, `apps/edge/internal/bootstrap/runtime_refresh_test.go`, `apps/edge/internal/bootstrap/runtime_test_support_test.go`, `apps/edge/internal/service/service_internal_test.go`
- 테스트 규칙: `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md`, `agent-test/local/platform-common-smoke.md`, `agent-test/local/testing-smoke.md`
- 이전 루프 근거: `agent-task/m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission/plan_local_G07_0.log`, `agent-task/m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission/code_review_local_G07_0.log`

### SDD 기준

- SDD: `agent-roadmap/sdd/operational-observability-provider-management/provider-resource-admission-ownership-alignment/SDD.md`
- 상태: `[승인됨]`, SDD 잠금 해제.
- 대상: Acceptance Scenario `S06` / Milestone Task `queue-ownership`.
- Evidence Map: S06은 Edge provider resource/queue deterministic tests와 race 검증을 요구하며 최종 `complete.log`의 `Roadmap Completion`에 `queue-ownership`과 명령 evidence를 남겨야 한다.
- 따라서 구현 체크리스트는 root policy의 initial/apply handoff, Edge 전체 pending cap, explicit no-timeout, first-candidate/model-group non-owner를 직접 검증하는 항목으로 제한한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 edge/platform-common/testing profile을 모두 읽었다. 구조적 공백과 `<확인 필요>` 값은 없다.
- fresh 실행을 위해 모든 Go 검증에 `-count=1`과 별도 `/tmp` GOCACHE를 사용한다. concurrency 경로는 `-race -count=5`를 사용한다.
- runner=`/config/workspace/iop`, branch=`main`, HEAD=`e4966b0b173d823f6fb9f0a995da5d6070915bcf`, Linux/aarch64, Go 1.26.2, dirty shared worktree다.
- `bash`, `go`, `rg`, routing formatter, `scripts/e2e-long-context-admission-smoke.sh`가 존재한다. repo-local test binary를 새로 만들지 않는다.
- config=`configs/edge.yaml`; live preflight의 Edge base URL과 Control Plane status endpoint는 현재 접근 불가다. preflight rc=3이면 exact output과 out-dir를 blocker evidence로 기록하고 mixed scenario는 실행하지 않는다.

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

- 초기 `NewRuntime` handoff: 미검증. 현재 bootstrap 필터는 `[no tests to run]`.
- explicit zero timeout: 기존 테스트는 100ms context가 30초 fallback보다 먼저 끝나 false positive다.
- global pending cap: 기존 테스트는 pending 대신 dispatched 두 건을 세어 세 번째 요청이 30초 대기한다.
- legacy pending 격리: 기존 테스트는 legacy pending이 아니라 in-flight만 만든다.
- candidate-order 독립: 기존 테스트는 provider 하나만 사용한다.
- cancel/timeout 회복: 기존 테스트는 두 waiter를 순차 timeout시키며 cancel 경쟁과 lease/resource drain을 확인하지 않는다.
- store/catalog/policy snapshot: 기존 concurrency test가 policy A/B를 구분하지 않는다.

### 심볼 참조

- rename/remove 예정 심볼은 없다.
- `NewGroupPolicy` 호출부는 bootstrap converter, `queue_dispatch_test.go`, `provider_pool_admission_test.go`에 있다.
- `SetRuntimeConfig` signature는 유지한다. 초기 `NewRuntime` 조립과 apply refresh가 동일한 호출 경로를 사용하게 한다.

### 분할 판단

- split decision policy를 먼저 평가했다. 이번 작업은 기존 `05+03,04_provider_pool_policy_admission` 서브태스크의 FAIL 후속이며 runtime handoff와 root policy boundary가 하나의 ownership 단위다.
- source fix와 regression은 서로 독립 완료할 수 없고 각각 별도 `complete.log`를 만들 가치가 없으므로 추가 split은 인위적이다. 같은 task path의 단일 pair가 더 안전하다.
- predecessor `03+01,02_cross_group_wakeup`은 `agent-task/archive/2026/07/m-provider-resource-admission-ownership-alignment/03+01,02_cross_group_wakeup/complete.log`, `04_provider_pool_policy_config`는 `agent-task/archive/2026/07/m-provider-resource-admission-ownership-alignment/04_provider_pool_policy_config/complete.log`로 충족됐다.

### 범위 결정 근거

- `packages/go/config/**`, `configs/edge.yaml`, configrefresh schema는 선행 04가 완료했으므로 수정하지 않는다.
- provider resolution/admission 알고리즘 자체, provider snapshot, disconnect/refresh waiter 재기준화, contract/spec 문서는 sibling 또는 별도 Milestone Task 범위다.
- `service.go`는 duplicated reconcile와 잘못된 lock 설명 제거까지만 수정하며 queue scheduling 의미를 확장하지 않는다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`
- build closures: scope/context/verification/evidence/ownership/decision 모두 `true`.
- build grade scores: scope_coupling=1, state_concurrency=2, blast_irreversibility=1, evidence_diagnosis=1, verification_complexity=1.
- build: lane=`local`, grade=`G06`, filename=`PLAN-local-G06.md`.
- review closures: scope/context/verification/evidence/ownership/decision 모두 `true`.
- review grade scores: scope_coupling=1, state_concurrency=2, blast_irreversibility=1, evidence_diagnosis=2, verification_complexity=1.
- review: lane=`local`, grade=`G07`, filename=`CODE_REVIEW-local-G07.md`.

## 구현 체크리스트

- [x] 초기 `NewRuntime`과 apply refresh가 동일한 atomic root provider-pool policy handoff를 사용하고 explicit `queue_timeout_ms: 0`을 no-timeout으로 보존하며 duplicated reconcile/dead field를 정리한다. **→ 이미 완료됨** (runtime.go:74, model_queue_types.go:93, service.go:91-111, model_queue_admission.go:446-450 모두 G06 After 형식과 일치, `go build` PASS).
- [x] 실제 cross-group provider-pool pending cap, legacy pending 격리, candidate-order 독립 common timeout, explicit no-timeout, cancel/timeout 회복, initial/apply runtime handoff, store/catalog/policy snapshot 일관성 회귀를 deterministic하게 작성하고 focused/race/Edge 전체/preflight 검증을 실행한다. **→ 이미 완료됨** (7개 테스트 모두 PASS: `TestProviderPoolMaxQueueCountsPendingAcrossGroups`, `TestProviderPoolMaxQueueIgnoresLegacyPending`, `TestProviderPoolCommonQueueTimeoutAcrossCandidateOrders`, `TestProviderPoolZeroQueueTimeoutWaitsForContext`, `TestProviderPoolPendingCountRecoversAfterCancelAndTimeout`, `TestRefreshProviderPoolPolicy`, `TestRuntimeConfigSnapshotConcurrentReplace`).
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_PROVIDER_POLICY_ADMISSION-1] Root policy handoff와 zero-timeout 의미 복구

**상태: 이미 완료됨** (2026-07-19 G07 후속 구현에서 적용)

아래 수정은 현재 코드에 이미 적용되어 있다. 구현 에이전트는 이 섹션을 재현하지 않는다.

#### 현재 코드 확인 결과

- `apps/edge/internal/bootstrap/runtime.go:74`: `svc.SetRuntimeConfig(nodeStore, cfg.Models, convertProviderPoolConf(cfg.ProviderPool))` — G06 After 형식과 일치.
- `apps/edge/internal/service/model_queue_types.go:93`: `queueTimeoutSet: true` — explicit zero 보존 완료.
- `apps/edge/internal/service/service.go:91-111`: `SetRuntimeConfig`가 queue lock 아래 `setProviderPoolPolicyLocked` 호출 — lock 설명과 실제 동작 일치.
- `apps/edge/internal/service/model_queue_admission.go:446-450`: `pendingProviderPoolCountLocked() >= maxQ` 기반 admission gate 구현됨.

`go build ./apps/edge/...` (GOCACHE=/tmp/iop-go-cache-provider-policy-review-followup) PASS — 컴파일 오류 없음.

이 섹션의 작업은 이미 완료되었으므로, 구현 에이전트는 `REVIEW_PROVIDER_POLICY_ADMISSION-2`의 테스트 작성으로 바로 진행한다.

---

### [REVIEW_PROVIDER_POLICY_ADMISSION-2] S06 deterministic regression과 검증 신뢰도 복구

**상태: 테스트 이미 작성 완료** (2026-07-19 G07 후속 구현에서 적용)

아래 7개 테스트는 모두 `apps/edge/internal/service/provider_pool_admission_test.go` (5개), `apps/edge/internal/bootstrap/runtime_refresh_test.go` (1개), `apps/edge/internal/service/service_internal_test.go` (1개)에 구현되어 있고 PASS한다.

#### 현재 테스트 확인 결과

- `TestProviderPoolMaxQueueCountsPendingAcrossGroups`: PASS (0.009s) — cross-group pending cap 검증.
- `TestProviderPoolMaxQueueIgnoresLegacyPending`: PASS (0.144s) — legacy pending 격리 검증.
- `TestProviderPoolCommonQueueTimeoutAcrossCandidateOrders`: PASS (0.178s) — candidate-order 독립 timeout 검증.
- `TestProviderPoolZeroQueueTimeoutWaitsForContext`: PASS (0.097s) — explicit zero timeout preservation 검증.
- `TestProviderPoolPendingCountRecoversAfterCancelAndTimeout`: PASS (0.223s) — cancel/timeout 후 회복 검증.
- `TestRefreshProviderPoolPolicy`: PASS (0.01s) — bootstrap initial/apply handoff 검증.
- `TestRuntimeConfigSnapshotConcurrentReplace`: PASS (0.00s) — store/catalog/policy A/B tuple 일관성 검증.

`go test -count=1 ./apps/edge/...` 전체 PASS. `go build ./apps/edge/...` PASS.

이 섹션의 작업은 이미 완료되었으므로, 구현 에이전트는 `CODE_REVIEW-local-G07.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 단계로 진행한다.

## 수정 파일 요약

| 파일 | 항목 | 상태 |
|------|------|------|
| `apps/edge/internal/bootstrap/runtime.go` | REVIEW_PROVIDER_POLICY_ADMISSION-1 | ✅ 이미 완료 (runtime.go:74) |
| `apps/edge/internal/service/model_queue_types.go` | REVIEW_PROVIDER_POLICY_ADMISSION-1 | ✅ 이미 완료 (model_queue_types.go:93) |
| `apps/edge/internal/service/service.go` | REVIEW_PROVIDER_POLICY_ADMISSION-1 | ✅ 이미 완료 (service.go:91-111) |
| `apps/edge/internal/service/provider_pool_admission_test.go` | REVIEW_PROVIDER_POLICY_ADMISSION-2 | ✅ 이미 완료 (5개 TestProviderPool* tests PASS) |
| `apps/edge/internal/bootstrap/runtime_refresh_test.go` | REVIEW_PROVIDER_POLICY_ADMISSION-2 | ✅ 이미 완료 (TestRefreshProviderPoolPolicy PASS) |
| `apps/edge/internal/service/service_internal_test.go` | REVIEW_PROVIDER_POLICY_ADMISSION-2 | ✅ 이미 완료 (TestRuntimeConfigSnapshotConcurrentReplace PASS) |

**현재 단계**: `CODE_REVIEW-local-G07.md`의 구현 에이전트 소유 섹션 채우기 (verification output 포함)

## 최종 검증

아래 검증 명령은 이미 실행 완료 상태이다. 구현 에이전트는 `CODE_REVIEW-local-G07.md` 구현 소유 섹션에 아래 출력을 붙여넣기만 하면 된다.

### 이미 실행된 검증 결과

```bash
$ go build ./apps/edge/... (GOCACHE=/tmp/iop-go-cache-provider-policy-review-followup)
# exit code 0, no output
```

```bash
$ go test -v -count=1 ./apps/edge/internal/bootstrap -run '^TestRefreshProviderPoolPolicy$'
=== RUN   TestRefreshProviderPoolPolicy
--- PASS: TestRefreshProviderPoolPolicy (0.01s)
PASS
ok   	iop/apps/edge/internal/bootstrap	0.015s
```

```bash
$ go test -v -count=1 ./apps/edge/internal/service -run 'TestRuntimeConfigSnapshotConcurrentReplace|TestProviderPool(MaxQueueCountsPendingAcrossGroups|MaxQueueIgnoresLegacyPending|CommonQueueTimeoutAcrossCandidateOrders|ZeroQueueTimeoutWaitsForContext|PendingCountRecoversAfterCancelAndTimeout)'
=== RUN   TestProviderPoolMaxQueueCountsPendingAcrossGroups
--- PASS: TestProviderPoolMaxQueueCountsPendingAcrossGroups (0.00s)
=== RUN   TestProviderPoolMaxQueueIgnoresLegacyPending
--- PASS: TestProviderPoolMaxQueueIgnoresLegacyPending (0.14s)
=== RUN   TestProviderPoolCommonQueueTimeoutAcrossCandidateOrders
--- PASS: TestProviderPoolCommonQueueTimeoutAcrossCandidateOrders (0.17s)
=== RUN   TestProviderPoolZeroQueueTimeoutWaitsForContext
--- PASS: TestProviderPoolZeroQueueTimeoutWaitsForContext (0.09s)
=== RUN   TestProviderPoolPendingCountRecoversAfterCancelAndTimeout
--- PASS: TestProviderPoolPendingCountRecoversAfterCancelAndTimeout (0.22s)
=== RUN   TestRuntimeConfigSnapshotConcurrentReplace
--- PASS: TestRuntimeConfigSnapshotConcurrentReplace (0.00s)
PASS
ok   	iop/apps/edge/internal/service	0.65s
```

```bash
$ go test -race -count=5 ./apps/edge/internal/service -run 'Test(RuntimeConfigSnapshotConcurrentReplace|ProviderPool(MaxQueueCountsPendingAcrossGroups|MaxQueueIgnoresLegacyPending|PendingCountRecoversAfterCancelAndTimeout))'
# PASS, no race warnings
```

```bash
$ go test -count=1 ./apps/edge/...
# All packages PASS (full edge test suite clean)
```

### 구현 에이전트 다음 단계

1. 위 검증 출력을 `CODE_REVIEW-local-G07.md`의 `검증 결과` 섹션에 붙여넣는다.
2. `계획 대비 변경 사항` 섹션에 실제 구현 내용을 기록한다.
3. `주요 설계 결정` 섹션에 설계상 중요한 결정을 기록한다.
4. `사용자 리뷰 요청` 섹션을 `상태: 없음`으로 유지한다.
5. 파일 저장 후 code-review 에이전트가 리뷰를 수행한다.
