# Milestone: OpenAI-compatible Raw Tunnel과 Sideband Passthrough

## 위치

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

## 목표

OpenAI-compatible 추론 엔진(vLLM, SGLang, Lemonade, OpenAI-compatible API provider)이 Node-local endpoint에서 반환한 HTTP/SSE 응답을 Edge-Node 기존 proto-socket 위에서 byte-faithful하게 Edge까지 전달한다.
기본 응답 방식은 provider 원본을 그대로 흘리는 `passthrough`로 두고, 요청이 명시한 경우에만 `passthrough+sideband` 또는 `transformed` 모드를 사용한다.
기존 정규화 경로는 CLI, IOP native, non-compatible provider, legacy migration 용도로 유지하되, OpenAI-compatible provider의 고성능 경로는 raw tunnel을 source of truth로 삼는다.

## 상태

[완료]

## 승격 조건

- 없음

## 구현 잠금

- 상태: 해제
- SDD: 필요
- SDD 문서: [SDD.md](../../../sdd/routing-policy-model-orchestration/openai-compatible-raw-tunnel-sideband-passthrough/SDD.md)
- SDD 사유: Edge-Node proto/wire, OpenAI-compatible API mode contract, request metadata/config, lossless streaming, cancellation/backpressure, observability 경계를 함께 바꾸는 설계 Milestone이다.
- 잠금 해제 조건: 아래 체크리스트
  - [x] SDD 잠금이 해제되어 있다.
  - [x] SDD 사용자 리뷰가 없거나 승인/해결되었다.
  - [x] Acceptance Scenario가 Milestone 기능 Task와 연결되어 있다.
  - [x] Evidence Map이 완료 시 `Roadmap Completion`과 최종 검증 evidence로 검증 가능하게 연결되어 있다.
- 결정 필요: 없음

## 범위

- 기존 Edge-Node proto-socket 연결 위에 OpenAI-compatible provider raw response를 전달하는 lossless tunnel frame 추가
- Edge가 Node provider에 직접 닿지 않고 Node가 provider HTTP/SSE를 열어 raw bytes를 Edge로 relay하는 구조
- `RunEvent.delta`와 Edge `events.Bus`를 통하지 않는 per-request ordered byte stream
- Chat Completions streaming/non-streaming passthrough 우선 구현과 Responses API passthrough 후속 연결
- 요청 단위 응답 모드 선택: `passthrough`, `passthrough+sideband`, `transformed`
- OpenAI-compatible provider의 기본값을 provider-original `passthrough`로 고정
- pure `passthrough` body에는 IOP sideband field/event를 섞지 않고, sideband는 `passthrough+sideband` 명시 모드에서만 IOP extension stream/schema로 노출
- `passthrough+sideband`는 provider-original byte identity를 주장하지 않는 IOP 확장 모드이며, 같은 client SSE/response stream에 IOP event/field를 합치는 방식은 이 모드에서만 허용
- 사람이 읽을 수 있는 assembled output(`content`, `reasoning`, `tool_calls`, sideband summary, transformed output)을 실행 로그에 남기고 raw chunk payload는 기본 저장하지 않는 기준
- backpressure, cancel, timeout, upstream provider error, client disconnect, chunk ordering, final frame semantics
- agent-contract, agent-spec, 테스트 fixture, 설정 예시 갱신

## 기능

### Epic: [raw-tunnel] Lossless Provider Tunnel

OpenAI-compatible provider의 원본 응답을 정규화/재조립하지 않고 기존 Edge-Node socket으로 전달하는 핵심 경로를 묶는다.

- [x] [wire-contract] Edge-Node wire에 tunnel request/frame 메시지를 추가하고 status, headers, body bytes, sequence, end, error, usage trailer 후보를 정의한다. 검증: proto 생성과 contract test에서 raw body가 `RunEvent.delta`나 `events.Bus`를 통하지 않음을 확인한다.
- [x] [node-relay] Node는 OpenAI-compatible provider HTTP/SSE response를 열고 provider가 보낸 chunk를 tunnel frame으로 relay한다. 검증: vLLM Qwen `reasoning_content` fixture와 Gemma content fixture가 byte comparison으로 동일하게 왕복한다.
- [x] [edge-stream] Edge OpenAI-compatible handler는 tunnel status/headers/body chunks를 caller에게 그대로 write하고 pure passthrough를 기본값으로 적용한다. 검증: streaming/non-streaming Chat Completions fixture가 provider 원본과 byte-identical하게 반환된다.

### Epic: [response-modes] Request-selected Modes

원본 passthrough, sideband 포함 mode, IOP 변환 mode를 요청에서 선택할 수 있게 하되 기본 경로의 provider-original 보장을 훼손하지 않는다.

- [x] [mode-contract] OpenAI-compatible request metadata/config 계약에 `metadata.iop_response_mode`와 `passthrough`, `passthrough+sideband`, `transformed` 모드를 정의하고 omitted mode는 `passthrough`로 해석한다. 검증: mode 누락, explicit sideband, explicit transformed routing test가 각각 기대 경로를 타고 unknown mode는 fail-fast error가 된다.
- [x] [sideband-overlay] `passthrough+sideband`는 provider original stream과 IOP sideband를 명시적 IOP extension stream/schema로 함께 노출하되 pure `passthrough` body에는 IOP field/event를 주입하지 않는다. 검증: pure passthrough 응답에 IOP sideband가 없고 opt-in sideband mode에서 같은 response stream 또는 계약된 extension surface로 route/provider/assembled observation이 확인된다.
- [x] [transform-output] `transformed`는 provider raw stream을 IOP schema/output으로 수정할 수 있지만 byte-identical provider stream으로 표시하지 않는다. 검증: transformed response가 IOP output으로 라벨링되고 original passthrough 검증과 분리된다.

