<!-- task=m-provider-resource-admission-ownership-alignment/06+05_refresh_consistency plan=1 tag=REVIEW_PROVIDER_POLICY_REFRESH -->

# Provider Resource/Policy Live Refresh 리뷰 보완 계획

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

구현과 검증을 완료한 뒤 `CODE_REVIEW-local-G08.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은 사용자 리뷰 요청이 아니다.

## 배경

G07 구현은 provider-pool timeout refresh의 상태를 추가했지만 실제 `SetRuntimeConfig` 경로에서 pending deadline을 rebase하지 않고, synthetic test helper가 그 누락을 가렸다. timeout disabled 상태의 재활성화와 legacy queue 격리도 보장되지 않으며, SDD S08이 요구한 실제 lease 기반 resource refresh·atomic apply·concurrent invariant 증거가 빠져 있다. 이번 후속은 G07의 Required 6건을 하나의 queue lifecycle 경계에서 최소 수정하고 fresh/race evidence로 닫는다.

## 사용자 리뷰 요청 흐름

선택된 Milestone lock 결정만 active `CODE_REVIEW-local-G08.md`의 `사용자 리뷰 요청` 템플릿에 기록한다. 구현 중 직접 사용자 prompt는 금지하며 code-review가 검증과 실제 `USER_REVIEW.md` 작성을 소유한다.

## 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:
  - `refresh-consistency`: provider resource와 공통 queue policy live refresh 정합성
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- 이전 active task path: `agent-task/m-provider-resource-admission-ownership-alignment/06+05_refresh_consistency/`
- 이전 계획 증거: `agent-task/m-provider-resource-admission-ownership-alignment/06+05_refresh_consistency/plan_local_G07_0.log`
- 이전 리뷰 증거: `agent-task/m-provider-resource-admission-ownership-alignment/06+05_refresh_consistency/code_review_local_G07_0.log`
- 이전 판정: `FAIL` — Required 6, Suggested 0, Nit 1
- 영향 파일:
  - `apps/edge/internal/service/model_queue_types.go`
  - `apps/edge/internal/service/model_queue_admission.go`
  - `apps/edge/internal/service/provider_scheduling_test.go`
  - `apps/edge/internal/service/service_internal_test.go`
  - `apps/edge/internal/service/model_queue_admission_test.go`
  - `apps/edge/internal/bootstrap/runtime_refresh_test.go`
- 실제 재검증 증거:
  - fresh service suite에서 `TestProviderPoolPolicyRefreshExtendsExistingWaiterTimeout`이 원래 deadline timeout으로 실패했다.
  - focused `-race -count=5`에서 `TestProviderPoolPolicyRefreshExtensionIgnoresStaleTimer`가 원래 timeout으로 실패했다.
  - 계획된 resource refresh 및 bootstrap atomic test 패턴은 각각 `[no tests to run]`이었다.
  - long-context admission smoke preflight는 config check PASS 후 외부 `/models`와 local Control Plane status 연결 실패로 rc=3이었고 mixed scenario는 실행하지 않았다. 증거 디렉터리: `/tmp/iop-long-admission-smoke-provider-policy-refresh-review`.
- Roadmap carryover: Task `refresh-consistency`, SDD Acceptance Scenario S08.

## 분석 결과

### 읽은 파일

- 규칙/라우팅: `AGENTS.md`, `agent-ops/rules/project/rules.md`, `agent-ops/rules/project/domain/edge/rules.md`, `agent-ops/rules/project/domain/testing/rules.md`, `agent-ops/rules/common/rules-roadmap.md`, `agent-ops/rules/common/rules-agent-spec.md`, `agent-ops/skills/common/router.md`, `agent-ops/skills/common/plan/SKILL.md`, `agent-ops/skills/common/finalize-task-routing/SKILL.md`, `agent-ops/skills/common/code-review/SKILL.md`
- 로드맵/SDD: `agent-roadmap/current.md`, 활성 Phase/Milestone, 승인된 `agent-roadmap/sdd/operational-observability-provider-management/provider-resource-admission-ownership-alignment/SDD.md`
- 계약/스펙: `agent-contract/index.md`, `agent-contract/inner/edge-config-runtime-refresh.md`, `agent-spec/index.md`, `agent-spec/runtime/provider-pool-config-refresh.md`
- service 소스: `apps/edge/internal/service/model_queue_types.go`, `model_queue_admission.go`, `model_queue_release.go`, `provider_resolution.go`, `provider_pool.go`, `service.go`
- 테스트: `model_queue_test_support_test.go`, `provider_scheduling_test.go`, `provider_scheduling_advanced_test.go`, `service_internal_test.go`, `model_queue_admission_test.go`, `long_context_queue_test.go`, `status_provider_test.go`, `apps/edge/internal/bootstrap/runtime_refresh_test.go`, `runtime_refresh_node_test.go`, `runtime_test_support_test.go`
- 테스트 규칙/프로필: `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md`

### SDD 기준

- SDD 상태는 `[승인됨]`이고 구현 잠금은 해제돼 있으며 별도 사용자 결정 항목이 없다.
- Acceptance Scenario S08과 Evidence Map 첫 행은 진행 중 lease와 pending item이 있는 상태에서 capacity shrink/raise 및 disable/re-enable 후 기존 요청 보존, over-capacity 신규 차단, 모든 waiter의 새 후보/capacity 재평가를 요구한다.
- Milestone Task `refresh-consistency`는 long capacity, priority, common queue policy와 atomic runtime refresh까지 포함하므로 아래 구현 체크리스트와 최종 검증을 해당 evidence에서 직접 도출했다.

### 테스트 환경 규칙과 현재 증거

- `test_env=local`; fresh service/bootstrap/edge tests와 Go race detector를 사용한다.
- 현재 환경: `/config/workspace/iop`, branch `main`, HEAD `2f560e3f3b6cca07d5744efcacda77109b4bf4ff`, Linux arm64, Go 1.26.2. 기존 dirty worktree와 관계없는 untracked `service.test`는 보존한다.
- 현재 preflight:

```bash
GOCACHE=/tmp/iop-go-cache-provider-policy-refresh-review scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-long-admission-smoke-provider-policy-refresh-review
```

- 결과는 rc=3이다. config check는 PASS했지만 외부 `/models`와 local Control Plane status가 연결되지 않았으므로 mixed scenario는 실행하지 않았다.

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

- `service_internal_test.go`의 inflight preservation test는 counter를 직접 주입하므로 실제 lease를 만들고 shrink 중 신규 lease를 차단했다가 release/raise 후 회복하는 흐름을 증명하지 않는다.
- `model_queue_admission_test.go`의 store refresh test는 manager `setStore`, capacity 3↔4, `providerPool=false`만 사용해 provider-pool policy와 resource를 한 atomic runtime snapshot으로 갱신하지 않는다.
- `runtime_refresh_test.go`는 policy field 관찰만 하며 진행 중 lease와 pending admission의 atomic convergence를 검증하지 않는다.
- 실제 lease 기반 capacity/long shrink-recovery, queued priority 변경, disable/re-enable 전체 waiter 재평가, atomic runtime apply, concurrent provider-policy refresh와 final-zero assertion이 없다.

### 심볼 참조

- 외부 rename/remove는 없다.
- 실제 call path는 `Service.SetRuntimeConfig` → `setProviderPoolPolicyLocked`이며, store/policy 교체와 pending deadline rebase 및 pump의 lock 순서가 핵심 변경 경계다.
- pending wait path는 `admitWithReason` → `waitForAdmission`, manager pump expiry, release/cancel removal이 같은 item membership와 current deadline을 공유한다.
- 기존 lease API, reservation/release ownership과 manager lock 순서는 유지한다.

### 분할 판단

- 기존 split source of truth인 `06+05_refresh_consistency`를 유지한다. timeout state machine, resource refresh, atomic apply와 race는 동일 queue item/lease lifecycle invariant라 새 sibling으로 나누지 않는다.
- 직접 predecessor 05는 `agent-task/archive/2026/07/m-provider-resource-admission-ownership-alignment/05+03,04_provider_pool_policy_admission/complete.log`의 PASS로 충족됐다.

### 범위 결정

- config/proto/contract/spec 의미 변경은 하지 않는다. 관련 문서 동기화는 기존 `contract-spec-sync` 후속 범위다.
- connectivity/offline terminal, snapshot source, backend capacity smoke는 별도 task 범위이며 여기서 확장하지 않는다.
- max queue shrink는 기존 waiter를 제거하지 않고 신규 enqueue만 새 상한으로 제한한다.
- timeout refresh는 원래 `enqueuedAt` 기준으로 재계산하며 legacy non-provider-pool queue에는 root provider-pool policy를 적용하지 않는다.

### 최종 라우팅

- isolated reassessment 입력에는 이전 grade/lane을 제공하지 않았다.
- build closure: atomic implementation unit=true, prerequisite closure=true, implementation evidence complete=true, test evidence complete=true, no unresolved blocker=true.
- review closure: atomic implementation unit=true, prerequisite closure=true, implementation evidence complete=true, test evidence complete=true, no unresolved blocker=true.
- build/review 점수: risk=1, breadth=2, test depth=1, concurrency/async=2, integration=2.
- 결과: build `local-G08` → `PLAN-local-G08.md`, review `local-G08` → `CODE_REVIEW-local-G08.md`.

## 구현 체크리스트

- [ ] production policy setter에서 provider-pool pending만 enqueue 기준 deadline으로 rebase하고 pump하며, enqueue 당시 timeout 0과 이후 disable/re-enable를 모두 처리하는 단일 timer state machine을 구현한다.
- [ ] synthetic refresh와 fixed sleep을 제거하고 production refresh 경로·명시적 queue-entry barrier로 timeout shorten/extend/disable/re-enable/stale-timer/max-queue shrink/legacy 격리를 검증한다.
- [ ] 실제 lease 기반 capacity/long shrink-recovery, queued priority/enabled 재평가와 bootstrap atomic runtime apply를 deterministic tests로 고정한다.
- [ ] concurrent `SetRuntimeConfig`/admission/release/cancel race에서 duplicate lease, over-capacity 증가 금지, peak와 final pending/resource/lease zero 불변식을 검증하고 fresh/race/preflight 명령을 수행한다.
- [ ] `CODE_REVIEW-local-G08.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_PROVIDER_POLICY_REFRESH-1] Production deadline refresh와 timer state machine

