# SDD: [route-01] IOP 실행 프리셋과 Hot Path

## 위치

- Milestone: [IOP 실행 프리셋과 Hot Path](../../../../archive/phase/knowledge-tool-optimization-extension/milestones/iop-hot-path-one-shot-execution.md)
- Phase: [PHASE.md](../../../../phase/knowledge-tool-optimization-extension/PHASE.md)

## 상태

[승인됨]

## SDD 잠금

- 상태: 해제
- 사용자 리뷰: 없음
- 잠금 항목:
  - [x] [D01] 외부 model은 mode별 model 묶음이 아니라 전체 execution preset에 매핑한다.
  - [x] [D02] preset은 fused selector/planner, 허용 mode와 mode별 downstream ordered stage/model/options를 소유한다.
  - [x] [D03] mode key는 확장 가능하게 두되 현재 구현 handler는 `direct`와 `light`로 제한한다.
  - [x] [D04] `request_id`를 여러 HTTP/tool/provider 호출을 묶는 사용자 작업 identity로 사용한다.
  - [x] [D05] plan-bearing route는 `.iop/job/<request_id>/plan.md`와 `review.md` pair만 만든다.
  - [x] [D06] route-01 구현은 caller tool schema에 대한 declarative binding과 다음 HTTP continuation으로 workspace artifact를 왕복했다. 이는 과거 구현 경계이지 “workspace 도구 실행은 외부 agent가 소유한다”는 제품 원칙이 아니다.
  - [x] [D07] routing부터 repair까지 의미 있는 모든 stage 출력을 사용자 stream에 표시한다.
  - [x] [D08] IOP는 하나의 model처럼 endpoint 표준 성공·오류·취소·length 의미를 유지한다.
  - [x] [D09] 현재 target protocol은 Claude native Messages streaming과 Pi Chat Completions streaming이다.
  - [x] [D10] target agent나 외부 workflow 제품의 runtime·config·contract를 IOP 실행 의존성으로 연결하지 않는다.
  - [x] [D11] 최종 one-shot은 실제 Claude→IOP `/v1/messages` POST 1회이며, request-scoped workspace/tool execution은 IOP Edge와 승인된 Mac IOP Node가 소유한다.
  - [x] [D12] D11의 구조와 Gemini 3.6 Flash high plan → ornith-fast work → Gemini 3.6 Flash high review/repair acceptance는 별도 [IOP 단일 요청 Agent 실행 SDD](../../../../sdd/knowledge-tool-optimization-extension/iop-owned-single-request-agent-execution/SDD.md)가 소유한다.

## 문제 / 비목표

- 문제: 현재 Stream Evidence Gate는 한 ingress request의 terminal을 제어하지만, Hot Path는 agent tool round-trip으로 나뉜 여러 endpoint call과 cloud/local stage를 하나의 논리 요청으로 묶어야 한다. 동시에 exposed model별 실행 방식과 model 배치를 operator가 preset으로 구성할 수 있어야 하며, Plan/Review artifact는 agent workspace에 최소 구조로 남겼다가 완료 시 제거해야 한다.
- 비목표:
  - `heavy` Plan/Review handler, 재계획, 반복 review와 사람 승인
  - 범용 DAG/workflow/plugin runtime
  - target agent별 hook/adapter 설치나 agent process 수정
  - 범용 interactive terminal/PTY, desktop session, 독립 scheduler 또는 장기 agent process를 IOP에 도입
  - `/v1/responses`, A2A와 IOP native protocol 지원
  - route evidence 학습, RAG local router와 production rollout

## Source of Truth

