공식 agy의 model-role functionResponse를 Chat tool 메시지로 변환한다. 원격 벤치 검증 기록과 후속 API surface 리팩터링 계획을 함께 반영한다.
15 KiB
15 KiB
SDD: [surface-01] Inference API Surface와 실행 Lifecycle 책임 경계 리팩터링
위치
- Milestone: Milestone 문서
- Phase: PHASE.md
상태
[승인됨]
SDD 잠금
- 상태: 해제
- 사용자 리뷰: 없음
- 잠금 항목:
- [D01] OpenAI, Anthropic, Gemini wire contract는 공통 DTO로 합치지 않고 각 surface adapter에 남긴다.
- [D02] provider admission·dispatch·attempt·cancel은 기존
runService/SubmitProviderPool경계를 재사용하고, protocol별 실행 준비와 endpoint commit·terminal은 각 기존 runtime이 소유한다. 하나의 universal lifecycle owner나 terminal DTO를 만들지 않는다. - [D03] 리팩터링은 caller-visible behavior, provider selection, native option passthrough와 benchmark 조건을 바꾸지 않는다.
- [D04]
iop-s0[bench-02]가 검토중 또는 완료 상태로 진입하고 workspace lock이 해제된 뒤 구현 plan을 시작한다. - [D05] 구현 plan 시작 시 benchmark 이후 drift를 제품 code/spec/contract와 benchmark-only harness/data로 분류한다. 제품 delta는 현재
dev반영 여부 또는 제외 근거를 고정하고, benchmark-only delta는 제품 baseline에 섞지 않는다. - [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 문서 | 범위, Task와 구현 잠금 원장 |
| API Contracts | OpenAI-Compatible API, Anthropic-Compatible Messages API, Gemini-Compatible API | caller-visible 동작 baseline |
| Current Spec | OpenAI-Compatible 입력 표면, Stream Evidence Gate | 현재 구현 책임과 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 |
구현 시작을 잠그는 비교 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, Anthropic-Compatible Messages API, Gemini-Compatible API
- 입력:
- 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를 변경한다.
- Gemini가 내부
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 모델 비교 벤치마크 .agent-roadmap-sync/locks.yamlentry: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
- Milestone 기능 Task와 Acceptance Scenario가 일치한다.
- Evidence Map이 code-review/complete.log에서 검증 가능하다.
- agent-contract를 쓰며 SDD에 계약 원문을 복제하지 않았다.
- 사용자 리뷰가 필요한 항목은 없고 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: 없음