#### 문제

`apps/edge/internal/service/model_queue_types.go:272`의 production setter는 새 policy를 저장하고 pump하지만 pending deadline을 rebase하지 않는다. `model_queue_types.go:341`의 helper는 provider-pool 여부를 확인하지 않아 legacy item을 오염시킬 수 있다. `model_queue_admission.go:497-548`, `558-638`은 초기 timeout 0 경로와 refresh로 0이 된 경로가 policy-change 관찰에서 이탈하고, stale timer가 zero deadline을 만료로 오인할 수 있다.

#### 해결 방법

`setProviderPoolPolicyLocked`가 manager lock 안에서 policy 저장, provider-pool pending deadline rebase, pump 순으로 한 번만 수행하게 한다. rebase helper는 `item.providerPool`과 유효한 enqueue timestamp를 확인하며 한 `now` snapshot을 사용한다.

waiter는 dispatch, context cancellation, timer channel, policy-change channel을 단일 loop에서 처리한다. timer는 판정 권한이 아니라 재확인 신호이며, manager lock 아래 현재 membership와 deadline을 읽어 non-zero current deadline이 실제 만료된 경우에만 timeout 처리한다. timeout 0은 `timerC=nil`로 두되 policy-change channel은 계속 관찰하고, 0→양수 전환 때 안전하게 timer를 생성/재설정한다.