| 영역 | 기준 | 메모 |
|------|------|------|
| Roadmap | [Milestone 문서](../../../../archive/phase/knowledge-tool-optimization-extension/milestones/iop-hot-path-one-shot-execution.md) | 범위, Task와 완료 상태 원장 |
| Config | `packages/go/config`, `configs/edge.yaml` | model/preset one-of, stage canonical model/resource reference와 load validation |
| Edge Runtime | `apps/edge/internal/openai`, `apps/edge/internal/service` | endpoint codec, logical request coordinator, route/stage dispatch |
| Stream Runtime | `packages/go/streamgate` | normalized event, release queue, terminal hold와 exactly-once commit |
| Current Spec | [Stream Evidence Gate 구현 스펙](../../../../../agent-spec/runtime/stream-evidence-gate.md) | 이미 구현된 request-local gate와 이번 cross-call coordinator의 경계 |
| API Contract | [OpenAI-Compatible API](../../../../../agent-contract/outer/openai-compatible-api.md), [Anthropic-Compatible Messages API](../../../../../agent-contract/outer/anthropic-compatible-api.md) | 외부 success/error/tool/stream terminal 원문 |
| Runtime Contract | [Edge Config And Runtime Refresh](../../../../../agent-contract/inner/edge-config-runtime-refresh.md), [Control Plane-Edge Wire](../../../../../agent-contract/inner/control-plane-edge-wire.md), [Edge-Node Runtime Wire](../../../../../agent-contract/inner/edge-node-runtime-wire.md) | config generation, managed principal projection/lease와 stage별 provider dispatch 원문 |
| User Decision | D01-D10 | 본 설계 대화에서 확정, 추가 사용자 결정 없음 |

## State Machine

| 상태 | 진입 조건 | 다음 상태 | 근거 |
|------|-----------|-----------|------|
| `accepted` | preset-backed model의 새 사용자 작업을 admission하고 `request_id`, request lineage, tool binding과 immutable preset generation을 고정 | `selecting`, `failed`, `cancelled` | ingress/toolset fingerprint, preset id/config generation |
| `selecting` | 최초 cloud selector/planner stage가 direct 결과·작업 tool call 또는 light artifact 준비·Plan/Review control tool call을 반환 | `direct_active`, `workspace_prepare_pending`, `plan_pair_pending`, `failed` | structural mode candidate, Edge gate reason, artifact tool-call ids |
| `direct_active` | Edge가 `direct`를 확정 | `agent_tool_wait`, `completed`, `failed`, `cancelled` | endpoint event/tool call/terminal |
| `workspace_prepare_pending` | `light`를 확정했고 선택된 write binding이 missing parent 생성을 보장하지 않아 고정 request directory 준비 tool call을 반환 | `agent_tool_wait`, `failed`, `cancelled` | prepare tool-call id와 issued relative path |
| `plan_pair_pending` | 최초 stage가 고정 request path의 Plan/Review pair 생성 tool call을 반환 | `agent_tool_wait`, `failed`, `cancelled` | paired tool-call ids와 expected paths |
| `agent_tool_wait` | agent가 실행해야 하는 tool call을 내보내고 endpoint turn을 정상 종료 | 저장된 resume stage, `failed`, `cancelled` | 다음 continuation frontier의 expected tool result set |
| `local_active` | Plan/Review pair의 성공 tool result를 모두 확인 | `agent_tool_wait`, `review_active`, `failed`, `cancelled` | local content/tool/terminal events |
| `review_active` | local completion candidate terminal을 hook하고 cloud reviewer를 dispatch | `agent_tool_wait`, `review_write_wait`, `failed`, `cancelled` | reviewer output, inspection tool과 review write tool call |
| `review_write_wait` | agent가 `review.md` 갱신 tool result를 반환 | `review_resolution_active`, `failed`, `cancelled` | review write tool result |
| `review_resolution_active` | cloud stage가 `review.md`를 읽어 pass면 finalize하고 defect면 수정·검증 | `agent_tool_wait`, `cleanup_pending`, `failed`, `cancelled` | review-resolution content/tool/terminal events |
| `cleanup_pending` | 저장된 success/error terminal intent를 확정하기 전에 request directory 삭제 tool call을 실행 | `completed`, `failed`, `cancelled` | pending terminal intent, cleanup tool result, server state release |
| `completed` | 최종 stage와 필수 cleanup이 성공 | 종료 | logical completion record와 마지막 HTTP turn terminal |
| `failed` | validation, write, timeout, provider/context/internal 실행 실패 | 종료 | endpoint-native 표준 error |
| `cancelled` | caller disconnect/abort 또는 표준 cancel | 종료 | endpoint-native cancellation |

State invariant:

