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

## 위치

- Roadmap: [ROADMAP.md](../../../../ROADMAP.md)
- Phase: [PHASE.md](../../../../phase/knowledge-tool-optimization-extension/PHASE.md)
- SDD: [SDD.md](../../../sdd/knowledge-tool-optimization-extension/iop-hot-path-one-shot-execution/SDD.md)

## 목표

외부에 노출하는 IOP model을 단일 provider target이 아니라 **실행 방식 전체를 정의하는 execution preset**에 연결한다.
각 preset은 허용 execution mode, fused selector/planner, mode별 downstream stage 순서와 stage별 model/options를 소유하며, 외부 호출자는 preset에 매핑된 model만 선택한다.
초기 Hot Path preset은 `direct`와 lightweight Plan/Review인 `light`를 제공한다. `direct`는 고성능·high-thinking·tool 사용도 가능한 Plan/Review 없는 경로이고, `light`는 cloud plan, local agent work, cloud review와 defect repair를 하나의 논리적 `request_id`로 연결한다.
이 마일스톤은 후속 `heavy` Plan/Review와 cloud-first 하이브리드 라우팅, RAG local router가 같은 preset·mode·decision contract를 확장할 수 있는 첫 vertical slice다.

이 구현은 execution preset, logical request coordinator, direct/light stage, endpoint codec과 관측 기반을 완료했지만 caller tool continuation을 사용하는 과도기 구조였다. 이는 “workspace 도구 실행은 외부 agent가 소유한다”는 제품 원칙이 아니며 최종 one-shot acceptance도 아니다. 사용자가 확정한 Claude 요청 정확히 1회와 IOP-owned Mac Node workspace/tool loop는 별도 후속 [[route-02] IOP 단일 요청 Agent 실행](../../../../phase/knowledge-tool-optimization-extension/milestones/iop-owned-single-request-agent-execution.md)이 소유한다.

## 상태

[완료]

## 구현 잠금

- 상태: 해제
- SDD: 필요
- SDD 문서: [IOP 실행 프리셋과 Hot Path SDD](../../../sdd/knowledge-tool-optimization-extension/iop-hot-path-one-shot-execution/SDD.md)
- SDD 사유: config/API schema, cross-call state machine, request identity/idempotency, streaming terminal과 artifact lifecycle을 함께 변경한다.
- SDD 상태: 승인됨
- SDD 잠금: 해제
- SDD 사용자 리뷰: 없음
- 잠금 해제 근거:
  - [x] execution preset이 외부 model에 매핑되는 전체 실행 정책이라는 경계를 확정했다.
  - [x] 현재 구현 범위를 `direct + light`와 Claude/Pi streaming으로 한정하고 `heavy`와 추가 mode의 확장 지점을 분리했다.
  - [x] `request_id`, workspace Plan/Review pair, stage 전이, 전체 사용자 출력, 오류·취소와 cleanup 기준을 확정했다.
  - [x] 필수 SDD를 작성하고 사용자 결정 사항을 반영했다.
- 결정 필요: 없음

## 범위

### 1. Execution preset과 외부 model

- top-level model catalog의 외부 model id는 기존 provider pool route 또는 execution preset 중 정확히 하나를 가리킨다.
- preset은 mode 내부의 model 묶음이 아니라 fused selector/planner, 허용 mode 집합, mode별 downstream stage 순서, 각 stage의 model reference와 옵션을 포함하는 전체 실행 정책이다.
- 현재 handler에서 `direct`는 selector/planner 결과와 tool loop를 그대로 사용해 downstream model stage가 없고, `light`는 downstream `local`, `review` stage를 순서대로 사용한다. `review` binding은 review 작성, 결과 확인과 defect repair가 끝날 때까지 고정한다.
- stage model reference는 raw provider/target이 아니라 기존 canonical model/resource를 가리킨다. managed credential mode에서는 각 reference가 같은 principal의 기존 projected route에 정확히 하나로 해석될 때만 virtual preset model을 노출·실행하며, 각 stage dispatch가 최신 route/credential binding을 재검증한다.
- 초기 mode 이름은 `direct`, `light`, `heavy`지만 config와 runtime은 등록된 mode handler를 조회하는 확장 가능한 key를 사용한다. 알 수 없거나 아직 구현되지 않은 mode는 시작 시 검증 오류로 거부한다.
- 같은 mode라도 preset마다 cloud/local model 배치와 thinking·timeout·token 옵션을 다르게 구성할 수 있다.
- `plan-only` preset은 `direct`를 제외할 수 있고, `high-think-one-shot` preset은 `direct`만 허용할 수 있다. 현재 구현에서는 등록된 `direct`와 `light` 조합만 실행 가능하다.
- current fused selector/planner는 별도 hidden marker나 mode-only 응답을 만들지 않는다. issued request path의 정확한 prepare/Plan·Review control tool-call shape가 `light` 후보이고 reserved artifact call이 없는 정상 content/reasoning/일반 작업 tool call은 `direct` 후보이며, Edge가 preset allowlist, capability, health와 config를 검증해 최종 mode와 stage binding을 확정한다. 자연어 reasoning은 route 권한으로 파싱하지 않는다.
- preset catalog와 model→preset mapping은 logical request 시작 시 immutable generation으로 고정한다. config refresh는 새 request에만 적용하고 진행 중인 tool round-trip의 mode/stage/model binding을 바꾸지 않는다.