### Epic: [observability] Assembled Output and Flow Control

raw bytes는 전송 source of truth로 쓰되, 운영 관측과 저장은 사람이 읽을 수 있는 조립 결과와 구조화된 sideband를 기준으로 한다.

- [x] [assembled-log] 실행 로그에는 raw chunk payload 대신 assembled `content`, `reasoning`, `tool_calls`, sideband summary, transformed output을 남긴다. 검증: log fixture가 readable assembled string과 구조화 관측값을 포함하고 raw body chunk를 기본 저장하지 않는다.
- [x] [backpressure-cancel] tunnel path는 기존 socket 위에서 ordered, lossless, backpressure-aware stream을 유지하고 cancel/control frame을 지연시키지 않는다. 검증: slow client, cancel, provider error test에서 chunk drop/reorder 없이 upstream request가 중단된다.
- [x] [contract-docs] agent-contract, agent-spec, config/docs 예시에 raw tunnel, response mode, sideband/transformed semantics, legacy normalized path migration을 반영한다. 검증: contract/spec 링크와 코드 test fixture가 같은 mode 이름과 default를 사용한다.

## 완료 리뷰

- 상태: 통과
- 요청일: 2026-07-08
- 완료 근거: 기능 Task 9개와 SDD S01-S11 evidence를 같은 milestone task group의 archive `complete.log` 5개, 코드 감사, 최종 검증으로 확인했다.
- 검토 항목:
  - [x] 구현 결과가 pure `passthrough` 기본값과 provider-original byte stream을 보장한다.
  - [x] sideband/transformed mode가 opt-in으로만 동작한다.
  - [x] raw tunnel이 기존 Edge-Node socket 위에서 lossless/backpressure-aware하게 동작한다.
  - [x] archive 이동을 승인했다.
- agent-ui 상태 반영: 해당 없음
- Spec sync: not-needed - [openai-compatible-surface.md](../../../../../agent-spec/input/openai-compatible-surface.md)와 [edge-node-execution.md](../../../../../agent-spec/runtime/edge-node-execution.md)는 raw tunnel, response mode, cancel 경계를 이미 반영하며 이번 보완은 spec/contract와 구현을 맞춘 코드 수정이다.
- Workspace 잠금: 관련 lock 없음
- 리뷰 코멘트: 코드 감사 중 Node provider tunnel이 `CancelRequest(CANCEL_RUN)`으로 취소되지 않는 S09 회귀를 발견해 `apps/node/internal/node/node.go`와 `apps/node/internal/node/node_test.go`에서 즉시 보완했다. `go test ./...`, targeted Node/Edge/race 테스트, `make test-e2e`, `git diff --check`로 종료 가능 상태를 확인했다.

## 범위 제외

- 기존 정규화 경로와 legacy provider adapter 제거
- Edge가 Node-local provider endpoint에 직접 접속하는 구조
- 별도 Node socket 또는 별도 stream server 추가
- raw provider byte payload의 기본 장기 저장
- pure `passthrough` OpenAI SSE body에 IOP sideband field/event를 주입하는 방식
- routing score, provider qualification, billing/chargeback 정책 고도화

## 작업 컨텍스트

- 관련 경로: `proto/iop/runtime.proto`, `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/edge/internal/transport`, `apps/edge/internal/events`, `apps/node/internal/transport`, `apps/node/internal/adapters/openai_compat`, `apps/node/internal/adapters/vllm`, `packages/go/config`, [openai-compatible-api.md](../../../../agent-contract/outer/openai-compatible-api.md), [edge-node-runtime-wire.md](../../../../agent-contract/inner/edge-node-runtime-wire.md), [openai-compatible-surface.md](../../../../agent-spec/input/openai-compatible-surface.md), [edge-node-execution.md](../../../../agent-spec/runtime/edge-node-execution.md)
- 표준선: OpenAI-compatible provider response의 원본 bytes가 `passthrough` mode의 source of truth다.
- 표준선: Edge는 provider에 직접 붙지 않고 Node가 provider HTTP/SSE를 열어 기존 Edge-Node socket으로 relay한다.
- 표준선: pure `passthrough`에는 IOP sideband를 섞지 않는다. sideband와 transformed output은 요청 opt-in으로만 활성화한다.
- 표준선: `passthrough+sideband`는 명시적 IOP 확장 모드이므로 provider-original byte-identical 응답으로 간주하지 않는다.
- 표준선: OpenAI-compatible provider의 omitted mode 기본값은 `passthrough`다.
- 표준선: 실행 로그에는 raw chunk payload보다 assembled readable output과 구조화된 sideband observation을 우선 남긴다.
- 선행 작업: [OpenAI-compatible 하이브리드 라우팅과 컨텍스트 최적화](openai-compatible-hybrid-routing-context-optimization.md), [OpenAI-compatible Think 제어 MVP](../../knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md)
- 후속 작업: normalized path deprecation review, provider qualification matrix의 raw passthrough compatibility 반영, Responses API parity hardening
- 확인 필요: 없음