- 한 `request_id`에는 동시에 하나의 active stage만 있고 preset/model/stage binding은 시작 시 고정한 config generation을 끝까지 사용한다.
- `light`가 확정된 뒤 directory 준비 continuation은 같은 selector/planner stage의 plan-authoring subphase로만 돌아간다. mode를 다시 선택하거나 `direct`로 전환하지 않는다.
- `review_active`, `review_write_wait`, `review_resolution_active`는 같은 `review` stage/model binding의 subphase다. review write result 뒤 새 reviewer를 선택하거나 다른 model로 전환하지 않는다.
- endpoint request가 이전 전체 conversation을 다시 포함해도 coordinator는 마지막 assistant tool-call 이후의 continuation frontier만 새 입력으로 소비한다. 이미 완료된 history의 tool result는 correlation evidence일 뿐 다시 실행하지 않는다.
- continuation은 endpoint별 canonical form으로 고정한 initial request prefix, 이미 commit된 assistant/tool transcript와 workspace tool binding fingerprint를 보존해야 한다. 과거 message, issued tool call argument나 선택된 tool schema가 바뀌면 새 작업으로 해석하지 않고 표준 validation error로 닫는다.
- 하나의 expected set에 속한 tool result는 바로 다음 continuation frontier 하나에서 순서와 무관하게 각각 한 번만 수락한다. 누락·unknown·중복 result는 stage를 재실행하지 않고 표준 validation error로 닫는다.
- `agent_tool_wait`는 resume stage를 함께 저장한다. tool-use/tool-call terminal은 agent 실행을 위해 각 HTTP turn에서 exactly-once commit하지만 논리 요청 state는 유지한다.
- local completion처럼 agent tool 실행이 필요 없는 stage terminal만 다음 stage 전환을 위해 보류한다. terminal gate는 content/reasoning/tool delta를 full-buffering하지 않는다.
- 각 HTTP turn에는 endpoint-native terminal이 하나씩 존재하고, logical success/error/cancel은 request state에서 한 번만 확정한다. 확정 뒤 active state를 즉시 제거하고 연결 단절 state에는 bounded TTL을 적용한다.
- 여러 internal stage가 같은 HTTP turn에서 이어져도 endpoint codec은 최초 outer response envelope 하나만 열고 provider response-start/terminal을 내부 transition evidence로 소비한다. 공개 content block index와 tool call id를 turn 범위에서 충돌 없이 재발급하고 마지막 외부 terminal만 commit한다.

## Interface Contract

- 계약 원문: [OpenAI-Compatible API](../../../../../agent-contract/outer/openai-compatible-api.md), [Anthropic-Compatible Messages API](../../../../../agent-contract/outer/anthropic-compatible-api.md), [Edge Config And Runtime Refresh](../../../../../agent-contract/inner/edge-config-runtime-refresh.md), [Control Plane-Edge Wire](../../../../../agent-contract/inner/control-plane-edge-wire.md), [Edge-Node Runtime Wire](../../../../../agent-contract/inner/edge-node-runtime-wire.md)
- config 입력:
  - `models[].id`: 외부에 노출되는 model identity다.
  - `models[].execution_preset`: provider mapping과 상호 배타적인 virtual preset reference다. 이 entry 자체에 provider credential slot을 부여하지 않는다.
  - `execution_presets[].id`: stable preset identity다.
  - `execution_presets[].selector`: `direct` 결과 또는 `light` artifact 작성을 같은 cloud stage에서 수행할 fused selector/planner model reference와 옵션이다. mode 판정 전용 stage는 추가하지 않으며, directory 준비가 필요하면 이 stage 안의 정상 tool continuation으로 처리한다.
  - `execution_presets[].allowed_modes[]`: selector가 선택할 수 있는 mode allowlist다.
  - `execution_presets[].routes.<mode>.stages[]`: fused selector/planner 뒤 mode handler가 소비하는 순서 있는 downstream role, canonical model/resource reference와 stage option이다. current `direct` handler는 downstream model stage가 없고 current `light` handler는 `local`, `review`를 순서대로 요구한다. raw provider id, principal route id, credential slot이나 target URL을 직접 가리키지 않는다.
  - `execution_presets[].workspace_tools`: plan-bearing mode의 canonical prepare-directory/read/write/delete operation을 caller `tools[]`에 양방향 매핑하는 ordered binding alternatives를 선언한다. write alternative는 missing parent 생성 보장 여부를 명시한다. 각 alternative는 actual tool name/schema matcher, argument encoder, result success/error matcher와 path/content/command 위치를 가지며 target agent 설치물이나 agent 이름 selector가 아니다.
  - preset catalog와 `models[].execution_preset` refresh는 기존 model catalog처럼 새 logical request에 live-apply할 수 있지만, active request는 시작 시 snapshot generation을 고정한다.
