<!-- task=m-provider-availability-capacity-queue-foundation/03_queue_capability_contract plan=0 tag=API -->

# Plan - Queue Capability Contract

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

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

## 배경

`capacity-config`의 설정 로딩과 Edge->Node payload 보존은 현재 브랜치에서 작은 작업으로 처리됐다. FIFO queue 본체가 설정값을 안전하게 쓰려면 adapter `Capabilities`가 `capacity`, `max_queue`, `queue_timeout_ms`, `request_timeout_ms`를 공통 형태로 노출해야 한다. 이 계획은 실행 큐 구현 전에 runtime 계약과 provider adapter capabilities만 좁게 정리한다.

## 사용자 리뷰 요청 흐름

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

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/node-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-test/local/edge-smoke.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/inference-provider-extension/PHASE.md`
- `agent-roadmap/phase/inference-provider-extension/milestones/provider-availability-capacity-queue-foundation.md`
- `apps/node/internal/runtime/types.go`
- `apps/node/internal/adapters/factory.go`
- `apps/node/internal/adapters/factory_internal_test.go`
- `apps/node/internal/adapters/ollama/ollama.go`
- `apps/node/internal/adapters/ollama/ollama_test.go`
- `apps/node/internal/adapters/vllm/vllm.go`
- `apps/node/internal/adapters/vllm/vllm_test.go`
- `packages/go/config/config.go`
- `packages/go/config/config_test.go`
- `apps/edge/internal/node/mapper.go`
- `apps/edge/internal/node/mapper_test.go`
- `proto/iop/runtime.proto`
- `configs/edge.yaml`

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md` 존재 및 읽음.
- 적용 profile: `agent-test/local/node-smoke.md`, `agent-test/local/platform-common-smoke.md`, `agent-test/local/edge-smoke.md`.
- 적용 명령: node는 `go test ./apps/node/...`, platform-common은 `go test ./packages/go/... ./proto/gen/...`, proto 변경 시 `make proto`.
- 이 계획은 node adapter/runtime 계약만 바꾸므로 focused 검증은 `go test -count=1 ./apps/node/internal/runtime ./apps/node/internal/adapters/ollama ./apps/node/internal/adapters/vllm ./apps/node/internal/adapters`로 둔다.

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

- `runtime.Capabilities`에 queue 설정 필드 추가: 기존 직접 테스트 없음, adapter capability tests에 assertion 추가 필요.
- Ollama/vLLM config -> capabilities 반영: 기존 `TestOllamaCapabilitiesQueryTags`, `TestVllmCapabilitiesQueryModels`, instance key tests가 인접 커버리지다. queue config assertion을 추가한다.
- FIFO admission 동작은 이 계획 범위가 아니며 `04+03_fifo_admission_queue`에서 검증한다.

### 심볼 참조

- renamed/removed symbols: none.
- changed symbols: `runtime.Capabilities` 필드 추가. 참조 위치는 `rg --sort path -n "Capabilities\\{|MaxConcurrency|ProviderStatus" apps/node` 기준으로 adapter tests, `node.go` capabilities handling, test doubles가 있다.

### 분할 판단

- split decision policy 평가 완료.
- 공유 task group: `agent-task/m-provider-availability-capacity-queue-foundation/`.
- `03_queue_capability_contract`: no dependencies. runtime/adapter capability contract only.
- `04+03_fifo_admission_queue`: depends on 03. FIFO admission/release/reject 본체.
- `05+04_queue_observe_snapshot`: depends on 04. queued snapshot 관측 반영.
- API/foundation과 concurrency rollout, observability는 위험과 검증 방식이 달라 split한다.

### 범위 결정 근거

- 포함: `apps/node/internal/runtime/types.go`, Ollama/vLLM adapter capability fields and tests.
- 제외: `apps/node/internal/node` admission queue, reject/release behavior, provider snapshot queued count. 이는 후속 split plan에서 구현한다.
- 제외: Edge service/control-plane snapshot mapper 변경. 현재 proto `ProviderSnapshot`에 `queued`가 이미 있고 Edge는 값을 보존한다.

### 빌드 등급

- `local-G05`: runtime 계약 확장이지만 파일 수와 테스트 범위가 작고 deterministic unit tests로 리뷰 가능하다.

## 구현 체크리스트

