# SDD: Stream Evidence Gate Core

## 위치

- Milestone: [Milestone 문서](../../../phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md)
- Phase: [PHASE.md](../../../../phase/knowledge-tool-optimization-extension/PHASE.md)

## 상태

[승인됨]

## SDD 잠금

- 상태: 해제
- 사용자 리뷰: 없음
- 잠금 항목: 없음

## 문제 / 비목표

- 문제: 여러 stream consumer가 raw protocol parser, bounded tail, response-start staging, release/terminal commit과 recovery를 자체 구현하면 repeat loop, tool-call syntax, missing tool-call, schema, workflow terminal replacement마다 byte 경계·eager HTTP commit·중복 `[DONE]`·post-commit 복구 안전성이 달라진다. 또한 filter fan-out 동안 provider event를 계속 무제한 적재하거나 각 consumer가 자체 로그만 남기면 메모리 경계와 같은 request timeline의 decision을 보장할 수 없다. Core는 normalized event 이후의 hold/release, single-flight evaluation, strategy별 recovery와 sanitized observation mechanics를 한 번만 제공해야 한다.
- 비목표:
  - raw OpenAI SSE, CLI JSON, agent-family protocol을 직접 parse한다.
  - 반복/문법/tool 필요성 같은 semantic detector 또는 LLM judge를 결정한다.
  - filter가 개별 retry loop/counter, raw request mutation, provider selection 또는 dispatch를 소유한다.
  - provider-pool의 후보 선택 알고리즘이나 filter별 corrective prompt의 의미를 Core가 결정한다.
  - 기본 rolling 경로에서 전체 응답을 buffer하거나 terminal gate를 hard bound 없이 운영하거나 시간 경과만으로 미검증 event를 release한다.
  - Edge provider-pool 또는 Node runtime의 구체 타입을 공통 Core package가 import한다.
  - cross-request 오류를 사건으로 저장·중복 집계하거나, 연결된 소스 저장소를 LLM으로 분석해 수정 제안·프로젝트 작업 문서·사용자 승인·변경 요청·병합·배포를 조율한다.

## Source of Truth

| 영역 | 기준 | 메모 |
|------|------|------|
| 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를 선반영하지 않는다. |
| 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과 별도다. |

## State Machine

| 상태 | 진입 조건 | 다음 상태 | 근거 |
|------|-----------|-----------|------|
| `request_bound` | host가 configured byte limit 안의 lossless ingress snapshot, registry/config generation, required filter capability와 recovery budget snapshot을 고정했다 | `attempt_dispatching`, `terminal_error` | 같은 request의 recovery cycle이 같은 policy, strategy budget과 request 전체 hard cap을 사용하고 oversize는 dispatch 전 종료 |
| `attempt_dispatching` | 최초 request 또는 rebuilt request가 준비됐다 | `filter_resolving`, `terminal_error` | host `AttemptDispatcher`가 admission을 한 번 수행해 actual model/provider/execution path/event source/controller를 반환 |
| `filter_resolving` | attempt의 실제 model/provider/capability가 확정됐다 | `normalized`, `terminal_error` | 고정된 registry snapshot으로 active filter set과 hold/failure policy를 attempt-local resolve. replace-attempt는 pending/look-behind를 초기화하고 continuation은 committed look-behind/release cursor를 보존 |
| `normalized` | codec이 raw provider/agent event를 typed normalized event로 변환했다 | `response_staging`, `evidence_holding`, `terminal_evaluating`, `terminal_error` | response-start/text/reasoning/tool/terminal/error event |
| `response_staging` | provider response-start 또는 protocol opening event가 도착했지만 safe output은 없다 | `evidence_holding`, `terminal_evaluating`, `terminal_error` | status/header/opening role을 `ReleaseSink`에 쓰지 않고 attempt-local staging |
| `evidence_holding` | hold mode가 요구한 rolling rune, terminal 또는 fragment completion evidence가 아직 부족하다 | `filter_evaluating`, `terminal_evaluating`, `terminal_error` | channel별 rolling/terminal/fragment mode와 hard bound. 시간은 release 조건이 아님 |
| `filter_evaluating` | subscribed event/hold trigger가 준비되거나 terminal batch가 확정됐다 | `arbitrating`, `terminal_error` | event-applicable/trigger-ready filter는 병렬 실행하고, subscribed event가 없으면 `not_applicable_for_epoch`, release-blocking trigger 미충족이면 `deferred_by_requirement`로 표시한다. complete outcome set을 모으는 동안 다음 ingress는 bounded backpressure |
| `arbitrating` | base event disposition과 모든 active filter outcome이 준비됐다 | `releasing`, `evidence_holding`, `recovery_planning`, `terminal_error` | deterministic single action. blocking deferred는 hold, eligible recovery는 candidate를 대체하고 unmatched provider error는 base terminal 유지 |
| `recovery_planning` | Arbiter가 하나의 `RecoveryIntent`를 선택했다 | `attempt_aborting`, `terminal_error` | exact/schema/일반 repair는 strategy budget과 request 전체 fault recovery hard cap을, managed provider-length continuation은 별도 context-window trajectory ledger를 확인한다. cancel, commit/terminal/tool side effect, strategy eligibility, same-plan re-entry guard를 통과하면 preparer/continuation에 필요한 bounded request-local snapshot과 cursor를 immutable하게 고정한다 |
| `attempt_aborting` | recovery eligibility가 통과했다 | `plan_preparing`, `rebuilding`, `terminal_error` | 현재 attempt를 idempotent cancel/close하고 실패/timeout이면 보조 plan 준비나 다음 attempt를 시작하지 않음 |
| `plan_preparing` | 이전 attempt ownership이 종료됐고 선택된 plan이 consumer별 보조 directive 준비를 요구한다 | `rebuilding`, `terminal_error` | optional `RecoveryPlanPreparer`를 plan/idempotency key당 최대 1회, bounded deadline으로 호출한다. filter barrier 밖에서 실행하고 실패/timeout이면 fallback 없이 terminal |
| `rebuilding` | 이전 attempt ownership이 종료됐고 보조 plan 준비가 완료됐거나 필요 없다 | `attempt_dispatching`, `terminal_error` | lossless ingress/continuation snapshot과 endpoint/family `RequestRebuilder`; cycle당 rebuilt request 하나 |
| `releasing` | Arbiter가 safe prefix 또는 protocol-safe replacement를 허용했다 | `stream_open`, `evidence_holding`, `terminal_evaluating` | 첫 release라면 staged response-start/opening event를 먼저 한 번 commit하고 safe event를 순서대로 전송 |
| `stream_open` | downstream transport/opening event 또는 body가 commit됐다 | `evidence_holding`, `terminal_evaluating`, `recovery_planning`, `done`, `terminal_error` | 이미 전송한 event rollback/exact/schema replay 금지. safe-prefix continuation 또는 pre-terminal replacement만 capability와 side-effect guard 아래 허용 |
| `terminal_evaluating` | terminal event가 evidence 충족 전 또는 후 도착했다 | `filter_evaluating`, `terminal_error` | terminal flag가 포함된 final `EvidenceBatch`, all-filter evaluation |
| `terminal_error` | provider idle/error, hard buffer overflow, blocking filter failure, recovery ineligible 또는 post-terminal error가 발생했다 | `done` | uncommitted이면 staged response를 버리고 host error status/body, stream-open이면 protocol terminal error만 한 번 전송 |
| `done` | terminal sequence 또는 terminal error가 downstream에 확정됐다 | 없음 | terminal event 1회 |