### 2. 논리 요청과 workspace artifact

- 최초 사용자 요청에 IOP가 caller가 덮어쓸 수 없는 path-safe opaque `request_id`를 발급하고, 이후 endpoint call, public/provider tool call/result, stage, provider attempt와 session id를 그 하위 identity로 연결한다. 이 id는 권한 증명이 아니며 Hot Path 전용 id를 별도로 만들지 않는다.
- logical request 시작 시 endpoint별 normalized request lineage와 선택 workspace tool binding fingerprint를 고정한다. continuation은 과거 request/tool transcript와 선택 tool schema를 그대로 보존해야 하며 변조·교체된 history는 같은 `request_id`에 연결하지 않는다.
- 현재 coordinator state는 Edge-local transient state다. tool continuation은 같은 Edge로 돌아와야 하며 state가 없는 failover/restart 요청을 새 `request_id`로 시작하지 않고 표준 오류로 닫는다. cross-Edge/durable resume은 현재 범위가 아니다.
- plan-bearing mode는 agent에 이미 제공된 structured file 또는 command tool을 정상 tool call로 사용해 현재 workspace의 `.iop/job/<request_id>/plan.md`와 `review.md`를 pair로 만든다.
- preset은 canonical workspace prepare-directory/read/write/delete operation과 caller tool schema를 양방향 변환하는 declarative ordered binding alternatives를 가진다. binding은 actual tool schema matcher, argument encoder, result success/error matcher와 missing parent 생성 보장 여부를 명시한다. Claude/Pi별 이름을 route 조건으로 쓰지 않고 실제 `tools[]` schema로 request-local binding을 고정하며, parent 생성 가능 write 또는 별도 prepare role과 deterministic result 판별을 포함한 조합이 맞지 않으면 admission error로 닫는다.
- plan/review stage model은 canonical artifact operation을 호출하고 Edge가 이를 caller의 실제 tool call로 변환해 사용자 stream에 내보낸 뒤 result를 원 stage call로 역매핑한다. 일반 작업 tool은 caller schema를 그대로 통과시키며 Edge가 실제 tool/workspace operation을 실행하지 않는다. command tool mapping은 fixed path/content, workspace containment와 exact success receipt를 Edge가 합성·검증한다.
- `plan.md`는 작업 목표·제약·검증 기준을 담고, `review.md`는 최초 생성 시 비어 있거나 pending 상태이며 cloud review가 결과·결함·후속 작업을 기록한다.
- manifest, revision 디렉터리, 미래용 빈 구조는 만들지 않는다.
- `direct`는 `.iop/job/<request_id>/`를 만들지 않는다.
- `.iop/job/<request_id>/`는 해당 logical request의 reserved namespace다. write binding이 missing parent 생성을 보장하지 않으면 최초 `light` tool turn은 이 directory를 준비하는 정확히 하나의 tool call로 제한한다. 그 뒤 Plan/Review 생성 turn은 정확한 pair tool call만 허용하고 같은 응답의 다른 작업 tool call이나 임의 sibling path는 거부한다.
- pair tool result는 다음 continuation frontier 하나에서 순서와 무관하게 각각 한 번만 소비하며, 둘 다 성공할 때만 local stage를 시작한다. 누락·중복·unknown result는 표준 validation error다.
- 구현된 route-01 경로는 caller tool continuation으로 workspace 작업을 왕복한다. 이 동작은 당시 구현 경계의 기록일 뿐 IOP의 workspace ownership 원칙이 아니며, route-02에서 IOP Edge/Mac Node 내부 실행으로 대체한다.

