<!-- task=m-provider-availability-capacity-queue-foundation/04+03_fifo_admission_queue plan=1 tag=REVIEW_REFACTOR -->

# Plan - FIFO Admission Queue Follow-up

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

이 계획은 `code_review_cloud_G06_0.log`의 Required 문제만 해결한다. 구현의 마지막 단계는 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이다. 검증을 실행하고 실제 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 둔 채 리뷰 준비 완료를 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope conflict 없이는 사용자에게 직접 묻지 말고, 차단 시 review stub의 `사용자 리뷰 요청` 섹션에 근거를 남긴다. `USER_REVIEW.md`, `complete.log`, log/archive 이동은 code-review 전용이다.

## 배경

1차 구현은 provider별 FIFO queue, queue overflow/timeout, store/event reason을 대부분 구현했지만, adapter gate와 global gate를 enqueue 시점에 동시에 reserve하면서 교차 adapter head-of-line blocking이 생길 수 있다. 또한 필수 repo 내부 edge-node 진단/full-cycle 증거가 보조 smoke로 대체되어 verification trust가 부족하다.

## 사용자 리뷰 요청 흐름

구현 중 사용자-only blocker는 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 구현 에이전트는 직접 질문, 채팅 선택지 제시, `request_user_input` 호출을 하지 않는다. code-review가 요청 타당성을 검증하고 실제 `USER_REVIEW.md` 작성을 소유한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/provider-availability-capacity-queue-foundation.md`
- Task ids:
  - `admission-gate`: Node provider executor가 `in_flight < capacity`일 때만 provider 호출을 시작하고, capacity가 찬 요청은 provider별 FIFO queue에 넣는다.
  - `queue-release`: 실행 중 요청이 응답, 실패, 취소, timeout으로 종료되면 `in_flight`를 줄이고 queue의 첫 요청을 실행 슬롯으로 승격한다.
  - `queue-reject`: `max_queue` 초과 또는 `queue_timeout` 초과 요청은 명확한 error/rejection reason으로 종료한다.
- Completion mode: check-on-pass

## 범위 결정 근거

- 포함: `admissionManager`/`admissionTicket`의 adapter/global gate 합성 순서 수정, global bottleneck 회귀 테스트, 필수 node smoke/full-cycle 증거 회복.
- 제외: `ProviderSnapshot.Queued` 채우기, Edge/Control Plane 변경, priority/weighted/preemptive queue.
- 1차 구현의 정상 FIFO, overflow, timeout, cancel/release tests는 유지하고 필요한 경우만 조정한다.

## 구현 체크리스트

- [ ] 교차 adapter global head-of-line blocking을 재현하는 failing regression test를 추가한다.
- [ ] adapter gate가 실제 grant된 뒤에만 global gate를 reserve/wait하도록 admission ticket 흐름을 수정한다.
- [ ] global wait 경로에서도 provider queue timeout 또는 admission timeout 정책이 일관되게 적용되는지 테스트로 고정한다.
- [ ] 기존 FIFO ordering, max_queue overflow, queue_timeout, success/failure/cancel release tests가 계속 통과하게 한다.
- [ ] 필수 repo 내부 edge-node 진단 또는 full-cycle 검증 증거를 `agent-ops/skills/project/e2e-smoke/SKILL.md` 기준으로 기록한다.
- [ ] 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 작업 항목

### [REVIEW_REFACTOR-1] Gate Composition Fix

문제: [run_manager.go](/config/workspace/iop/apps/node/internal/node/run_manager.go:278)의 `enqueue()`는 adapter gate에서 대기 중인 ticket도 global gate에 즉시 등록한다. 이 때문에 global slot이 비었을 때 아직 adapter slot을 얻지 못한 ticket이 global head를 선점할 수 있고, 다른 adapter의 실행 가능한 queued run이 불필요하게 막힌다.

해결 방법:

- `enqueue()`에서는 adapter gate reservation까지만 수행한다.
- `wait()`에서 adapter gate가 grant된 뒤 global gate를 reserve/wait한다.
- global wait 실패 또는 context/timeout 실패 시 이미 얻은 adapter slot을 반드시 release한다.
- provider queue timeout이 "admission 대기" 전체에 적용되어야 하는지 현재 계약과 테스트 이름에 맞게 명확히 고정한다. 최소한 global wait 때문에 무기한 대기하거나 `max_queue`가 우회되는 동작은 남기지 않는다.

필수 회귀 테스트:

- `apps/node/internal/node/node_test.go`
- 시나리오: global concurrency=2, adapter A/B capacity=1, max_queue 충분.
- A1과 B1이 실행 중일 때 A2를 먼저 enqueue하고 B2를 다음 enqueue한다.
- B1만 release하면 B2가 즉시 시작해야 하며, A1 release를 기다리면 실패다.
- global wait에 걸린 run이 queue timeout 정책으로 종료되는 테스트도 추가하거나 기존 timeout 테스트를 확장한다.

중간 검증:

```bash
go test -count=1 ./apps/node/internal/node -run 'TestAdmissionQueue_.*Global|TestAdmissionQueue_.*Queue|TestConcurrencyLimit'
```

예상: PASS.

### [REVIEW_REFACTOR-2] Verification Evidence Recovery

문제: [code_review_cloud_G06_0.log](/config/workspace/iop/agent-task/m-provider-availability-capacity-queue-foundation/04+03_fifo_admission_queue/code_review_cloud_G06_0.log:155)는 `scripts/dev/edge.sh` + `scripts/dev/node.sh` 기반 repo 내부 edge-node 진단/full-cycle 검증을 생략했다. 이 변경은 node 실행/admission path에 닿으므로 보조 `./scripts/e2e-smoke.sh`만으로 완료 증거가 아니다.

해결 방법:

- `agent-ops/skills/project/e2e-smoke/SKILL.md` 기준으로 임시 config/포트를 사용해 repo 내부 edge-node 진단을 수행한다.
- edge console에서 `/nodes`, `/capabilities`, `/transport`, 메시지 2회, background run, `/sessions`, `/terminate-session` 결과를 기록한다.
- node local `[node-message]` payload와 edge `[node-*-message]` payload가 run별로 내용/순서까지 동일한지 기록한다.
- 수행 불가 시에는 실제 실행한 명령, stdout/stderr, user-owned blocker 여부, 재개 조건을 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청`에 남긴다. 단순 evidence gap은 사용자 리뷰 요청이 아니라 후속 에이전트가 재시도해야 할 항목이다.

중간 검증:

```bash
./scripts/e2e-smoke.sh
```

예상: PASS. 단, 이 명령은 보조 smoke이며 full-cycle 대체 증거로 기록하지 않는다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/node/internal/node/run_manager.go` | REVIEW_REFACTOR-1 |
| `apps/node/internal/node/node_test.go` | REVIEW_REFACTOR-1 |
| `agent-task/m-provider-availability-capacity-queue-foundation/04+03_fifo_admission_queue/CODE_REVIEW-cloud-G06.md` | REVIEW_REFACTOR-2 evidence 기록 |

## 최종 검증

```bash
go test -count=1 ./apps/node/internal/node
go test -race -count=1 ./apps/node/internal/node
go test -count=1 ./apps/node/...
./scripts/e2e-smoke.sh
```

추가 필수 검증: `agent-ops/skills/project/e2e-smoke/SKILL.md` 기준의 `scripts/dev/edge.sh` + `scripts/dev/node.sh` repo 내부 edge-node 진단/full-cycle 결과를 `CODE_REVIEW-*-G??.md`에 실제 stdout/stderr 또는 요약 evidence로 기록한다.
