# SDD: [surface-01] Inference API Surface와 실행 Lifecycle 책임 경계 리팩터링 ## 위치 - Milestone: [Milestone 문서](../../../phase/knowledge-tool-optimization-extension/milestones/inference-api-surface-execution-lifecycle-refactor.md) - Phase: [PHASE.md](../../../phase/knowledge-tool-optimization-extension/PHASE.md) ## 상태 [승인됨] ## SDD 잠금 - 상태: 해제 - 사용자 리뷰: 없음 - 잠금 항목: - [x] [D01] OpenAI, Anthropic, Gemini wire contract는 공통 DTO로 합치지 않고 각 surface adapter에 남긴다. - [x] [D02] provider admission·dispatch·attempt·cancel은 기존 `runService`/`SubmitProviderPool` 경계를 재사용하고, protocol별 실행 준비와 endpoint commit·terminal은 각 기존 runtime이 소유한다. 하나의 universal lifecycle owner나 terminal DTO를 만들지 않는다. - [x] [D03] 리팩터링은 caller-visible behavior, provider selection, native option passthrough와 benchmark 조건을 바꾸지 않는다. - [x] [D04] `iop-s0` `[bench-02]`가 검토중 또는 완료 상태로 진입하고 workspace lock이 해제된 뒤 구현 plan을 시작한다. - [x] [D05] 구현 plan 시작 시 benchmark 이후 drift를 제품 code/spec/contract와 benchmark-only harness/data로 분류한다. 제품 delta는 현재 `dev` 반영 여부 또는 제외 근거를 고정하고, benchmark-only delta는 제품 baseline에 섞지 않는다. - [x] [D06] 완료 evidence는 deterministic characterization과 기존 benchmark artifact 비교를 기본으로 한다. 외부 provider live smoke나 benchmark 재실행은 별도 환경·비용 승인이 있을 때만 추가한다. ## 문제 / 비목표 - 문제: 현재 Edge는 `apps/edge/internal/service`의 `SubmitProviderPool`/`SubmitProviderTunnel`로 provider admission과 dispatch를 이미 공통화했지만, ingress orchestration과 endpoint lifecycle 책임은 `apps/edge/internal/openai` 안에서 경로별로 다르게 조립된다. 특히 Gemini ingress는 Chat request와 내부 HTTP 요청/response writer를 합성해 `handleChatCompletions`에 재진입하므로 Chat handler의 validation·오류·commit 방식에 간접 결합된다. Anthropic native/bridge, OpenAI passthrough/normalized, single-request는 서로 다른 terminal contract를 가지므로 기존 service 경계를 넘어 request/terminal schema까지 공통화하면 회귀 위험이 크다. - 비목표: - 서로 다른 외부 API field와 event를 하나의 범용 request/response schema로 축소 - 신규 기능, provider 최적화, routing/retry/filter 정책 변경 - Control Plane, Edge-Node wire, config/proto 계약 변경 - benchmark pipeline 또는 비교 결과 수정 - 기존 `SubmitProviderPool`과 겹치는 새 all-surface executor 또는 모든 endpoint terminal을 소유하는 중앙 state machine 도입 ## Source of Truth | 영역 | 기준 | 메모 | |------|------|------| | Roadmap | [Milestone 문서](../../../phase/knowledge-tool-optimization-extension/milestones/inference-api-surface-execution-lifecycle-refactor.md) | 범위, Task와 구현 잠금 원장 | | API Contracts | [OpenAI-Compatible API](../../../../agent-contract/outer/openai-compatible-api.md), [Anthropic-Compatible Messages API](../../../../agent-contract/outer/anthropic-compatible-api.md), [Gemini-Compatible API](../../../../agent-contract/outer/gemini-compatible-api.md) | caller-visible 동작 baseline | | Current Spec | [OpenAI-Compatible 입력 표면](../../../../agent-spec/input/openai-compatible-surface.md), [Stream Evidence Gate](../../../../agent-spec/runtime/stream-evidence-gate.md) | 현재 구현 책임과 lifecycle 설명 | | Surface/Ingress Code | `apps/edge/internal/openai/` | surface codec, validation, projector, Stream Evidence Gate와 operation-specific ingress orchestration 구현 | | Provider Execution | `apps/edge/internal/service/`의 `SubmitProviderPool`, `SubmitProviderTunnel`, `SubmitRun` | provider admission·dispatch·attempt·Node cancellation의 기존 source of truth | | Benchmark Baseline | [iop-s0 `[bench-02]` Milestone](../../../../../iop-s0/agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/iop-one-shot-agent-model-comparison.md) | 구현 시작을 잠그는 비교 work owner와 최종 evidence | | User Decision | 없음 | D01-D06은 기존 code/contract와 사용자 요청 범위에서 도출한 기술 기준이며 신규 제품 결정은 없다. | ## State Machine | 상태 | 진입 조건 | 다음 상태 | 근거 | |------|-----------|-----------|------| | `surface_received` | endpoint가 request와 surface auth header를 수신 | `surface_validated`, `terminal_error`, `cancelled` | surface adapter가 credential form과 body를 소유 | | `surface_validated` | surface validation, 공통 principal resolver와 route snapshot 완료 | `admitted`, `terminal_error`, `cancelled` | surface adapter + shared auth/projection resolver | | `admitted` | immutable protocol-specific execution input이 준비됨 | `attempting`, `terminal_error`, `cancelled` | ingress orchestration이 기존 service request를 구성 | | `attempting` | 기존 service가 provider candidate와 operation을 확정하고 attempt 시작 | `pre_commit`, `terminal_error`, `cancelled` | `SubmitProviderPool`/`SubmitProviderTunnel` | | `pre_commit` | endpoint runtime이 아직 caller-visible byte를 commit하지 않음 | `committed`, `terminal_error`, `cancelled` | Stream Evidence Gate, endpoint projector 또는 single-request coordinator | | `committed` | endpoint-native status/header/opening event가 최초 commit됨 | `terminal_success`, `terminal_error`, `cancelled` | surface별 wire writer/terminal state machine | | `terminal_success` | endpoint-native success terminal과 해당 경로의 usage finalization 완료 | 종료 | endpoint runtime의 exactly-once terminal evidence | | `terminal_error` | pre-commit envelope 또는 post-commit endpoint-native error terminal 확정 | 종료 | surface error projection과 기존 terminal winner | | `cancelled` | caller context 취소가 해당 경로의 terminal winner가 됨 | 종료 | endpoint가 service/Node cancel을 전파하고 이후 wire write 금지 | State invariant: - 한 public request의 각 lifecycle 전이에는 owner가 하나만 있고 endpoint terminal winner도 하나만 존재한다. 모든 전이를 하나의 새 중앙 owner로 이동하지 않는다. - surface adapter는 credential form, decode/validation/error/SSE 형식을 소유한다. 공통 auth/projection resolver와 service provider selection/attempt identity/Node cancellation은 중복 구현하지 않는다. - operation-specific ingress 실행 함수는 OpenAI/Anthropic/Gemini public DTO나 `http.ResponseWriter`를 `apps/edge/internal/service`로 넘기지 않는다. 기존 service request/result를 사용하고 endpoint projector hook도 service에 주입하지 않는다. - Stream Evidence Gate와 single-request coordinator는 기존 pre-commit/terminal state machine을 계속 소유하며 새 universal terminal DTO로 치환하지 않는다. - raw passthrough body는 route에 필요한 bounded field만 읽고 unknown/provider-native field를 제거하지 않는다. translated body도 `extra_body`를 포함한 생성 결과를 손실 없이 전달한다. - commit 전후의 오류 projection은 surface 계약을 따르며, 다른 surface의 handler나 HTTP round-trip을 통해 얻지 않는다. ## Interface Contract - 계약 원문: [OpenAI-Compatible API](../../../../agent-contract/outer/openai-compatible-api.md), [Anthropic-Compatible Messages API](../../../../agent-contract/outer/anthropic-compatible-api.md), [Gemini-Compatible API](../../../../agent-contract/outer/gemini-compatible-api.md) - 입력: - authenticated request snapshot: principal, public route/model, immutable projection/binding revision과 cancellation context다. - protocol operation: Chat Completions, Responses, Anthropic Messages 또는 surface가 명시적으로 변환한 upstream operation이다. - response mode: buffered, normalized stream 또는 raw tunnel stream의 실행 의미다. - execution payload: raw passthrough body 또는 surface가 검증해 만든 provider request body/normalized input이다. - 출력: - 기존 service result: selected execution path, caller에 노출하지 않는 attempt attribution과 run/tunnel handle이다. - endpoint runtime input: 기존 RunEvent/tunnel frame/single-request progress 중 해당 operation이 이미 사용하는 bounded 결과다. - endpoint terminal: surface projector나 기존 coordinator가 자기 error/terminal contract로 확정하며 공통 service 결과 타입으로 만들지 않는다. - 금지: - Gemini가 내부 `http.Request`/`ResponseWriter`를 만들어 Chat handler를 호출한다. - 공통 service가 Gemini/Anthropic/OpenAI public response envelope나 SSE event 이름을 생성한다. - endpoint projector callback이나 `http.ResponseWriter`를 provider service interface에 추가한다. - 기존 `SubmitProviderPool`과 같은 capability를 포장만 바꿔 중복 구현한다. - 공통 DTO를 만들기 위해 surface-specific field, unknown field 또는 provider-native option을 버린다. - 리팩터링 중 provider fallback, retry budget, output filter, single-request stage semantics를 변경한다. ## Acceptance Scenarios | ID | Milestone Task | Given | When | Then | |----|----------------|-------|------|------| | S01 | `baseline-freeze` | `iop-s0` benchmark가 검토중 또는 완료이고 final report/evidence가 고정됨 | 구현 plan 전 consistency check를 수행 | target/current revision, 제품 delta 반영·제외 근거, benchmark-only delta 분리, 대표 terminal/native-option baseline과 workspace lock `true`가 연결된다. | | S02 | `boundary-map` | 세 외부 API와 raw/normalized/single-request 경로가 존재 | 책임/의존 지도를 검토 | surface, shared auth resolver, 기존 service, endpoint runtime의 단계별 소유권이 겹치지 않고 API/terminal DTO 공통화가 비범위로 표시된다. | | S03 | `execution-entrypoint` | Gemini direct와 virtual preset 요청 | Gemini ingress를 실행 | Chat handler 내부 HTTP 재진입이나 중복 service port 없이 기존 provider/preset execution capability를 호출하고 Gemini contract 결과를 반환한다. | | S04 | `surface-adapters` | 각 surface의 정상·validation·auth·provider 오류 입력 | endpoint별 adapter/projector를 실행 | 외부 status, error envelope, model echo와 SSE event 순서가 baseline과 동일하다. | | S05 | `lifecycle-owner` | 정상, provider 오류, timeout, pre/post-commit failure, caller cancel | stream/non-stream lifecycle을 종료 | 단계별 owner가 하나이고 public terminal과 request usage가 exactly once이며 취소 뒤 추가 wire write가 없다. | | S06 | `native-option-preservation` | unknown OpenAI field, Anthropic native extension, Gemini thinking `extra_body`와 model alias | raw 또는 translated dispatch를 수행 | selected provider body에 허용 field가 보존되고 unsupported 의미는 기존 provider/surface 오류로 귀결된다. | | S07 | `contract-regression` | OpenAI Chat/Responses, Anthropic Messages, Gemini direct/single-request characterization matrix와 기존 benchmark artifact | deterministic package test와 artifact 비교를 실행 | caller-visible behavior와 benchmark admission 조건에 의도하지 않은 차이가 없고 별도 승인 없는 live provider 호출은 발생하지 않는다. | | S08 | `spec-sync` | 리팩터링 구현과 회귀 검증 완료 | contract source pointer와 implementation spec을 점검 | 외부 계약 의미는 유지되고 source path·책임 경계·현재 스펙이 실제 코드와 일치하며 기존 계약과 다른 제품 동작은 별도 후보로 분리된다. | ## Evidence Map | Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 | |----------|-------------------|------------------|---------------------------| | S01 | benchmark target/current revision, 제품/benchmark-only delta 분류, lock checker `true`, baseline matrix와 digest | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/baseline-freeze/` | `baseline-freeze` task id별 dependency/drift/baseline evidence | | S02 | surface/common responsibility map와 forbidden dependency check | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/boundary-map/` | `boundary-map` task id별 architecture evidence | | S03 | Gemini production call graph/search, 기존 service 호출과 direct/preset regression | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/execution-entrypoint/` | `execution-entrypoint` task id별 no-handler-reentry/no-duplicate-port evidence | | S04 | endpoint codec/projector ownership tests와 dependency review | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/surface-adapters/` | `surface-adapters` task id별 wire-contract evidence | | S05 | terminal/cancel/usage concurrency matrix | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/lifecycle-owner/` | `lifecycle-owner` task id별 exactly-once evidence | | S06 | raw/translated request capture와 native field preservation tests | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/native-option-preservation/` | `native-option-preservation` task id별 lossless evidence | | S07 | deterministic Edge package test 결과와 기존 benchmark artifact comparison | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/contract-regression/` | `contract-regression` task id별 baseline comparison 및 no-unapproved-live-call evidence | | S08 | agent-spec/contract drift check와 문서 diff | `agent-task/m-inference-api-surface-execution-lifecycle-refactor/spec-sync/` | `spec-sync` task id별 final source-pointer/spec evidence | ## Cross-repo Dependencies - 대상: [iop-s0 `[bench-02]` IOP 원샷 Agent 모델 비교 벤치마크](../../../../../iop-s0/agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/iop-one-shot-agent-model-comparison.md) - `.agent-roadmap-sync/locks.yaml` entry: `iop:inference-api-surface-execution-lifecycle-refactor` - workspace lock 해제 기준: 대상 Milestone이 `[검토중]` 또는 `[완료]`로 전환되어 benchmark matrix/report와 baseline evidence가 더 이상 실행 중 변경되지 않고, lock status가 `enable`로 동기화된다. - 로컬 구현 잠금 추가 기준: 대상/current revision 사이의 변경을 제품 delta와 benchmark-only delta로 분류하고, 제품 delta가 현재 `dev`에 반영됐거나 명시적으로 제외됐다는 근거를 `baseline-freeze`에 남긴다. ## Drift Check - [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다. - [x] Evidence Map이 code-review/complete.log에서 검증 가능하다. - [x] agent-contract를 쓰며 SDD에 계약 원문을 복제하지 않았다. - [x] 사용자 리뷰가 필요한 항목은 없고 D01-D06으로 경계를 확정했다. ## 사용자 리뷰 이력 - 2026-08-13: API 방식 자체가 달라 범용 request/terminal interface가 어렵다는 사용자 문제 제기를 바탕으로, benchmark 완료 뒤 구현하되 현시점에는 surface 계약 분리와 기존 provider service 경계 재사용을 기준으로 Milestone을 먼저 작성했다. ## 작업 컨텍스트 - 표준선: surface-specific anti-corruption adapter + existing provider service capability + transition별 single owner. Operation-specific ingress 함수는 필요한 경로에만 추출하고 물리 package 이동은 의존 방향을 검증하는 최소 범위로 제한한다. - 후속 SDD: 없음