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

# Provider Snapshot Public Reader 동시성 Barrier 증거 보완 계획

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

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

## 배경

현재 forced-order 테스트는 public reader를 호출하지만 reader가 끝난 뒤 writer를 시작해 실제 queue/service lock 경합을 만들지 않는다. 따라서 `ListNodeSnapshots()`의 queue lock이 제거되어도 old 조회, config apply, new 조회의 순차 흐름으로 통과한다. production 코드는 유지하고 public reader의 queue lock 획득을 증명하는 service-lock barrier와 bounded cleanup만 보완한다.

## 사용자 리뷰 요청 흐름

선택된 Milestone lock 결정만 active `CODE_REVIEW-local-G06.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/07+03_snapshot_source`
- Archived plan: `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/plan_local_G06_5.log`
- Archived review: `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/code_review_local_G06_5.log`
- Verdict: FAIL
- Findings: Required 2, Suggested 0, Nit 0.
  - reader 결과를 받은 뒤 writer를 시작해 public reader와 runtime writer가 queue/service lock 경계에서 경합하지 않으며 queue lock 제거 회귀를 잡지 못한다.
  - reader/writer completion을 raw receive로 기다리고 waiter timeout을 성공 처리해 bounded failure cleanup과 terminal 검증이 없다.
- Reviewer cleanup: 호출자 없는 test helper 둘과 `buildSnapshotLocked`의 stale test 노출 설명은 비동작성 정리됐다.
- Affected files: `apps/edge/internal/service/status_provider_test.go`.
- Verification evidence:
  - reviewer fresh format/diff와 targeted snapshot suite, exact/concurrent 20회, race 5회, `go test -count=1 -timeout 120s ./apps/edge/...`는 PASS했다.
  - provider-pool preflight는 config check PASS 후 configured model/status endpoint 접근 불가로 BLOCKED(rc=3), evidence=`/tmp/iop-long-admission-smoke-provider-snapshot-review6b`.
- Roadmap carryover: `snapshot-source`는 public `ListNodeSnapshots()`가 queue lock을 실제 획득한 상태에서 writer를 대기시킨 deterministic old/new tuple과 bounded cleanup이 반복·race·Edge 전체 검증과 함께 통과할 때만 완료 대상으로 유지한다.
- Narrow reread allowed: 위 `plan_local_G06_5.log`, `code_review_local_G06_5.log` 두 파일만 필요 시 읽는다.

## 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

## 분석 결과

### 읽은 파일