## Interface Contract

- 계약 원문: [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가 매칭되지 않아도 이 기본 의미는 사라지지 않는다.
  - `StreamTraceContext`: runtime이 이미 가진 내부 `request_id`, `run_id`, provider id, model id correlation이다. Core는 새 public field를 만들지 않고 이 값을 observation에 전파한다.
  - `FilterContext`: immutable request-local config generation, attempt/epoch, environment, endpoint/family, model group/actual model/provider/execution path, stream, commit/terminal/tool-side-effect state와 trace correlation이다.
  - `FilterRegistrySnapshot`: request 시작 시 고정한 stable filter id별 구현과 config generation이다. admission 전 `RequiredFilterCapabilities`로 필수 후보를 제한하고 actual target이 정해진 각 attempt에서 environment/model/provider/capability별 active set, priority, hold mode와 `blocking|observe_only` enforcement를 resolve한다. config reload는 다음 request부터 반영하고 현재 request의 retry에는 섞지 않는다.
  - `EvidenceBatch`: 같은 evaluation epoch의 normalized event snapshot, channel별 pending, bounded committed look-behind, staged response-start metadata, terminal 여부와 commit state를 read-only accessor로 제공한다. 모든 trigger-ready filter가 같은 logical snapshot을 읽고 mutable map/slice 참조를 공유하지 않는다. replace-attempt는 buffer를 초기화하고 continuation은 committed look-behind/release cursor만 보존하며 observation/log로 원문을 전달하지 않는다.
  - `stream_hold.evidence_runes`: 기본 500. environment/model/provider policy가 제공하는 Unicode rune evidence window다.
  - `FilterHoldRequirement`: 대상 channel, `none|rolling_window|terminal_gate|fragment_gate`, subscribed normalized event kinds, `evidence_runes`, terminal/fragment trigger와 `max_buffer_runes` hard bound다. `none` event-only filter는 channel release를 막지 않는다. Core는 channel별 strongest blocking requirement를 합성하고 filter가 별도 raw buffer나 unbounded hold를 만들지 못하게 한다.
  - `Filter`: Go interface로 stable `ID`, attempt-level `Applies`, `HoldRequirement`/event subscription, synchronous `Evaluate(context.Context, FilterContext, EvidenceBatch) (FilterDecision, error)`를 제공한다. 공통 context는 caller cancel과 bounded deadline을 전달하며 구현은 취소를 준수해야 한다. Gate Coordinator가 fan-out/수집을 관리하고 구현은 concurrency, request mutation, submit을 소유하지 않는다.
  - `FilterDecision`: `pass`, `observe`, `violation`, `fatal`, `replacement` 중 하나다. `consumer_id`, stable `filter_id`, `rule_id`, sanitized evidence와 선택적 `RecoveryIntent`를 포함한다. evidence 수집 종료점은 static hold requirement가 결정하므로 filter가 평가 뒤 무기한 `need_more_evidence`로 hold를 연장하지 않는다.
  - `FilterOutcome`: active filter마다 `evaluated(FilterDecision)`, `evaluation_error`, `not_applicable_for_epoch`, `deferred_by_requirement` 중 하나다. not-applicable은 subscribed event가 없어 release를 막지 않는 outcome이고, deferred는 static blocking trigger 미충족이라 pass로 간주하지 않는다. terminal/hard bound에서 계속 deferred면 invalid/fail policy로 수렴한다.
  - `FilterFailurePolicy`: Registry가 filter 외부에서 정한다. blocking filter error/deadline은 `fatal`로, observe-only filter error/deadline은 `observe_error` outcome으로 정규화되며 둘 다 all-complete 결과와 observation에 포함된다. caller cancel/host shutdown은 barrier를 취소하고 no-release로 종료한다.
  - `FailureCause`: terminal failure의 내부 원인 한 단계다. `stage`, 안정 `code`, consumer/filter/rule id만 가지며 raw stack trace, provider body/endpoint, user prompt, output/reasoning 원문, tool args/result, 인증 정보는 가질 수 없다. `FailureCauseChain`은 request-local 최대 4단계이고 consumer와 Coordinator가 append-only로 조립한다.
  - `RecoveryIntent`: `exact_replay`, `continuation_repair`, `schema_repair`, `managed_continuation` strategy id와 typed repair directive, sanitized reason, filter priority를 가진다. raw body/auth, attempt counter, provider 선택 또는 실행 함수는 포함하지 않는다.
  - `RecoveryBudget`: immutable request-local `max_recovery_attempts_total`, strategy별 limit과 사용량을 가진다. fault recovery cap 기본값이자 MVP 절대 상한은 최초 provider 실행을 제외한 3회이며 request 시작 시 policy snapshot으로 고정한다. policy는 `0..3`에서 낮출 수만 있고 3 초과는 config load/refresh validation error다. exact/schema와 일반 failure continuation dispatch를 모두 합산하고 각 strategy cap보다 우선한다. `managed_continuation`은 이 cap을 소비하지 않고 별도 `ManagedTrajectoryBudget`을 사용한다. 어느 fault cap이든 소진되면 새 fault plan을 만들지 않고 terminal로 수렴하며 filter/strategy를 바꿔 우회할 수 없다.
  - `ManagedTrajectoryBudget`: managed profile에서만 쓰는 immutable request-local ledger다. provider attempt cap, 모델 context window, reserve, consumer가 request 시작에 고정한 optional caller logical output cap과 original request·channel별 assistant prefix를 조립한 뒤의 실제 `rebuilt_prompt_tokens`를 request-local로 고정·계상하며 다음 dispatch allowance는 `min(policy attempt cap, remaining_caller_logical_cap(if set), context_window - rebuilt_prompt_tokens - reserve)`다. provider attempt cap은 내부 운영 단위이고 caller cap은 logical trajectory 전체에 한 번만 적용한다. assistant prefix는 rebuilt prompt에 이미 포함되므로 누적 output을 별도 합산하지 않는다. allowance 또는 context 여유가 없으면 continuation을 만들지 않는다. output-cap `length` 진행은 fault retry가 아니므로 3회 cap으로 자르지 않되, cancel, complete tool call/side effect, terminal commit 또는 consumer/endpoint Rebuilder가 미완성 tool fragment를 lossless continuation prefix로 직렬화하지 못한 경우에는 같은 stream의 final terminal 하나로 수렴한다. Core는 raw fragment를 해석하거나 observation에 넣지 않는다. context 여유 또는 caller logical cap 소진일 때만 host가 endpoint-native logical `length` terminal과 단일 종료 marker를 직렬화하고 attempt 중간 `length`는 commit하지 않는다.
  - `IngressSnapshot`: endpoint/family rebuilder가 unknown caller field를 손실 없이 보존할 수 있는 request-local snapshot이다. `max_ingress_snapshot_bytes` 기본값이자 MVP 절대 상한은 16 MiB이며 policy는 이보다 낮출 수만 있고 request 시작 시 고정한다. host는 `io.ReadAll` 전에 `http.MaxBytesReader` 또는 동등한 limit+1 판정을 raw body에 적용한다. OpenAI JSON endpoint는 raw body를 canonical lossless representation으로 사용하고, 다른 codec의 lossless tree는 byte-preserving round-trip fixture가 있을 때만 허용한다. `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을 넘으면 수용하지 않는다. ingress/rebuild 초과는 snapshot/filter/log/cross-request cache에 원문을 남기거나 provider/recovery budget을 소비하지 않고 terminal로 끝내며 raw auth header도 보존하지 않는다. request 종료/cancel/overflow에서는 retained object를 release한다.
  - `AttemptDispatcher`: host가 구현하며 rebuilt request와 required capability를 기존 admission에 전달해 actual model/provider/execution path, normalized event source와 `AttemptController`를 가진 `AttemptBinding` 하나를 반환한다. concrete provider selection/auth/model rewrite 알고리즘은 Core 밖에 있다.
  - `AttemptController`: 현재 attempt의 provider transport cancel/close와 ownership release를 idempotent하게 수행한다. Core가 plan 선택 시 고정한 request-local preparation/continuation snapshot과 cursor는 지우지 않는다. recovery는 성공적인 abort 또는 명시적 already-closed 확인 전에 preparer나 다음 dispatch를 호출하지 않는다.
  - `RecoveryPlanPreparer`: 선택된 plan이 consumer별 bounded directive 준비를 요구할 때 host/consumer가 구현하는 optional interface다. Core가 all-complete arbitration과 eligibility 판정, current attempt ownership 종료 뒤 plan/idempotency key당 최대 1회 bounded deadline으로 호출한다. 입력은 plan 선택 시 고정한 request-local bounded preparation snapshot이며 구체 범위는 consumer 계약이 정하고 observation/log에는 복제하지 않는다. preparer는 provider admission/dispatch, retry/fallback, budget mutation을 소유하지 않고 성공 시 typed directive만 보강한다. 실패는 bounded cause를 가진 terminal로 수렴하며 outbound recovery dispatch가 없으므로 request recovery budget을 소비하지 않는다. snapshot은 성공·실패·cancel 뒤 release한다.
  - `RequestRebuilder`: host/endpoint/family가 bounded lossless ingress snapshot, selected plan과 continuation snapshot을 새 request로 조립한다. exact replay는 admission rewrite 전 caller raw body를 보존하고 continuation/schema만 typed patch를 적용한다. rebuild 전 예상 peak와 할당 후 실제 peak `retained_bytes`를 모두 확인하고 한도를 넘으면 기존 snapshot과 임시 output을 즉시 release한 뒤 dispatch하지 않는다.
  - `ReleaseSink`: host transport가 staged response-start, safe event, replacement, terminal/error를 순서대로 commit하고 현재 commit state를 반환한다. 첫 commit 뒤 status/header를 다시 쓰거나 opening role/event를 중복 전송하지 않는다.
- 출력:
  - `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#오류-응답)으로 직렬화한다.
  - `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를 재계산한다.
  - `FilterObservation`: filter evaluation 또는 lifecycle/coordinator decision마다 emit하는 내부 timeline event다. 기존 request/run/provider/model correlation과 config generation, attempt/epoch, consumer/filter/rule id, hold mode, event kind, effective/pending rune, decision/failure policy, commit state, terminal reason, plan id/strategy/resume mode/shared attempt, preparer id/status/deadline outcome, 최대 4개의 sanitized cause code와 sanitized evidence를 담는다. 기존 sink가 저장·보존을 소유하며 preparer input/output, raw output/prompt/tool args/result/auth와 delta 원문은 담지 않는다.
- 금지:
  - `stream_hold.evidence_runes`가 부족한 event를 시간 경과만으로 release하지 않는다.
  - provider idle/timeout 시 pending tail을 flush하지 않는다.
  - Core가 raw protocol parser, caller-specific policy, cross-request cache, LLM judge를 소유하지 않는다.
  - 이미 전송한 event를 rollback하거나 exact/schema replay하지 않는다. continuation/replacement도 기존 bytes를 suppress하지 않고 terminal/tool side effect 뒤에는 실행하지 않는다.
  - 활성 filter outcome이 모두 수집되기 전에 release/retry/replace하지 않는다. filter error/deadline을 silent pass로 간주하지 않는다.
  - 하나의 evaluation epoch를 겹쳐 실행하거나 evaluation 중 provider event를 unbounded queue에 적재하지 않는다.
  - provider response status/header 또는 opening role/event를 safe release 전에 eager commit하지 않는다.
  - terminal gate hard bound 초과 시 partial output을 release하지 않는다.
  - 현재 attempt cancel/close ownership이 끝나기 전에 다음 recovery attempt를 dispatch하지 않는다.
  - filter가 request를 직접 mutate하거나 retry loop/counter, provider admission, request submit을 실행하지 않는다.
  - 선택된 recovery plan의 후처리인 `RecoveryPlanPreparer`/translator를 filter evaluation 또는 all-complete barrier 안에서 실행하지 않는다. consumer가 별도 Filter로 선언한 bounded LLM judge까지 금지하는 규칙은 아니지만, 해당 Filter는 자신의 invocation cap/deadline/failure policy를 지켜야 한다. preparer 실패를 재호출/fallback으로 우회하거나 recovery dispatch 없이 budget을 소비하지 않는다.
  - 같은 evaluation epoch/recovery cycle에서 둘 이상의 `RecoveryPlan` 또는 outbound retry를 실행하지 않는다. 단, request-local strategy budget과 request 전체 hard cap이 모두 남아 있고 새 attempt가 다시 violation을 반환하면 다음 cycle을 시작할 수 있다.
  - `max_recovery_attempts_total`을 3보다 높이거나 strategy별 limit 합으로 request 전체 cap을 우회하지 않는다.
  - request body를 unbounded `io.ReadAll`한 뒤 길이만 검사하지 않는다. `max_ingress_snapshot_bytes`를 넘는 요청이나 rebuilt request를 snapshot으로 보존하거나 provider에 dispatch하지 않는다.
  - OpenAI JSON raw body 외 표현을 byte-preserving 증거 없이 exact replay canonical source로 사용하거나 canonical lossless representation의 full copy를 둘 이상 유지하지 않는다.
  - `FilterObservation`에 raw output, raw request/prompt, tool args/result, 인증 정보 또는 caller 제품명을 넣지 않는다.
  - raw stack trace나 provider endpoint/body를 `FailureCauseChain`, `TerminalResult`, public error message, `FilterObservation`에 넣지 않는다.

## Acceptance Scenarios

| ID | Milestone Task | Given | When | Then |
|----|----------------|-------|------|------|
| S01 | `evidence-tail` | rolling text delta가 pending에 누적되고 이전 safe prefix가 release됐다 | 기본 500 rune 또는 policy override 200 rune 증거가 충족돼 다음 batch를 만든다 | filter는 같은 크기의 bounded committed look-behind와 pending을 함께 보아 경계 반복을 판정하고 전체 응답을 buffer하지 않는다. replace-attempt는 초기화하고 continuation은 look-behind/cursor를 보존한다 |
| S02 | `evidence-tail` | 한국어 UTF-8 multi-byte 문자열이 chunk 경계에서 나뉜다 | evidence rune을 계산한다 | byte가 아닌 Unicode rune으로 정확히 계산하고 깨진 문자 없이 release한다 |
| S03 | `commit-boundary` | evidence 미충족 pending tail과 staged response-start가 있고 terminal event가 온다 | Core가 최종 all-filter evaluation을 한다 | safe response-start/output 또는 terminal error가 한 번만 결정되고 eager status/role은 없다 |
| S04 | `commit-boundary` | evidence 미충족 pending tail 상태에서 provider idle timeout이 난다 | terminal error를 처리한다 | pending tail은 release하지 않고 terminal error만 전송한다 |
| S05 | `commit-boundary` | Core가 safe prefix를 전송해 stream이 열렸다 | 이후 provider error 또는 filter violation이 난다 | already released event는 rollback/exact/schema replay하지 않고 continuation-safe가 아니면 terminal policy로 끝낸다 |
| S06 | `policy-hook` | output validation, syntax gate, missing-tool gate, integrity filter, workflow terminal hook이 같은 Core를 소비한다 | 각 filter가 자기 detector decision과 선택적 `RecoveryIntent`를 반환한다 | semantic policy/intent는 filter별로 분리되고 request mutation/retry loop/rebuild/dispatch는 공통 Coordinator만 수행한다 |
| S07 | `policy-hook` | rolling, schema terminal, tool fragment와 provider-error event-only filter가 같은 request에서 활성이다 | Core가 channel requirement와 event applicability outcome을 합성한다 | rolling은 조기 violation 가능, schema는 terminal 전 blocking deferred, tool은 fragment gate, 평상시 provider-error는 not-applicable로 content를 막지 않는다. duplicate buffer/commit은 없다 |
| S08 | `filter-observation` | repeat guard와 syntax gate가 stable filter id 및 sanitized fingerprint/count/offset evidence를 제공한다 | Core가 filter와 coordinator lifecycle event를 emit한다 | 같은 request/run/provider/model timeline에서 config generation, attempt/epoch, staging, 각 decision/failure policy, plan/strategy/resume mode를 추적할 수 있고 raw output/prompt/tool args는 없다 |
| S09 | `event-contract` | OpenAI와 agent-family codec이 response-start를 포함한 서로 다른 raw event를 같은 normalized table로 변환한다 | transport-agnostic Core와 host ReleaseSink가 event를 처리한다 | Core가 raw parser나 Edge/Node internal type을 import하지 않고 typed event/host interface만으로 같은 lifecycle을 통과한다 |
| S10 | `adoption-doc` | output validation, syntax, missing-tool, integrity, workflow consumer 문서가 Core를 참조한다 | consumer boundary와 observation/recovery mapping을 검토한다 | 모든 consumer가 Core link, own semantic policy/intent, stable filter id와 sanitized observation을 명시한다. recovery consumer는 strategy/request-total cap과 common RecoveryPlan을, ingress snapshot consumer는 bounded snapshot을 사용하고 raw buffer·snapshot/rebuild·retry loop를 중복 구현하지 않는다 |
| S11 | `filter-registry` | request 중 config reload가 일어나고 recovery admission이 provider를 바꾸며 required filter capability가 있다 | registry가 request snapshot과 각 attempt actual target으로 active set을 resolve한다 | 같은 config generation을 유지하면서 provider별 set은 다시 계산되고 unsupported candidate는 dispatch 전 제외되며 disabled/duplicate filter는 평가되지 않는다 |
| S12 | `parallel-evaluation` | ready filter, terminal-trigger filter, error-event-only filter가 있고 평가 중 provider event가 더 도착한다 | Gate Coordinator가 evaluated/deferred/not-applicable outcome과 bounded backpressure를 만든다 | complete outcome set 전 action하지 않고 blocking deferred는 pass가 아니며 event-only not-applicable은 release를 막지 않는다. race/overlap/unbounded queue가 없고 failure/cancel policy가 적용된다 |
| S13 | `decision-arbiter` | release/error/terminal base disposition과 pass/not-applicable/deferred/violation/fatal/replacement outcome이 섞여 있다 | Arbiter가 결과를 합성한다 | unmatched provider error는 terminal, matched eligible error는 recovery, blocking deferred는 hold가 되고 priority/stable id로 single action만 선택한다 |
| S14 | `recovery-coordinator` | 두 filter가 같은 epoch에 retryable violation을 반환하고 strategy budget과 기본/절대 상한 3회의 request 전체 recovery cap이 남아 있다 | Coordinator가 intent를 dedupe하고 commit/side-effect별 eligibility와 두 budget을 판정한다 | cycle마다 plan/idempotency key/dispatch 하나만 만들고 exact/schema는 uncommitted에, continuation은 safe stream-open에만 허용한다. 0/1/3회 policy는 적용되고 4 이상 config는 거부되며 strategy 또는 전체 cap 소진, cancel/side-effect/re-entry 위반은 다른 strategy 우회 없이 terminal로 끝낸다 |
| S15 | `request-rebuilder` | configured byte limit 안에서 unknown caller field가 있는 Chat/Responses raw snapshot과 exact/continuation/schema directive가 있다 | endpoint rebuilder와 host dispatcher가 새 attempt를 만든다 | OpenAI JSON raw body를 canonical source로 하나만 보존하고 bounded typed view/rebuild allocation을 계상한다. exact는 admission rewrite 전 caller body와 unknown field를 보존하고 typed patch만 적용한다. concrete model/auth는 admission에서 다시 계산되고 normalized↔tunnel path 전환도 새 `AttemptBinding`으로 이어진다 |
| S16 | `vertical-slice` | model/provider on/off 가능한 `NoopFilter`와 test-only `InjectedViolationFilter`가 등록돼 있다 | staged response-start부터 filters, Arbiter, abort, Rebuilder, Dispatcher, ReleaseSink까지 한 사이클 돈다 | disabled/enabled pass, eager header/role 없음, injected violation one retry, simultaneous violation single retry, provider/path switch, failure policy, backpressure, exhausted terminal이 end-to-end로 검증된다 |
| S17 | `commit-boundary` | provider가 response-start를 보낸 뒤 user body release 전에 filter-matched 500 body/error를 보낸다 | provider-error filter가 exact replay intent를 반환한다 | original status/header/role은 commit되지 않고 retry 성공 attempt의 response-start와 output만 한 번 노출된다 |
| S18 | `recovery-coordinator` | 정상 text prefix가 이미 release된 뒤 repeat filter가 continuation intent를 반환한다 | Coordinator가 tool/terminal side effect가 없는 stream-open eligibility를 확인한다 | released prefix와 committed look-behind/cursor를 보존하고 새 attempt의 opening/prefix 중복 없이 같은 stream에 continuation만 이어 쓰며 exact/schema intent는 거부된다 |
| S19 | `evidence-tail` | terminal-gate filter가 활성이고 provider output이 configured hard bound를 넘는다 | Core가 buffer overflow를 감지한다 | partial output이나 staged response-start를 release하지 않고 attempt를 취소한 뒤 terminal error로 끝낸다 |
| S20 | `recovery-coordinator` | recovery가 선택됐지만 현재 attempt abort가 timeout 또는 실패한다 | Coordinator가 다음 dispatch를 준비한다 | next attempt를 시작하지 않고 terminal로 끝내 두 live provider attempt와 중복 side effect를 방지한다 |
| S21 | `event-contract` | consumer가 `repetition_loop_detected` 뒤 auxiliary recovery step 실패를 뜻하는 `recovery_notice_translation_failed` 원인을 terminal로 올린다 | Core가 terminal result와 host ReleaseSink를 처리한다 | 원인 사슬은 최대 4개의 sanitized code로 보존되고, host는 endpoint별 외부 오류 하나만 전송한다. raw stack/provider body는 observation과 public output에 없다 |
| S22 | `request-rebuilder` | ingress raw body가 pre-read limit을 넘거나 raw body가 gate와 같아도 typed view/rebuild 임시 output을 포함한 logical current peak retained size가 기본값/절대 상한 16 MiB 또는 작은 policy override를 넘는다 | host가 limit+1 overflow를 snapshot 생성 전에 판정하고 SnapshotBuilder/Rebuilder가 owned backing은 합산하되 shared backing은 한 번만 세어 typed view 추가 직후와 rebuild 할당 전후에 retained bytes를 다시 검사한다 | pre-read limit-1/limit은 body gate만 통과하고 limit+1은 즉시 거부된다. 이후 initial retained overflow는 endpoint host의 request-too-large 오류, rebuild overflow는 commit state에 맞는 recovery terminal error 하나로 끝난다. canonical raw body와 임시 object를 release하고 request-local cache·filter·로그에 남기지 않으며 provider dispatch/recovery budget 소비가 없고 16 MiB 초과 config는 거부된다 |
| S23 | `recovery-coordinator` | all-complete Arbiter가 보조 directive 준비가 필요한 continuation plan 하나를 선택했다 | Coordinator가 bounded preparation/continuation snapshot과 cursor를 고정하고 current provider transport ownership을 종료한 뒤 registered `RecoveryPlanPreparer`를 실행한다 | abort가 snapshot을 지우지 않고 preparer는 filter barrier 밖에서 plan/idempotency key당 최대 1회와 bounded deadline을 지킨다. 성공 뒤에만 rebuild/dispatch하고 timeout/invalid/error는 재호출/fallback 없이 single terminal로 끝내며 outbound dispatch가 없으므로 recovery budget을 소비하지 않는다. snapshot은 모든 종료 경로에서 release된다 |
| S24 | `recovery-coordinator` | managed profile의 16K provider attempt가 output-cap `length` terminal을 두 번 반환했고 context window/reserve 여유와 (설정된 경우) 남은 caller logical cap이 있으며 safe prefix가 이미 release됐다 | semantic filter가 `managed_continuation` intent를 반환하고 Coordinator가 trajectory allowance를 계산한다 | fault recovery 3회 cap을 소비하지 않고 original request와 channel별 assistant prefix/cursor로 같은 downstream stream을 이어 간다. 중간 `length`/`[DONE]`·opening/prefix 중복은 없고, context 여유 또는 caller logical cap 소진 때만 endpoint-native logical `length` terminal과 종료 marker를 한 번 전달한다. complete tool call·cancel·lossless fragment serialization 실패에서는 endpoint별 final terminal 하나만 전달한다 |

## Evidence Map

| Scenario | Required Evidence | `agent-task` 연결 | 완료 Evidence 기대 |
|----------|-------------------|------------------|---------------------------|
| S01 | 200/500-rune policy, pending+look-behind bound, cross-boundary repeat, replace reset/continuation preserve tests | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `evidence-tail`, rolling threshold/bounded look-behind/recovery-mode assertion |
| S02 | Korean multi-byte split chunk rune fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `evidence-tail`, Unicode boundary assertion |
| S03 | terminal-before-evidence with staged response-start fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `commit-boundary`, no eager commit/single terminal assertion |
| S04 | provider idle timeout before evidence fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `commit-boundary`, pending-tail no-release assertion |
| S05 | uncommitted/stream-open/terminal-committed error and strategy matrix | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `commit-boundary`, no rollback/exact-schema post-open prohibition assertion |
| S06 | OpenAI and agent-family fake codec consumer decision/intent matrix, direct-submit prohibition check | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `policy-hook`, consumer semantic/intent ownership and common recovery ownership assertion |
| S07 | rolling/terminal/fragment mixed-mode composition and channel-bound tests | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `policy-hook`, strongest bounded requirement/single buffer assertion |
| S08 | multi-consumer observation timeline with config/attempt/epoch/staging/failure/resume mode and raw absence | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `filter-observation`, one raw-free request timeline assertion |
| S09 | OpenAI/agent-family fake codec response-start/event table and host-interface package dependency test | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `event-contract`, transport-agnostic typed contract/no internal import assertion |
| S10 | five dependent Milestone Core-link/filter-id/sanitized-observation/limits/common-RecoveryPlan mapping review | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `adoption-doc`, consumer documentation/no duplicate raw buffer/snapshot/rebuild/retry loop assertion |
| S11 | config-generation isolation, policy precedence, required capability admission, provider-switch and duplicate-id tests | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `filter-registry`, snapshot/attempt re-resolution/preflight assertion |
| S12 | evaluated/deferred/not-applicable mixed outcomes, barrier, race, backpressure, failure/cancel fixtures | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `parallel-evaluation`, complete outcome set/deferred-vs-event-only/single-flight assertion |
| S13 | base disposition + all outcome arbitration matrix, matched/unmatched error and deterministic repeats | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `decision-arbiter`, default terminal preservation/single-action assertion |
| S14 | simultaneous intent, commit-strategy matrix, 0/1/3회 및 4 이상 config validation, bounded cycles, strategy/request-total cap 교차 소진, cancel/side-effect/re-entry fixtures | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `recovery-coordinator`, one plan/dispatch per cycle, absolute total-cap 우선과 no strategy bypass assertion |
| S15 | Chat/Responses bounded raw canonical exact/continuation/schema rebuild, byte-preserving alternative codec, unknown field, auth safety and path-switch tests | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `request-rebuilder`, caller-body equality/retained-byte accounting/host admission/AttemptBinding assertion |
| S16 | staged-start `NoopFilter`/`InjectedViolationFilter` vertical integration with path switch and backpressure | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `vertical-slice`, request-to-recovery-to-release one-cycle assertion |
| S17 | response-start + matched 500 before body, successful replay response exposure fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `commit-boundary`, original start hidden/final start once assertion |
| S18 | stream-open repeat continuation, preserved cursor/look-behind and duplicate opening/prefix suppression fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `recovery-coordinator`, safe post-open continuation/exact-schema rejection assertion |
| S19 | terminal-gate hard buffer overflow and attempt cancel fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `evidence-tail`, fail-closed/no partial release assertion |
| S20 | attempt abort timeout/failure before next dispatch fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `recovery-coordinator`, no overlapping live attempt assertion |
| S21 | bounded failure-cause chain, one terminal result, Chat/Responses host error codec fake fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `event-contract`, raw-free cause chain/endpoint-specific single-error assertion |
| S22 | host pre-read raw-body limit-1/limit/limit+1, exact-limit body+typed-view overflow, configured smaller limit, rebuild pre/post-allocation peak overflow, initial-vs-rebuild terminal and release/raw-absence fixtures | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `request-rebuilder`, body-gate-vs-total-retained 구분/no unbounded read/no dispatch/no budget/no raw retention and 16 MiB absolute-cap assertion |
| S23 | all-complete snapshot freeze, transport-only abort-before-prepare, plan/idempotency-key single call, success/timeout/invalid/error, no-fallback/no-budget/snapshot-release fixtures | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `recovery-coordinator`, preparer의 filter-barrier 외부 실행/one-shot deadline/success-only rebuild/request-local snapshot lifetime assertion |
| S24 | 16K output-cap `length` 2회 이상, context/reserve 및 caller logical cap allowance, original request + channel prefix rebuild, same-stream cursor/opening/prefix/terminal/tool-boundary fixture | `agent-task/m-stream-evidence-gate-core/...` | `Roadmap Completion`에 `recovery-coordinator`, fault 3회 cap과 trajectory ledger 분리·중간 terminal 억제·단일 final terminal assertion |

## Cross-repo Dependencies

- 없음

## Drift Check

- [x] Milestone 기능 Task와 Acceptance Scenario가 일치한다.
- [x] Evidence Map이 code-review/complete.log에서 검증 가능하다.
- [x] agent-contract를 쓰는 경우 SDD에 계약 원문을 복제하지 않았다.
- [x] 사용자 리뷰가 필요한 항목은 없음으로 확인했다.

## 사용자 리뷰 이력

- 2026-07-23: 사용자 요청으로 evidence-based pending tail을 공통 stream mechanics로 분리했다. 기본 500-rune hold와 time-based release 금지는 확정됐다.
- 2026-07-23: 사용자 요청으로 여러 consumer filter의 decision을 같은 request timeline에서 추적할 수 있는 raw-free `FilterObservation` 공통 계약을 추가했다.
- 2026-07-23: Coordinator를 별도 Milestone으로 분리하지 않고 이 Core Milestone 안의 독립 컴포넌트로 두기로 했다. 활성 filter는 동일 immutable evidence batch를 병렬 평가하고 all-complete barrier 뒤 결과를 합성하며, filter는 model/provider별 on/off 가능한 공통 interface 구현체로 detector와 `RecoveryIntent`만 제공한다. 공통 Coordinator가 하나의 plan, strategy/request-total budget, endpoint별 request rebuild와 single re-admission을 소유한다.
- 2026-07-23: 재검토에서 HTTP/SSE response-start staging, rolling/terminal/fragment hold 분리, single-flight backpressure, request-local config snapshot, strategy별 post-commit eligibility와 host adapter interface를 보강했다. 특히 exact/schema replay는 uncommitted에 한정하고, 반복 continuation은 이미 보낸 safe prefix를 보존한 stream-open 복구로 명시했다.
- 2026-07-23: 안정성 재검토에서 strategy별 budget을 합산하는 최초 실행 제외 기본값/절대 상한 3회의 request 전체 recovery hard cap과 기본값/절대 상한 16 MiB lossless ingress snapshot retained-byte hard limit을 추가했다. OpenAI JSON raw body를 canonical source로 하나만 보존하고 host pre-read limit을 적용하도록 확정했다.
- 2026-07-23: consumer별 번역/보조 호출이 병렬 filter barrier 안에서 반복 실행되지 않도록 optional `RecoveryPlanPreparer`를 all-complete/Arbiter와 current attempt ownership 종료 뒤의 one-shot 단계로 추가했다. preparer 실패는 fallback·recovery dispatch·budget 소비 없이 terminal로 수렴한다.
- 2026-07-24: 사용자가 작은 provider `max_tokens` attempt cap에서도 논리적으로 긴 출력을 같은 stream에 이어야 한다고 확정했다. provider output-cap `length`는 semantic consumer가 판정하고 Core는 original request/channel별 assistant prefix·cursor를 보존해 context-window/reserve와 rebuilt prompt token 기반 `ManagedTrajectoryBudget`으로만 다음 attempt를 허용한다. 이는 오류 recovery가 아니므로 fault recovery 3회 cap과 분리하며, 중간 terminal은 외부에 노출하지 않는다.
- 2026-07-25: 재검증에서 rebuilt prompt가 assistant prefix를 이미 포함하므로 누적 output을 다시 합산하지 않도록 allowance 식을 보정했다. 또한 provider attempt cap은 내부 운영값, caller가 명시한 output cap은 논리 요청 전체의 별도 상한으로 고정했다. 둘 중 logical cap이 소진될 때만 endpoint-native `length` terminal을 한 번 전달한다.
- 2026-07-23: cross-request 오류 수집·안전한 지문 기반 중복 집계·연결 소스 분석·수정 제안·프로젝트 작업 문서·사용자 승인·변경 요청·병합·배포·재발 확인은 별도 범용 플랫폼으로 프로젝트화하기로 확정했다. Core는 동기 요청 경로에서 이 루프를 실행하지 않고 raw-free terminal/observation event를 전달하는 경계만 소유한다.

## 작업 컨텍스트

- 표준선: `packages/go/streamgate`는 codec과 semantic filter 사이의 transport-agnostic boundary다. Gate Coordinator가 state/single-flight fan-out/all-complete barrier를, Arbiter가 single action을, RecoveryPlan Coordinator가 strategy eligibility, strategy별 budget, request 전체 hard cap과 abort 뒤 optional one-shot `RecoveryPlanPreparer` 호출 순서를 담당한다. raw parser, concrete admission/auth/model rewrite, preparer 의미와 response writer는 host/consumer interface 뒤에 둔다.
- 구현 접점: Edge `writeProviderTunnelResponse`의 provider response-start header flush와 `streamChatCompletion`의 opening role write는 현재 eager commit 지점이므로 `ReleaseSink` 뒤로 이동한다. `streamBufferedChatCompletion`/`completeChatCompletion`의 tool-validation retry loop는 새 Coordinator의 첫 migration 대상이며 기존 loop와 공존시키지 않는다.
- 표준선: default rolling hold는 text/reasoning release barrier다. terminal 전체가 필요한 schema/judge는 explicit bounded `terminal_gate`, incomplete tool fragment는 `fragment_gate`를 선언한다. rolling look-behind는 사용자 전송을 지연시키지 않고 cross-boundary 판정에만 쓰며 terminal gate를 제외한 기본 경로는 content 전체를 보관하지 않는다.
- 표준선: response status/header와 opening role/event도 user-visible commit이다. 첫 safe release 전에는 staging하고, stream-open 이후 exact/schema replay는 금지한다. continuation recovery는 기존 safe prefix와 look-behind/release cursor를 보존하고 terminal/tool side effect 전 같은 downstream stream에 이어 쓰는 별도 resume mode다.
- 표준선: request 시작 시 registry/config generation을 고정한다. recovery가 provider/path를 바꾸면 같은 snapshot으로 attempt-local active set을 다시 resolve하고, required filter capability는 admission 후보 조건으로 전달한다.
- 표준선: Core는 관측 envelope와 request/run/provider/model correlation을 emit하지만 filter 의미나 observation 저장·보존을 소유하지 않는다. filter는 자기 stable filter/rule id와 sanitized evidence만 채우며, 기존 observability sink가 모든 filter/coordinator decision을 하나의 `FilterObservation` timeline으로 남긴다.
- 표준선: 별도 오류 수정 플랫폼은 `오류 발생 → 수집·민감정보 제거 → 안정 지문 기반 사건 생성/중복 count → 실행 버전·커밋·저장소 연결 → 비동기 LLM 분석과 재현 근거 → 중립 수정 제안 → 프로젝트별 작업 문서 → 사용자 승인 → 격리 수정·테스트·독립 검토 → 변경 요청 → 병합·배포 → 재발 관찰` 생명주기를 소유한다. 같은 오류는 새 작업을 만들지 않고 canonical 사건의 count와 first/last seen·영향 버전만 갱신한다.
- 표준선: 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를 선반영하지 않는다.
- 표준선: 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](../../../../sdd/knowledge-tool-optimization-extension/openai-compatible-output-validation-filters/SDD.md)