- [ ] `runtime.Capabilities`에 queue 설정 필드를 추가한다.
- [ ] Ollama adapter가 `config.OllamaConf`의 `capacity`, `max_queue`, `queue_timeout_ms`, `request_timeout_ms`를 보존하고 capabilities에 노출한다.
- [ ] vLLM adapter가 `config.VllmConf`의 `capacity`, `max_queue`, `queue_timeout_ms`, `request_timeout_ms`를 보존하고 capabilities에 노출한다.
- [ ] adapter capability tests에 configured queue settings assertion을 추가한다.
- [ ] 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] Runtime Capabilities Queue Fields

문제: [types.go](/config/workspace/iop/apps/node/internal/runtime/types.go:96)의 `Capabilities`는 `MaxConcurrency`만 있어 `max_queue`, `queue_timeout_ms`, `request_timeout_ms`를 Node admission layer로 전달할 공통 경로가 없다.

해결 방법:

Before:
```go
// apps/node/internal/runtime/types.go:96
type Capabilities struct {
	AdapterName    string
	InstanceKey    string
	Targets        []string
	MaxConcurrency int
	ProviderStatus ProviderStatus
}
```

After:
```go
type Capabilities struct {
	AdapterName       string
	InstanceKey       string
	Targets           []string
	MaxConcurrency    int
	MaxQueue          int
	QueueTimeoutMS    int
	RequestTimeoutMS  int
	ProviderStatus    ProviderStatus
}
```

수정 파일 및 체크리스트:
- [ ] `apps/node/internal/runtime/types.go`: queue config fields 추가.
- [ ] existing test doubles는 zero value로 유지되는지 확인한다.

테스트 작성: 별도 runtime package test는 만들지 않는다. 필드 전달은 adapter tests에서 검증한다.

중간 검증:
```bash
go test -count=1 ./apps/node/internal/runtime
```
예상: no test files 또는 PASS.

### [API-2] Provider Adapter Capability Wiring

문제: [ollama.go](/config/workspace/iop/apps/node/internal/adapters/ollama/ollama.go:23)와 [vllm.go](/config/workspace/iop/apps/node/internal/adapters/vllm/vllm.go:25)는 새 queue 설정을 adapter struct에 보존하지 않고, capabilities도 hardcoded capacity만 반환한다.

해결 방법:

Before:
```go
// apps/node/internal/adapters/ollama/ollama.go:61
return runtime.Capabilities{
	AdapterName:    Name,
	InstanceKey:    o.instanceName,
	Targets:        targets,
	MaxConcurrency: 4,
	ProviderStatus: runtime.NormalizeProviderStatus(status),
}
```

After:
```go
return runtime.Capabilities{
	AdapterName:      Name,
	InstanceKey:      o.instanceName,
	Targets:          targets,
	MaxConcurrency:   effectiveCapacity(o.capacity, 4),
	MaxQueue:         o.maxQueue,
	QueueTimeoutMS:   o.queueTimeoutMS,
	RequestTimeoutMS: o.requestTimeoutMS,
	ProviderStatus:   runtime.NormalizeProviderStatus(status),
}
```

수정 파일 및 체크리스트:
- [ ] `apps/node/internal/adapters/ollama/ollama.go`: struct fields, constructor assignment, capabilities fields.
- [ ] `apps/node/internal/adapters/vllm/vllm.go`: struct fields, constructor assignment, capabilities fields.
- [ ] zero/negative handling은 config load에서 non-negative를 보장하되, adapter는 `capacity<=0`이면 기존 default capacity를 유지한다.

테스트 작성:
- [ ] `apps/node/internal/adapters/ollama/ollama_test.go`: configured queue values appear in capabilities.
- [ ] `apps/node/internal/adapters/vllm/vllm_test.go`: configured queue values appear in capabilities.

중간 검증:
```bash
go test -count=1 ./apps/node/internal/adapters/ollama ./apps/node/internal/adapters/vllm
```
예상: PASS.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/node/internal/runtime/types.go` | API-1 |
| `apps/node/internal/adapters/ollama/ollama.go` | API-2 |
| `apps/node/internal/adapters/vllm/vllm.go` | API-2 |
| `apps/node/internal/adapters/ollama/ollama_test.go` | API-2 |
| `apps/node/internal/adapters/vllm/vllm_test.go` | API-2 |

## 최종 검증

```bash
go test -count=1 ./apps/node/internal/runtime ./apps/node/internal/adapters/ollama ./apps/node/internal/adapters/vllm ./apps/node/internal/adapters
```

예상: PASS. Go test cache output은 허용하지 않는다. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