- 규칙/라우팅: `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/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`
- 활성/이전 루프: `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/PLAN-local-G06.md`, `agent-task/m-provider-resource-admission-ownership-alignment/07+03_snapshot_source/CODE_REVIEW-local-G06.md`
- 선행 완료: `agent-task/archive/2026/07/m-provider-resource-admission-ownership-alignment/03+01,02_cross_group_wakeup/complete.log`
- 로드맵/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/control/control-plane-operations.md`, `agent-contract/index.md`, `agent-contract/inner/edge-config-runtime-refresh.md`, `agent-contract/inner/control-plane-edge-wire.md`
- production context: `apps/edge/internal/service/service.go`, `apps/edge/internal/service/status_provider.go`, `apps/edge/internal/service/model_queue_snapshot.go`
- 변경 대상 test 전체: `apps/edge/internal/service/status_provider_test.go`
- 테스트 규칙/프로필: `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md`, `agent-test/local/testing-smoke.md`
- plan/review template: `agent-ops/skills/common/plan/templates/review-stub-template.md`, `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`

### SDD 기준

- SDD: `agent-roadmap/sdd/operational-observability-provider-management/provider-resource-admission-ownership-alignment/SDD.md`, 상태 `[승인됨]`, 잠금 `해제`.
- 대상: Acceptance Scenario S07 / Milestone Task `snapshot-source`.
- S07은 실행·대기·반환 중 일반·long in-flight가 lease state와 같고 queued/long_queued가 live candidate pressure여야 한다.
- Evidence Map의 S07 row는 deterministic Edge provider resource/queue tests와 race 검증을 요구한다. 따라서 public reader lock acquisition을 실제 production lock order로 강제하고 exact old/new tuple, bounded cleanup, 반복·race·Edge 전체 검증을 구현 체크리스트와 최종 evidence에 고정한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md`, `agent-test/local/testing-smoke.md`를 읽었다.
- fresh Go test는 `/tmp` GOCACHE와 `-count=1` 또는 명시 반복 횟수를 사용한다. 변경 파일 format/diff, exact test 존재, deterministic/concurrent 20회, snapshot lifecycle, race 5회, Edge 전체 회귀를 적용한다.
- 테스트 환경 프리플라이트: runner `/config/workspace/iop`, branch `main`, HEAD `546a3f8a123cd2fb6f6faf3dbd9c655f71c3d0fd`, dirty worktree, Linux aarch64, Go `1.26.2`, `go=/config/.local/bin/go`, `curl=/bin/curl`이다. source는 현재 checkout을 그대로 검증하며 sibling 변경과 repo-local `service.test`를 수정하지 않는다. 별도 binary/artifact는 필요 없고 config는 `configs/edge.yaml`, runtime identity는 `edge-toki-labs-dev`, model/status 표면은 `:18083`과 `127.0.0.1:18001`이다. config check는 PASS했지만 두 endpoint는 접근 불가해 preflight rc=3이며 evidence는 `/tmp/iop-long-admission-smoke-provider-snapshot-review6b`다. 이는 별도 `capacity-smoke` 책임의 외부 blocker이며 test-only 구현 결정은 막지 않는다.
- reviewer fresh run에서 exact/concurrent 20회, targeted snapshot suite, race 5회와 Edge 전체가 PASS했다. 이 green 출력은 현재 fixture가 queue lock 제거 회귀를 검출한다는 evidence가 아니므로 source invariant를 함께 검증한다.

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

- `TestProviderSnapshotRuntimeRefreshIsOldOrNew`는 public surface를 호출하지만 writer가 reader 완료 뒤 시작되어 reader의 queue lock 획득과 writer 대기를 증명하지 않는다.
- reader/writer completion이 raw receive이고 waiter timeout이 non-fatal이라 실패 경로의 bounded cleanup과 terminal drain evidence가 없다.
- provider별 exact presence/tuple과 fallback available/disabled 양 상태, reader별 first-error delivery는 현재 구현되어 있고 후속에서 보존한다.
- normal/long lifecycle, resolver error/empty, 반복·race와 Edge 전체 회귀는 기존 테스트가 유지한다.

### 심볼 참조

- 후속 구현에서 rename/remove가 필요한 production symbol은 없다.
- public 경계는 `Service.ListNodeSnapshots`, writer 경계는 `Service.SetRuntimeConfig`, reader가 service lock에서 멈추는 지점은 `runtimeConfigSnapshot`이다.
- test에서 `buildSnapshotLocked()` 직접 호출은 없으며 후속에서도 금지한다.
- 이전 리뷰에서 호출자 없는 `matchAnySnapshotTuple`, `assertExactDisabledSnapshot`은 제거됐고 `rg --sort path`로 잔여 참조가 없음을 확인했다.

### 분할 판단

- split decision policy를 먼저 재평가했다. 기존 split subtask `07+03_snapshot_source`를 유지하며 새 sibling을 만들지 않는다.
- 변경은 한 test fixture의 queue→service lock ordering과 그 failure cleanup으로 같은 ownership, 같은 검증, 같은 failure mode를 가진다. API/production 변경, 별도 도메인, 독립 산출물 경계가 없어 추가 split은 인위적인 coordination만 만든다.
- predecessor index `03`은 `agent-task/archive/2026/07/m-provider-resource-admission-ownership-alignment/03+01,02_cross_group_wakeup/complete.log`의 PASS로 충족됐다.

### 범위 결정 근거