### 3. `direct`와 `light` 실행 흐름

- 최초 cloud selector/planner stage는 사용자 요청과 preset control을 한 번에 받아 `direct` 응답·tool 작업을 시작하거나, `light`를 선택해 artifact 작성을 수행한다. 현재 Hot Path에서 mode 판정만을 위한 별도 model stage를 추가하지 않는다. missing parent 준비가 필요하면 `light`를 고정한 채 같은 selector/planner stage의 정상 tool continuation으로 처리하고 mode를 다시 판정하지 않는다.
- `direct`는 같은 logical request에서 직접 응답하거나 agent tool을 사용해 작업하고, Plan/Review stage 없이 완료한다. 빠르거나 약한 model만을 뜻하지 않는다.
- `light`는 최초 stage가 낸 두 artifact tool result가 성공한 뒤 local worker로 전환한다.
- local prompt는 immutable 사용자 작업과 `plan.md`·paired `review.md` 경로를 명시한다. route-01 구현에서는 local model이 caller tool round-trip으로 두 파일을 읽고 작업·검증한 뒤 completion candidate를 냈다.
- Stream Evidence Gate가 local completion terminal을 판정하면 cloud reviewer로 전환한다. reviewer는 필요한 inspection tool round-trip 뒤 `review.md`를 채운다.
- reviewer는 immutable 사용자 작업, artifact path와 committed local 결과 correlation을 입력으로 받는다. review write tool result가 돌아오면 같은 cloud `review` stage/model이 `review.md`를 읽는다. pass이면 cleanup으로 진행하고, defect이면 agent와 정상 tool round-trip으로 수정·검증한 뒤 cleanup으로 진행한다. Edge가 workspace file 내용을 직접 읽거나 review text를 파싱해 verdict를 재판정하지 않는다.
- 현재 `light`는 review transition을 한 번만 수행한다. repair 완료 뒤 두 번째 review loop를 만들지 않으며, repair stage의 정상 tool turn 수를 별도 “수정 횟수” 성공 상태로 제한하지 않는다.

### 4. Streaming, terminal과 오류

- routing, plan, local work, local completion candidate, review, defect, repair와 최종 결과의 의미 있는 content/reasoning/tool-call 출력은 모두 사용자에게 endpoint-native streaming으로 보인다.
- credential, 내부 control prompt와 protocol metadata만 사용자 출력에서 제외한다.
- Stream Evidence Gate는 terminal event만 hold 대상으로 삼고 stage content delta는 release한다. agent가 tool을 실행해야 하는 tool-use/tool-call terminal은 각 HTTP turn을 exactly-once로 정상 종료하고, 다음 ingress를 같은 `request_id`에 연결한다.
- 여러 internal stage가 같은 HTTP turn에서 이어지면 endpoint codec이 internal response-start/terminal을 transition evidence로 소비하고 공개 block/tool id를 충돌 없이 다시 매겨 하나의 outer response envelope로 encode한다. 내부 provider 응답 envelope를 중첩해서 내보내지 않는다.
- 각 HTTP turn은 endpoint-native terminal을 하나씩 갖지만, 한 `request_id`의 logical completion은 마지막 turn에서 한 번만 확정된다. 완료·실패·취소 뒤 같은 request가 stage를 다시 실행하거나 두 번째 completion을 만들지 않는다.
- endpoint usage와 caller output cap은 같은 HTTP turn에서 실행한 internal stage 전체를 기준으로 중복 없이 집계·적용하고, logical request 전체 usage는 `request_id` observability로 별도 연결한다.
- workspace/file-write capability가 없거나 read-only이면 preset admission을 거부하고 해당 endpoint의 표준 API 오류를 반환한다. server-only artifact나 cloud-direct 대체 경로로 조용히 우회하지 않는다.
- timeout, provider/context/config/internal execution 실패는 표준 API 오류, 사용자 abort는 표준 cancellation, 출력 상한은 endpoint-native length terminal로 처리한다. partial-success 전용 상태를 추가하지 않는다.
- 성공한 `light` 요청은 agent tool 경계에서 request directory cleanup을 확인한 뒤 최종 성공하고 server state를 즉시 제거한다. 오류 중 tool round-trip이 가능한 경우 artifact cleanup을 best-effort로 시도한다.
- caller cancel/연결 단절 뒤에는 hidden cleanup 작업을 계속하지 않는다. server state TTL은 IOP state만 회수하며 workspace artifact 삭제를 보장하지 않으므로, 남을 수 있는 orphan request id와 reserved relative path를 raw content 없이 관측 가능하게 한다.