- runtime 입력:
  - 외부 `model`, messages, tools와 endpoint-native option을 보존한다.
  - 새 작업이면 Edge가 caller 입력으로 덮어쓸 수 없는 path-safe opaque `request_id`를 만들고, continuation이면 이전에 IOP가 발행한 public tool call id와 request history의 마지막 미소비 frontier를 active state에 대조한다. 공개 id는 최소 128-bit 충돌 저항성을 가지며 active id 충돌 시 재발급하고 authorization secret으로 사용하지 않는다.
  - admission 때 endpoint별 canonical request lineage와 선택된 workspace role의 tool name/schema fingerprint를 고정한다. continuation은 committed transcript와 이 fingerprint를 보존해야 하며 provider-native tool id는 public issued id와 별도 내부 mapping으로만 연결한다.
  - active coordinator는 current milestone에서 Edge-local transient state다. deployment는 continuation을 같은 Edge로 보내는 affinity를 제공해야 하며 다른 Edge/restart로 state가 사라진 continuation은 새 request로 재해석하지 않고 표준 invalid-state/API error로 닫는다.
  - `request_id`는 최초 authenticated `principal_ref`를 고정한다. continuation token이 달라도 같은 principal로 검증되어야 하며 cross-principal continuation은 provider/tool dispatch 전에 endpoint auth error로 닫는다.
  - managed mode에서 Edge는 각 stage의 canonical model/resource reference를 authenticated principal projection의 existing route `resource_selector`에 대조한다. selector와 모든 allowed mode stage가 각각 정확히 하나의 active projected route에 해석될 때만 virtual preset model을 list/admit하고, zero/ambiguous match는 authorization/config error다.
  - virtual preset authorization을 위해 새 projection message나 credential slot을 만들지 않는다. stage dispatch마다 해석된 existing route의 current revision/credential binding과 lease를 재검증하고 revoke/expiry를 다른 slot·route·mode로 우회하지 않는다.
  - legacy mode에서도 stage model/resource reference는 기존 model catalog/provider resolution을 거치며 preset config가 raw caller credential이나 provider target을 삽입하지 않는다.
  - current `direct/light` mode candidate는 selector 자연어나 숨은 marker를 파싱하지 않고 output shape으로 판정한다. issued request path의 정확한 prepare/pair control tool call이면 `light`, reserved artifact control call이 없는 정상 content/reasoning/일반 작업 tool call이면 `direct` 후보이고, partial pair·충돌 shape·다른 reserved path는 validation error다. Edge가 preset allowlist와 capability gate를 적용해 최종 확정한다.
  - plan-bearing internal stage에는 IOP canonical artifact operation schema를 제공한다. route-01 Edge는 model의 canonical call을 선택된 caller tool name/arguments와 public tool call id로 변환해 stream에 내보내고, continuation의 endpoint-native result를 original stage call로 역매핑했다. 이 과도기 동작은 route-02의 IOP-owned internal tool loop로 대체 대상이다.
  - plan-bearing mode admission은 declared tools 중 workspace file write/read/delete와, write가 missing parent를 만들지 못할 때 directory prepare를 수행할 role binding을 요구한다. Edge는 Claude/Pi 이름이 아니라 실제 tool name과 JSON schema로 request-local ordered alternative를 선택해 해당 binding을 logical request에 고정하고, 맞는 조합이 없거나 deterministic result success/error를 판별할 수 없거나 continuation에서 schema가 바뀌면 provider dispatch 전에 오류로 닫는다.
  - structured tool binding은 workspace-relative path와 no-escape 의미를 보장해야 한다. canonical operation이 command tool에 바인딩되면 Edge가 issued relative path와 write content로 command를 결정적으로 합성하고 shell-safe content encoding, canonical cwd containment, symlink escape 거부와 exact success receipt를 적용한다. model이 임의 artifact command/path를 만들거나 opaque command result를 성공으로 확정하게 하지 않는다.
- 내부 identity:
  - `request_id`: 하나의 사용자 작업과 preset state machine identity다. server-generated path-safe opaque id이며 노출 가능하지만 권한 증명으로 사용하지 않는다.
  - `principal_ref`: request 시작 시 고정하는 owner identity이며 request id 재사용과 cross-principal continuation을 차단한다.
  - `call_id`: 개별 inbound HTTP turn identity다.
  - `stage_id`: selector-planner/local/review/cleanup identity다. state machine subphase를 별도 model stage identity로 만들지 않는다.
  - `lineage_hash`, `toolset_fingerprint`: normalized immutable request prefix/committed transcript와 선택 workspace tool binding의 continuation fence다.
  - `attempt_id`, provider session/run id와 tool call id는 `request_id + stage_id` 하위 correlation이다.
