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

# Code Review Reference - API

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> Fill implementation-owned sections and real verification output before reporting ready for review.
> Do not ask the user directly; record user-only blockers in `사용자 리뷰 요청`.

## 개요

date=2026-06-10
task=m-node-multi-target-serving-foundation/05+03,04_edge_owned_options, plan=0, tag=API

## 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

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

> **[REVIEW AGENT ONLY]** 종결 절차는 코드리뷰 에이전트 전용이다.

request option이 route/profile owned option을 덮지 못하는지 테스트와 구현을 같이 확인한다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| [API-1] Edge-Owned Runtime Options | [x] |

## 구현 체크리스트

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

## 코드리뷰 전용 체크리스트

- [x] `코드리뷰 결과`에 판정을 append한다.
- [x] active `CODE_REVIEW-local-G07.md`를 `code_review_local_G07_N.log`로 아카이브한다.
- [x] active `PLAN-local-G07.md`를 `plan_local_G07_M.log`로 아카이브한다.
- [x] PASS이면 `complete.log` 작성 후 archive 이동한다.
- [ ] WARN/FAIL이면 후속 상태를 작성한다.

## 계획 대비 변경 사항

- `apps/edge/internal/openai/chat_handler.go`, `responses_handler.go`: 계획에는 수정 대상으로 포함되어 있으나 실제 변경 없음. chat handler는 이미 request options를 그대로 service로 전달하고 있어 정책에 맞음. responses handler는 options 필드가 없어 `num_ctx` 경유 불가. 두 파일 모두 추가 변경이 필요 없음을 확인.
- `packages/go/config/config.go`: 수정 없음. `OllamaInstanceConf.ContextSize` 및 `OllamaConf.ContextSize` 필드가 이미 Edge-owned canonical source 역할을 충분히 수행함.
- `agent-ops/rules/project/domain/node/rules.md`: 계획에 없었으나 코드와 규칙 일관성을 위해 Ollama context_size 정책 설명 수정.

## 주요 설계 결정

- 정책 집행 위치: Edge handler 레벨이 아닌 node adapter 레벨(`ollamaOptionsFromInput`)에서 적용. Edge는 route당 context_size를 갖지 않으므로 Edge에서 강제할 방법이 없음. Adapter는 생성 시 config의 `contextSize`를 이미 보유함.
- 강제 정책: `if _, hasNumCtx := options["num_ctx"]; !hasNumCtx` 조건 제거 → `options["num_ctx"] = contextSize`로 무조건 덮어쓰기. `contextSize == 0`이면 할당 자체를 skip하므로 미설정 adapter는 기존 동작 유지.
- 테스트 전략: `ollama_test.go`에서 adapter-level 강제 검증(실제 HTTP mock), `server_test.go`에서 edge passthrough 검증(fakeRunService)으로 계층 분리.

## 사용자 리뷰 요청

_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._

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

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

- request `options.num_ctx`가 profile context size보다 우선하지 않는다.
- chat/responses 양쪽 경로가 같은 정책을 따른다.
- allow-pass-through option과 forced-owned option이 코드에서 구분된다.

## 검증 결과

### API-1 중간 검증

```bash
$ go test -count=1 ./apps/edge/internal/openai/... ./apps/node/internal/adapters/ollama/...
ok  	iop/apps/edge/internal/openai	1.508s
ok  	iop/apps/node/internal/adapters/ollama	0.007s
```

### 최종 검증

```bash
$ go test -count=1 ./apps/edge/... ./apps/node/...
ok  	iop/apps/edge/cmd/edge	0.057s
ok  	iop/apps/edge/internal/bootstrap	0.027s
ok  	iop/apps/edge/internal/controlplane	4.461s
ok  	iop/apps/edge/internal/edgecmd	0.014s
ok  	iop/apps/edge/internal/events	0.004s
ok  	iop/apps/edge/internal/input	0.009s
ok  	iop/apps/edge/internal/input/a2a	0.008s
ok  	iop/apps/edge/internal/node	0.006s
ok  	iop/apps/edge/internal/openai	1.511s
ok  	iop/apps/edge/internal/opsconsole	0.009s
FAIL	iop/apps/edge/internal/service (pre-existing: TestListNodeSnapshotsWithConfig)
FAIL	iop/apps/edge/internal/transport (pre-existing: TestBuildConfigPayload_OllamaVllmOneof, TestEdgeServerIntegration)
ok  	iop/apps/node/cmd/node	0.012s
ok  	iop/apps/node/internal/adapters	0.009s
ok  	iop/apps/node/internal/adapters/cli	42.085s
ok  	iop/apps/node/internal/adapters/cli/status	39.765s
ok  	iop/apps/node/internal/adapters/ollama	0.009s
ok  	iop/apps/node/internal/adapters/vllm	0.007s
ok  	iop/apps/node/internal/bootstrap	0.261s
ok  	iop/apps/node/internal/node	0.014s
ok  	iop/apps/node/internal/router	0.005s
ok  	iop/apps/node/internal/store	0.044s
ok  	iop/apps/node/internal/terminal	0.435s
ok  	iop/apps/node/internal/transport	5.135s

※ service/transport 실패는 이 작업 이전부터 존재하는 사전 실패 (git stash 확인).
   이 작업 대상 패키지(openai, ollama) 전체 PASS.
```

## 코드리뷰 결과

- 종합 판정: PASS
- 차원별 평가:
  - correctness: Pass
  - completeness: Pass
  - test coverage: Pass
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Pass
  - verification trust: Pass
- 발견된 문제: 없음
- 검증 메모:
  - 리뷰 중 `go test -count=1 ./apps/edge/internal/openai/... ./apps/node/internal/adapters/ollama/...`를 재실행했고 통과했다.
  - 리뷰 중 `go test -count=1 ./apps/edge/... ./apps/node/...`를 재실행했으며, 보고된 기존 실패와 같은 `apps/edge/internal/service`의 `TestListNodeSnapshotsWithConfig`, `apps/edge/internal/transport`의 `TestBuildConfigPayload_OllamaVllmOneof`, `TestEdgeServerIntegration` 실패를 확인했다. 실패 지점은 이번 diff의 `options.num_ctx` 강제 정책과 직접 연결되지 않는 기존 single-instance adapter fixture 계약이다.
  - 리뷰 중 stale README 설명을 `apps/node/README.md`에서 비동작 문서 정리로 수정했다.
- 다음 단계: PASS이므로 `complete.log` 작성 후 task directory를 archive로 이동한다.