## 기능

### Epic: [preset-surface] Execution Preset 표면

- [x] [preset-model] 외부 model catalog entry가 provider route 또는 virtual execution preset 중 하나에 매핑되고, principal별 stage route 해석·authorization과 성공·오류·model echo의 외부 identity를 유지한다.
- [x] [preset-schema] preset이 fused selector/planner, 허용 mode, mode별 downstream ordered stage와 stage별 model reference/options를 소유하고 logical request가 immutable config generation을 고정한다.
- [x] [route-selector] fused selector/planner의 structural direct/light output shape를 Edge가 preset allowlist와 deterministic capability/health gate로 검증해 별도 marker·자연어 parsing 없이 최종 mode와 stage binding을 확정한다.
- [x] [hot-preset] 초기 Hot Path preset이 `direct`와 `light`를 실행하고 등록되지 않았거나 구현되지 않은 `heavy`/추가 mode binding을 시작 시 거부한다.

### Epic: [request-flow] Request Coordinator와 Plan/Review

- [x] [request-identity] 하나의 `request_id`가 같은 principal의 여러 endpoint call, public/provider tool call/result, stage, provider attempt와 session을 연결하고 immutable request lineage/tool binding을 보존하면서 반복되는 전체 history와 새 continuation frontier를 구분한다.
- [x] [artifact-pair] 최초 cloud selector/planner가 `light`를 선택하면 canonical artifact operation을 실제 caller tool로 양방향 매핑해 필요할 때 reserved request directory를 먼저 준비하고 정확한 Plan/Review pair만 만든 뒤, 각 expected result frontier와 deterministic success를 검증하고 pair 결과를 순서와 무관하게 확인한 뒤 local stage로 전환한다.
- [x] [direct-flow] `direct`가 Plan/Review artifact 없이 응답·high-thinking·agent tool 작업을 수행하고 정상 완료한다.
- [x] [light-flow] `light`가 cloud plan → local agent work → cloud review write → cloud review-resolution/repair를 수행하고 Edge의 review file 직접 읽기나 두 번째 review loop 없이 완료한다.
- [x] [cleanup] 성공 시 agent tool result로 request artifact 삭제를 확인하고 server state를 정리하며, cancel/연결 단절에서는 server TTL과 workspace orphan 관측의 책임을 분리한다.

### Epic: [stream-protocol] Stream과 Agent Protocol

- [x] [terminal-control] Stream Evidence Gate를 terminal-only hold로 재사용하고 cross-stage response envelope, block/tool id, usage/output cap을 endpoint codec에서 일관되게 합성해 HTTP turn terminal과 logical completion의 exactly-once 경계를 분리한다.
- [x] [anthropic-gate] Claude가 사용하는 native Anthropic `/v1/messages` streaming에 normalized event codec, terminal gate와 request continuation correlation을 연결한다.
- [x] [chat-gate] Pi가 사용하는 OpenAI `/v1/chat/completions` streaming에서 tool call/result와 stage 전이를 동일한 `request_id`로 연결한다.
- [x] [error-cancel] endpoint별 표준 오류, timeout, cancellation과 length terminal을 유지하고 custom partial-success 상태를 만들지 않는다.

### Epic: [quality-ops] 검증과 운영

- [x] [preset-validation] model/preset one-of, stage route authorization, mode handler, declarative workspace tool schema·argument·result·containment binding, reserved path와 option 범위를 load/admission에서 fail-closed 검증한다.
- [x] [route-observability] request/preset/mode/stage/attempt identity, route 근거, timing과 terminal outcome을 raw prompt·output·credential 없이 관측한다.
- [x] [hot-smoke] 기존 Claude/Pi caller-continuation smoke는 최종 제품 구조를 검증하지 않으므로 수행하지 않고 종료 범위에서 제외했다. 실제 검증은 route-02의 Claude 단일 POST smoke로 이관했다.