- stage 입력:
  - selector/planner는 immutable caller request/history, caller tool schema, preset control과 issued artifact path를 받는다.
  - `local`은 같은 immutable 사용자 작업과 committed selector/planner 결과, issued `plan.md`·`review.md` 경로를 받고 route-01 caller tool continuation으로 두 파일을 읽은 뒤 작업·검증하도록 지시받는다.
  - `review`는 immutable 사용자 작업, issued artifact path와 committed local completion/output correlation을 받고 필요한 workspace inspection, `review.md` 작성, 같은 stage의 review read와 pass 또는 defect repair를 수행한다.
  - stage input builder는 이전 internal control prompt, credential/provider target과 다른 principal/request의 transcript를 포함하지 않는다. active request 중 새 user instruction이 섞인 continuation은 tool-result frontier로 수락하지 않는다.
- artifact 출력:
  - 상대 workspace root: `.iop/job/<request_id>/`
  - 파일: `plan.md`, `review.md`만 사용한다.
  - selected write binding이 missing parent 생성을 보장하지 않으면 최초 `light` tool turn에는 issued request directory를 준비하는 정확히 하나의 tool call만 허용한다. 그 성공 result 뒤 같은 selector/planner stage의 plan-authoring subphase를 재개한다.
  - Plan/Review 생성 tool turn은 issued `request_id`의 두 파일을 만드는 expected set만 허용한다. 같은 응답의 다른 작업 tool call, 다른 request id, sibling file과 path traversal은 release하지 않고 표준 validation error로 닫는다.
  - route-01 Edge는 declarative binding으로 tool argument의 reserved relative suffix와 content field를 검증하고 caller continuation으로 실행 결과를 받았다. 이 문장은 제품 ownership 원칙이 아니며 route-02에서는 승인된 Mac IOP Node가 workspace root 해석·권한·실행을 소유한다.
  - 두 create/write tool result는 바로 다음 continuation frontier에 임의 순서로 함께 있어야 한다. pinned binding의 endpoint error flag, result matcher 또는 Edge-issued exact receipt로 둘 다 성공이 확정될 때만 local stage를 dispatch한다. opaque result, 일부 생성이나 실패는 local로 넘기지 않고 가능한 범위에서 cleanup을 시도한다.
- stream 출력:
  - routing, plan, local work/completion candidate, review, defect, repair와 final의 content/reasoning/tool call을 endpoint-native 순서로 release한다. terminal-only hold가 이 delta를 숨기거나 전체 stage를 buffer하지 않는다.
  - 한 HTTP turn 안에서 stage/provider가 바뀌어도 Anthropic message/content-block 순서와 Chat chunk/tool-call 순서를 하나의 outer response로 다시 encode한다. 내부 response id, response-start, finish reason과 terminal을 그대로 중첩하지 않는다.
  - stage/model/provider 내부 id, control prompt, credential과 raw observation payload는 공개 stream에 합성하지 않는다.
  - exposed response model identity는 내부 stage target과 관계없이 caller가 선택한 model id를 유지한다.
  - endpoint usage는 해당 HTTP turn에서 실제 소비한 internal stage usage를 중복 없이 합산하고, logical request 전체 합계는 `request_id` observability에서 별도로 집계한다. caller output cap은 한 outer response의 공개 출력 전체에 적용해 stage 전환으로 우회하지 않는다.
- route 의미:
  - `direct`: fused selector/planner가 reserved artifact control call 없이 낸 결과와 일반 작업 tool loop를 그대로 실행하고 별도 downstream model stage나 Plan/Review artifact를 만들지 않는다. model의 강도, thinking 또는 agent tool 사용 여부와 독립적이다.
  - `light`: fused selector/planner의 Plan/Review pair, `local` worker와 하나의 cloud `review` stage 안에서 review write·review-resolution/repair를 수행한다. Edge는 `review.md`를 직접 읽거나 text parsing으로 verdict를 판정하지 않는다.
  - `heavy`: 예약된 초기 vocabulary지만 이번 milestone에는 handler가 없으므로 binding 시 validation error다.
  - 추가 mode: 등록된 handler가 생기기 전에는 config validation error다.
  - 후속 advisory-only selector는 이 fused selector의 의미를 조용히 바꾸지 않는다. route-03에서 explicit selection strategy와 mode별 entry stage 계약을 추가해 기존 fused preset과 구분하며, 이번 milestone에는 그 미래 필드나 빈 stage를 선반영하지 않는다.
