From 0565d2be66ccac0ea189ce9b9910e0fa190b634b Mon Sep 17 00:00:00 2001 From: toki Date: Tue, 28 Jul 2026 06:18:14 +0900 Subject: [PATCH] chore: sync roadmap, spec, contract updates and stream evidence gate --- agent-contract/outer/openai-compatible-api.md | 10 +- .../milestones/stream-evidence-gate-core.md | 34 +++--- .../stream-evidence-gate-core/SDD.md | 14 +-- .../PHASE.md | 4 +- agent-roadmap/priority-queue.md | 53 ++++---- agent-spec/index.md | 2 + agent-spec/input/openai-compatible-surface.md | 13 +- .../runtime/provider-pool-config-refresh.md | 9 +- agent-spec/runtime/stream-evidence-gate.md | 113 ++++++++++++++++++ 9 files changed, 192 insertions(+), 60 deletions(-) rename agent-roadmap/{ => archive}/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md (84%) rename agent-roadmap/{ => archive}/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md (97%) create mode 100644 agent-spec/runtime/stream-evidence-gate.md diff --git a/agent-contract/outer/openai-compatible-api.md b/agent-contract/outer/openai-compatible-api.md index 75befb7..9afa7be 100644 --- a/agent-contract/outer/openai-compatible-api.md +++ b/agent-contract/outer/openai-compatible-api.md @@ -81,17 +81,15 @@ Edge는 이 값을 provider tunnel request의 `openai.provider_auth.target_heade - normalized Chat Completions stream의 런타임 오류는 같은 `type/message` envelope를 SSE `data`로 한 번 쓰고 `[DONE]`으로 종료한다. - normalized `/v1/responses`는 현재 streaming을 지원하지 않는다. provider-pool raw passthrough stream은 선택된 provider의 status/header/body를 그대로 relay하며 IOP envelope로 감싸지 않는다. -### 계획된 Stream Evidence Gate 오류 확장 +### Stream Evidence Gate ingress 및 terminal 오류 Chat Completions와 Responses ingress에는 configured request snapshot 상한이 body 첫 read 전에 적용된다. body 또는 typed semantic view가 상한을 넘거나 rebuild peak 회계가 실패하면 provider admission 없이 HTTP `413`, `error.type="invalid_request_error"` 한 번으로 종료한다. 이 오류의 `message`는 내부 byte 수, snapshot reference, Core 오류 이름을 노출하지 않는다. 기존 public error body는 계속 `error.type`과 `error.message`만 가지며 size/trace/causes 같은 필드를 추가하지 않는다. -위 bounded ingress/size 오류 호환성은 활성 계약이다. 아래 복구 terminal 확장은 전체 Stream Evidence Gate cycle 조립 전까지 구현 목표로 남는다. +위 bounded ingress/size 오류 호환성은 활성 계약이다. `openai.stream_evidence_gate.enabled=true`이면 지원되는 Chat Completions와 streaming provider-tunnel 경로가 [완료된 Stream Evidence Gate Core Milestone](../../agent-roadmap/archive/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md)의 request-local runtime을 사용한다. runtime은 response status/header와 opening event를 첫 safe release까지 보류하고, filter 결과를 모두 모은 뒤 release, terminal 또는 bounded recovery 중 하나만 실행한다. 기본값 `false`에서는 기존 compatibility 경로를 유지한다. -[Stream Evidence Gate Core Milestone](../../agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md)이 구현되기 전까지 아래 동작은 활성 외부 API 계약이 아닌 구현 목표다. +복구 요청 조립 또는 dispatch가 실패하면 endpoint별 오류 하나만 보낸다. 내부 원인 사슬은 raw stack trace, provider endpoint/body, user prompt, output/reasoning 원문, tool args/result, 인증 정보를 포함하지 않으며 외부 JSON/SSE에 `causes`, `stack`, `trace` 같은 확장 필드로 노출하지 않는다. -반복 복구 안내문은 언어 판별이나 번역용 보조 모델을 호출하지 않고 고정 영어 문구를 사용한다. 이 경로에는 보조 모델 호출 실패 유형을 추가하지 않는다. - -복구 요청 조립 또는 dispatch가 실패하면 Stream Evidence Gate 구현이 정한 기존 terminal 오류 분류로 endpoint별 오류 하나만 보낸다. 내부 원인 사슬은 raw stack trace, provider endpoint/body, user prompt, output/reasoning 원문, tool args/result, 인증 정보를 포함하지 않으며 외부 JSON/SSE에 `causes`, `stack`, `trace` 같은 확장 필드로 노출하지 않는다. +Core 활성화만으로 반복, missing tool-call, schema 같은 semantic filter가 자동 활성화되지는 않는다. 현재 production registry는 공통 mechanics와 적용 가능한 request-local tool validation을 제공하며, 추가 semantic filter와 corrective directive는 각 소비 Milestone이 등록한다. ## Responses API diff --git a/agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md b/agent-roadmap/archive/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md similarity index 84% rename from agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md rename to agent-roadmap/archive/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md index 467dea5..f4cb483 100644 --- a/agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md +++ b/agent-roadmap/archive/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md @@ -2,8 +2,8 @@ ## 위치 -- Roadmap: [ROADMAP.md](../../../ROADMAP.md) -- Phase: [PHASE.md](../PHASE.md) +- Roadmap: [ROADMAP.md](../../../../ROADMAP.md) +- Phase: [PHASE.md](../../../../phase/knowledge-tool-optimization-extension/PHASE.md) ## 목표 @@ -12,7 +12,7 @@ OpenAI-compatible output validation, incomplete tool-call syntax, missing tool-c ## 상태 -[진행중] +[완료] ## 구현 잠금 @@ -60,27 +60,31 @@ OpenAI-compatible output validation, incomplete tool-call syntax, missing tool-c 선택된 intent를 bounded recovery plan으로 만들고 current attempt 종료부터 lossless request rebuild와 단일 재admission까지의 실행 소유권을 공통화한다. -- [ ] [recovery-coordinator] Arbiter가 선택한 하나의 `RecoveryIntent`를 strategy별 budget, fault recovery의 request 전체 `max_recovery_attempts_total` hard cap, caller cancel, terminal/tool side effect, strategy별 commit eligibility, same-plan re-entry guard로 검증해 `exact_replay|continuation_repair|schema_repair|managed_continuation` 중 하나의 `RecoveryPlan`으로 만든다. fault recovery 전체 cap은 최초 provider 실행을 제외한 exact/schema/provider-error/일반 repair dispatch를 합산하며 기본값이자 MVP 절대 상한은 3회다. provider output-cap terminal의 managed continuation은 오류 recovery가 아니라 progress trajectory로 분류하고, request 시작 시 고정한 attempt cap·context window·reserve·consumer가 고정한 optional caller logical output cap과 Rebuilder가 조립 뒤 측정한 `rebuilt_prompt_tokens`의 다음 allowance가 남을 때만 별도 `ManagedTrajectoryBudget`으로 dispatch한다. assistant prefix는 rebuilt prompt에 포함되므로 누적 output과 이중 계상하지 않는다. fault cap은 strategy cap보다 우선하고 어느 cap이든 소진되면 다른 fault filter/strategy로 우회하지 않고 terminal로 끝낸다. exact/schema는 `transport_uncommitted`에서만 replace-attempt로 실행하고, continuation은 `stream_open`에서도 released safe prefix/cursor를 보존한 continue-stream plan으로 실행할 수 있다. plan 선택 시 Core는 preparer/continuation에 필요한 bounded request-local snapshot과 cursor를 immutable하게 고정한다. 새 dispatch 전에 현재 `AttemptController`의 provider transport ownership만 idempotent cancel/close하고 실패하면 두 provider를 병행하지 않고 terminal로 끝낸다. 선택된 plan이 consumer별 보조 준비를 요구하면 Core는 all-complete/Arbiter와 attempt ownership 종료 뒤 optional `RecoveryPlanPreparer`를 plan/idempotency key당 최대 1회, bounded deadline으로 호출한다. preparer는 Filter 병렬 평가에 참여하거나 provider 선택/retry/fallback을 실행하지 않으며 실패는 dispatch 없이 terminal로 끝난다. recovery budget은 preparer 호출이 아니라 실제 outbound recovery dispatch 직전에만 소비하고 bounded preparation snapshot은 성공·실패·cancel 뒤 release한다. cycle당 plan/dispatch는 하나지만 두 cap에 여유가 있으면 다음 attempt 결과를 새 cycle로 평가한다. 검증: 동시 violation, pre/post-commit strategy matrix, 0/1/3회 policy와 4회 이상 config rejection, strategy cap과 request 전체 cap의 교차 소진, bounded multi-cycle, snapshot-freeze/transport-only abort, abort-before-prepare/dispatch, preparer 단일 호출/deadline/failure-no-budget/snapshot-release, cancel/side-effect/re-entry fixture가 통과한다. -- [ ] [request-rebuilder] transport-agnostic Coordinator가 기본값이자 MVP 절대 상한 16 MiB이며 request 시작 시 immutable하게 고정되는 `max_ingress_snapshot_bytes` 안의 request-local lossless ingress snapshot과 selected directive를 endpoint/family별 `RequestRebuilder`에 전달하고, host `AttemptDispatcher`가 새 admission과 concrete provider/model/auth 계산을 수행한다. host는 `io.ReadAll` 전에 `http.MaxBytesReader` 또는 동등한 limit+1 판정으로 raw body를 제한하며 policy는 16 MiB 이하로만 낮출 수 있다. OpenAI JSON endpoint는 raw body를 canonical lossless representation으로 보존하고, 다른 lossless tree는 byte-preserving round-trip fixture가 있는 codec만 허용한다. `retained_bytes`는 runtime heap 추정치가 아니라 request가 소유한 backing byte/string buffer의 보수적 logical byte 합이며 shared backing은 한 번만 센다. SnapshotBuilder는 필요한 bounded typed semantic view를 더한 직후, RequestRebuilder는 임시 output을 할당하기 전과 후에 current peak를 다시 검사하고 canonical full copy를 둘 이상 유지하지 않는다. raw body가 pre-read gate와 같아도 typed view를 포함한 total retained limit을 넘으면 dispatch 전에 거부한다. ingress limit 초과는 snapshot 생성/provider dispatch 전에 fail-closed하며 filter/로그/cross-request cache에 원문을 노출하지 않고 auth도 저장하지 않는다. rebuilt request도 같은 limit을 다시 확인하고 request 종료/cancel/overflow에서 retained object를 release한다. dispatcher는 actual model/provider/execution path와 normalized event source를 가진 `AttemptBinding`을 반환하며 normalized↔tunnel path 전환도 같은 Core cycle에 연결한다. 검증: caller raw body/unknown field 보존, continuation/schema typed patch, Chat/Responses serializer, auth 비보존, provider/path 전환, pre-read raw body limit-1/limit/limit+1, exact-limit body+typed-view overflow, 16 MiB 초과 config rejection, shared-backing logical peak accounting과 rebuild 전후 overflow/no-dispatch/no-raw-log/release fixture가 통과한다. +- [x] [recovery-coordinator] Arbiter가 선택한 하나의 `RecoveryIntent`를 strategy별 budget, fault recovery의 request 전체 `max_recovery_attempts_total` hard cap, caller cancel, terminal/tool side effect, strategy별 commit eligibility, same-plan re-entry guard로 검증해 `exact_replay|continuation_repair|schema_repair|managed_continuation` 중 하나의 `RecoveryPlan`으로 만든다. fault recovery 전체 cap은 최초 provider 실행을 제외한 exact/schema/provider-error/일반 repair dispatch를 합산하며 기본값이자 MVP 절대 상한은 3회다. provider output-cap terminal의 managed continuation은 오류 recovery가 아니라 progress trajectory로 분류하고, request 시작 시 고정한 attempt cap·context window·reserve·consumer가 고정한 optional caller logical output cap과 Rebuilder가 조립 뒤 측정한 `rebuilt_prompt_tokens`의 다음 allowance가 남을 때만 별도 `ManagedTrajectoryBudget`으로 dispatch한다. assistant prefix는 rebuilt prompt에 포함되므로 누적 output과 이중 계상하지 않는다. fault cap은 strategy cap보다 우선하고 어느 cap이든 소진되면 다른 fault filter/strategy로 우회하지 않고 terminal로 끝낸다. exact/schema는 `transport_uncommitted`에서만 replace-attempt로 실행하고, continuation은 `stream_open`에서도 released safe prefix/cursor를 보존한 continue-stream plan으로 실행할 수 있다. plan 선택 시 Core는 preparer/continuation에 필요한 bounded request-local snapshot과 cursor를 immutable하게 고정한다. 새 dispatch 전에 현재 `AttemptController`의 provider transport ownership만 idempotent cancel/close하고 실패하면 두 provider를 병행하지 않고 terminal로 끝낸다. 선택된 plan이 consumer별 보조 준비를 요구하면 Core는 all-complete/Arbiter와 attempt ownership 종료 뒤 optional `RecoveryPlanPreparer`를 plan/idempotency key당 최대 1회, bounded deadline으로 호출한다. preparer는 Filter 병렬 평가에 참여하거나 provider 선택/retry/fallback을 실행하지 않으며 실패는 dispatch 없이 terminal로 끝난다. recovery budget은 preparer 호출이 아니라 실제 outbound recovery dispatch 직전에만 소비하고 bounded preparation snapshot은 성공·실패·cancel 뒤 release한다. cycle당 plan/dispatch는 하나지만 두 cap에 여유가 있으면 다음 attempt 결과를 새 cycle로 평가한다. 검증: 동시 violation, pre/post-commit strategy matrix, 0/1/3회 policy와 4회 이상 config rejection, strategy cap과 request 전체 cap의 교차 소진, bounded multi-cycle, snapshot-freeze/transport-only abort, abort-before-prepare/dispatch, preparer 단일 호출/deadline/failure-no-budget/snapshot-release, cancel/side-effect/re-entry fixture가 통과한다. +- [x] [request-rebuilder] transport-agnostic Coordinator가 기본값이자 MVP 절대 상한 16 MiB이며 request 시작 시 immutable하게 고정되는 `max_ingress_snapshot_bytes` 안의 request-local lossless ingress snapshot과 selected directive를 endpoint/family별 `RequestRebuilder`에 전달하고, host `AttemptDispatcher`가 새 admission과 concrete provider/model/auth 계산을 수행한다. host는 `io.ReadAll` 전에 `http.MaxBytesReader` 또는 동등한 limit+1 판정으로 raw body를 제한하며 policy는 16 MiB 이하로만 낮출 수 있다. OpenAI JSON endpoint는 raw body를 canonical lossless representation으로 보존하고, 다른 lossless tree는 byte-preserving round-trip fixture가 있는 codec만 허용한다. `retained_bytes`는 runtime heap 추정치가 아니라 request가 소유한 backing byte/string buffer의 보수적 logical byte 합이며 shared backing은 한 번만 센다. SnapshotBuilder는 필요한 bounded typed semantic view를 더한 직후, RequestRebuilder는 임시 output을 할당하기 전과 후에 current peak를 다시 검사하고 canonical full copy를 둘 이상 유지하지 않는다. raw body가 pre-read gate와 같아도 typed view를 포함한 total retained limit을 넘으면 dispatch 전에 거부한다. ingress limit 초과는 snapshot 생성/provider dispatch 전에 fail-closed하며 filter/로그/cross-request cache에 원문을 노출하지 않고 auth도 저장하지 않는다. rebuilt request도 같은 limit을 다시 확인하고 request 종료/cancel/overflow에서 retained object를 release한다. dispatcher는 actual model/provider/execution path와 normalized event source를 가진 `AttemptBinding`을 반환하며 normalized↔tunnel path 전환도 같은 Core cycle에 연결한다. 검증: caller raw body/unknown field 보존, continuation/schema typed patch, Chat/Responses serializer, auth 비보존, provider/path 전환, pre-read raw body limit-1/limit/limit+1, exact-limit body+typed-view overflow, 16 MiB 초과 config rejection, shared-backing logical peak accounting과 rebuild 전후 overflow/no-dispatch/no-raw-log/release fixture가 통과한다. ### Epic: [integration-adoption] Vertical Slice와 Consumer Adoption 공통 mechanics를 실제 host cycle로 연결하고 raw-free 관측과 후속 consumer 문서 계약까지 닫아 중복 구현을 방지한다. -- [ ] [vertical-slice] production semantic filter보다 먼저 model/provider별 on/off 가능한 `NoopFilter`와 test-only `InjectedViolationFilter`로 `request snapshot → host dispatch → staged response-start → Core evidence hold → parallel filters → all-complete Arbiter → RecoveryPlan → abort → optional prepare → rebuild → single re-admission → release` 한 사이클을 얇게 완성한다. 검증: disabled passthrough, enabled pass, eager header/role 없음, injected violation one retry success, optional preparer success/failure, two violation single retry, provider/path switch, filter failure mode, backpressure, retry exhausted terminal fixture가 통과한다. -- [ ] [filter-observation] Core가 filter/coordinator decision마다 기존 request/run/provider/model correlation과 config generation, attempt/epoch, `consumer_id`, `filter_id`, `rule_id`, hold mode, event kind, effective/pending rune, decision/error policy, commit state, terminal reason, plan id/strategy/shared attempt, preparer id/status/deadline outcome, 최대 4개의 sanitized cause code와 consumer-provided sanitized evidence를 하나의 `FilterObservation` timeline event로 emit한다. 저장·보존은 기존 observability sink가 소유한다. preparer input/output와 raw output/prompt/tool args/result/auth 값은 허용하지 않으며 filter가 평가되지 않은 delta마다 observation을 만들지 않는다. 검증: 병렬 filter 시작/완료, response staging, arbitration, release/terminal/recovery/abort/prepare/rebuild/dispatch가 하나의 request timeline에서 stable id, bounded cause와 sanitized fingerprint/count/offset만으로 추적된다. -- [x] [adoption-doc] [OpenAI-compatible 출력 검증 필터](openai-compatible-output-validation-filters.md), [OpenAI-compatible Incomplete Tool Call Syntax Gate](openai-compatible-incomplete-tool-call-syntax-gate.md), [OpenAI-compatible Runtime Output Integrity Filter](openai-compatible-runtime-output-integrity-filter.md), [LLM 판별 기반 Missing Tool Call 재시도 Gate](llm-judged-missing-tool-call-retry-gate.md), [에이전트 작업 루프 오케스트레이션 MVP](../../automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md)에 이 Core의 소비 경계, 각자 남는 semantic policy/intent, stable filter id와 `FilterObservation` mapping, 공통 RecoveryPlan 및 bounded `FailureCauseChain`/endpoint별 단일 외부 오류 직렬화 사용을 기록한다. recovery consumer는 strategy/request-total cap을, ingress snapshot consumer는 bounded snapshot을 사용한다. 검증: 각 Milestone이 자신에게 적용되는 Core interface와 limit을 명시하고 raw stream buffer·request snapshot/rebuild·retry loop·공개 오류 사슬 직렬화를 재구현하지 않는다. +- [x] [vertical-slice] production semantic filter보다 먼저 model/provider별 on/off 가능한 `NoopFilter`와 test-only `InjectedViolationFilter`로 `request snapshot → host dispatch → staged response-start → Core evidence hold → parallel filters → all-complete Arbiter → RecoveryPlan → abort → optional prepare → rebuild → single re-admission → release` 한 사이클을 얇게 완성한다. 검증: disabled passthrough, enabled pass, eager header/role 없음, injected violation one retry success, optional preparer success/failure, two violation single retry, provider/path switch, filter failure mode, backpressure, retry exhausted terminal fixture가 통과한다. +- [x] [filter-observation] Core가 filter/coordinator decision마다 기존 request/run/provider/model correlation과 config generation, attempt/epoch, `consumer_id`, `filter_id`, `rule_id`, hold mode, event kind, effective/pending rune, decision/error policy, commit state, terminal reason, plan id/strategy/shared attempt, preparer id/status/deadline outcome, 최대 4개의 sanitized cause code와 consumer-provided sanitized evidence를 하나의 `FilterObservation` timeline event로 emit한다. 저장·보존은 기존 observability sink가 소유한다. preparer input/output와 raw output/prompt/tool args/result/auth 값은 허용하지 않으며 filter가 평가되지 않은 delta마다 observation을 만들지 않는다. 검증: 병렬 filter 시작/완료, response staging, arbitration, release/terminal/recovery/abort/prepare/rebuild/dispatch가 하나의 request timeline에서 stable id, bounded cause와 sanitized fingerprint/count/offset만으로 추적된다. +- [x] [adoption-doc] [OpenAI-compatible 출력 검증 필터](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-output-validation-filters.md), [OpenAI-compatible Incomplete Tool Call Syntax Gate](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-incomplete-tool-call-syntax-gate.md), [OpenAI-compatible Runtime Output Integrity Filter](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-runtime-output-integrity-filter.md), [LLM 판별 기반 Missing Tool Call 재시도 Gate](../../../../phase/knowledge-tool-optimization-extension/milestones/llm-judged-missing-tool-call-retry-gate.md), [에이전트 작업 루프 오케스트레이션 MVP](../../../../phase/automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md)에 이 Core의 소비 경계, 각자 남는 semantic policy/intent, stable filter id와 `FilterObservation` mapping, 공통 RecoveryPlan 및 bounded `FailureCauseChain`/endpoint별 단일 외부 오류 직렬화 사용을 기록한다. recovery consumer는 strategy/request-total cap을, ingress snapshot consumer는 bounded snapshot을 사용한다. 검증: 각 Milestone이 자신에게 적용되는 Core interface와 limit을 명시하고 raw stream buffer·request snapshot/rebuild·retry loop·공개 오류 사슬 직렬화를 재구현하지 않는다. ## 완료 리뷰 -- 상태: 없음 -- 요청일: 없음 -- 완료 근거: 기능 Task가 아직 충족되지 않았다. +- 상태: 통과 +- 요청일: 2026-07-28 +- 완료 근거: + - 동일 `m-stream-evidence-gate-core` task group의 archive `complete.log` 25개를 대조했고, 미체크 Task 4개는 정확한 Milestone 경로·Task id·`PASS` 완료 근거를 갖는다. + - 현재 구현 파일과 Git 이력에서 recovery 순서·budget, lossless request rebuild, 실제 Edge vertical cycle, raw-free observation correlation을 확인했다. + - `make proto`, 관련 config refresh test와 `go test -race -count=1 ./packages/go/streamgate ./apps/edge/internal/openai ./packages/go/config`가 현재 코드 트리에서 통과했다. + - 현행 구현 스펙 [Stream Evidence Gate](../../../../../agent-spec/runtime/stream-evidence-gate.md), [OpenAI-compatible 입력 표면](../../../../../agent-spec/input/openai-compatible-surface.md), [Provider Pool Config와 Runtime Refresh](../../../../../agent-spec/runtime/provider-pool-config-refresh.md)와 [외부 OpenAI-compatible API 계약](../../../../../agent-contract/outer/openai-compatible-api.md)을 구현에 맞게 동기화했다. - 검토 항목: - - [ ] 모든 consumer가 동일한 normalized event/release contract를 사용하고 raw parser를 Core에 중복하지 않는다. - - [ ] rolling/terminal/fragment hold, staged response-start, all-filter completion barrier, single-flight backpressure, deterministic single action, idle no-release, strategy별 post-commit eligibility, common RecoveryPlan/rebuild/dispatcher, single terminal sequence와 raw-free `FilterObservation` timeline 검증이 Evidence Map과 일치한다. + - [x] 모든 consumer가 동일한 normalized event/release contract를 사용하고 raw parser를 Core에 중복하지 않는다. + - [x] rolling/terminal/fragment hold, staged response-start, all-filter completion barrier, single-flight backpressure, deterministic single action, idle no-release, strategy별 post-commit eligibility, common RecoveryPlan/rebuild/dispatcher, single terminal sequence와 raw-free `FilterObservation` timeline 검증이 Evidence Map과 일치한다. - agent-ui 상태 반영: 해당 없음 -- 리뷰 코멘트: 없음 +- 리뷰 코멘트: 코드레벨 종료 감사에서 blocking 결함이 없었고 계약·현행 스펙 동기화를 완료했다. 큰 이슈나 별도 plan은 필요하지 않다. ## 범위 제외 @@ -103,5 +107,5 @@ OpenAI-compatible output validation, incomplete tool-call syntax, missing tool-c - 표준선(선택): managed provider length continuation은 filter가 provider output-cap terminal을 의미 판정해 `managed_continuation` intent를 낼 때만 Core가 같은 downstream stream의 safe prefix, look-behind, release cursor와 terminal gate ownership을 보존해 진행한다. 이는 exact/schema/오류 repair의 최대 3회 fault cap과 별도의 context-window trajectory이며, 다음 dispatch allowance는 작은 attempt cap과 `remaining_caller_logical_cap(if set)`과 `context_window - rebuilt_prompt_tokens - reserve`의 최소값으로 계산한다. provider attempt cap은 내부 운영 단위이며 caller cap은 논리 요청 전체에 한 번만 적용한다. rebuilt prompt는 original request와 보존한 assistant prefix를 포함하므로 누적 output을 별도 합산하지 않는다. context 여유 소진, caller cancel, complete tool call/side effect, 미완성 fragment 복구 실패에서는 단일 final terminal로 수렴한다. context 여유 또는 caller logical cap 소진에서만 host가 endpoint-native logical `length` terminal과 단일 종료 marker를 한 번 직렬화하며, attempt 중간 terminal은 commit하지 않는다. - 표준선(선택): `FilterObservation`은 Core가 emit하는 공통 내부 관측 envelope이며, 저장·보존은 기존 observability sink가 소유한다. Core는 기존 request/run/provider/model correlation과 stream lifecycle 필드를 연결하고, consumer는 stable `consumer_id`/`filter_id`/`rule_id`와 fingerprint·count·offset 같은 sanitized evidence만 제공한다. 이는 외부 API field나 raw output 보존 정책을 바꾸지 않는다. - 선행 작업: 없음 -- 후속 작업: [OpenAI-compatible 출력 검증 필터](openai-compatible-output-validation-filters.md), [OpenAI-compatible Incomplete Tool Call Syntax Gate](openai-compatible-incomplete-tool-call-syntax-gate.md), [OpenAI-compatible Runtime Output Integrity Filter](openai-compatible-runtime-output-integrity-filter.md), [LLM 판별 기반 Missing Tool Call 재시도 Gate](llm-judged-missing-tool-call-retry-gate.md), [에이전트 작업 루프 오케스트레이션 MVP](../../automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md) +- 후속 작업: [OpenAI-compatible 출력 검증 필터](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-output-validation-filters.md), [OpenAI-compatible Incomplete Tool Call Syntax Gate](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-incomplete-tool-call-syntax-gate.md), [OpenAI-compatible Runtime Output Integrity Filter](../../../../phase/knowledge-tool-optimization-extension/milestones/openai-compatible-runtime-output-integrity-filter.md), [LLM 판별 기반 Missing Tool Call 재시도 Gate](../../../../phase/knowledge-tool-optimization-extension/milestones/llm-judged-missing-tool-call-retry-gate.md), [에이전트 작업 루프 오케스트레이션 MVP](../../../../phase/automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md) - 확인 필요: 없음 diff --git a/agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md b/agent-roadmap/archive/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md similarity index 97% rename from agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md rename to agent-roadmap/archive/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md index 04df723..e57fa2b 100644 --- a/agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md +++ b/agent-roadmap/archive/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md @@ -3,7 +3,7 @@ ## 위치 - Milestone: [Milestone 문서](../../../phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md) -- Phase: [PHASE.md](../../../phase/knowledge-tool-optimization-extension/PHASE.md) +- Phase: [PHASE.md](../../../../phase/knowledge-tool-optimization-extension/PHASE.md) ## 상태 @@ -33,8 +33,8 @@ |------|------|------| | Roadmap | [Milestone 문서](../../../phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md) | 범위, consumer, 완료 evidence 기준 | | Code | `packages/go/streamgate`, `packages/go/config`, `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/node/internal/runtime`, `apps/node/internal/adapters/openai_compat`, `apps/node/internal/adapters/cli` | transport-agnostic Core와 host codec/rebuilder/dispatcher/release sink의 책임 경계 | -| Contract | [openai-compatible-api.md](../../../../agent-contract/outer/openai-compatible-api.md) | OpenAI caller surface는 기존 계약을 유지하고 Core는 내부 normalized event만 소비한다 | -| Config Contract | [edge-config-runtime-refresh.md](../../../../agent-contract/inner/edge-config-runtime-refresh.md) | limit 정책의 실제 config field/default/validation/refresh 분류를 구현할 때 함께 갱신한다. 현재 active 계약에 미구현 field를 선반영하지 않는다. | +| Contract | [openai-compatible-api.md](../../../../../agent-contract/outer/openai-compatible-api.md) | OpenAI caller surface는 기존 계약을 유지하고 Core는 내부 normalized event만 소비한다 | +| Config Contract | [edge-config-runtime-refresh.md](../../../../../agent-contract/inner/edge-config-runtime-refresh.md) | limit 정책의 실제 config field/default/validation/refresh 분류를 구현할 때 함께 갱신한다. 현재 active 계약에 미구현 field를 선반영하지 않는다. | | User Decision | 현재 사용자 요청 | 기본 500-rune evidence hold, no time-based release, 공통 Core 분리, model/provider별 filter on/off, 동일 immutable evidence batch의 활성 filter 병렬 평가와 all-complete barrier, filter intent를 하나의 공통 RecoveryPlan으로 재조립·재admission하는 Coordinator를 같은 Milestone에 두는 방향이 확정됐다. consumer별 외부 보조 준비는 filter barrier 안이 아니라 plan 선택/current attempt 종료 뒤 optional `RecoveryPlanPreparer`로 직렬화한다. terminal failure는 bounded sanitized 원인 사슬을 내부에 보존하고 endpoint host가 외부 OpenAI-compatible 오류로 한 번만 평탄화한다. cross-request 오류 사건의 중복 집계와 LLM 기반 소스 분석·수정 제안·승인·변경 요청·병합·배포는 Core 밖의 별도 범용 플랫폼으로 프로젝트화한다. | | Managed Length Decision | 현재 사용자 요청 | provider output-cap terminal은 semantic filter가 판정하고 Core는 same-stream continuation mechanics만 제공한다. managed profile은 작은 provider attempt `max_tokens`로 dispatch하며, 원본 요청과 channel별 assistant prefix를 rebuild한 논리 trajectory는 실제 context window 여유와 reserve, caller가 명시한 경우 logical output cap으로 제한한다. provider attempt cap은 내부 운영값이고 caller cap은 논리 요청 전체에 한 번만 적용한다. 이는 fault recovery 3회 cap과 별도다. | @@ -62,7 +62,7 @@ ## Interface Contract -- 계약 원문: [openai-compatible-api.md](../../../../agent-contract/outer/openai-compatible-api.md) +- 계약 원문: [openai-compatible-api.md](../../../../../agent-contract/outer/openai-compatible-api.md) - 입력: - `NormalizedEvent`: codec이 생성한 `response_start`, `text_delta`, `reasoning_delta`, `tool_call_fragment`, `terminal`, `provider_error` 중 하나다. `terminal`은 provider terminal reason(예: output-cap `length`)을 raw body 없이 typed metadata로 포함할 수 있다. `response_start`는 status와 host가 allowlist로 정규화한 header metadata를 포함한다. hop-by-hop header와 body 변환 시 무효가 되는 `Content-Length`는 staging/release 대상에서 제외한다. Core는 raw wire bytes나 caller 제품명을 받지 않는다. - `BaseEventDisposition`: Core가 event lifecycle에서 만드는 `hold`, `release_candidate`, `terminal_success_candidate`, `terminal_error_candidate`다. response-start는 hold, user-facing safe delta는 release candidate, normal terminal은 success terminal candidate, provider error는 error terminal candidate다. filter가 매칭되지 않아도 이 기본 의미는 사라지지 않는다. @@ -89,7 +89,7 @@ - 출력: - `ReleaseEvent`: filter 통과 safe prefix 또는 허용된 replacement다. - `CommitState`: `transport_uncommitted`, `stream_open`, `terminal_committed`다. HTTP status/header flush, SSE/agent opening event 또는 첫 body 중 가장 이른 user-visible write가 `stream_open`이다. exact/schema replay는 uncommitted에 한정하고 continuation/replacement는 별도 capability matrix를 따른다. - - `TerminalResult`: terminal event 또는 terminal error를 한 번만 전송한다. terminal error는 선택적 bounded `FailureCauseChain`과 외부 오류의 `type`/`code`/안전한 message template/`param` descriptor를 가진다. Core는 이를 재해석하지 않고 `ReleaseSink`에 전달하며 endpoint codec이 [외부 오류 계약](../../../../agent-contract/outer/openai-compatible-api.md#오류-응답)으로 직렬화한다. + - `TerminalResult`: terminal event 또는 terminal error를 한 번만 전송한다. terminal error는 선택적 bounded `FailureCauseChain`과 외부 오류의 `type`/`code`/안전한 message template/`param` descriptor를 가진다. Core는 이를 재해석하지 않고 `ReleaseSink`에 전달하며 endpoint codec이 [외부 오류 계약](../../../../../agent-contract/outer/openai-compatible-api.md#오류-응답)으로 직렬화한다. - `ArbitrationResult`: base disposition과 모든 filter outcome을 합성한 `release`, `hold`, `terminal`, `recover`, `replacement` 단일 action이다. hold는 blocking deferred가 hard bound 전일 때만, recover는 eligible intent가 base candidate를 대체할 때만 선택한다. unmatched error는 terminal을 유지하고 같은 epoch에서 action/dispatch를 둘 이상 만들지 않는다. - `RecoveryPlan`: 선택된 strategy, `replace_attempt|continue_stream` resume mode, contributing filter/rule ids, plan/idempotency key, strategy attempt와 request 전체 recovery attempt, 각 limit, typed directive, optional bounded preparation snapshot reference와 preparer id/status, commit/side-effect eligibility와 continuation cursor를 포함한다. RecoveryPlan Coordinator만 생성하며 preparer 성공 전에는 rebuild/dispatch 가능한 final plan으로 표시하지 않는다. snapshot 원문은 observation에 직렬화하지 않는다. - `RebuiltRequest`: `RequestRebuilder`가 immutable ingress snapshot과 plan directive로 만든 endpoint별 새 attempt다. 기존 admission 경로가 provider를 다시 선택하고 auth를 재계산한다. @@ -206,6 +206,6 @@ - 표준선: filter interface는 context-aware synchronous pure evaluation 형태로 유지하고 Gate Coordinator가 goroutine fan-out/수집, single-flight backpressure와 cancel/deadline fail policy를 관리한다. 이로써 filter 구현이 concurrency, request mutation, attempt counter, provider admission을 각각 재구현하지 않는다. - 표준선: 최초 vertical slice는 production semantic detector 대신 model/provider별 on/off 가능한 `NoopFilter`와 test-only `InjectedViolationFilter`로 공통 파이프라인 한 사이클을 먼저 검증한다. - 표준선: host는 ingress body를 읽기 전에 기본값/절대 상한 16 MiB의 `max_ingress_snapshot_bytes`를 적용한다. OpenAI JSON은 raw body를 canonical source로 하나만 보존하고 Core/Rebuilder가 typed view와 rebuild 임시 output까지 retained byte를 계상한다. limit 초과는 provider dispatch와 recovery budget 소비 전에 fail-closed한다. -- 표준선: limit policy를 실제 config에 구현할 때 [Edge Config And Runtime Refresh Contract](../../../../agent-contract/inner/edge-config-runtime-refresh.md)에 field/default/range와 refresh 분류를 함께 반영한다. 현재 active contract에는 미구현 config field를 선반영하지 않는다. +- 표준선: limit policy를 실제 config에 구현할 때 [Edge Config And Runtime Refresh Contract](../../../../../agent-contract/inner/edge-config-runtime-refresh.md)에 field/default/range와 refresh 분류를 함께 반영한다. 현재 active contract에는 미구현 config field를 선반영하지 않는다. - 표준선: managed provider-length continuation은 `length` semantic detector를 Core에 넣지 않는다. Core는 terminal staging, safe prefix/look-behind/cursor 보존, current attempt ownership 종료, trajectory allowance 계산, single re-admission과 final terminal만 소유한다. fault recovery의 최대 3회 cap과 managed context-window trajectory는 서로 다른 ledger이며, assistant prefill capability와 endpoint별 rebuild 의미는 consumer/codec이 결정한다. -- 후속 SDD: [OpenAI-compatible 출력 검증 필터 SDD](../openai-compatible-output-validation-filters/SDD.md) +- 후속 SDD: [OpenAI-compatible 출력 검증 필터 SDD](../../../../sdd/knowledge-tool-optimization-extension/openai-compatible-output-validation-filters/SDD.md) diff --git a/agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md b/agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md index d67b628..8339327 100644 --- a/agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md +++ b/agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md @@ -29,8 +29,8 @@ Phase를 가로지르는 실제 다음 작업 선택은 [전역 마일스톤 실 - 경로: [openai-compatible-tool-call-boundary-hardening](../../archive/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-tool-call-boundary-hardening.md) - 요약: provider-pool/OpenAI-compatible 응답에서 raw text tool-call block, unknown tool name, chat-template sentinel token이 클라이언트 화면으로 새지 않도록 Edge tool-call 경계를 검증/정규화한다. -- [진행중] Stream Evidence Gate Core - - 경로: [stream-evidence-gate-core](milestones/stream-evidence-gate-core.md) +- [완료] Stream Evidence Gate Core + - 경로: [stream-evidence-gate-core](../../archive/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md) - 요약: codec의 response-start/event를 첫 safe release까지 stage하고 500-rune rolling, bounded terminal/fragment hold, pre-read 기본값/절대 상한 16 MiB raw-canonical ingress snapshot과 request-snapshot 기반 Filter Registry를 제공한다. Gate Coordinator가 single-flight all-complete evaluation/commit을, RecoveryPlan Coordinator와 host adapter가 strategy별 budget과 최초 실행 제외 기본값/절대 상한 3회의 request 전체 cap 아래 abort·optional one-shot plan prepare·lossless rebuild·cycle별 single re-admission을 담당한다. - [계획] OpenAI-compatible 출력 검증 필터 diff --git a/agent-roadmap/priority-queue.md b/agent-roadmap/priority-queue.md index 051fa88..0c4cd3a 100644 --- a/agent-roadmap/priority-queue.md +++ b/agent-roadmap/priority-queue.md @@ -4,80 +4,77 @@ ## 실행 순서 -1. [Stream Evidence Gate Core](phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md) - staged response-start, rolling/terminal/fragment hold, bounded ingress snapshot, model/provider별 Registry, single-flight all-complete evaluation과 strategy/request-total cap 아래 abort·optional one-shot plan prepare·host rebuild/re-admission을 공통 mechanics로 제공한다. - -2. [IOP Agent CLI Runtime](phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md) +1. [IOP Agent CLI Runtime](phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md) 현재 Python 감시·dispatcher와 Node CLI runtime의 전체 동등성을 단일 Go CLI Provider·AgentTaskManager 및 독립 `iop-agent` binary로 이전한다. -3. [OpenAI-compatible 출력 검증 필터](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-output-validation-filters.md) +2. [OpenAI-compatible 출력 검증 필터](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-output-validation-filters.md) OpenAI-compatible single-stream 반복과 incoming request history에 누적된 assistant 반복, JSON contract 검증/repair 경로를 안정화한다. -4. [OpenAI-compatible Incomplete Tool Call Syntax Gate](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-incomplete-tool-call-syntax-gate.md) +3. [OpenAI-compatible Incomplete Tool Call Syntax Gate](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-incomplete-tool-call-syntax-gate.md) terminal provider 응답의 incomplete tool-call syntax를 deterministic하게 판정한다. -5. [OpenAI-compatible Runtime Output Integrity Filter](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-runtime-output-integrity-filter.md) +4. [OpenAI-compatible Runtime Output Integrity Filter](phase/knowledge-tool-optimization-extension/milestones/openai-compatible-runtime-output-integrity-filter.md) terminal output invariant와 공통 filter/retry pipeline을 정의한다. -6. [LLM 판별 기반 Missing Tool Call 재시도 Gate](phase/knowledge-tool-optimization-extension/milestones/llm-judged-missing-tool-call-retry-gate.md) +5. [LLM 판별 기반 Missing Tool Call 재시도 Gate](phase/knowledge-tool-optimization-extension/milestones/llm-judged-missing-tool-call-retry-gate.md) tool 사용 의도 누락 케이스를 LLM judge와 buffered retry 후보로 검토한다. -7. [Tool Call 판정 모델 Gate 리뷰](phase/knowledge-tool-optimization-extension/milestones/tool-call-validator-model-gate-review.md) +6. [Tool Call 판정 모델 Gate 리뷰](phase/knowledge-tool-optimization-extension/milestones/tool-call-validator-model-gate-review.md) schema만으로 어려운 tool-call 후보에 validator 모델을 쓸지 검토한다. -8. [Pi CLI Provider Integration](phase/automation-runtime-bridge/milestones/pi-cli-provider-integration.md) +7. [Pi CLI Provider Integration](phase/automation-runtime-bridge/milestones/pi-cli-provider-integration.md) Pi를 Node CLI provider 실행 후보에 추가하고 OpenAI-compatible route smoke로 안정화한다. -9. [CLI Agent Group Grade Routing](phase/automation-runtime-bridge/milestones/cli-agent-group-grade-routing.md) +8. [CLI Agent Group Grade Routing](phase/automation-runtime-bridge/milestones/cli-agent-group-grade-routing.md) lane/grade 파일명과 `metadata.agent_group.task_file` 기반 CLI agent group 라우팅 계약을 정리한다. -10. [에이전트 작업 루프 오케스트레이션 MVP](phase/automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md) +9. [에이전트 작업 루프 오케스트레이션 MVP](phase/automation-runtime-bridge/milestones/agent-workflow-loop-orchestration-mvp.md) 일반 사용자 요청을 direct/Plan/Milestone으로 분류하고, 사용자 agent의 tool call로 만든 작업 파일을 IOP가 읽어 다음 실행·리뷰·완료 단계까지 연결한다. -11. [Provider 사용량 알림과 운영 표면](phase/automation-runtime-bridge/milestones/provider-usage-notification-operations-surface.md) +10. [Provider 사용량 알림과 운영 표면](phase/automation-runtime-bridge/milestones/provider-usage-notification-operations-surface.md) 공통 runtime의 quota/status/failure event를 소비해 macOS·Desktop·후속 외부 채널에 전달하는 알림과 이력 표면을 스케치한다. -12. [단계 호출과 검증 최적화 MVP](phase/knowledge-tool-optimization-extension/milestones/knowledge-tool-validation-optimization.md) +11. [단계 호출과 검증 최적화 MVP](phase/knowledge-tool-optimization-extension/milestones/knowledge-tool-validation-optimization.md) planner/generator/verifier 단계 호출과 runtime schema 검증 실행 모드를 스케치한다. -13. [원격 코딩/유지보수 작업 환경](phase/automation-runtime-bridge/milestones/remote-workspace-operations-environment.md) +12. [원격 코딩/유지보수 작업 환경](phase/automation-runtime-bridge/milestones/remote-workspace-operations-environment.md) workspace-bound execution 기반 원격 코딩/유지보수 운영 경계를 스케치한다. -14. [Personal Local Edge 패키징과 배포 모드 프로파일](phase/personal-edge-packaging-deployment/milestones/personal-local-edge-deployment-profiles.md) +13. [Personal Local Edge 패키징과 배포 모드 프로파일](phase/personal-edge-packaging-deployment/milestones/personal-local-edge-deployment-profiles.md) personal/server/fleet 배포 모드와 capability gate 경계를 스케치한다. -15. [요청 실행 로그와 Usage Ledger 기반](phase/operational-observability-provider-management/milestones/request-execution-log-usage-ledger-foundation.md) +14. [요청 실행 로그와 Usage Ledger 기반](phase/operational-observability-provider-management/milestones/request-execution-log-usage-ledger-foundation.md) 요청별 provider/model 선택, timing, token, status/error를 구조화된 ledger로 남기는 기반을 스케치한다. -16. [Update Plane 안정 프로토콜](phase/update-plane-self-update-foundation/milestones/update-plane-stable-protocol.md) +15. [Update Plane 안정 프로토콜](phase/update-plane-self-update-foundation/milestones/update-plane-stable-protocol.md) hello/status, manifest, command, event, recovery 최소 계약을 스케치한다. -17. [Host-local Manager 기반 자체 업데이트](phase/update-plane-self-update-foundation/milestones/host-local-manager-self-update.md) +16. [Host-local Manager 기반 자체 업데이트](phase/update-plane-self-update-foundation/milestones/host-local-manager-self-update.md) manager/updater의 release staging, 검증, restart, rollback 실행 모델을 정리한다. -18. [Edge/Node 롤아웃과 복구 정책](phase/update-plane-self-update-foundation/milestones/edge-node-rollout-recovery-policy.md) +17. [Edge/Node 롤아웃과 복구 정책](phase/update-plane-self-update-foundation/milestones/edge-node-rollout-recovery-policy.md) Edge/Node rolling update, 실패/재연결/rollback 보고 정책을 스케치한다. -19. [Provider Runtime 설정과 모델 획득 오케스트레이션](phase/operational-observability-provider-management/milestones/provider-runtime-model-acquisition-orchestration.md) +18. [Provider Runtime 설정과 모델 획득 오케스트레이션](phase/operational-observability-provider-management/milestones/provider-runtime-model-acquisition-orchestration.md) provider runtime launch/profile, model download/cache/verification 경계를 스케치한다. -20. [Provider-Device-Model Qualification 리포트와 Lifecycle 관리](phase/operational-observability-provider-management/milestones/provider-device-model-qualification-report.md) +19. [Provider-Device-Model Qualification 리포트와 Lifecycle 관리](phase/operational-observability-provider-management/milestones/provider-device-model-qualification-report.md) provider/device/model별 compatibility, performance, quality, lifecycle 리포트 경계를 정리한다. -21. [Provider 입력 컨텍스트 선택과 축소](phase/knowledge-tool-optimization-extension/milestones/request-context-assembly-optimization.md) +20. [Provider 입력 컨텍스트 선택과 축소](phase/knowledge-tool-optimization-extension/milestones/request-context-assembly-optimization.md) provider dispatch 전에 무관한 과거 요청-답변 단위를 제거하고, 유지한 답변·tool/search 결과 안에서도 필요한 문단·코드 블록·구간만 남기는 입력 context 최적화를 스케치한다. -22. [장기 기억과 RAG 업데이트 사이클 (2차)](phase/knowledge-tool-optimization-extension/milestones/long-term-memory-rag-second-wave.md) +21. [장기 기억과 RAG 업데이트 사이클 (2차)](phase/knowledge-tool-optimization-extension/milestones/long-term-memory-rag-second-wave.md) repo 장기 기억, RAG 저장소, update cycle, MCP 기반 context 절약 후보를 스케치한다. -23. [Advisor와 Context Hook 확장 (2차)](phase/knowledge-tool-optimization-extension/milestones/advisor-context-hook-second-wave.md) +22. [Advisor와 Context Hook 확장 (2차)](phase/knowledge-tool-optimization-extension/milestones/advisor-context-hook-second-wave.md) advisor 역할과 여러 기능을 실행 흐름에 연결하는 Context Hook 경계를 스케치한다. -24. [oto 자동화 스케줄러와 CI-CD 연동 (2차)](phase/automation-runtime-bridge/milestones/oto-automation-scheduler-second-wave.md) +23. [oto 자동화 스케줄러와 CI-CD 연동 (2차)](phase/automation-runtime-bridge/milestones/oto-automation-scheduler-second-wave.md) oto 기반 자동화, scheduler, CI-CD 연동 후보를 스케치한다. -25. [Flutter Desktop Control UI](phase/automation-runtime-bridge/milestones/flutter-desktop-control-ui.md) +24. [Flutter Desktop Control UI](phase/automation-runtime-bridge/milestones/flutter-desktop-control-ui.md) `iop-agent` local proto-socket을 소비해 YAML 전체 설정과 project·실행·오류·로그를 관리하는 macOS Flutter 설정·운영 UI를 제공한다. -26. [Unity 3D Desktop Character](phase/automation-runtime-bridge/milestones/unity-3d-desktop-character.md) +25. [Unity 3D Desktop Character](phase/automation-runtime-bridge/milestones/unity-3d-desktop-character.md) 같은 local proto-socket을 독립적으로 소비하고 작업 상태를 투명 배경 3D 캐릭터와 animation으로 표현하는 macOS Unity client를 제공한다. diff --git a/agent-spec/index.md b/agent-spec/index.md index 48ad496..c1c4905 100644 --- a/agent-spec/index.md +++ b/agent-spec/index.md @@ -24,6 +24,7 @@ AI agent가 작업 전에 읽는 지도이기도 하지만, 사람도 "지금 - 실행 경로: Edge와 Node 사이의 등록, 실행, 이벤트, provider raw tunnel, 취소, command 흐름은 `runtime/edge-node-execution`에서 본다. - 런타임 라우팅/설정: provider-pool, `models[]`, `nodes[].providers[]`, live config refresh는 `runtime/provider-pool-config-refresh`에서 본다. +- 출력 검증 런타임: staged response-start, evidence hold/release, filter arbitration, bounded recovery/rebuild, raw-free observation은 `runtime/stream-evidence-gate`에서 본다. - 외부 HTTP 입력: OpenAI-compatible 호출, model-driven raw tunnel은 `input/openai-compatible-surface`, A2A JSON-RPC 호출은 `input/a2a-json-rpc-surface`에서 본다. - 운영 제어: Control Plane, Edge enrollment, fleet/edge status, Flutter Client 상태 소비는 `control/control-plane-operations`에서 본다. @@ -32,6 +33,7 @@ AI agent가 작업 전에 읽는 지도이기도 하지만, 사람도 "지금 | id | 상태 | 언제 읽나 | path | 주요 근거 | |----|------|-----------|------|-----------| | `runtime/edge-node-execution` | 부분 | Edge-Node TCP/protobuf transport, Node 등록, run/cancel/command, provider raw tunnel, adapter 실행, Node local run store를 확인할 때 | `agent-spec/runtime/edge-node-execution.md` | `agent-contract/inner/edge-node-runtime-wire.md`, `apps/edge/internal/service/run_submit.go`, `apps/node/internal/node/run_handler.go` | +| `runtime/stream-evidence-gate` | 구현됨 | Stream Evidence Gate의 normalized event, evidence hold/release, filter registry, recovery coordinator, OpenAI request rebuild와 observation을 확인할 때 | `agent-spec/runtime/stream-evidence-gate.md` | `packages/go/streamgate/runtime.go`, `apps/edge/internal/openai/stream_gate_runtime.go`, `agent-contract/outer/openai-compatible-api.md` | | `runtime/provider-pool-config-refresh` | 부분 | `models[]`, `nodes[].providers[]`, provider-pool dispatch, long-context admission, Edge/Node config refresh를 확인할 때 | `agent-spec/runtime/provider-pool-config-refresh.md` | `agent-contract/inner/edge-config-runtime-refresh.md`, `packages/go/config/provider_types.go`, `apps/edge/internal/configrefresh/classify.go` | | `input/openai-compatible-surface` | 부분 | `/v1/models`, `/v1/chat/completions`, `/v1/responses`, OpenAI-compatible auth/metadata/workspace/tool handling, model-driven raw tunnel, usage metric, 외부 `model` route를 확인할 때 | `agent-spec/input/openai-compatible-surface.md` | `agent-contract/outer/openai-compatible-api.md`, `apps/edge/internal/openai/chat_handler.go`, `apps/edge/internal/openai/normalized_sse.go`, `apps/edge/internal/openai/usage_metrics.go` | | `input/a2a-json-rpc-surface` | 부분 | Edge A2A JSON-RPC, `message/send`, `tasks/get`, `tasks/cancel`, A2A task store와 bearer auth를 확인할 때 | `agent-spec/input/a2a-json-rpc-surface.md` | `agent-contract/outer/a2a-json-rpc-api.md`, `apps/edge/internal/input/a2a/server.go`, `apps/edge/internal/input/a2a/task_store.go` | diff --git a/agent-spec/input/openai-compatible-surface.md b/agent-spec/input/openai-compatible-surface.md index de61bd0..f7e4e56 100644 --- a/agent-spec/input/openai-compatible-surface.md +++ b/agent-spec/input/openai-compatible-surface.md @@ -12,6 +12,12 @@ source_evidence: - type: code path: apps/edge/internal/openai/chat_handler.go notes: Chat Completions request validation, route dispatch, tool/reasoning 정책 + - type: code + path: apps/edge/internal/openai/stream_gate_ingress.go + notes: body 첫 read 전 ingress 상한과 request-local snapshot + - type: code + path: apps/edge/internal/openai/stream_gate_runtime.go + notes: runtime-enabled Chat과 provider tunnel response lifecycle - type: code path: apps/edge/internal/openai/normalized_sse.go notes: normalized Chat Completions SSE stream과 terminal event 처리 @@ -74,6 +80,7 @@ Edge가 OpenAI-compatible HTTP 요청을 받아 내부 `adapter + target` 실행 | legacy route 변환 | legacy route는 외부 `model`을 route entry의 `adapter`, `target`, `node`, `session_id`, queue policy로 변환한다. | | metadata/workspace 처리 | `metadata.workspace`는 `RunRequest.workspace`로 분리하고, 일반 metadata는 최대 16개 string key/value만 허용한다. | | Chat Completions | `/v1/chat/completions`는 non-streaming과 streaming SSE를 지원한다. | +| bounded ingress와 Stream Evidence Gate | Chat/Responses body를 첫 read 전에 최대 16 MiB로 제한한다. `openai.stream_evidence_gate.enabled=true`인 지원 경로는 response-start staging, filter arbitration, bounded recovery와 단일 terminal을 `runtime/stream-evidence-gate`에 위임한다. | | model-driven response path | request `model`이 가리키는 provider capability가 provider raw tunnel 또는 normalized RunEvent path를 결정한다. caller metadata는 route나 response shape를 선택하지 않는다. | | provider raw passthrough | `passthrough`는 provider status/header/body bytes를 기존 Edge-Node tunnel로 relay하고 pure response body에 IOP 확장 envelope를 섞지 않는다. | | provider-native field 보존 | provider raw tunnel route는 `model` served target rewrite와 auth/header 처리 외에 selected provider가 지원하는 OpenAI-compatible 표준 field와 provider extension field를 보존한다. | @@ -88,7 +95,7 @@ Edge가 OpenAI-compatible HTTP 요청을 받아 내부 `adapter + target` 실행 ## 범위 -- 포함: OpenAI-compatible HTTP auth, request validation, route resolution, metadata/workspace 처리, chat/responses 변환, provider-pool dispatch handoff, tool/reasoning/strict output 처리. +- 포함: OpenAI-compatible HTTP auth, bounded ingress, request validation, route resolution, metadata/workspace 처리, chat/responses 변환, provider-pool dispatch handoff, tool/reasoning/strict output 처리. - 제외: OpenAI 원문 API 전체 호환, legacy `/v1/completions`, A2A JSON-RPC, Node adapter별 provider HTTP 세부, Control Plane 운영 API. ## 주요 흐름 @@ -126,6 +133,7 @@ sequenceDiagram ## 설정/데이터/이벤트 - `configs/edge.yaml`의 `openai` 섹션이 listener, bearer token, legacy adapter/target, model routes, strict output을 제공한다. +- `openai.stream_evidence_gate`는 기본 비활성이고, recovery cap 0..3과 16 MiB 이하 ingress snapshot 상한을 설정한다. 변경은 현재 restart-required다. - top-level `models[]`가 있으면 OpenAI model list와 provider-pool dispatch에서 legacy route보다 우선한다. - provider-pool model group은 capacity + priority + availability 기준으로 provider candidate를 먼저 선택하고, 선택된 provider가 OpenAI-compatible 호출 방식을 지원하면 raw tunnel passthrough로 dispatch한다. Ollama/CLI/native provider가 선택되면 normalized `RunRequest` path로 dispatch한다. - provider capacity와 long-context slot은 model alias별이 아니라 `node_id + provider_id`별로 공유한다. queue pending 상한과 timeout은 Edge root `provider_pool` policy이며, lease 반환·refresh·disconnect/reconnect가 모든 model group waiter를 global enqueue 순서로 재평가한다. @@ -145,6 +153,7 @@ sequenceDiagram ## 검증 - `go test ./apps/edge/internal/openai` +- `go test -race -count=1 ./packages/go/streamgate ./apps/edge/internal/openai ./packages/go/config` - `go test ./apps/edge/internal/service` - `go test ./apps/edge/internal/openai -run 'Tunnel|UsageMetrics|ToolValidation|Dispatch|Reasoning|Retry'` - `rg --fixed-strings "cloud_equivalent_cost" docs/openai-usage-grafana.md` @@ -154,6 +163,7 @@ sequenceDiagram ## 한계와 주의사항 - normalized(non-provider) `/v1/responses`는 non-streaming string input만 지원한다. provider model group route의 `/v1/responses`는 raw passthrough로 streaming과 Codex/unknown field를 그대로 provider에 전달한다. +- Stream Evidence Gate 활성화만으로 반복, missing tool-call, schema 같은 semantic filter가 자동 활성화되지는 않는다. 해당 mechanics와 현재 지원 경로는 `agent-spec/runtime/stream-evidence-gate.md`를 따른다. - `/v1/completions`는 제공하지 않는다. - OpenAI-compatible request에 provider/Ollama 전용 root field를 추가하지 않는다. - workspace는 prompt 본문에 섞지 않고 metadata에서 분리한다. @@ -184,3 +194,4 @@ sequenceDiagram - 2026-07-14: provider 미보고 reasoning text에 estimated-token counter(`iop_openai_reasoning_estimated_tokens_total`, `estimation_method="chars_div_4"`) 추가와 provider-reported reasoning 우선 기준을 반영. - 2026-07-18: 저장소 구조 분해 뒤 streaming, provider tunnel, split test의 `source_evidence`를 현재 경로로 동기화. - 2026-07-22: cross-model provider resource admission, provider-pool 공통 queue policy와 live candidate 소진 시 502 unavailable 의미를 현재 service/OpenAI 구현과 계약 기준으로 동기화. +- 2026-07-28: bounded ingress와 Stream Evidence Gate 활성 경로·한계·검증 포인터를 현재 구현 기준으로 반영. diff --git a/agent-spec/runtime/provider-pool-config-refresh.md b/agent-spec/runtime/provider-pool-config-refresh.md index b6199b1..d43208f 100644 --- a/agent-spec/runtime/provider-pool-config-refresh.md +++ b/agent-spec/runtime/provider-pool-config-refresh.md @@ -48,6 +48,9 @@ source_evidence: - type: test path: packages/go/config/provider_catalog_validation_config_test.go notes: provider/model 참조와 validation 검증 + - type: test + path: packages/go/config/stream_evidence_gate_config_test.go + notes: Stream Evidence Gate 기본값, recovery cap과 ingress 상한 검증 - type: test path: apps/edge/internal/node/mapper_test.go notes: provider-first adapter payload, Seulgivibe alias/provider label 검증 @@ -94,6 +97,7 @@ Edge 설정에서 provider-pool이 어떻게 모델 실행 후보를 고르고, | long-context admission | estimated input token이 threshold 이상이면 `context_class=long`으로 분류하고, provider long slot이 있으면 일반 capacity slot과 함께 점유한다. | | config refresh dry-run/apply | loopback admin HTTP `POST /refresh`가 candidate config를 dry-run 또는 apply한다. | | refresh classification | listener, Edge identity, bootstrap path, adapter structural 변경 등은 restart-required로 분류한다. | +| Stream Evidence Gate config | `openai.stream_evidence_gate`는 runtime 활성화, request-total/strategy fault recovery cap과 ingress snapshot 상한을 제공하며 현재 restart-required로 분류된다. | | mutable apply | 적용 가능한 변경은 Edge `Cfg`, `NodeStore`, service/input model catalog, OpenAI long-context threshold를 copy-on-write로 교체한다. | | Node config refresh push | 변경이 있으면 Edge가 dispatch-ready Node에 node-specific `NodeConfigRefreshRequest`를 push한다. accepted지만 pending인 Node는 register response config를 적용한 뒤 ready가 될 때까지 push 대상이 아니다. | | Node registry swap | Node는 refresh payload로 새 adapter registry를 만들고 router registry를 swap한다. old registry stop은 active run이 있으면 drain 이후로 지연한다. | @@ -103,7 +107,7 @@ Edge 설정에서 provider-pool이 어떻게 모델 실행 후보를 고르고, ## 범위 -- 포함: Edge config load/default/validation, provider-pool dispatch, queue admission, long-context admission, config refresh classification/apply, Node config refresh payload. +- 포함: Edge config load/default/validation, Stream Evidence Gate 설정, provider-pool dispatch, queue admission, long-context admission, config refresh classification/apply, Node config refresh payload. - 제외: 개별 adapter의 provider API 호출 세부, OpenAI HTTP request/response shape, Control Plane 원격 config 변경 UX, private credential 관리. ## 주요 흐름 @@ -140,6 +144,7 @@ sequenceDiagram ## 설정/데이터/이벤트 - `long_context_threshold_tokens` 기본 예시는 `100000`이고 0 이하 값은 config load에서 거부된다. +- `openai.stream_evidence_gate.enabled` 기본값은 `false`다. request fault recovery는 0..3, strategy cap은 request-total 이하, ingress snapshot은 1..16777216 bytes이며 설정 변경은 restart-required다. - `provider_pool.max_queue`는 0/생략 시 기본값 `16`, `queue_timeout_ms`는 생략 시 `30000`이고 명시적 0은 timeout 없음이다. canonical root key가 없을 때만 서로 같은 legacy provider queue pair를 승격하며 값이 다르면 load를 거부한다. - `nodes[].providers[].capacity`와 `long_context_capacity`는 provider resource 속성이고 같은 provider를 공유하는 model alias가 합산 점유한다. `total_context_tokens`는 runtime ledger가 아니라 `context_window_tokens * long_context_capacity` 정적 validation 값이다. - provider `enabled=false`는 dispatch pool에서 제외하지만 adapter process lifecycle 변경을 의미하지 않는다. @@ -168,6 +173,7 @@ sequenceDiagram - provider health는 현재 config/provider snapshot 기반이다. 모든 runtime에 대한 active health probe가 완성된 것은 아니다. - refresh admin API는 operator-local 표면이다. 접근 제어 없이 public interface에 노출하지 않는다. +- Stream Evidence Gate의 request-local lifecycle과 지원 OpenAI 경로는 `agent-spec/runtime/stream-evidence-gate.md`에서 관리한다. - adapter structural 변경은 contract상 restart-required로 분류된다. Node handler가 registry swap을 지원하더라도 Edge refresh classifier가 허용한 변경만 apply해야 한다. - no-change apply는 runtime snapshot을 교체하지만 Node push는 생략한다. - `NodeRuntimeConfig.concurrency`는 legacy metadata이며 provider-pool admission의 node-wide capacity로 쓰지 않는다. @@ -186,3 +192,4 @@ sequenceDiagram - 2026-07-18: 저장소 구조 분해 뒤 config, provider resolution/admission, split test의 `source_evidence`를 현재 경로로 동기화. - 2026-07-22: pending accepted connection과 dispatch-ready connection을 구분하고, ready ack 뒤에만 provider candidate 복구·refresh push·queued waiter pump가 일어나는 현재 동작을 반영. - 2026-07-22: root provider-pool queue policy, cross-model provider lease, global queue 재평가, refresh lease 보존과 connectivity 기반 snapshot 의미를 현재 구현·계약·테스트 기준으로 동기화. +- 2026-07-28: Stream Evidence Gate 설정 기본값·상한·restart-required 분류와 runtime spec 포인터를 반영. diff --git a/agent-spec/runtime/stream-evidence-gate.md b/agent-spec/runtime/stream-evidence-gate.md new file mode 100644 index 0000000..8446bea --- /dev/null +++ b/agent-spec/runtime/stream-evidence-gate.md @@ -0,0 +1,113 @@ +--- +spec_doc_type: spec +spec_id: runtime/stream-evidence-gate +status: 구현됨 +source_evidence: + - type: contract + path: agent-contract/outer/openai-compatible-api.md + notes: OpenAI-compatible ingress, stream commit와 terminal 오류 계약 + - type: contract + path: agent-contract/inner/edge-config-runtime-refresh.md + notes: Stream Evidence Gate 설정과 restart-required 분류 계약 + - type: code + path: packages/go/streamgate/runtime.go + notes: request-local event, evaluation, release와 recovery lifecycle + - type: code + path: packages/go/streamgate/recovery_coordinator.go + notes: abort, optional prepare, rebuild, budget consume와 single dispatch 순서 + - type: code + path: apps/edge/internal/openai/stream_gate_runtime.go + notes: OpenAI Chat과 provider tunnel host wiring + - type: code + path: apps/edge/internal/openai/openai_request_rebuilder.go + notes: bounded lossless OpenAI request rebuild + - type: test + path: packages/go/streamgate/runtime_test.go + notes: Core lifecycle, recovery와 terminal 검증 + - type: test + path: apps/edge/internal/openai/stream_gate_vertical_slice_test.go + notes: Edge 실제 admission과 full-cycle 검증 + - type: test + path: apps/edge/internal/openai/filter_observation_sink_test.go + notes: raw-free observation allowlist와 correlation 검증 +--- + +# 스펙: Stream Evidence Gate + +## 목적 + +codec이 정규화한 provider event를 downstream에 쓰기 전에 evidence와 모든 활성 filter 결과를 확인하고, 한 번의 release·terminal·recovery 결정으로 수렴시키는 현재 request-local runtime을 설명한다. + +## 기능 목록 + +| 기능 | 설명 | +|------|------| +| normalized event contract | response-start, text/reasoning, tool-call, terminal, provider-error event와 base disposition을 transport와 분리한다. | +| evidence hold | 기본 500 Unicode rune rolling window와 bounded terminal/fragment gate를 사용하며 안전한 prefix만 release한다. | +| staged commit | status/header/opening event를 첫 safe release까지 보류하고 `transport_uncommitted`, `stream_open`, `terminal_committed` 상태에서 terminal을 한 번만 commit한다. | +| filter registry와 arbitration | request 시작의 registry/config generation을 고정하고 attempt별 active filter를 다시 해석한 뒤 병렬 결과를 모두 모아 deterministic action 하나를 선택한다. | +| bounded recovery | exact replay, continuation repair, schema repair는 request-total·strategy별 fault cap 안에서 실행하며 managed continuation은 별도 trajectory budget을 사용한다. | +| request rebuild | 기본값이자 절대 상한 16 MiB의 ingress snapshot에서 OpenAI JSON unknown field를 보존하고 필요한 typed subtree만 bounded patch한다. | +| host re-admission | 현재 provider ownership을 닫은 뒤 optional one-shot prepare, rebuild, budget consume, 단일 dispatch 순서로 새 actual model/provider/path binding을 설치한다. | +| raw-free observation | request correlation, attempt/epoch, filter/rule, decision, recovery와 bounded sanitized cause/evidence만 timeline sink로 보낸다. | + +## 범위 + +- 포함: transport-agnostic Core, OpenAI-compatible Chat runtime, provider-pool mixed path, Chat/Responses streaming provider tunnel, request-local ingress/rebuild와 Edge observation sink. +- 제외: 반복·missing tool-call·schema 같은 semantic detector 자체, provider/model 선택 알고리즘, raw parser, cross-request 저장과 범용 오류 수정 workflow. + +## 주요 흐름 + +```mermaid +sequenceDiagram + participant Host as Edge host + participant Core as Stream Gate Core + participant Filters + participant Provider + participant Sink as Release sink + + Host->>Core: request snapshot + initial AttemptBinding + Provider->>Core: normalized response-start/event + Core->>Core: stage + evidence hold + Core->>Filters: immutable EvidenceBatch 병렬 평가 + Filters-->>Core: all outcomes + alt release 또는 terminal + Core->>Sink: safe release / single terminal + else recovery + Core->>Provider: current attempt abort + Core->>Host: optional prepare + bounded rebuild + Host->>Provider: single re-admission + Provider->>Core: next attempt events + end +``` + +## 계약 + +- 외부 OpenAI-compatible 오류와 stream framing: `agent-contract/outer/openai-compatible-api.md` +- Edge 설정과 refresh 분류: `agent-contract/inner/edge-config-runtime-refresh.md` +- Edge-Node provider tunnel wire: `agent-contract/inner/edge-node-runtime-wire.md` + +## 설정/데이터/이벤트 + +- `openai.stream_evidence_gate.enabled` 기본값은 `false`이며 활성화 시 지원 경로의 response lifecycle을 Core가 소유한다. +- `max_request_fault_recovery`는 0..3, `max_strategy_fault_recovery`는 0..request-total이고 생략 시 request-total을 상속한다. +- `max_ingress_snapshot_bytes`는 1..16777216이며 생략 시 16 MiB다. raw body limit은 첫 read 전에 적용되고 canonical body, typed view와 rebuild peak가 같은 request-local ledger에 포함된다. +- Stream Evidence Gate 설정 변경은 현재 restart-required다. request가 시작된 뒤 config/registry snapshot은 바뀌지 않는다. +- production Core registry는 공통 Noop filter와 적용 가능한 request-local tool validation을 포함한다. 추가 semantic filter는 별도 소비 Milestone이 등록한다. + +## 검증 + +- `make proto` - generated protobuf가 현재 schema와 일치해야 한다. +- `go test -race -count=1 ./packages/go/streamgate ./apps/edge/internal/openai ./packages/go/config` - Core, Edge vertical cycle, request rebuild, observation과 config 경계가 통과해야 한다. +- `git diff --check` - 문서와 코드 diff에 공백 오류가 없어야 한다. + +## 한계와 주의사항 + +- normalized `/v1/responses`는 현재 streaming을 지원하지 않으며 해당 non-stream path는 Stream Evidence Gate runtime을 사용하지 않는다. +- direct provider tunnel의 non-stream response는 기존 buffered passthrough 경로를 유지한다. ingress 상한은 runtime 활성 여부와 무관하게 적용된다. +- Core 활성화만으로 후속 semantic filter가 자동 활성화되지는 않는다. +- observation은 저장소가 아니라 event envelope이며 보존·조회 정책은 host observability sink가 소유한다. + +## 변경 기록 + +- 2026-07-28: Stream Evidence Gate Core 완료 감사에서 현재 Core, Edge wiring, 계약과 테스트 근거로 targeted spec 생성.