# Milestone: OpenAI-compatible Provider Passthrough 계약 동기화

## 위치

- Roadmap: [ROADMAP.md](../../../../ROADMAP.md)
- Phase: [PHASE.md](../PHASE.md)

## 목표

OpenAI-compatible provider 경로를 request `model`이 가리키는 provider capability 기준으로 결정하고, provider가 지원하는 OpenAI-compatible 표준 payload와 provider-native extension payload를 Edge allowlist 없이 raw tunnel로 전달한다.
`metadata`는 route/response selector가 아니라 IOP가 아는 key를 read-only로 발췌하는 실행/관측 문맥으로 정리하고, caller-facing response mode selector와 provider body sideband 주입 경로를 제거한다.

## 상태

[완료]

## 승격 조건

- 없음

## 구현 잠금

- 상태: 해제
- SDD: 필요
- SDD 문서: [SDD.md](../../../sdd/routing-policy-model-orchestration/openai-compatible-provider-passthrough-contract-sync/SDD.md)
- SDD 사유: OpenAI-compatible API 계약, Edge routing, provider tunnel body, dev-corp field smoke에 영향을 주는 Milestone이다.
- 잠금 해제 조건:
  - [x] SDD 잠금이 해제되어 있다.
  - [x] SDD 사용자 리뷰가 없거나 승인/해결되었다.
  - [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
  - [x] Evidence Map이 완료 시 Roadmap Completion과 최종 검증 evidence로 검증 가능하게 연결되어 있다.
- 결정 필요: 없음

## 범위

- Edge OpenAI-compatible Chat Completions와 Responses provider-pool passthrough request/response 경계
- direct legacy OpenAI-compatible provider route의 public response selector 제거와 model/provider capability 기준 정렬
- `metadata` known-key 발췌 책임 정리: workspace, task, principal, usage/log/observability
- provider-native payload preservation: `chat_template_kwargs`, 새 OpenAI-compatible field, provider-specific extension field와 중첩 값
- Node provider tunnel request body와 Edge-Node tunnel metadata의 selector 제거
- dev-corp Spark Ornith/vLLM 계열 또는 dev gx10 Ornith/vLLM 계열 field passthrough smoke

## 기능

### Epic: [route-contract] Model-driven Routing Contract

OpenAI-compatible 요청의 경로 선택을 caller metadata가 아니라 `model`이 가리키는 provider capability로만 결정하도록 계약과 코드를 동기화한다.

- [x] [selector-remove] caller-facing response mode selector 파싱, 분기, header/envelope, 테스트 fixture를 제거한다. 내부 metric/log label이 필요하면 caller 입력과 연결되지 않는 관측명으로만 남긴다. 검증: archive를 제외한 코드/계약/문서 검색에서 public selector field와 selector mode 설명이 남지 않는다.
- [x] [model-route] Chat Completions와 Responses에서 `model` -> route/provider capability -> passthrough 또는 normalized path가 결정된다. 검증: OpenAI-compatible provider는 raw tunnel, CLI/Ollama/native provider는 normalized path를 타는 Edge unit test가 통과한다.
- [x] [metadata-known] `metadata`는 route selector가 아니라 IOP known-key를 read-only로 발췌하는 container로만 처리된다. 검증: workspace/task/principal/usage/log key는 내부 문맥으로 복사되고, 원본 `metadata` payload와 임의 metadata key는 provider passthrough body에서 제거/변형되지 않으며 route/response path를 바꾸지 않는 테스트가 통과한다.

### Epic: [provider-pass] Provider-native Field Passthrough

vLLM, vLLM-MLX, Lemonade, SGLang, Seulgivibe 같은 OpenAI-compatible provider가 지원하는 request surface를 Edge가 자체 allowlist로 제한하지 않게 한다.

- [x] [field-preserve] provider-pool과 direct OpenAI-compatible provider tunnel body는 `model` served target rewrite와 auth/header 처리 외에 provider-native request payload를 보존한다. 검증: `chat_template_kwargs`, 새 임의 provider field, tools/stream_options/store와 중첩 값 fixture가 provider request body에 그대로 남는 Edge/Node 테스트가 통과한다.
- [x] [provider-error] provider가 모르는 field는 Edge가 선판단하지 않고 provider HTTP status/body로 relay한다. 검증: fake provider가 extension field를 거부하는 fixture에서 Edge가 provider error를 변환 없이 전달한다.
- [x] [policy-priority] catalog generation policy와 IOP 내부 기본값 처리는 caller가 명시한 provider-native thinking field를 삭제하거나 대체하지 않는다. 검증: `chat_template_kwargs.enable_thinking=false`가 있는 요청에서 `think`/budget 주입 또는 rewrite가 provider-native 값을 덮지 않는다.

### Epic: [verification] Verification and Deployment Evidence

계약, 테스트, dev-corp smoke가 같은 설계 의도를 증명하도록 완료 evidence를 남긴다.

- [x] [contract-sync] agent-contract, inner wire contract, README/docs, roadmap/SDD 포인터가 model-driven passthrough와 metadata known-key 발췌 기준으로 정리된다. 검증: `rg`로 public selector 필드/모드 설명이 archive를 제외한 최신 문서에 남지 않는다.
- [x] [go-tests] Edge OpenAI handler, service provider-pool tunnel, Node OpenAI-compatible adapter 관련 테스트가 새 계약 기준으로 통과한다. 검증: `go test ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/node/internal/adapters/openai_compat` 또는 동등 범위가 통과한다.
- [x] [devcorp-smoke] dev-corp IOP 경유 Ornith Spark 또는 dev IOP 경유 gx10 Ornith 요청에서 `chat_template_kwargs.enable_thinking=false`가 provider까지 전달된다. 검증: direct provider와 IOP 경유 단일 호출 모두 첫 content가 빠르게 오고 reasoning 생성이 없거나 provider-native think-off 결과와 일치한다.

## 완료 리뷰

- 상태: 통과
- 요청일: 2026-07-14
- 완료 근거: `provider-error`, `policy-priority`는 local fake provider/fixture 기반 회귀 테스트와 `GOCACHE=/tmp/iop-go-cache go test ./apps/edge/internal/openai ./apps/edge/internal/service ./apps/node/internal/adapters/openai_compat` 통과로 충족했다. `devcorp-smoke`는 사용자 승인 동등 환경인 dev gx10에서 direct provider와 IOP dev Edge 경유 모두 `chat_template_kwargs.enable_thinking=false` streaming smoke가 HTTP 200, first content 약 0.1s, reasoning chunk 0개, finish_reason `stop`으로 통과했고 Edge 로그가 `provider_id=gx10-vllm`, `execution_path=provider_tunnel`을 기록했다. 2026-07-14 종료 감사에서 selector surface 검색, 대상 Go 테스트, 전체 `go test ./...`, `git diff --check`가 통과했고 agent-spec 동기화를 완료했다.
- 검토 항목:
  - [x] 모든 기능 Task와 Task별 검증 evidence가 `Roadmap Completion` 또는 완료 리뷰 수동 검증 evidence에 남아 있다.
  - [x] SDD Evidence Map이 최종 검증 evidence와 일치한다.
  - [x] dev gx10 smoke 결과가 문서화되어 있다.
- agent-ui 상태 반영: 해당 없음
- 리뷰 코멘트: 남은 완료 차단 항목 없음. Spec sync: Spec updated ([openai-compatible-surface](../../../../../agent-spec/input/openai-compatible-surface.md), [index](../../../../../agent-spec/index.md)).

## 범위 제외

- 새 route scorer, hybrid local/cloud routing policy, score learning loop 구현
- provider runtime launch/restart option 변경
- output validation filter의 schema/repair policy 구현
- archive 문서의 과거 결정 기록 재작성
- billing/chargeback, 조직 IAM, 장기 retention 정책

## 작업 컨텍스트

- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/node/internal/adapters/openai_compat`, `agent-contract/outer/openai-compatible-api.md`, `agent-contract/inner/edge-node-runtime-wire.md`, `agent-test/dev-corp`
- 표준선(선택): OpenAI-compatible provider 경로는 provider-compatible proxy처럼 동작하고, Edge는 provider field를 자체 구현/해석하지 않고 provider가 판단하도록 전달한다.
- 표준선(선택): `model`이 1차 route source of truth이며, selected provider capability가 passthrough와 normalized path를 결정한다.
- 표준선(선택): `metadata`는 workspace/task/principal/usage/log 같은 IOP known-key를 read-only로 발췌하는 container이며 response mode selector가 아니다.
- 표준선(선택): IOP 확장 field는 OpenAI-compatible 기본 surface 위의 보완 surface이고 provider-native field를 대체하지 않는다.
- 선행 작업: 기존 raw tunnel과 model group mixed dispatch 구현
- 후속 작업: OpenAI-compatible hybrid routing/context optimization, output validation filters
- 확인 필요: 없음
