<!-- task=m-provider-resource-admission-ownership-alignment/13+09_disconnect_queue_settlement plan=0 tag=REFACTOR -->

# Authoritative disconnect queue settlement

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

선행 09의 matching active/archive `complete.log`를 확인한 뒤 구현한다. 구현 에이전트는 코드·테스트 변경, 구현 검증, active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성까지만 수행한다. 모두 채운 뒤 active pair를 유지하고 구현 실행을 종료한다. 이 저장 상태가 runtime의 `review-ready` 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. code-review 실행, 역할 전환, 판정, review 전용 섹션 수정, archive/log rename, `USER_REVIEW.md`·`complete.log` 작성, 후속 pair 생성·구현은 금지한다. runtime은 사용자에게 묻거나 준비 완료를 보고하지 않고 별도 review-agent instance를 즉시 배정하며 같은 agent의 새 turn·resume·compaction으로 대체하지 않는다. 선택 Milestone의 `구현 잠금 > 결정 필요`만 linked evidence와 함께 review stub의 `사용자 리뷰 요청`에 기록하고 같은 file-state handoff를 사용한다.

## 배경

선행 child가 live resolver의 terminal unavailable outcome과 queue removal 계약을 만든다. 이 child는 current-generation disconnect에 그 계약을 연결해 남은 provider fallback을 즉시 pump하고, 마지막 후보 소멸 waiter를 timeout 전에 끝낸다. event fanout 포화는 correctness 조건이 아니어야 한다.

## 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:
  - `disconnect-queue-resolution`: authoritative disconnect 시 fallback 또는 immediate unavailable
- Completion mode: check-on-pass

## 분석 결과

### 세분화 경계

- 이 child는 원본 REFACTOR-2의 disconnect generation fence, global pump, fallback/terminal settlement와 event-drop 회귀를 소유한다.
- terminal outcome type과 resolver 분류는 `09+08_terminal_unavailable_outcome`의 완료 계약을 소비하며 다시 설계하지 않는다.
- offline snapshot, reconnect activation/pump, Node retry는 다른 sibling 범위다.

### 변경 범위

- `apps/edge/internal/service/model_queue_release.go`
- `apps/edge/internal/service/model_queue_admission_test.go`
- `apps/edge/internal/service/queue_dispatch_test.go`
- 필요 시 `apps/edge/internal/service/status_provider_test.go`

## 구현 체크리스트

- [ ] current-owner disconnect가 남은 provider fallback을 즉시 pump하고 마지막 후보 소멸 item은 queue timeout 전에 제거·unavailable 통지한다.
- [ ] event fanout 포화와 disconnect/terminal 경쟁에서도 queue, lease, reservation, candidate pressure가 남지 않는 deterministic/race test를 추가한다.
- [ ] 대상/Edge/전체 회귀와 보조 entrypoint smoke 결과 또는 blocker를 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우고 active pair를 유지한 채 구현 실행을 종료한다. 이 저장 상태가 runtime의 review-ready 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. 구현 에이전트는 code-review를 실행하거나 review 전용 작업을 수행하지 않는다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] Authoritative disconnect resolution and event-drop regression

문제: `apps/edge/internal/service/model_queue_release.go:87-137`은 candidate 제거 후 pump만 하며 terminal no-candidate item을 직접 settle하지 못한다.

해결 방법: current generation disconnect를 queue lock 아래 적용하고 모든 group candidate를 live resolver로 재구성한 뒤 한 번의 global pump에서 fallback/terminal을 결정한다. waiter channel 통지는 non-blocking으로 유지하고 caller abandon 시 reservation release 규칙을 보존한다.

```go
// Before: candidate 제거 뒤 기존 snapshot으로 pump
m.dropLeasesForNodeLocked(nodeID)
m.pumpAllLocked()

// After: current generation fence 뒤 live resolution으로
// dispatchable/fallback/terminal unavailable을 한 global pass에서 결정한다.
m.fenceNodeGenerationLocked(nodeID, generation)
m.resolveAndPumpAllLocked()
```

수정 파일 및 체크리스트:

- [ ] `apps/edge/internal/service/model_queue_release.go`: disconnect 후 terminal resolution ordering.
- [ ] `apps/edge/internal/service/model_queue_admission_test.go`: no-candidate immediate unavailable, queue/lease zero.
- [ ] `apps/edge/internal/service/queue_dispatch_test.go`: surviving provider fallback과 last-provider disconnect 통합 경로.
- [ ] 필요 시 `apps/edge/internal/service/status_provider_test.go`: terminal 뒤 candidate pressure 0.

테스트 작성: capacity-1 holder/waiter fixture와 saturated event subscriber를 사용해 no-candidate settlement, surviving-provider fallback, event backpressure 무관성, terminal send exactly-once를 검증한다.

## 의존 관계 및 구현 순서

- `09+08_terminal_unavailable_outcome`의 matching `complete.log`가 필요하다.
- 선행 outcome contract를 변경하지 않고 disconnect lifecycle에 연결한 뒤 deterministic test와 race 회귀를 닫는다.

## 최종 검증

- `gofmt -d apps/edge/internal/service/model_queue_release.go apps/edge/internal/service/model_queue_admission_test.go apps/edge/internal/service/queue_dispatch_test.go apps/edge/internal/service/status_provider_test.go` → 출력 없음.
- `go test -race -count=1 ./apps/edge/internal/service` → PASS.
- `go test -count=1 ./apps/edge/...` → PASS.
- `go test -count=1 ./...` → PASS.
- `IOP_E2E_PROFILE=mock ./scripts/e2e-smoke.sh` → 보조 startup/register/run/command/shutdown PASS 또는 명시 blocker.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우고 active pair를 유지한 채 구현 실행을 종료한다. 이 저장 상태가 runtime의 `review-ready` 신호이며 별도 handoff 파일·사용자 메시지를 만들지 않는다. 구현 에이전트는 code-review를 실행하거나 review 전용 작업을 수행하지 않고, runtime은 별도 review 에이전트 instance에 즉시 인계한다.