Before:

```go
m.providerPoolPolicy = policy
m.pumpAllLocked()
```

After:

```go
m.providerPoolPolicy = policy
m.refreshProviderPoolPendingDeadlinesLocked(now)
m.pumpAllLocked()
```

Before:

```go
if timeout <= 0 {
	return waitWithoutPolicyRefresh(ctx, item)
}
```

After:

```go
for {
	timerC = timerChannelForCurrentDeadline(timer, item)
	select {
	case result := <-item.waitCh:
		return result
	case <-ctx.Done():
		return m.cancelQueuedItem(ctx, item)
	case <-timerC:
		// lock, re-read membership/deadline, expire only a non-zero elapsed deadline
	case <-item.policyChange:
		// lock, re-read current deadline, disable/rearm timer and continue
	}
}
```

#### 수정 파일 및 체크리스트

- [ ] `apps/edge/internal/service/model_queue_types.go`: production setter의 provider-pool-only deadline rebase와 pump ordering을 수정한다.
- [ ] `apps/edge/internal/service/model_queue_admission.go`: 초기 zero와 이후 disable/re-enable를 포함하는 단일 timer state machine을 구현한다.
- [ ] `apps/edge/internal/service/provider_scheduling_test.go`: synthetic helper, fixed sleep, unused `buildQueuedWaiter`와 중복 주석을 제거하고 production-path regressions를 작성한다.