- 오류와 종료:
  - principal/preset/stage route authorization 실패, file/tool capability 부재, pair 생성/갱신/cleanup 실패, missing Edge-local state, 잘못된 continuation, stage timeout과 provider 실패는 endpoint 표준 오류다.
  - 별도 partial-success, review-unavailable 또는 repair-limit 성공 상태를 만들지 않는다.
  - success는 delete tool result를 확인한 뒤 확정한다. 오류 중 agent round-trip이 가능한 경우 primary error를 pending terminal intent로 보존한 채 cleanup은 best-effort로 수행하고, cleanup 결과 뒤 primary error를 표준 오류로 확정한다. cleanup 실패가 primary error를 성공이나 다른 mode로 바꾸지 않는다.
  - caller abort/연결 단절 뒤에는 hidden repair/cleanup model call을 계속하지 않는다. server TTL은 IOP state만 회수하며 workspace artifact 삭제를 보장하지 않는다. orphan request id와 reserved relative path는 raw file content 없이 관측하되 자동 삭제를 성공으로 가장하지 않는다.
  - caller의 output cap은 endpoint-native length terminal 의미를 유지한다.
- 금지:
  - caller/agent 이름을 route selector로 사용하거나 Claude/Pi binary를 patch하지 않는다.
  - `direct` 실패를 `light`로, write 불가 `light`를 server-only/cloud-direct로 조용히 바꾸지 않는다.
  - model이 임의 path, preset 밖 mode, provider credential 또는 stage target을 실행 권한으로 확정하게 하지 않는다.
  - virtual preset을 단일 provider credential route처럼 projection에 합성하거나 principal별 route id를 static preset config에 하드코딩하지 않는다.
  - artifact manifest, revision tree, durable workflow state 또는 외부 workflow contract를 만들지 않는다.

## Acceptance Scenarios

