<!-- task=m-provider-resource-admission-ownership-alignment/03+01,02_cross_group_wakeup plan=0 tag=REFACTOR -->

# Code Review Reference - REFACTOR

> **[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/03+01,02_cross_group_wakeup, plan=0, tag=REFACTOR

## 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:
  - `cross-group-wakeup`: provider 변화 뒤 전역 enqueue 순서 기반 재평가
- Completion mode: check-on-pass

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

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

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

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G07.md` → `code_review_cloud_G07_N.log`, `PLAN-cloud-G07.md` → `plan_cloud_G07_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-provider-resource-admission-ownership-alignment/03+01,02_cross_group_wakeup/`로 이동한다. 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-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [REFACTOR-1] Enqueue sequence 기반 global pending scheduler | [x] |
| [REFACTOR-2] Resource 변화 trigger와 dispatch 직전 live re-evaluation | [x] |
| [REFACTOR-3] Scheduler race·누수 회귀 고정 | [x] |

## 구현 체크리스트

- [x] queue item에 단조 증가 `enqueue_seq`를 부여하고 모든 model group에서 가장 이른 현재 dispatch 가능한 item을 선택하는 global pump를 구현·검증한다.
- [x] lease 반환, capacity refresh, provider disable/re-enable, node exclusion이 global pump를 호출하고 dispatch 직전 live resource eligibility를 재확인하도록 구현·검증한다.
- [x] long-full head 뒤 normal 진행, cross-group FIFO, starvation·중복 예약·slot 누수 없음과 final zero counter를 deterministic/race 테스트로 검증한다.
- [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_{review_lane}_GNN_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_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/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.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로 이동한다.

## 계획 대비 변경 사항

- **global pending index를 별도 slice로 두지 않고 group queue에서 파생했다.** 계획은 `model_queue_types.go`에 global pending index 추가를 명시했고, sequence allocator(`modelQueueManager.enqueueSeq`)와 `queueItem.enqueueSeq`는 그대로 추가했다. 다만 pending item 저장소를 이중화하는 대신 `pendingItemsLocked()`가 매 pump마다 모든 group queue를 `enqueueSeq` 순으로 정렬해 전역 순서를 산출한다. 계획 REFACTOR-1의 "group queue는 ... global index에서 파생하되 이중 mutation helper를 하나로 제한한다" 요구를 방향만 뒤집어 충족한 것으로, 저장소가 하나뿐이라 cancel/timeout/disconnect 경로에서 두 index가 어긋날 여지 자체가 없다. 삽입은 `enqueueItemLocked`, 제거는 `removeQueuedItemLocked` 단일 helper로 통일했다.
- **`tryDispatchLocked(group)`을 유지하지 않고 `pumpAllLocked()`로 대체했다.** 계획의 Before/After는 release 경로만 교체하는 형태였으나, group-local pump가 남아 있으면 호출자마다 전역/지역 pump를 고르는 실수 여지가 생긴다. 모든 release/refresh/exclusion 경로가 같은 pump 하나를 부르도록 함수를 제거하고 호출부(테스트 2곳 포함)를 전환했다.
- **`service.go`에는 pump 호출을 직접 추가하지 않고 `setStore()` 안에 두었다.** 계획은 `service.go`가 refresh 뒤 global pump를 호출하도록 했으나, pump는 manager mutex 아래에서만 안전하고 `setStore`가 이미 그 lock 안에서 resource 정합화를 수행한다. `SetNodeStore`/`SetRuntimeConfig`/refresh admin 모두 `setStore` 하나를 지나므로 호출 누락 경로가 생기지 않는다. `service.go`에는 이 계약을 명시하는 주석만 갱신했다.
- **`provider_resolution.go` helper 추출 범위를 dispatch field 매핑으로 한정했다.** `applyProviderDispatchFields()`로 capacity/long capacity/priority/adapter/type/execution path 매핑을 추출해 최초 resolution과 queued re-resolution이 공유한다. health/models/adapter-instance 필터까지 재적용하지는 않았다 — 사유는 아래 설계 결정 참고.
- **계획에 없던 `queue_reservation_test.go` fixture를 1줄 수정했다.** fixture가 candidate에는 `longContextCapacity=1`을 선언하면서 node record에는 long capacity를 선언하지 않아, live 재해석 도입 후 long slot이 예약되지 않아 실패했다. record가 live source가 되었으므로 fixture를 자기모순 없는 상태로 맞췄다(`LongContextCapacity: longCapacity`). 검증 의도(long lease 예약/반환 대칭)는 그대로다.
- **계획된 3개 외에 회귀 2개를 추가했다.** `TestGlobalPumpNoLeakAfterMixedLongAndNormalDrain`(long_context_queue_test.go, 혼합 반복 후 counter 0 — 계획 REFACTOR-3 체크리스트 항목)과 `TestGlobalPumpPreservesProviderTieBreakWithinSequence`(provider_scheduling_test.go — 계획 REFACTOR-1 체크리스트 항목)다.

## 주요 설계 결정

- **전역 FIFO의 기준은 group 내 위치가 아니라 manager 단조 `enqueueSeq`다.** provider resource는 `(node_id, provider_id)` 단위로 여러 model group이 공유하므로, group queue 안의 순서는 같은 provider를 기다리는 다른 group의 waiter와 아무 순서 관계도 갖지 못한다. `pumpOnceLocked()`는 전체 pending을 arrival 순으로 훑어 **현재 dispatch 가능한 가장 이른 item 하나**를 예약하고 재스캔한다. dispatch 불가능한 item은 순번을 소비하지 않고 skip되므로 long-full head가 뒤의 normal 요청을 막지 않고(SDD D05/D06), dispatch 가능한 item들 사이에서는 FIFO가 유지되어 바쁜 group이 조용한 group을 굶기지 못한다.
- **selection과 reservation을 한 critical section으로 묶었다.** `reserveCandidateLocked()`가 live eligibility 재확인 → slot 예약 → lease 발급을 한 번에 수행하고, `admit`의 즉시 dispatch 경로와 pump 경로가 같은 helper를 쓴다. 스캔과 예약 사이에 release/refresh/disconnect가 끼어들어 사라진 여유에 slot을 잡는 경로가 구조적으로 없어지고, 예약된 slot이 lease 없이 관측되는 창도 없다.
- **queued candidate가 소유하는 것은 identity뿐이고, dispatch 입력은 live에서 다시 읽는다.** `liveCandidateLocked()`는 node entry / provider id / served target은 그대로 두고 capacity, long capacity, priority, adapter, execution path를 현재 node record에서 재해석하며, 사라졌거나 disable된 provider는 후보에서 제외한다. queue에서 오래 기다린 요청이 enqueue 당시 snapshot으로 예약하는 경로를 없애는 것이 목적이다.
- **live 재해석에 health/models/adapter-instance 필터는 재적용하지 않았다.** SDD Interface Contract가 dispatch 직전 재확인을 요구하는 대상은 capacity/enabled/connectivity/priority다. health나 served-model 멤버십은 최초 후보 결정(admission 진입 자격)의 계약이고, 이를 pump에서 다시 적용하면 queue 진입 자격과 dispatch 자격의 소유권이 뒤섞인다. connectivity는 node disconnect 시 `releaseNode`가 후보에서 제거하는 기존 경로가 담당한다.
- **refresh는 release가 알려줄 수 없는 유일한 wake-up 원인이라 `setStore` 안에서 pump한다.** capacity 증가나 provider re-enable은 어떤 lease 반환도 발생시키지 않으므로, pump가 없으면 refresh가 방금 풀어준 waiter가 자기 group event 또는 timeout까지 잠든다. `setStore(nil)`도 pump한다(테스트/부트스트랩 경로에서 store가 비워질 때 pending 판정이 바뀔 수 있다).
- **`releaseNode`는 group별 pump를 전부 없애고 마지막에 한 번만 pump한다.** 예전에는 candidate 필터링과 pump가 같은 group loop 안에서 번갈아 일어나 아직 disconnect node를 후보로 들고 있는 group이 pump될 수 있었다. 이제 모든 group의 후보 정리가 끝난 뒤 한 번 pump하므로, 어떤 waiter도 이미 끊긴 node를 배정받을 수 없다.
- **회귀는 negative control로 검증했다.** 신규 `TestGlobalPump*` 6개가 vacuous pass가 아님을 확인하기 위해 release 경로를 group-local pump로, `setStore`를 pump 없이 되돌린 임시 패치에서 전체 실행해 6개 모두 FAIL(cross-group 대기 테스트는 30s timeout)을 확인한 뒤 구현을 복원했다. 임시 패치 잔재는 남기지 않았다(`pumpGroupOnlyLocked` grep 0건).

## 사용자 리뷰 요청

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

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

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

- global pending item의 enqueue sequence가 한 번만 부여되고 모든 제거 경로에서 index가 일치하는지 확인한다.
- blocked long item은 건너뛰되 현재 dispatch 가능한 item끼리 FIFO를 지키는지 확인한다.
- release/refresh/disable/exclusion과 cancel이 경쟁해도 dispatch 직전 live eligibility 확인과 lease reservation이 원자적인지 확인한다.

## 검증 결과

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

필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.

### REFACTOR-1 중간 검증

```text
$ GOCACHE=/tmp/iop-go-cache go test -count=1 ./apps/edge/internal/service -run 'TestGlobalPump(WakesDifferentModelGroup|PreservesEarliestDispatchableSequence|LongHeadDoesNotBlockNormalOtherGroup)$'
ok  	iop/apps/edge/internal/service	0.007s
```

`-v` 상세 (같은 필터, 개별 항목 확인용):

```text
=== RUN   TestGlobalPumpLongHeadDoesNotBlockNormalOtherGroup
--- PASS: TestGlobalPumpLongHeadDoesNotBlockNormalOtherGroup (0.00s)
=== RUN   TestGlobalPumpWakesDifferentModelGroup
--- PASS: TestGlobalPumpWakesDifferentModelGroup (0.00s)
=== RUN   TestGlobalPumpPreservesEarliestDispatchableSequence
--- PASS: TestGlobalPumpPreservesEarliestDispatchableSequence (0.00s)
PASS
ok  	iop/apps/edge/internal/service	0.049s
```

### REFACTOR-2 중간 검증

```text
$ GOCACHE=/tmp/iop-go-cache go test -count=1 ./apps/edge/internal/service -run 'TestGlobalPump(CapacityRefreshWakesWaiter|DisabledProviderIsNotDispatched|NodeExclusionFallsBackAcrossGroups)$'
ok  	iop/apps/edge/internal/service	0.095s
```

`-v` 상세:

```text
=== RUN   TestGlobalPumpCapacityRefreshWakesWaiter
--- PASS: TestGlobalPumpCapacityRefreshWakesWaiter (0.00s)
=== RUN   TestGlobalPumpDisabledProviderIsNotDispatched
--- PASS: TestGlobalPumpDisabledProviderIsNotDispatched (0.00s)
=== RUN   TestGlobalPumpNodeExclusionFallsBackAcrossGroups
--- PASS: TestGlobalPumpNodeExclusionFallsBackAcrossGroups (0.03s)
PASS
ok  	iop/apps/edge/internal/service	0.081s
```

### REFACTOR-3 중간 검증

```text
$ GOCACHE=/tmp/iop-go-cache go test -race -count=1 ./apps/edge/internal/service -run 'TestGlobalPumpConcurrentReleaseCancelRefreshNoLeak$'
ok  	iop/apps/edge/internal/service	1.108s
```

race detector 경고 없음. 테스트가 검증하는 불변식: 한 요청당 lease 정확히 1개, provider in-flight peak ≤ 설정된 최대 capacity, long in-flight peak ≤ long capacity, 종료 후 resource/lease/pending 전부 0.

### 회귀 유효성 확인 (negative control)

계획에 없는 추가 확인이다. release 경로를 group-local pump로, `setStore`를 pump 없이 되돌린 임시 패치에서 신규 테스트를 실행해 vacuous pass가 아님을 확인했다.

```text
$ GOCACHE=/tmp/iop-go-cache go test -count=1 ./apps/edge/internal/service -run 'TestGlobalPump'   # (임시 되돌림 상태)
--- FAIL: TestGlobalPumpWakesDifferentModelGroup (0.00s)
--- FAIL: TestGlobalPumpPreservesEarliestDispatchableSequence (0.00s)
--- FAIL: TestGlobalPumpPreservesProviderTieBreakWithinSequence (0.00s)
--- FAIL: TestGlobalPumpCapacityRefreshWakesWaiter (0.00s)
--- FAIL: TestGlobalPumpDisabledProviderIsNotDispatched (0.00s)
--- FAIL: TestGlobalPumpNodeExclusionFallsBackAcrossGroups (30.01s)
FAIL
FAIL	iop/apps/edge/internal/service	30.214s
```

확인 후 구현을 복원했고, 임시 helper 잔재는 남아 있지 않다(`grep -n "pumpGroupOnlyLocked" apps/edge/internal/service/*.go` 출력 없음).

### 최종 검증

```text
$ gofmt -d apps/edge/internal/service/model_queue_types.go apps/edge/internal/service/model_queue_admission.go apps/edge/internal/service/model_queue_release.go apps/edge/internal/service/service.go apps/edge/internal/service/provider_resolution.go apps/edge/internal/service/model_queue_admission_test.go apps/edge/internal/service/long_context_queue_test.go apps/edge/internal/service/provider_scheduling_test.go apps/edge/internal/service/service_internal_test.go apps/edge/internal/service/queue_dispatch_test.go apps/edge/internal/service/model_queue_test_support_test.go
(출력 없음)

$ GOCACHE=/tmp/iop-go-cache go test -count=1 ./apps/edge/...
ok  	iop/apps/edge/cmd/edge	0.114s
ok  	iop/apps/edge/internal/bootstrap	0.893s
ok  	iop/apps/edge/internal/configrefresh	0.075s
ok  	iop/apps/edge/internal/controlplane	4.545s
ok  	iop/apps/edge/internal/edgecmd	0.025s
ok  	iop/apps/edge/internal/edgevalidate	0.012s
ok  	iop/apps/edge/internal/events	0.009s
ok  	iop/apps/edge/internal/input	0.010s
ok  	iop/apps/edge/internal/input/a2a	0.033s
ok  	iop/apps/edge/internal/node	0.014s
ok  	iop/apps/edge/internal/openai	7.102s
ok  	iop/apps/edge/internal/opsconsole	0.027s
ok  	iop/apps/edge/internal/service	3.438s
ok  	iop/apps/edge/internal/transport	2.396s

$ GOCACHE=/tmp/iop-go-cache go test -race -count=1 ./apps/edge/internal/service -run 'TestGlobalPump'
ok  	iop/apps/edge/internal/service	1.096s
```

추가 실행(계획 외, 위생 확인):

```text
$ gofmt -d apps/edge/internal/service/queue_reservation_test.go
(출력 없음)

$ git diff --check
(출력 없음)

$ GOCACHE=/tmp/iop-go-cache go vet ./apps/edge/...
apps/edge/internal/openai/input_estimator.go:97:26: method WriteByte(b byte) should have signature WriteByte(byte) error
```

`go vet` 경고는 이번 변경 범위 밖인 `apps/edge/internal/openai/input_estimator.go`의 기존 항목이며, 이 작업에서 건드리지 않았다.

---

> **[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, 개요, Roadmap Targets, 리뷰 지시 | Fixed | 구현 에이전트는 수정하지 않는다. |
| 구현 항목별 완료 여부 | Implementing agent | 항목명은 고정하고 `[ ]`만 `[x]`로 바꾼다. |
| 구현 체크리스트 | Implementing agent | 문구/순서는 고정하고 체크만 한다. |
| 코드리뷰 전용 체크리스트 | Review agent | 구현 에이전트는 수정하지 않는다. |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | 실제 내용을 기록한다. |
| 사용자 리뷰 요청 | Implementing agent | Milestone lock 결정 차단일 때만 채운다. |
| 리뷰어를 위한 체크포인트 | Fixed | 구현 에이전트는 수정하지 않는다. |
| 검증 결과 | Implementing agent | 명령은 고정하고 실제 출력만 채운다. |

## 코드리뷰 결과

- 종합 판정: FAIL

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| Correctness | Fail | enqueue 시점에 후보에서 제외된 provider가 refresh로 다시 eligible해져도 pending item이 그 provider를 재발견하지 못한다. |
| Completeness | Fail | `provider disable/re-enable` 뒤 모든 관련 pending item을 재평가한다는 계획·SDD 범위를 기존 candidate snapshot 안에서만 구현했다. |
| Test coverage | Fail | 기존 re-enable 테스트는 provider가 enqueue 전에 candidate에 들어간 경우만 검증해 최초 disabled/capacity 0 후보가 live refresh로 열리는 경로를 놓친다. |
| API contract | Pass | 외부 API와 wire schema 변경은 없고 기존 dispatch surface를 유지한다. |
| Code quality | Pass | global sequence, 단일 pending 저장소, 원자적 reserve/release 구조와 포맷은 정리되어 있다. |
| Implementation deviation | Fail | `queueItem.candidates`를 고정 identity 집합으로 유지한 설계가 live candidate universe 재평가 요구를 축소한다. |
| Verification trust | Pass | 구현 문서의 Go 검증 출력은 fresh 재실행과 일치했다. live smoke는 preflight blocker를 별도 확인했다. |
| Spec conformance | Fail | SDD Interface Contract의 refresh 후 live config/registry 후보 재구성과 provider re-enable 즉시 pump 의미를 충족하지 못한다. |

### 발견된 문제

- Required — `apps/edge/internal/service/model_queue_types.go:119`, `apps/edge/internal/service/model_queue_admission.go:318`, `apps/edge/internal/service/provider_resolution.go:421`: pending item은 enqueue 당시 `candidates`만 저장하고 pump도 그 slice만 스캔한다. 그런데 최초 resolution은 disabled provider와 capacity 0 provider를 slice에서 제거한다. 따라서 다른 active provider가 full이라 요청이 queue에 들어간 뒤, 처음부터 disabled였던 대체 provider를 re-enable해도 `setStore()`가 pump를 호출할 뿐 새 provider identity를 추가하지 못해 요청이 계속 대기한다. 임시 진단 테스트에서 active provider A를 점유하고 provider B를 disabled 상태로 enqueue한 뒤 B를 re-enable했지만 `waitCh`가 dispatch되지 않아 재현됐다. queue item이 model group의 logical live resolver 또는 동등한 current candidate-universe 입력을 보유하게 하고, `pumpOnceLocked()`가 dispatch 직전에 현재 store/catalog/registry로 후보 집합과 served target을 다시 구성한 뒤 기존 원자 reserve를 수행하도록 수정해야 한다. `apps/edge/internal/service/service_internal_test.go:399`의 기존 테스트와 별도로 “enqueue 시 후보에 없던 disabled provider re-enable” 및 “capacity 0 → positive” 회귀를 추가하고 global sequence·counter zero·race 불변식을 함께 검증한다.

### 리뷰 검증

- `gofmt -d <계획 및 추가 fixture Go 파일>`: PASS, 출력 없음.
- `git diff --check`: PASS, 출력 없음.
- `GOCACHE=/tmp/iop-go-cache-review-g07 go test -count=1 ./apps/edge/internal/service -run 'TestGlobalPump(WakesDifferentModelGroup|PreservesEarliestDispatchableSequence|LongHeadDoesNotBlockNormalOtherGroup|CapacityRefreshWakesWaiter|DisabledProviderIsNotDispatched|NodeExclusionFallsBackAcrossGroups)$'`: PASS.
- `GOCACHE=/tmp/iop-go-cache-review-g07 go test -race -count=5 ./apps/edge/internal/service -run '^TestGlobalPump'`: PASS.
- `GOCACHE=/tmp/iop-go-cache-review-g07 go test -count=1 ./apps/edge/...`: PASS.
- 임시 재현 `TestReviewG07ReenabledProviderMissingFromQueuedSnapshot`: FAIL as expected — `re-enabled provider-b was not added to the queued request's candidate set`; 진단 파일은 실행 직후 제거했다.
- `GOCACHE=/tmp/iop-go-cache-review-g07 scripts/e2e-long-context-admission-smoke.sh --preflight --out-dir /tmp/iop-long-admission-smoke-review-g07-rerun`: BLOCKED(rc=3). `configs/edge.yaml` check는 PASS했지만 기본 `/models` endpoint와 Control Plane status endpoint가 이 runner에서 접근 불가했다. live scenario는 실행하지 않았으며 남은 위험으로 유지한다.

### 다음 단계

- FAIL: archived review의 Required finding을 해결하는 `REVIEW_REFACTOR` 후속 plan/review pair를 같은 active task directory에 생성한다.