#### 테스트 작성

- `TestProviderPoolPolicyRefreshShortensExistingWaiterTimeout`
- `TestProviderPoolPolicyRefreshExtendsExistingWaiterTimeout`
- `TestProviderPoolPolicyRefreshDisablesExistingWaiterTimeout`
- `TestProviderPoolPolicyRefreshReenablesExistingWaiterTimeout`
- `TestProviderPoolPolicyRefreshExtensionIgnoresStaleTimer`
- `TestProviderPoolMaxQueueShrinkPreservesExistingWaiters`
- `TestProviderPoolPolicyRefreshDoesNotChangeLegacyWaiter`
- 실제 `SetRuntimeConfig` 또는 production setter를 사용하고 `waitForQueueLen` 같은 명시적 barrier로 enqueue를 확인한다. queue 진입 동기화에 `time.Sleep`을 쓰지 않는다.

#### 중간 검증

```bash
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/service -run 'TestProviderPool(PolicyRefreshShortensExistingWaiterTimeout|PolicyRefreshExtendsExistingWaiterTimeout|PolicyRefreshDisablesExistingWaiterTimeout|PolicyRefreshReenablesExistingWaiterTimeout|PolicyRefreshExtensionIgnoresStaleTimer|MaxQueueShrinkPreservesExistingWaiters|PolicyRefreshDoesNotChangeLegacyWaiter)$'
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -race -count=5 ./apps/edge/internal/service -run 'TestProviderPoolPolicyRefresh'
```

기대 결과: production refresh 경로에서 모든 transition과 stale-timer 경계가 PASS하고 legacy deadline이 변하지 않으며 data race가 없다.

### [REVIEW_PROVIDER_POLICY_REFRESH-2] Actual lease resource refresh와 runtime atomicity

#### 문제

`apps/edge/internal/service/service_internal_test.go:267`은 resource counter를 직접 주입한다. `model_queue_admission_test.go:883`은 provider-pool이 아닌 manager store만 3↔4로 바꾸며, `apps/edge/internal/bootstrap/runtime_refresh_test.go:526`은 policy field만 관찰한다. 따라서 실제 lease가 capacity/long shrink 뒤 보존되는지, over-capacity 동안 신규 admission이 막히는지, priority/enabled와 root policy가 한 runtime apply로 pending waiter에 수렴하는지 증거가 없다.

#### 해결 방법

서비스 admission으로 normal/long 실제 lease를 만든 뒤 runtime config의 capacity를 in-flight 아래로 낮춘다. 기존 lease/counter가 유지되고 추가 lease가 증가하지 않는 것을 확인한 다음 release 또는 capacity raise로 waiter가 진행하는지 검증한다. 두 provider의 priority를 뒤집고 enabled 상태를 전환해 이미 queued인 request가 current candidate universe와 새 selection policy로 재평가되는지 확인한다.