| ID | Milestone Task | Given | When | Then |
|----|----------------|-------|------|------|
| S01 | `preset-model` | provider model과 principal별 zero/one/multiple stage route match가 함께 설정됨 | virtual preset model list/admission/response를 조회 | 모든 stage가 unique-authorized인 preset만 노출되고 내부 stage target 대신 외부 model id가 유지된다. |
| S02 | `preset-schema` | 서로 다른 allowed mode/stage binding을 가진 preset과 active request | config를 refresh | 새 request만 새 generation을 사용하고 active tool round-trip은 기존 immutable snapshot을 유지한다. |
| S03 | `route-selector` | selector가 direct content/일반 tool, 정확한 prepare/pair, partial·충돌 artifact shape를 각각 반환 | Edge가 output shape와 preset allowlist로 decision을 확정 | 자연어 route parsing 없이 허용된 direct/light만 통과하고 malformed·금지 mode는 deterministic reason의 표준 오류가 된다. |
| S04 | `hot-preset` | `direct/light` Hot Path와 `heavy/custom` binding | startup validation | direct/light만 실행 가능하고 구현되지 않은 handler는 fail-closed된다. |
| S05 | `request-identity` | 전체 history를 반복하는 same-principal call, 과거 message/tool schema 변조, cross-principal 또는 missing-Edge-state continuation | 새 tool result frontier를 수신 | immutable lineage/tool binding을 보존한 active frontier만 exactly-once 연결하고 나머지는 새 request나 stage로 재실행하지 않는다. |
| S06 | `artifact-pair` | parent 생성 가능 structured binding 또는 receipt 가능한 command/prepare binding이 있는 light 요청 | missing parent 준비와 한 continuation의 역순 pair result가 왕복 | canonical call이 actual tool로 매핑되고 exact 성공이 확인된 reserved path의 두 파일 뒤에만 local stage가 시작된다. |
| S07 | `direct-flow` | direct로 판정된 text/high-think/tool 요청 | stage가 완료 | Plan/Review 경로 없이 작업하며 `.iop/job/<request_id>`를 만들지 않는다. |
| S08 | `light-flow` | immutable user task와 artifact path를 받은 local 결과가 pass 또는 defect인 light 요청 | review write result 뒤 같은 cloud review stage를 재개 | stage별 input이 격리되고 cloud stage가 review를 읽어 finalize 또는 repair하며 Edge file read/text verdict나 두 번째 review는 없다. |
| S09 | `cleanup` | artifact가 생성된 성공·오류·연결 단절 요청 | cleanup/terminal/TTL을 수행 | 성공은 delete result 뒤 닫히고 server TTL과 workspace orphan 보장 범위가 구분되어 관측된다. |
| S10 | `terminal-control` | 한 HTTP turn의 여러 stage가 response-start, content와 completion/tool terminal을 생성 | terminal-only Stream Evidence Gate와 endpoint codec이 release/hold/re-encode | outer envelope, block/tool id와 usage는 한 번만 일관되게 보이고 각 HTTP turn terminal과 logical completion이 각각 exactly-once다. |
| S11 | `anthropic-gate` | Claude native `/v1/messages` streaming과 `tool_use/tool_result` | direct/light를 실행 | Anthropic event ordering과 stop/error shape를 유지하며 stage continuation이 연결된다. |
| S12 | `chat-gate` | Pi `/v1/chat/completions` streaming과 `tool_calls/tool` result | direct/light를 실행 | Chat delta/finish/[DONE] 규약을 유지하며 stage continuation이 연결된다. |
| S13 | `error-cancel` | write 불가, timeout, provider error, context error, cancel과 output cap | 각 경로가 terminal | endpoint 표준 error/cancel/length 의미만 반환하고 partial-success 상태가 없다. |
| S14 | `preset-validation` | dangling/unauthorized stage route, one-of 위반, unsupported mode 또는 workspace tool schema/path/result/containment contract | load/admission을 수행 | credential/provider dispatch나 reserved namespace tool release 전에 validation/auth error로 거부된다. |
| S15 | `route-observability` | direct/light와 실패 요청 | metric/log를 수집 | raw prompt/output/credential 없이 request/preset/mode/stage/attempt와 outcome을 연결한다. |
| S16 | `hot-smoke` | route-01의 Claude/Pi caller-continuation smoke | 사용자 종료 결정 검토 | 최종 제품 구조를 검증하지 않으므로 수행하지 않고 route-02의 actual Claude single-POST smoke로 이관한다. |

## Evidence Map

| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|----------|-------------------|------------------|---------------------------|
| S01 | config/catalog, managed projection zero/one/ambiguous stage match와 model echo API test | `agent-task/m-iop-hot-path-one-shot-execution/preset-model/` | `preset-model` virtual authorization·identity evidence |
| S02 | preset decode/normalize와 refresh generation-isolation unit test | `agent-task/m-iop-hot-path-one-shot-execution/preset-schema/` | `preset-schema` snapshot/refresh fixture 집계 |
| S03 | structural output-shape, allowlist와 hard-gate table test | `agent-task/m-iop-hot-path-one-shot-execution/route-selector/` | `route-selector` no-marker/no-natural-language-parse 결정 reason 검증 |
| S04 | direct/light 성공과 heavy/custom startup rejection test | `agent-task/m-iop-hot-path-one-shot-execution/hot-preset/` | `hot-preset` handler registry evidence |
| S05 | full-history/frontier, lineage·tool schema mutation, public/provider tool-id mapping, cross-principal/missing-state rejection와 concurrency race test | `agent-task/m-iop-hot-path-one-shot-execution/request-identity/` | `request-identity` owner/affinity/lineage/frontier evidence |
| S06 | canonical↔actual mapping, parent-capable write/별도 prepare, exact receipt/opaque result, reversed pair result, missing/extra tool와 path traversal rejection integration test | `agent-task/m-iop-hot-path-one-shot-execution/artifact-pair/` | `artifact-pair` mapping·directory prepare·result/expected-set/path evidence |
| S07 | direct text/high-think/tool integration test와 artifact absence | `agent-task/m-iop-hot-path-one-shot-execution/direct-flow/` | `direct-flow` no-artifact evidence |
| S08 | stage-input isolation과 pass/defect review-write/resolution state-machine integration test | `agent-task/m-iop-hot-path-one-shot-execution/light-flow/` | `light-flow` immutable-task/no-Edge-file-read/one-review evidence |
| S09 | success delete acknowledgement, error best-effort와 disconnect TTL test | `agent-task/m-iop-hot-path-one-shot-execution/cleanup/` | `cleanup` server/workspace 책임 분리 evidence |
| S10 | cross-stage response-start suppression, block/tool id remap, usage/output-cap 집계, normalized delta ordering, per-turn terminal과 logical completion race test | `agent-task/m-iop-hot-path-one-shot-execution/terminal-control/` | `terminal-control` single-envelope/terminal-only hold evidence |
| S11 | Anthropic fragmented SSE/tool_use/error fixture와 handler integration test | `agent-task/m-iop-hot-path-one-shot-execution/anthropic-gate/` | `anthropic-gate` native Messages wire evidence |
| S12 | Chat fragmented SSE/tool_calls/error fixture와 handler integration test | `agent-task/m-iop-hot-path-one-shot-execution/chat-gate/` | `chat-gate` Pi-compatible wire evidence |
| S13 | endpoint별 error/cancel/length table test | `agent-task/m-iop-hot-path-one-shot-execution/error-cancel/` | `error-cancel` no-custom-status evidence |
| S14 | invalid config/route authorization/tool-schema/result matcher/reserved-path/containment admission table test | `agent-task/m-iop-hot-path-one-shot-execution/preset-validation/` | `preset-validation` fail-closed evidence |
| S15 | raw-free log/metric field allowlist test | `agent-task/m-iop-hot-path-one-shot-execution/route-observability/` | `route-observability` redaction evidence |
| S16 | 사용자 종료 결정과 route-02 `claude-smoke` 연결 | route-01 완료 리뷰와 `agent-task/m-iop-owned-single-request-agent-execution/claude-smoke/` | 기존 cross-call smoke 미수행 공개와 single-POST 최종 검증 이관 |