## 완료 리뷰

- 상태: 통과
- 요청일: 2026-08-06
- 완료 근거: execution preset/config generation, request coordinator, direct/light flow, artifact pair, endpoint terminal/error, cleanup과 raw-free observability 구현 및 각 `agent-task/m-iop-hot-path-one-shot-execution/**/complete.log` 근거를 완료했다. 사용자가 기존 route-01을 완료·아카이빙하고 최종 one-shot 구조를 route-02로 분리하도록 승인했다.
- 검토 항목: 없음
- 리뷰 코멘트: 기존 Claude/Pi cross-call live smoke는 사용자가 확정한 제품 구조가 아니므로 완료 조건에서 제외했다. route-01 산출물은 route-02가 재사용할 구현 기반이며 exact single-request 제품 acceptance로 해석하지 않는다.

## 범위 제외

- `heavy`의 장기 Plan/Review lifecycle, 재계획, 여러 review cycle와 사람 승인
- Claude→IOP `/v1/messages` POST 정확히 1회 안에서 IOP Edge/Mac Node가 workspace tool loop와 Gemini plan → ornith-fast work → Gemini review/repair를 완료하는 구조
- cloud evidence를 학습 corpus로 승격하거나 RAG local router를 운영하는 기능
- 범용 DAG/workflow/plugin engine과 미래 mode를 위한 manifest·revision·빈 디렉터리
- target agent별 hook/adapter 설치, Claude/Pi 프로세스 패치 또는 agent update 수명주기 추적
- 범용 interactive terminal/PTY, desktop session, 독립 scheduler와 장기 workflow
- `/v1/responses`, A2A와 IOP native protocol의 execution preset 지원
- cross-Edge state replication, Edge restart 뒤 continuation과 durable resume
- provider 설치, model 다운로드, hardware qualification과 credential 관리

## 작업 컨텍스트

- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/edge/internal/authprojection`, `apps/edge/internal/controlplane`, `packages/go/config`, `packages/go/streamgate`, `configs/edge.yaml`
- 관련 계약: [OpenAI-Compatible API Contract](../../../../../agent-contract/outer/openai-compatible-api.md), [Anthropic-Compatible Messages API Contract](../../../../../agent-contract/outer/anthropic-compatible-api.md), [Edge Config And Runtime Refresh Contract](../../../../../agent-contract/inner/edge-config-runtime-refresh.md), [Control Plane-Edge Wire Contract](../../../../../agent-contract/inner/control-plane-edge-wire.md), [Edge-Node Runtime Wire Contract](../../../../../agent-contract/inner/edge-node-runtime-wire.md)
- 현재 구현 기준: [Stream Evidence Gate 구현 스펙](../../../../../agent-spec/runtime/stream-evidence-gate.md)
- 표준선(선택): preset stage의 model reference는 기존 canonical model/provider resolution을 재사용하며 provider id나 target 의미를 core에 하드코딩하지 않는다.
- 표준선(선택): `request_id`는 하나의 사용자 작업 identity이고 각 HTTP call의 endpoint request id, tool call id와 provider session/attempt id는 그 하위 correlation이다.
- 구현 당시 경계: caller tool round-trip 때문에 개별 HTTP stream이 endpoint-native terminal로 닫히고 다음 ingress가 같은 logical request를 이어갈 수 있었다. 이 경계는 route-01의 과거 구현 사실이며 최종 one-shot 정의가 아니다.
- 후속 제품 표준선: [[route-02] IOP 단일 요청 Agent 실행](../../../../phase/knowledge-tool-optimization-extension/milestones/iop-owned-single-request-agent-execution.md)은 실제 Claude→IOP POST 1회 안에서 IOP Edge/Mac Node가 request-scoped workspace/tool execution을 소유한다.
- 선행 작업: [Stream Evidence Gate Core](stream-evidence-gate-core.md)
- 후속 작업: [[route-02] IOP 단일 요청 Agent 실행](../../../../phase/knowledge-tool-optimization-extension/milestones/iop-owned-single-request-agent-execution.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)
- 종료 정리: 기존 이름과 `[route-01]` identity를 유지해 완료·아카이빙했으며 활성 실행 큐에서는 제거했다.
- 실행 순서와 차단 관계: [전역 마일스톤 실행 순서](../../../../priority-queue.md)
- 확인 필요: 없음