bootstrap test는 하나의 config refresh가 provider attributes와 root provider-pool queue policy를 같은 snapshot으로 적용하되 기존 lease를 보존하는지를 서비스의 관찰 가능한 결과로 검증한다. direct counter injection은 setup 증거로 사용하지 않는다.

Before:

```go
res.inFlight = 3
svc.SetRuntimeConfig(shrinkStore, catalog)
```

After:

```go
leases := admitActualProviderPoolLeases(svc)
svc.SetRuntimeConfig(shrinkStore, catalog)
assertExistingLeasesPreserved()
assertNoAdditionalLeaseWhileOverCapacity()
releaseAndAssertQueuedAdmissionRecovers(leases)
```

#### 수정 파일 및 체크리스트

- [ ] `apps/edge/internal/service/service_internal_test.go`: actual lease 기반 capacity/long shrink-recovery와 priority/enabled waiter 재평가를 검증한다.
- [ ] `apps/edge/internal/bootstrap/runtime_refresh_test.go`: lease 보존과 provider attributes/root policy atomic apply integration test를 추가한다.
- [ ] `apps/edge/internal/service/model_queue_admission_test.go`: 필요한 queue invariant helper/assertion만 추가하며 production behavior를 우회하지 않는다.

#### 테스트 작성

- `TestRefreshCapacityShrinkPreservesLeaseAndBlocksUntilRecovery`
- `TestRefreshLongCapacityShrinkPreservesLeaseAndBlocksLongAdmission`
- `TestRefreshPriorityChangesQueuedProviderSelection`
- `TestRefreshDisableReenableReevaluatesAllWaiters`
- `TestRefreshRuntimeSnapshotPreservesLeaseAndAppliesPolicyAtomically`

#### 중간 검증

```bash
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/service -run 'TestRefresh(CapacityShrinkPreservesLeaseAndBlocksUntilRecovery|LongCapacityShrinkPreservesLeaseAndBlocksLongAdmission|PriorityChangesQueuedProviderSelection|DisableReenableReevaluatesAllWaiters)$'
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/bootstrap -run 'TestRefreshRuntimeSnapshotPreservesLeaseAndAppliesPolicyAtomically$'
```

기대 결과: `[no tests to run]`이 아니며 shrink 중 기존 lease 보존/신규 증가 금지, release/raise/re-enable/priority 변경 후 즉시 회복한다.

### [REVIEW_PROVIDER_POLICY_REFRESH-3] Concurrent refresh/race evidence

#### 문제

기존 race test는 production `SetRuntimeConfig`의 provider resource와 root policy atomic swap을 실제 provider-pool admission/release/cancel과 함께 반복하지 않아 G07 defect를 검출하지 못했다. duplicate lease, refresh 이후 over-capacity 증가 금지, peak와 final-zero를 동시에 고정한 evidence가 없다.

#### 해결 방법

`TestRefreshConcurrentAdmissionReleasePreservesProviderPolicyInvariants`를 추가한다. 두 개의 유효 runtime config를 반복 `SetRuntimeConfig`하며 capacity/long capacity shrink/raise, priority, enabled와 queue timeout/max queue를 바꾸고, actual `providerPool=true` normal/long admission·release·cancel goroutine을 barrier로 동시에 시작한다.

각 lease identity를 추적해 중복 release/ownership을 막고, shrink로 이미 over-capacity인 값은 보존하되 refresh 이후 새 lease가 counter를 더 올리지 않는지 검사한다. config별 허용 의미에 맞춰 peak를 기록하며 종료 후 pending queue, normal/long resource counter와 live lease가 모두 0인지 확인한다. queue 진입 동기화에는 fixed sleep을 쓰지 않고 bounded context만 실패 상한으로 사용한다.

#### 수정 파일 및 체크리스트

- [ ] `apps/edge/internal/service/model_queue_admission_test.go` 또는 `service_internal_test.go`: production-path concurrent refresh invariant test를 추가한다.
- [ ] G07에서 추가된 unused helper와 중복 주석을 제거한다.