- `apps/edge/internal/service/status_provider_test.go`만 수정한다.
- `ListNodeSnapshots`, `SetRuntimeConfig`, queue snapshot production 구현과 config/contract/spec/roadmap/SDD 본문은 변경하지 않는다.
- concurrent provider presence/state storm의 현재 assertion과 sibling subtask 파일, repo-local `service.test`, external endpoint/runtime을 수정·삭제하지 않는다.
- live capacity 1 field smoke는 별도 `capacity-smoke` Task 책임으로 유지한다.

### 최종 라우팅

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

## 의존 관계 및 구현 순서

1. service write lock으로 public reader를 service snapshot 지점에 멈추고 reader의 queue lock 획득을 bounded probe로 증명한다.
2. writer를 reader 뒤 queue 대기 상태로 시작한 다음 service lock을 풀어 old reader → new writer 순서를 강제한다.
3. 모든 barrier/waiter wait와 cleanup을 bounded하게 만들고 반복·race·Edge 전체 검증과 provider-pool preflight를 실행한다.

## 구현 체크리스트

- [ ] `TestProviderSnapshotRuntimeRefreshIsOldOrNew`가 service write lock 아래 public `ListNodeSnapshots()` reader의 queue lock 획득을 bounded `TryLock` probe로 증명하고 writer를 그 queue lock 뒤에 대기시킨 다음 exact old `available/1/1`과 writer 완료 뒤 new `disabled/0/0`을 public surface에서 검증하며 `-count=20` 반복으로 재현되게 한다.
- [ ] reader/writer/waiter의 모든 completion wait와 실패 cleanup을 explicit timeout으로 제한하고 waiter dispatch/error/terminal drain을 검증하며 provider별 exact concurrent assertion을 보존한 뒤 targeted·race·Edge 전체 검증과 provider-pool preflight 실제 출력을 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-1] Public reader lock acquisition과 writer handoff 강제

#### 문제

`apps/edge/internal/service/status_provider_test.go:1628-1655`는 main goroutine이 queue lock을 풀고 reader 결과를 받은 뒤 writer를 시작한다. 이 순차 구조는 public reader가 queue lock을 잃어도 통과하며 `status_provider.go:36-38`의 queue-held critical section 회귀를 검출하지 못한다.

#### 해결 방법

main goroutine이 `svc.mu` write lock을 잡은 상태에서 public reader를 시작한다. reader는 `ListNodeSnapshots()`에서 queue lock을 잡은 뒤 `runtimeConfigSnapshot()`의 service read lock에서 멈춘다. main은 자신이 queue lock을 보유하지 않은 상태에서 bounded `TryLock` probe 실패로 reader의 queue lock 획득을 증명한 후 writer를 시작하고 service lock을 해제한다. reader는 old tuple을 반환하고 queue lock을 놓으며, 그 뒤 writer가 disabled config를 적용한다.

Before (`status_provider_test.go:1628-1655`):

```go
svc.queue.mu.Lock()
go func() {
	readerResult <- svc.ListNodeSnapshots()
}()
runtime.Gosched()
svc.queue.mu.Unlock()
oldSnaps := <-readerResult

go func() {
	svc.SetRuntimeConfig(disabledStore, catalog, groupPolicy{})
	close(writerDone)
}()
<-writerDone
```

After:

```go
svc.mu.Lock()
serviceLocked := true
defer func() {
	if serviceLocked {
		svc.mu.Unlock()
	}
}()

go func() {
	readerResult <- svc.ListNodeSnapshots()
}()
if err := waitForQueueLockHeld(svc.queue, time.Second); err != nil {
	svc.mu.Unlock()
	serviceLocked = false
	t.Fatal(err)
}

go func() {
	svc.SetRuntimeConfig(disabledStore, catalog, groupPolicy{})
	close(writerDone)
}()
svc.mu.Unlock()
serviceLocked = false

oldSnaps := receiveSnapshotsWithin(t, readerResult, time.Second)
waitDoneWithin(t, writerDone, time.Second)
```

