<!-- task=m-stream-evidence-gate-core/17+13,16_openai_request_rebuilder plan=0 tag=OPENAI_REBUILDER -->

# Plan - OpenAI bounded ingress와 request rebuild/dispatch

## 배경

Chat/Responses handlers는 현재 body를 unbounded `io.ReadAll`하고 raw bytes와 typed request를 병렬 보존한다. Core snapshot을 실제 ingress에 적용하고 endpoint별 exact/continuation/schema rebuild를 기존 admission에 다시 연결한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md`
- Task ids: `request-rebuilder`
- Completion mode: check-on-pass

## 분석 결과

- 읽은 파일: `chat_handler.go`, `responses_handler.go`, request types/decoders, `dispatch_context.go`, `server.go`, `provider_tunnel.go`, `provider_model_rewrite.go`, service `provider_tunnel.go`, OpenAI outer contract와 SDD S12/S15/S18.
- handlers의 body read를 공통 pre-read gate로 바꿔 configured limit 전에 `MaxBytesReader` 또는 limit+1 equivalent로 overflow를 구분한다. snapshot build/typed view 실패 전에는 identity/auth를 저장하거나 provider dispatch를 호출하지 않는다.
- OpenAI JSON canonical source는 ingress bytes 한 벌이다. typed envelope/request는 builder ledger에 포함하고 auth header는 snapshot 밖에서 매 dispatch 시 재계산한다.
- endpoint rebuilder는 exact에서 caller canonical bytes를 그대로 재사용한다. continuation/schema는 canonical bytes를 가리키는 bounded top-level field-span index로 대상 subtree만 교체하고 다른 byte range를 single temporary output에 복사한다; persistent `map[string]json.RawMessage`/lossless tree는 canonical body의 중복 보존이므로 금지한다. temporary output pre/post peak를 Core guard로 검사한다.
- host dispatcher는 existing `SubmitRun`/`SubmitProviderTunnel`/`SubmitProviderPool` admission을 호출하고 actual binding을 반환한다. normalized↔tunnel path 변경은 새 admission 결과로만 결정하며 rebuilder가 provider/model/auth를 선택하지 않는다.
- 전용 tests에서 dispatch spy와 log observer를 사용하고 기존 대형 handler tests는 회귀 실행만 한다.
- `test_env=local`, platform-common+edge profiles. build/review closure true; build=`grade-boundary`, scores=`2/2/2/1/2`, loop-risk=`temporal_state,boundary_contract,structured_interpretation,variant_product`, `PLAN-cloud-G09.md`; official review same G09, Codex `gpt-5.6-sol` xhigh.

## 구현 체크리스트

- [ ] REBUILD-1 Chat/Responses pre-read limit+1 gate와 request-local snapshot lifecycle을 적용한다.
- [ ] REBUILD-2 exact/continuation/schema OpenAI JSON rebuilder와 retained peak 검사를 구현한다.
- [ ] REBUILD-3 기존 admission을 감싼 AttemptDispatcher/Binding/Controller adapter를 구현한다.
- [ ] REBUILD-4 unknown field/auth 비보존/path switch/overflow/no-dispatch/release fixtures를 추가한다.
- [ ] REBUILD-5 config/streamgate/OpenAI/service 회귀와 diff 검증을 수행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 구현 항목

### [REBUILD-1] bounded ingress

- 새 `apps/edge/internal/openai/stream_gate_ingress.go`: configured default/limit snapshot, bounded read, endpoint semantic view, release owner.
- `chat_handler.go:16`, `responses_handler.go:16`: unbounded `io.ReadAll`을 제거하고 overflow를 sanitized 413/invalid request 한 번으로 종료한다.
- `dispatch_context.go:18`: naked `rawBody` 대신 snapshot-backed canonical accessor/lease를 보유한다.

### [REBUILD-2] endpoint rebuilder

- 새 `openai_request_rebuilder.go`: Core `RequestRebuilder` 구현. Chat messages/Responses input에 continuation prefix, schema typed patch를 적용하고 caller unknown fields는 canonical byte spans로 보존하고 patch 대상 typed subtree만 직렬화한다. field order/whitespace를 포함한 비대상 byte range를 그대로 복사하며 persistent RawMessage tree를 만들지 않는다.
- `provider_model_rewrite.go:112,157`: model/policy patch도 같은 single-output retained guard를 사용하게 하며 exact no-patch byte identity를 보존한다.

### [REBUILD-3] host dispatcher

- 새 `stream_gate_dispatcher.go`: `runService`의 세 existing admission surface를 endpoint/path-neutral Core binding으로 변환한다. controller close/cancel은 current transport만 idempotent하게 종료한다.
- `server.go:19`와 provider tunnel dispatch callsites는 raw auth를 snapshot에 넣지 않고 매 dispatch closure에서 계산한다.

### [REBUILD-4] tests/contracts

- 새 `stream_gate_ingress_test.go`, `openai_request_rebuilder_test.go`, `stream_gate_dispatcher_test.go`: limit-1/limit/limit+1, exact limit+typed overflow, Chat/Responses unknown field byte-range 보존, continuation/schema patch, persistent RawMessage tree 부재, shared backing, rebuilt overflow/no dispatch, auth absence, provider/path switch, cancel/release.
- `agent-contract/outer/openai-compatible-api.md`: internal size gate/error compatibility와 public field 불변을 기록한다.

## 의존 관계 및 구현 순서

`13`과 `16` PASS → REBUILD-1 → REBUILD-2 → REBUILD-3 → REBUILD-4/5. `20`이 이 host adapter를 Core cycle과 조립한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| Chat/Responses handlers, `dispatch_context.go`, 새 ingress file | REBUILD-1 |
| 새 rebuilder file, `provider_model_rewrite.go` | REBUILD-2 |
| 새 dispatcher file, `server.go`/provider callsites | REBUILD-3 |
| 새 focused tests, OpenAI outer contract | REBUILD-4 |

## 최종 검증

- `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT`
- `go test -count=1 ./packages/go/streamgate ./packages/go/config ./apps/edge/internal/openai ./apps/edge/internal/service`
- `go test -race -count=1 ./packages/go/streamgate ./apps/edge/internal/openai`
- `git diff --check`

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.

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

구현/test/evidence만 소유하고 active pair를 유지한다. user-review/finalization/roadmap은 official reviewer/runtime 소유다.
