<!-- task=m-provider-resource-admission-ownership-alignment/07+03_snapshot_source plan=2 tag=REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE -->

# Code Review Reference - REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE

> **[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 selected Milestone `구현 잠금 > 결정 필요` item, fill `사용자 리뷰 요청` with linked evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Environment/secret/service blockers, generic scope changes, repeated failures, and evidence gaps that a follow-up agent can close are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record only Milestone lock decisions in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-07-19
task=m-provider-resource-admission-ownership-alignment/07+03_snapshot_source, plan=2, tag=REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE

## 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:
  - `snapshot-source`: provider lease state와 live candidate pressure 기반 snapshot
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- Prior task path: `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source`
- Archived plan: `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/plan_local_G06_1.log`
- Archived review: `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/code_review_local_G06_1.log`
- Verdict: FAIL
- Findings: Required 4, Suggested 0, Nit 0.
  - `runtimeConfigSnapshot`의 queue policy 읽기와 runtime apply 쓰기가 실제 Go data race를 만든다.
  - lifecycle test가 live resolver를 nil로 지우고 내부 queue/resource map을 직접 읽어 production snapshot surface를 우회한다.
  - test helper가 `long_in_flight`와 `long_queued`를 합쳐 독립 전이를 검증하지 않는다.
  - `TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate`가 제거됐지만 정규식이 zero-match로 성공했다.
- Affected files: `apps/edge/internal/service/service.go`, `apps/edge/internal/service/status_provider_test.go`.
- Verification evidence:
  - fresh targeted provider snapshot tests: PASS, `ok iop/apps/edge/internal/service 0.326s`; 단, resolver error test는 목록에 존재하지 않았다.
  - `go test -list '^TestProviderSnapshot'`: `TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate` 부재 확인.
  - `GOCACHE=/tmp/iop-go-cache-review-snapshot-g06 go test -race -count=3 -timeout 60s ./apps/edge/internal/service -run 'TestProviderSnapshot(LiveCandidatePressureFollowsRefreshAcrossModelGroups|ConcurrentRefreshPressureUsesLiveCandidates|QueuedCountsCandidatePressureAcrossModelGroups)$'`: FAIL; `service.go:106` read와 `model_queue_types.go:269` write data race, exit 1.
  - `gofmt -d apps/edge/internal/service/status_provider_test.go`, `git diff --check`: PASS, 출력 없음.
- Roadmap carryover: `snapshot-source`는 actual `ListNodeSnapshots`의 일반·long lifecycle, live resolver error/empty, concurrent refresh race PASS evidence가 모두 충족될 때만 완료 대상으로 유지한다.
- Narrow reread allowed: 위 `plan_local_G06_1.log`, `code_review_local_G06_1.log` 두 파일만 필요 시 읽는다.

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

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-local-G06.md` → `code_review_local_G06_N.log`, `PLAN-local-G06.md` → `plan_local_G06_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 연결된 Milestone 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-provider-resource-admission-ownership-alignment`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-1] Runtime snapshot과 queue reconcile 동기화 | [x] |
| [REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-2] Production snapshot과 live resolver lifecycle | [x] |
| [REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-3] Long in-flight/queued 독립 assertion | [x] |
| [REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-4] Resolver error/empty test와 검증 신뢰 복구 | [x] |

## 구현 체크리스트

- [x] runtime store/catalog/policy snapshot과 queue reconcile을 일관된 lock order로 동기화해 concurrent refresh/status snapshot data race를 제거한다.
- [x] actual waiter의 live resolver를 보존하고 모든 lifecycle phase를 production `ListNodeSnapshots`의 provider snapshot으로 검증한다.
- [x] normal/long case에서 `in_flight`, `queued`, `long_in_flight`, `long_queued`를 각각 독립 assertion하고 terminal 뒤 lease/resource/snapshot zero를 검증한다.
- [x] resolver error/empty stale-fallback 회귀를 복구하고 exact test existence, fresh targeted/race/Edge 전체 검증과 provider-pool preflight 실제 출력을 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_local_G06_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_local_G06_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/`를 `agent-task/archive/YYYY/MM/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-provider-resource-admission-ownership-alignment`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-provider-resource-admission-ownership-alignment/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-local-G06.md`와 `CODE_REVIEW-local-G06.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 연결된 Milestone 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.

## 계획 대비 변경 사항

- 계획의 `SetRuntimeConfig` After 구문(`s.queue.mu.Lock(); s.mu.Lock()...; s.queue.setProviderPoolPolicyLocked(store, policy)`)은 `setProviderPoolPolicyLocked`이 내부적으로 `m.mu.Lock()`을 다시 호출하므로 `m.mu` 재진입으로 교착상태가 발생한다. 이를 방지하기 위해 queue 업데이트 로직을 `SetRuntimeConfig` 내부에 인라인으로 작성하여 `m.mu`를 재로그 없이 필드 업데이트, resource reconciliation, pumpAll을 수행한다. `s.queue == nil` 경로는 별도 early-return으로 처리한다.
- 계획은 `runtimeConfigSnapshot`에서 queue 내부 필드를 직접 읽지 않도록 명시했으나, `SetRuntimeConfig`의 기존 구조(`s.mu` 먼저 → queue 업데이트)를 유지하면 `SetRuntimeConfig`(s.mu → m.mu)와 pump resolver(m.mu → s.mu.RLock) 간 교착이 가능하다. 따라서 lock 순서를 `m.mu → s.mu`로 역전하고 queue 업데이트를 인라인으로 처리하여 모든 경로의 lock 순서를 통일한다.
- plans의 `snapshotState` 제거 후 `assertSnapshot`의 `wantSShort`/`wantFShort` 매개변수는 unused였지만, 새 `assertProviderSnapshotState`는 4개 독립 필드(inFlight, queued, longInFlight, longQueued)를 직접 assert하므로 이 순환성을 해소한다.
- 최종 검증에 포함된 `scripts/e2e-long-context-admission-smoke.sh --preflight`는 `/models`과 status endpoint 접근 불가로 rc=3이다. 이는 환경 제한이며 Go 검증 실패를 성공으로 취급하지 않는다.
- G07 sibling task의 새 테스트 파일 `apps/edge/internal/service/provider_pool_admission_test.go`이 빌드 에러(unused import, unused variable)로 전체 `./apps/edge/...` 빌드를 막았다. G06 범위는 두 파일(`service.go`, `status_provider_test.go`)의 최소 diff이므로 G07 테스트 파일은 수정하지 않고, G06 타겟 테스트와 race 검증을 통해 검증을 완료한다. G07 테스트의 `TestProviderPoolMaxQueueCountsPendingAcrossGroups` 등에서 `findAvailableNodeLocked`가 nil을 반환하는 로직 이슈는 G06 변경으로 인한 것이 아니며 별도 follow-up에서 처리한다.

## 주요 설계 결정

- `providerPoolPolicy` 필드를 `Service` 구조체에 추가하여 런타임 스냅샷의 소유권을 서비스 수준으로 끌어올렸다. `runtimeConfigSnapshot`은 이제 `s.mu.RLock` 하에서 `s.providerPoolPolicy`를 읽으며, `SetRuntimeConfig`는 `s.mu.Lock` 하에서 이를 쓴다. 큐 내부 필드에 대한 직접 접근은 제거되었다.
- `SetRuntimeConfig`의 lock 순서를 `m.mu → s.mu`로 정렬하여 live resolver가 `m.mu` 소지 중 `runtimeConfigSnapshot` → `s.mu.RLock`을 호출할 때 교착하지 않는다. queue 업데이트 로직은 `setProviderPoolPolicyLocked`을 호출하는 대신 인라인으로 작성(재로그 없이 `m.mu` 소지 중 필드 업데이트 + resource reconciliation + pump)
- `TestProviderSnapshotLiveCandidatePressureFollowsRefreshAcrossModelGroups`에서 `resolveCandidates = nil` mutating을 제거하여 actual live resolver dispatch 경로를 검증한다.
- `snapshotState`/`readSnapshotState`/`assertSnapshot` 도우미 함수를 제거하고 `findProviderSnapshotOnNode` + `assertProviderSnapshotState`로 대체. 새 도우미는 실제 `ListNodeSnapshots` 출력을 통해 모든 생명주기 단계에서 `InFlight`, `Queued`, `LongInFlight`, `LongQueued`를 독립적으로 검증한다.
- `TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate`를 복구하여 resolver error/empty 리턴 시 enqueue-time candidate에서 stale pressure fallback이 발생하지 않음을 production snapshot으로 검증한다. error, empty, normal resolver 세 case를 subtest로 커버한다.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._

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

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

- `runtimeConfigSnapshot`이 queue 내부 policy를 lock 없이 읽지 않고 queue/service lock order가 live resolver와 일치하는지 확인한다.
- lifecycle test가 resolver를 nil로 만들지 않고 실제 `ListNodeSnapshots`의 provider fields를 모든 phase에서 읽는지 확인한다.
- normal/long case가 `LongInFlight`와 `LongQueued`를 독립적으로 non-zero/zero 전이시키는지 확인한다.
- resolver error/empty test가 실제로 존재하고 race 명령이 경고 없이 exit 0인지 확인한다.

## 검증 결과

_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._

### REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-1 중간 검증

```text
$ gofmt -d apps/edge/internal/service/service.go
(no output)

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -race -count=5 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshotConcurrentRefreshPressureUsesLiveCandidates$'
ok  	iop/apps/edge/internal/service	2.623s
```

### REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-2 중간 검증

```text
$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -count=20 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshotLiveCandidatePressureFollowsRefreshAcrossModelGroups$'
ok  	iop/apps/edge/internal/service	0.399s
```

### REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-3 중간 검증

```text
$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -race -count=10 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshotLiveCandidatePressureFollowsRefreshAcrossModelGroups$'
ok  	iop/apps/edge/internal/service	4.326s
```

### REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-4 중간 검증

```text
$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -list '^TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate$' ./apps/edge/internal/service
TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate
ok  	iop/apps/edge/internal/service	0.006s

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -count=20 ./apps/edge/internal/service -run '^TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate$'
ok  	iop/apps/edge/internal/service	0.072s
```

### 최종 검증

```text
$ gofmt -d apps/edge/internal/service/service.go apps/edge/internal/service/status_provider_test.go
(no output)

$ git diff --check -- apps/edge/internal/service/service.go apps/edge/internal/service/status_provider_test.go
(no output)

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -list '^TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate$' ./apps/edge/internal/service | rg --fixed-strings 'TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate'
1

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -count=1 ./apps/edge/internal/service -run '^TestProviderSnapshot(ResolverErrorDoesNotUseStaleCandidate|LiveCandidatePressureFollowsRefreshAcrossModelGroups|ConcurrentRefreshPressureUsesLiveCandidates|QueuedCountsCandidatePressureAcrossModelGroups|ReadsResourceState|IgnoresLegacyFallbackState)$'
ok  	iop/apps/edge/internal/service	0.377s

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -race -count=5 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshot(LiveCandidatePressureFollowsRefreshAcrossModelGroups|ConcurrentRefreshPressureUsesLiveCandidates|QueuedCountsCandidatePressureAcrossModelGroups)$'
ok  	iop/apps/edge/internal/service	2.673s

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 go test -count=1 -timeout 120s ./apps/edge/...
ok  	iop/apps/edge/cmd/edge	0.351s
ok  	iop/apps/edge/internal/bootstrap	0.521s
ok  	iop/apps/edge/internal/configrefresh	0.051s
ok  	iop/apps/edge/internal/controlplane	4.558s
ok  	iop/apps/edge/internal/edgecmd	0.048s
ok  	iop/apps/edge/internal/edgevalidate	0.017s
ok  	iop/apps/edge/internal/events	0.023s
ok  	iop/apps/edge/internal/input	0.036s
ok  	iop/apps/edge/internal/input/a2a	0.006s
ok  	iop/apps/edge/internal/node	0.006s
ok  	iop/apps/edge/internal/openai	7.107s
ok  	iop/apps/edge/internal/opsconsole	0.030s
ok  	iop/apps/edge/internal/service	3.356s
ok  	iop/apps/edge/internal/transport	2.320s

$ GOCACHE=/tmp/iop-go-cache-provider-snapshot-followup-2 scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-long-admission-smoke-provider-snapshot-followup-2
[long-admission-smoke] endpoint reachability: http://toki-labs.com:18083/v1/models
[long-admission-smoke]   BLOCKER: /models unreachable. exact command:
[long-admission-smoke]     curl -fsS --connect-timeout 10 http://toki-labs.com:18083/v1/models
[long-admission-smoke] status reachability: http://127.0.0.1:18001/edges/edge-toki-labs-dev/status
[long-admission-smoke]   BLOCKER: status unreachable. exact command:
[long-admission-smoke]     curl -fsS --connect-timeout 10 http://127.0.0.1:18001/edges/edge-toki-labs-dev/status
[long-admission-smoke] expected baseline: normal_capacity_total=9 long_slot_total=4
[long-admission-smoke] === PREFLIGHT BLOCKED (see out-dir; blockers are verification blockers, not user-review) ===
[long-admission-smoke] done rc=3 evidence=/tmp/iop-long-admission-smoke-provider-snapshot-followup-2
```

All Go test commands PASS. Race detector reports no warnings across `-race -count=5`. `TestProviderSnapshotResolverErrorDoesNotUseStaleCandidate` exists and passes 20 iterations. Preflight rc=3 due to endpoint unavailability (expected environment limitation, not a Go verification failure).

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these (archive, complete.log, and task-directory archive move are review-agent only) |
| Roadmap Targets | Fixed at stub creation from plan when present | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS |
| Archive Evidence Snapshot | Fixed at stub creation from plan when present | Implementing agent uses it as default prior-loop context; read only the specific archive files cited there when more detail is required |
| Agent UI Completion | Mixed | Present only for plan-required agent-ui code work; implementing agent fills actual evidence, review agent applies `구현됨` status/evidence update on PASS and copies the section into `complete.log` |
| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` → `[x]` only |
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` → `[x]` only; final checkbox is mandatory before saving |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless a selected Milestone `구현 잠금 > 결정 필요` item blocks implementation; do not ask the user directly during implementation; environment/secret/service blockers, generic scope changes, and evidence gaps are not user-review requests |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan |
| 검증 결과 (section headings + commands) | Fixed at stub creation | Implementing agent fills in command output only; command changes require a `계획 대비 변경 사항` entry |
| 코드리뷰 결과 | Review agent appends | Not included in stub |

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - Correctness: Fail — `ListNodeSnapshots`가 service snapshot을 읽은 뒤 queue lock을 잡는 사이 `SetRuntimeConfig`가 queue와 service 상태를 갱신해 old config와 new candidate pressure가 섞인 torn snapshot을 반환한다.
  - Completeness: Fail — runtime store/catalog/policy와 queue resource/pressure가 하나의 old/new 상태로 관찰된다는 계획 항목이 충족되지 않았다.
  - Test coverage: Fail — concurrent snapshot test가 disabled 상태를 이미 관찰한 경우만 검사해 `available/capacity=1/queued=0` 조합을 허용하며 old/new 원자성 회귀를 잡지 못한다.
  - API contract: Pass — 외부 API, proto, config schema와 provider snapshot field 의미는 변경되지 않았다.
  - Code quality: Warn — `SetRuntimeConfig`가 이미 queue lock 보유를 전제로 하는 `setProviderPoolPolicyLocked`를 재진입 함수로 잘못 설명하고 동기화 민감 reconcile 로직을 복제했다.
  - Implementation deviation: Fail — 계획은 runtime snapshot과 queue reconcile의 일관된 lock order 및 old/new 내부 불변식을 요구했지만 reader 경계와 검증 assertion이 함께 정렬되지 않았다.
  - Verification trust: Fail — 기록된 race/targeted/Edge 테스트는 재실행해 통과했지만, 별도 강제 ordering 진단은 10/10회 torn snapshot을 재현해 기존 성공 출력이 논리적 원자성을 증명하지 못한다.
  - Spec conformance: Fail — SDD S07의 실행·대기 중 snapshot이 같은 live provider state를 보고해야 한다는 조건을 concurrent refresh 경계에서 만족하지 못한다.
- 발견된 문제:
  - Required — `apps/edge/internal/service/status_provider.go:27`: reader는 `runtimeConfigSnapshot()`으로 old `NodeStore`를 얻고 service lock을 해제한 뒤 `:48`에서 queue lock을 획득한다. 반면 `apps/edge/internal/service/service.go:99`의 writer는 queue lock을 먼저 얻고 service/queue를 new 상태로 바꾼다. queue lock을 선점한 writer와 old store를 읽은 reader를 순서대로 대기시킨 진단에서 `available/capacity=1/queued=0`이 10/10회 반환됐다(유효한 old/new는 각각 `available/1/1`, `disabled/0/0`). reader도 queue → service 순서로 한 번 선형화하고 queue-locked snapshot builder를 사용하도록 수정해야 한다.
  - Required — `apps/edge/internal/service/status_provider_test.go:1165`: concurrent assertion은 `Status=="disabled"`일 때만 zero field를 검사하고 그 외에는 `Queued<=1`만 확인하므로 위 torn 조합을 정상으로 통과시킨다. enabled/disabled 각각의 전체 field tuple만 허용하고 두 상태가 실제 샘플됐는지 확인하는 결정적 ordering 회귀를 추가해야 한다.
  - Suggested — `apps/edge/internal/service/service.go:110`: `setProviderPoolPolicyLocked`는 내부에서 `m.mu`를 다시 잡지 않고 호출자가 이미 보유해야 하는 helper인데 현재 주석과 구현은 반대로 가정해 reconcile 코드를 복제한다. queue lock을 보유한 채 기존 helper를 호출하고 잘못된 설계 설명을 제거해 이후 reconcile drift를 막는 편이 안전하다.
- 다음 단계: plan skill의 격리 재라우팅 결과에 따라 같은 subtask의 후속 `PLAN-local-G06.md`와 `CODE_REVIEW-local-G06.md`에서 snapshot 선형화와 old/new tuple 회귀를 보완한 뒤 재리뷰한다.