#### 테스트 작성

- `TestRefreshConcurrentAdmissionReleasePreservesProviderPolicyInvariants`
- deterministic start/queue barrier와 실제 lease identity/counter assertions를 사용한다.

#### 중간 검증

```bash
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -race -count=5 ./apps/edge/internal/service -run 'TestRefreshConcurrentAdmissionReleasePreservesProviderPolicyInvariants|TestProviderPoolPolicyRefresh'
```

기대 결과: data race, duplicate lease와 shrink 이후 추가 over-admission이 없고 매 iteration final counters가 0이다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/edge/internal/service/model_queue_types.go` | REVIEW_PROVIDER_POLICY_REFRESH-1 |
| `apps/edge/internal/service/model_queue_admission.go` | REVIEW_PROVIDER_POLICY_REFRESH-1 |
| `apps/edge/internal/service/provider_scheduling_test.go` | REVIEW_PROVIDER_POLICY_REFRESH-1, REVIEW_PROVIDER_POLICY_REFRESH-3 |
| `apps/edge/internal/service/service_internal_test.go` | REVIEW_PROVIDER_POLICY_REFRESH-2, REVIEW_PROVIDER_POLICY_REFRESH-3 |
| `apps/edge/internal/service/model_queue_admission_test.go` | REVIEW_PROVIDER_POLICY_REFRESH-2, REVIEW_PROVIDER_POLICY_REFRESH-3 |
| `apps/edge/internal/bootstrap/runtime_refresh_test.go` | REVIEW_PROVIDER_POLICY_REFRESH-2 |

## 최종 검증

```bash
gofmt -d apps/edge/internal/service/model_queue_types.go apps/edge/internal/service/model_queue_admission.go apps/edge/internal/service/provider_scheduling_test.go apps/edge/internal/service/service_internal_test.go apps/edge/internal/service/model_queue_admission_test.go apps/edge/internal/bootstrap/runtime_refresh_test.go
git diff --check
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/service -run 'TestProviderPool(PolicyRefreshShortensExistingWaiterTimeout|PolicyRefreshExtendsExistingWaiterTimeout|PolicyRefreshDisablesExistingWaiterTimeout|PolicyRefreshReenablesExistingWaiterTimeout|PolicyRefreshExtensionIgnoresStaleTimer|MaxQueueShrinkPreservesExistingWaiters|PolicyRefreshDoesNotChangeLegacyWaiter)$'
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/service -run 'TestRefresh(CapacityShrinkPreservesLeaseAndBlocksUntilRecovery|LongCapacityShrinkPreservesLeaseAndBlocksLongAdmission|PriorityChangesQueuedProviderSelection|DisableReenableReevaluatesAllWaiters)$'
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/bootstrap -run 'TestRefreshRuntimeSnapshotPreservesLeaseAndAppliesPolicyAtomically$'
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -race -count=5 ./apps/edge/internal/service -run 'TestRefreshConcurrentAdmissionReleasePreservesProviderPolicyInvariants|TestProviderPoolPolicyRefresh'
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/internal/service ./apps/edge/internal/bootstrap
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh go test -count=1 ./apps/edge/...
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-long-admission-smoke-review-provider-policy-refresh
```

preflight가 OK일 때만 다음 명령을 실행한다.

```bash
GOCACHE=/tmp/iop-go-cache-review-provider-policy-refresh scripts/e2e-long-context-admission-smoke.sh --preflight --scenario mixed --out-dir /tmp/iop-long-admission-smoke-review-provider-policy-refresh-mixed
```

preflight rc=3이면 mixed scenario를 실행하지 않고 exact stdout/stderr와 out-dir를 `CODE_REVIEW-local-G08.md`에 기록한다. 모든 Go test는 fresh run이어야 하며 `[no tests to run]`을 PASS로 취급하지 않는다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-local-G08.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운다. 이 파일 작성이 구현의 마지막 단계다.