공통 완료 검증은 최소 `go test -race -count=1 ./packages/go/streamgate ./packages/go/config ./apps/edge/internal/openai ./apps/edge/internal/service`와 `git diff --check`를 포함한다. 실제 provider/agent smoke는 credential과 writable test workspace를 갖춘 환경에서 별도 실행 evidence로 남긴다.
각 `agent-task/m-iop-hot-path-one-shot-execution/<task-id>/complete.log`는 동일한 Milestone Task id와 최종 검증 결과를 기록하고, 완료 리뷰에서 S01-S16 Evidence Map과 대조한다.

## Cross-repo Dependencies

- 없음
- `.agent-roadmap-sync/locks.yaml`에 이 milestone을 잠그는 항목이 없다.

## Drift Check

- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
- [x] 사용자 리뷰가 필요한 항목은 남아 있지 않으며 `USER_REVIEW.md`를 만들지 않았다.

## 사용자 리뷰 이력

- 2026-08-02: execution preset, direct/light 현재 범위, heavy/추가 mode 확장, request identity, workspace artifact, visible streaming, 오류·취소와 외부 workflow 비의존 경계를 대화에서 확정했다.
- 2026-08-05: 사용자가 logical request와 caller continuation을 one-shot으로 보는 해석을 철회했다. Claude의 실제 POST 1회, IOP/Mac Node-owned workspace/tool loop, Gemini high plan → ornith-fast work → Gemini high review/repair를 최종 방향으로 확정했다.
- 2026-08-06: 기존 route-01은 구현된 기반까지 완료·아카이빙하고, 최종 구조는 별도 route-02로 분리하도록 확정했다.

## 작업 컨텍스트

- 표준선: 기존 top-level model catalog/provider pool, endpoint-native tool call/result, Stream Evidence Gate의 normalized event·terminal gate·exactly-once commit을 재사용한다.
- 구현 순서: config/preset catalog → request coordinator → direct → workspace prepare/Plan·Review pair → local/review/repair → protocol gate → cleanup/observability/smoke 순이다.
- 후속 SDD: [IOP 단일 요청 Agent 실행](../../../../sdd/knowledge-tool-optimization-extension/iop-owned-single-request-agent-execution/SDD.md), [Heavy Plan/Review 실행과 검증 MVP](../../../../phase/knowledge-tool-optimization-extension/milestones/knowledge-tool-validation-optimization.md), [Execution Preset 하이브리드 Mode 라우팅](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-hybrid-request-execution-routing.md), [RAG 기반 Local Routing Model 운영 전환](../../../../phase/knowledge-tool-optimization-extension/milestones/rag-local-routing-model-operations.md)