`waitForQueueLockHeld`는 main이 queue lock을 보유하지 않은 상태에서만 호출하고, deadline 전 `TryLock()`이 성공하면 즉시 unlock/yield 후 재시도하며 실패하면 reader가 lock을 보유한 것으로 판정한다. timeout 전에 service lock을 반드시 해제하고 test helper 안에서 `t.Fatal`을 호출하지 않는다.

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

- [ ] `apps/edge/internal/service/status_provider_test.go`: service write lock과 queue `TryLock` deadline으로 public reader가 queue lock을 보유한 상태를 만든다.
- [ ] `apps/edge/internal/service/status_provider_test.go`: reader가 queue lock을 보유한 뒤에만 writer를 시작하고 service lock 해제로 old reader → new writer handoff를 강제한다.
- [ ] `apps/edge/internal/service/status_provider_test.go`: exact old/new tuple과 public surface assertion을 보존하고 direct `buildSnapshotLocked()` 호출을 추가하지 않는다.

#### 테스트 작성

- 수정: `apps/edge/internal/service/status_provider_test.go`의 `TestProviderSnapshotRuntimeRefreshIsOldOrNew`.
- 새 test name은 만들지 않는다.
- fixture: enabled holder/waiter, service write-lock barrier, public reader, disabled runtime writer.
- assertion: queue lock 획득 probe가 성공하고 reader는 old `available/1/1/0/0`, writer 뒤 public surface는 new `disabled/0/0/0/0`이다. `ListNodeSnapshots()`가 queue lock을 잡지 않으면 probe가 timeout/error로 실패한다.

#### 중간 검증

```bash
gofmt -d apps/edge/internal/service/status_provider_test.go
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -list '^TestProviderSnapshotRuntimeRefreshIsOldOrNew$' ./apps/edge/internal/service | rg --fixed-strings 'TestProviderSnapshotRuntimeRefreshIsOldOrNew'
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -count=20 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshotRuntimeRefreshIsOldOrNew$'
```

기대 결과: format diff 없음, exact test name 존재, public reader lock acquisition과 old/new handoff 20회 PASS.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-2] Bounded failure cleanup과 waiter terminal drain

#### 문제

`apps/edge/internal/service/status_provider_test.go:1642`, `:1655`는 reader/writer channel을 raw receive로 기다리고 `:1670-1674`의 waiter timeout은 non-fatal log로 처리한다. barrier 회귀 시 package timeout까지 정지하거나 waiter error/lease 잔여를 성공으로 숨길 수 있다.

#### 해결 방법

reader result, writer completion, waiter result를 모두 `select`와 명시적 timeout으로 기다린다. service lock 보유 여부를 local flag와 deferred cleanup으로 관리해 어느 failure path에서도 lock을 남기지 않는다. waiter는 error와 non-nil run을 검증하고 dispatch terminal event를 적용한 뒤 provider resource와 lease count가 0인지 확인한다.

Before (`status_provider_test.go:1642-1674`):

```go
oldSnaps := <-readerResult
<-writerDone

select {
case <-waiterResult:
case <-time.After(2 * time.Second):
	t.Log("waiter did not dispatch within timeout (non-fatal for tuple regression)")
}
```

After:

```go
var oldSnaps []NodeSnapshot
select {
case oldSnaps = <-readerResult:
case <-time.After(time.Second):
	t.Fatal("public snapshot reader did not complete")
}
select {
case <-writerDone:
case <-time.After(time.Second):
	t.Fatal("runtime config writer did not complete")
}

var waiter submitResult
select {
case waiter = <-waiterResult:
case <-time.After(2 * time.Second):
	t.Fatal("waiter did not dispatch after holder release")
}
if waiter.err != nil || waiter.run == nil {
	t.Fatalf("waiter result: run=%v err=%v", waiter.run, waiter.err)
}
```

