<!-- task=m-openai-compatible-raw-tunnel-sideband-passthrough/02+01_edge_stream plan=1 tag=REVIEW_API -->

# Plan - REVIEW_API

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

이 plan은 이전 code-review `FAIL`의 Required 1건만 처리한다. 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 `CODE_REVIEW-local-G04.md`의 `사용자 리뷰 요청` 섹션에 기록하고 멈춘다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/routing-policy-model-orchestration/milestones/openai-compatible-raw-tunnel-sideband-passthrough.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/routing-policy-model-orchestration/milestones/openai-compatible-raw-tunnel-sideband-passthrough.md)
- Task ids:
  - `edge-stream`: Edge OpenAI-compatible handler는 tunnel status/headers/body chunks를 caller에게 그대로 write하고 pure passthrough를 기본값으로 적용한다.
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- Current archived plan: `agent-task/m-openai-compatible-raw-tunnel-sideband-passthrough/02+01_edge_stream/plan_cloud_G07_0.log`
- Current archived review: `agent-task/m-openai-compatible-raw-tunnel-sideband-passthrough/02+01_edge_stream/code_review_cloud_G07_0.log`
- Verdict: FAIL
- Required summary:
  - Required: omitted-mode provider-pool passthrough skips active catalog generation policy because `apps/edge/internal/openai/chat_handler.go:65` enters `tunnelChatCompletionPassthrough` before `applyModelCatalogGenerationPolicyToChat`; existing generation policy tests now cover only `metadata.iop_response_mode=transformed`.
- Affected files:
  - `apps/edge/internal/openai/chat_handler.go`
  - `apps/edge/internal/openai/stream.go`
  - `apps/edge/internal/openai/server_test.go`
- Verification evidence from archived loop:
  - `go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/openai` PASS during review rerun.
  - `go test -count=1 -race ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/openai` PASS during review rerun.
  - `go test -count=1 ./apps/edge/...` PASS during review rerun.
  - `gofmt -l apps/edge` and `git diff --check` produced no output during review rerun.
- Roadmap carryover:
  - Same Milestone and Task id `edge-stream`.
  - SDD target scenario remains S04: omitted mode default passthrough with streaming/non-streaming response comparison.
- Narrow archive reread allowed:
  - `agent-task/m-openai-compatible-raw-tunnel-sideband-passthrough/02+01_edge_stream/plan_cloud_G07_0.log`
  - `agent-task/m-openai-compatible-raw-tunnel-sideband-passthrough/02+01_edge_stream/code_review_cloud_G07_0.log`

## 범위 결정 근거

- 포함: provider-pool omitted-mode passthrough에서 active generation policy 계약을 지키도록 request body 생성과 테스트를 보강한다.
- 제외: mode-contract의 unknown mode fail-fast, `passthrough+sideband`, transformed output 정식 semantics, Responses API passthrough parity, field runtime smoke.
- 이 후속은 deterministic `httptest`와 기존 OpenAI handler/service 단위 테스트로 판정 가능하므로 `local-G04`로 라우팅한다.

## 구현 체크리스트

- [ ] Omitted-mode provider-pool passthrough request body applies model catalog generation policy before Node tunnel dispatch without adding IOP sideband to the response.
- [ ] `apps/edge/internal/openai/server_test.go` has an omitted-mode passthrough provider-pool test proving `default_max_tokens`/`min_max_tokens`/`default_thinking_token_budget` reach the provider request body while the response body stays byte-identical.
- [ ] Existing transformed normalized generation policy tests still pass or are adjusted only if semantics stay the same.
- [ ] `go test -count=1 ./apps/edge/internal/openai`를 실행한다.
- [ ] `go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/openai`를 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_API-1] Provider-Pool Passthrough Generation Policy

문제:

```go
// current: apps/edge/internal/openai/chat_handler.go
if passthroughResponseMode(runMeta) && routeUsesProviderTunnel(dispatch) {
    s.tunnelChatCompletionPassthrough(...)
    return
}
outputPolicy := s.resolveOutputPolicy(basePrompt)
if catalogEntry := s.findProviderPoolEntry(req.Model); catalogEntry != nil {
    applyModelCatalogGenerationPolicyToChat(&req, *catalogEntry, outputPolicy.Strict)
}
```

provider-pool catalog policy가 omitted-mode tunnel passthrough에서 적용되지 않는다. active 계약은 `default_max_tokens`, `min_max_tokens`, `default_thinking_token_budget`을 OpenAI-compatible 요청을 내부 실행으로 넘기기 전에 적용하도록 요구한다.

해결 방법:

- `outputPolicy`와 provider-pool catalog entry를 passthrough 분기 전에 계산한다.
- passthrough body builder가 served target rewrite와 함께 policy-applied `max_tokens`, `thinking_token_budget`, strict-output 조건의 `think=true`를 provider request JSON에 반영하게 한다.
- caller가 명시한 `think=false`, `reasoning_effort=none`, explicit token limit 보존 규칙은 기존 `applyModelCatalogGenerationPolicyToChat`와 동일하게 유지한다.
- response relay에는 어떤 IOP sideband/event/field도 추가하지 않는다.

수정 파일 및 체크리스트:

- [ ] `apps/edge/internal/openai/chat_handler.go`
- [ ] `apps/edge/internal/openai/stream.go` 또는 passthrough body helper가 위치한 기존 openai 파일
- [ ] `apps/edge/internal/openai/server_test.go`

테스트 작성:

- omitted mode, provider-pool catalog route, provider fixture 사용.
- catalog에 `DefaultMaxTokens`, `MinMaxTokens`, `DefaultThinkingTokenBudget`를 설정한다.
- caller request가 `max_tokens`와 `thinking_token_budget`을 생략했을 때 provider가 받은 JSON body에 정책값이 들어가는지 확인한다.
- caller response body는 provider fixture body와 byte-identical해야 한다.

중간 검증:

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

## 최종 검증

```bash
go test -count=1 ./apps/edge/internal/openai
go test -count=1 ./apps/edge/internal/transport ./apps/edge/internal/service ./apps/edge/internal/openai
```

기대 결과: 모두 PASS. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-local-G04.md`의 구현 에이전트 소유 섹션을 채운다.
