<!-- task=m-node-multi-target-serving-foundation/05+03,04_edge_owned_options plan=0 tag=API -->

# Plan - API

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

구현 완료 전 `CODE_REVIEW-local-G07.md`를 실제 구현 내용과 검증 출력으로 채운다. 사용자 전용 blocker는 review stub에 기록하고 직접 질문하지 않는다.

## 배경

사용자는 context window/runner sizing이 agent request마다 달라져 모델 로딩/언로딩이 흔들리는 것을 원하지 않는다. 현재 Ollama 단일 adapter에는 `num_ctx` override 방어가 들어갔지만, route/profile 기반 멀티 타겟 구조에서도 Edge-owned option이 최종 소유권을 가져야 한다.

## 사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 `사용자 리뷰 요청`에 기록한다. code-review가 실제 user-review stop 여부를 판단한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/inference-provider-extension/milestones/node-multi-target-serving-foundation.md`
- Task ids:
  - `edge-owned-options`: context window와 runner sizing 옵션은 Edge config가 최종 소유하며, 외부 agent request의 `options.num_ctx` 같은 값이 Edge-owned 값을 변경하지 못한다.
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/node-smoke.md`
- `apps/edge/internal/openai/chat_handler.go`
- `apps/edge/internal/openai/responses_handler.go`
- `apps/edge/internal/openai/server_test.go`
- `apps/node/internal/adapters/ollama/ollama.go`
- `apps/node/internal/adapters/ollama/ollama_test.go`
- `packages/go/config/config.go`

### 테스트 환경 규칙

- test_env: `local`
- unit contract는 `go test ./apps/edge/... ./apps/node/...`다. live agent request override smoke는 field-smoke task에서 처리한다.

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

- 현재 `ollamaOptionsFromInput`은 단일 `contextSize`를 `num_ctx`로 강제한다 (`apps/node/internal/adapters/ollama/ollama.go:298`).
- route/profile별 context ownership과 OpenAI handler에서 request option이 어떻게 전달되는지에 대한 end-to-end 단위 테스트가 부족하다.
- `keep_alive`나 runner sizing 성격의 추가 옵션 소유권 기준이 명문화되어 있지 않다.

### 심볼 참조

- rename/remove 예정 심볼: 없음. `ollamaOptionsFromInput`, OpenAI request option pass-through, route/profile config 필드 참조를 grep한다.

### 분할 판단

- predecessor `03`: route catalog 완료 필요. 현재 active plan, complete 없음.
- predecessor `04`: engine profile 완료 필요. 현재 active plan, complete 없음.
- 이 작업은 옵션 소유권 정책만 다루며 provider profile 구조 자체는 수정하지 않는다.

### 범위 결정 근거

- 새로운 provider 추가나 route catalog schema 변경은 선행 task 범위다.
- 실제 원격 모델 로딩/언로딩 관찰은 field-smoke로 넘긴다.

### 빌드 등급

- build: `local-G07`, review: `local-G07`. 정책은 중요하지만 단위 테스트로 검출 가능하고 범위가 명확하다.

## 의존 관계 및 구현 순서

- `05+03,04_edge_owned_options`는 `03+01_route_catalog`와 `04+01,02_engine_profiles` 완료 후 구현한다.

## 구현 체크리스트

- [ ] Edge route/profile config의 context/runner sizing 옵션이 request option보다 우선한다.
- [ ] OpenAI chat/responses에서 request `options.num_ctx` 등 runner sizing override가 내부 profile 값을 바꾸지 못한다.
- [ ] provider별 option merge 정책을 테스트로 고정한다.
- [ ] 최종 검증 명령을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [API-1] Edge-Owned Runtime Options

- 문제: 단일 Ollama adapter에는 `num_ctx` 방어가 있지만 (`apps/node/internal/adapters/ollama/ollama.go:305`), route/profile 기반에서는 외부 request option과 Edge-owned profile option의 merge 우선순위가 다시 불명확해질 수 있다.
- 해결 방법: Edge config route/profile의 runner sizing option을 canonical source로 정의하고, handler 또는 provider adapter에서 request options를 allow/pass-through와 forced-owned option으로 분리한다. `num_ctx`처럼 runner sizing에 영향이 큰 옵션은 Edge-owned 값이 있을 때 항상 덮어쓴다.
- 수정 파일 및 체크리스트:
  - [ ] `packages/go/config/config.go`: route/profile option ownership 필드 확인 또는 보강.
  - [ ] `apps/edge/internal/openai/chat_handler.go`: request option 전달 시 route/profile metadata 유지.
  - [ ] `apps/edge/internal/openai/responses_handler.go`: responses path도 같은 정책 적용.
  - [ ] `apps/node/internal/adapters/ollama/ollama.go`: profile별 forced option 적용.
- 테스트 작성: 추가한다. `server_test.go`와 `ollama_test.go`에 request `options.num_ctx=8192`가 route/profile `context_size=262144`로 덮이는 테스트를 둔다. provider별 runner sizing option 목록은 최소 `num_ctx`로 시작하고 확장 가능하게 한다.
- 중간 검증:
  - `go test -count=1 ./apps/edge/internal/openai/... ./apps/node/internal/adapters/ollama/...`

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/go/config/config.go` | API-1 |
| `apps/edge/internal/openai/chat_handler.go` | API-1 |
| `apps/edge/internal/openai/responses_handler.go` | API-1 |
| `apps/edge/internal/openai/server_test.go` | API-1 |
| `apps/node/internal/adapters/ollama/ollama.go` | API-1 |
| `apps/node/internal/adapters/ollama/ollama_test.go` | API-1 |

## 최종 검증

```bash
go test -count=1 ./apps/edge/... ./apps/node/...
```

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