waiter dispatch의 terminal event 후 `providerResourceCounts`와 `leaseCount`가 모두 0인지 검증한다.

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

- [ ] `apps/edge/internal/service/status_provider_test.go`: reader, writer, waiter wait를 모두 explicit timeout으로 제한한다.
- [ ] `apps/edge/internal/service/status_provider_test.go`: failure path에서 service lock이 남지 않도록 cleanup ownership을 명시한다.
- [ ] `apps/edge/internal/service/status_provider_test.go`: waiter error/run/dispatch/terminal과 최종 counter/lease drain을 검증한다.
- [ ] `apps/edge/internal/service/status_provider_test.go`: concurrent storm의 provider presence, fallback 양 상태, bounded first-error assertion을 변경하지 않는다.

#### 테스트 작성

- 수정: `TestProviderSnapshotRuntimeRefreshIsOldOrNew`.
- 별도 test 추가는 생략한다. 같은 fixture의 success/failure synchronization과 terminal drain이 하나의 ordering invariant이므로 기존 regression test에서 함께 검증한다.

#### 중간 검증

```bash
git diff --check -- apps/edge/internal/service/status_provider_test.go
if rg --sort path -n 'buildSnapshotLocked\(' apps/edge/internal/service/status_provider_test.go; then exit 1; fi
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -count=20 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshot(RuntimeRefreshIsOldOrNew|ConcurrentRefreshPressureUsesLiveCandidates)$'
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -race -count=5 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshot(RuntimeRefreshIsOldOrNew|LiveCandidatePressureFollowsRefreshAcrossModelGroups|ConcurrentRefreshPressureUsesLiveCandidates|QueuedCountsCandidatePressureAcrossModelGroups)$'
```

기대 결과: whitespace/direct internal call 없음, exact/concurrent 20회와 race 5회가 timeout, deadlock, race detector 경고 없이 PASS.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/edge/internal/service/status_provider_test.go` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-1, REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_PROVIDER_SNAPSHOT_SOURCE-2 |

## 최종 검증

```bash
gofmt -d apps/edge/internal/service/status_provider_test.go
git diff --check -- apps/edge/internal/service/status_provider_test.go
if rg --sort path -n 'buildSnapshotLocked\(' apps/edge/internal/service/status_provider_test.go; then exit 1; fi
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -list '^TestProviderSnapshotRuntimeRefreshIsOldOrNew$' ./apps/edge/internal/service | rg --fixed-strings 'TestProviderSnapshotRuntimeRefreshIsOldOrNew'
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -count=20 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshot(RuntimeRefreshIsOldOrNew|ConcurrentRefreshPressureUsesLiveCandidates)$'
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -count=1 ./apps/edge/internal/service -run '^TestProviderSnapshot(ResolverErrorDoesNotUseStaleCandidate|RuntimeRefreshIsOldOrNew|LiveCandidatePressureFollowsRefreshAcrossModelGroups|ConcurrentRefreshPressureUsesLiveCandidates|QueuedCountsCandidatePressureAcrossModelGroups|ReadsResourceState|IgnoresLegacyFallbackState)$'
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -race -count=5 -timeout 60s ./apps/edge/internal/service -run '^TestProviderSnapshot(RuntimeRefreshIsOldOrNew|LiveCandidatePressureFollowsRefreshAcrossModelGroups|ConcurrentRefreshPressureUsesLiveCandidates|QueuedCountsCandidatePressureAcrossModelGroups)$'
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 go test -count=1 -timeout 120s ./apps/edge/...
GOCACHE=/tmp/iop-go-cache-provider-snapshot-public-reader-followup6 scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-long-admission-smoke-provider-snapshot-public-reader-followup6
```

기대 결과: format/diff/direct-call/exact existence/fresh deterministic/concurrent/targeted/race/Edge 전체 PASS. preflight는 endpoint 가용 시 PASS하고, 동일 endpoint 미가용 시 rc=3과 실제 blocker stdout/stderr/evidence 경로를 기록한다.

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