<!-- task=m-stream-evidence-gate-core/01_event_contract_types plan=1 tag=REVIEW_API -->
<!-- plan-model=GPT-5 -->

# Stream Gate Event Contract Required Findings 후속 구현 계획

## 구현 에이전트 규칙

- 이 task에는 encoded predecessor가 없다. Worker는 `agent-task/**`나 archive를 검색하지 않는다.
- 아래 세 production 파일만 수정하고 구현 체크리스트와 검증 명령을 따른다.
- review stub의 구현 소유 필드와 명령 출력만 채운다.
- `review-ready`를 보고하고 종료한다. code-review, archive, terminal file 작성, 다음 agent 시작은 금지한다.

## 배경

첫 구현은 package compile에는 성공했지만 승인된 SDD S09/S21의 normalized event table, filter decision/outcome, immutable evidence, bounded terminal failure 계약과 다른 공개 타입을 만들었다. archived FAIL의 Required finding은 모두 `packages/go/streamgate`의 세 production 파일 안에서 닫히며, 테스트 작성과 codec/host closure는 이미 분리된 dependent sibling이 소유한다. 이 후속 작업은 공개 계약을 SDD에 맞게 교정하고 dependent sibling이 검증할 안정적인 타입 경계를 제공한다.

## Archive Evidence Snapshot

- 이전 pair:
  - `agent-task/m-stream-evidence-gate-core/01_event_contract_types/plan_local_G04_0.log`
  - `agent-task/m-stream-evidence-gate-core/01_event_contract_types/code_review_local_G05_0.log`
- 판정: `FAIL`
- Required:
  - event kind/base disposition/commit state 상수가 SDD와 다르고 unknown 및 kind-disposition 불일치를 거부하지 않는다.
  - response-start status와 kind별 typed payload가 없으며 공개 disposition과 header map이 계약을 우회하거나 변이시킨다.
  - `FilterDecision`/`FilterOutcome` 의미가 뒤바뀌고 필수 variant와 identity/evidence/intent 필드가 빠졌다.
  - recovery strategy/directive/reason이 임의 문자열이라 strategy별 typed directive와 raw-free evidence 경계가 없다.
  - `EvidenceBatch`가 response-start header를 얕게 복사하고 committed look-behind를 제공하지 않는다.
  - arbitrary-length/invalid cause와 공개 cause slice 때문에 최대 4단계 불변조건이 깨진다.
  - external descriptor와 terminal success/error 상호 배제가 SDD의 단일 안전 오류 직렬화 경계를 표현하지 못한다.
- Suggested: 없음
- Nit: 없음
- 영향 파일: `packages/go/streamgate/event.go`, `packages/go/streamgate/filter_contract.go`, `packages/go/streamgate/terminal.go`
- 기존 검증 evidence: formatter/package compile/Edge·Node transport 회귀는 PASS했으나 package에 test 파일이 없었고, untracked package에 대한 `git diff --check`는 whitespace 증거로 신뢰할 수 없었다.
- Roadmap carryover: 이 sibling은 `event-contract`의 부분 구현이다. 직접 단위 테스트는 `03+01_event_contract_unit_tests`, S09/S21 fake codec·host·import-boundary closure와 최종 Milestone Task 완료 근거는 `02+01+03_codec_contract_fixtures`가 소유한다.

## 분석 결과

### 읽은 파일

- `agent-roadmap/current.md`: 활성 Stream Evidence Gate Core 선택
- `agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md`: Phase 경계
- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md`: `event-contract` 범위, 잠금, sibling closure
- `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`: 전체, S09/S21 및 Evidence Map
- `agent-ops/rules/project/domain/platform-common/rules.md`: 공통 package/import 경계
- `agent-test/local/rules.md`: local 환경 기준
- `agent-test/local/platform-common-smoke.md`: platform-common 검증 profile
- `agent-contract/index.md`: matching outer contract 라우팅
- `agent-contract/outer/openai-compatible-api.md:1`: 1-100, 현재 외부 error envelope와 계획된 단일 terminal error 경계
- `agent-spec/index.md`: matching living spec 라우팅
- `agent-spec/input/openai-compatible-surface.md`: 현재 OpenAI-compatible normalized/passthrough terminal 동작
- `agent-task/m-stream-evidence-gate-core/01_event_contract_types/plan_local_G04_0.log`: 이전 scope와 sibling write ownership
- `agent-task/m-stream-evidence-gate-core/01_event_contract_types/code_review_local_G05_0.log`: FAIL Required 및 기존 검증 evidence
- `packages/go/streamgate/event.go`: 전체
- `packages/go/streamgate/filter_contract.go`: 전체
- `packages/go/streamgate/terminal.go`: 전체
- 테스트 파일: 이 sibling의 현재 package에는 없음. dependent sibling이 작성한다.

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`
- 상태/잠금: `[승인됨]`, `해제`, `USER_REVIEW.md` 없음
- 대상 Acceptance Scenario:
  - `S09` → `event-contract`: OpenAI/agent-family codec이 exact normalized event/base disposition table과 transport-agnostic host interface를 공유한다.
  - `S21` → `event-contract`: sanitized cause code를 최대 4단계로 보존하고 endpoint host가 외부 오류 하나만 직렬화한다.
- Evidence Map:
  - S09: fake codec response-start/event table과 package dependency test
  - S21: bounded failure-cause chain, terminal result, Chat/Responses host error codec fake fixture
- 적용: 이 계획은 S09/S21이 소비할 production 타입과 validation/deep-copy 불변조건만 교정한다. 직접 unit fixture는 `03`, fake codec/host와 import-boundary Evidence Map closure는 `02`의 최종 검증으로 남긴다.

### 테스트 환경 규칙

- `test_env`: `local`
- 읽은 규칙: `agent-test/local/rules.md`, `agent-test/local/platform-common-smoke.md`
- 구현 단계 명령: 세 파일 `gofmt -d`, `make proto`, fresh streamgate package compile, Edge/Node transport 회귀, import boundary 확인
- review 단계: 같은 명령의 원문 evidence를 확인하고 Required별 source validation을 재대조한다.
- Go test cache: 새 공개 계약을 실제로 compile하므로 `-count=1`
- 외부 endpoint/credential/docker/port: 사용하지 않음
- `git diff --check`: 현재 package가 untracked라 false PASS가 가능하므로 검증 계약에서 제외하고 `gofmt -d`를 whitespace evidence로 사용한다.
- 불완전한 환경값: 없음. protoc/generator 또는 Go toolchain 부재는 PASS가 아니라 명령과 오류를 기록한 blocker evidence다.

### 테스트 커버리지 공백

- exact event/base-disposition/commit-state table과 unknown rejection: 현재 test 없음, `03+01_event_contract_unit_tests`가 정상/경계를 작성한다.
- kind별 typed payload와 response-start deep copy: 현재 test 없음, `03`이 constructor/accessor mutation fixture를 작성한다.
- decision/outcome variant, strategy-directive 일치, sanitized evidence shape: 현재 test 없음, `03`이 variant validation을 작성한다.
- pending/look-behind deep copy: 현재 test 없음, `03`이 입력/접근자 변이 격리를 작성한다.
- cause cap/invalid cause/terminal mutual exclusion: 현재 test 없음, `03`이 arbitrary-length와 success/error 경계를 작성한다.
- OpenAI/agent codec table, endpoint별 단일 error, import boundary: `02+01+03_codec_contract_fixtures`가 S09/S21 closure를 작성한다.

### 심볼 참조

- rename/remove 후보:
  - `EventKindToolCall`, `EventKindToolResult`, `EventKindTerminalSuccess`, `EventKindTerminalProviderError`, `EventKindTerminalHostError`
  - `BaseDispositionStaged`, `BaseDispositionCommitted`, `BaseDispositionAbandoned`
  - `CommitStateHold`, `CommitStateCommitted`, `CommitStateAbandoned`
  - string alias 형태의 `FilterDecision`, `FilterOutcome`
- 현재 call site: 정의 파일 외 없음. `packages/go/streamgate` 전체가 untracked 신규 package이고 active production consumer는 아직 없다.
- dependent test siblings는 `01` 완료 뒤 새 공개 계약을 소비하므로 이 구현에서 테스트 파일을 선제 수정하지 않는다.

### 분할 판단

- 선택 candidate: archived FAIL Required를 해결하는 기존 `01_event_contract_types`
- 단일 유지: follow-up은 exact task path를 유지하며 새 sibling을 만들지 않는다.
- complete immediate sibling set:
  - `01_event_contract_types`: 세 production 계약 파일 교정
  - `03+01_event_contract_unit_tests`: `01` 완료 뒤 직접 unit/boundary test
  - `02+01+03_codec_contract_fixtures`: `01`과 `03` 완료 뒤 fake codec/host/import closure
- write set: `packages/go/streamgate/event.go`, `filter_contract.go`, `terminal.go`
- shared mutable state: 없음. dependent siblings는 이 production API를 읽고 별도 `_test.go`만 쓴다.
- collision: 없음. 기존 디렉터리 dependency `03+01`, `02+01+03`이 API 생산 → unit 검증 → closure 순서를 표현한다.
- predecessor: `01`에는 없음.
- 더 분할하지 않는 이유: 세 파일의 enum, typed union, deep-copy, terminal validation이 하나의 공개 계약으로 상호 참조하며 부분 적용 시 package API가 일시적으로 모순된다.

### 범위 결정 근거

- 수정은 현재 세 production 파일로 제한한다. archived Required가 모두 이 write set 안에 있고 사용자가 이 범위만 요청했다.
- `*_test.go`는 `03`, codec/host fixture와 package dependency test는 `02`의 명시 소유이므로 수정하지 않는다.
- `apps/edge/**`, `apps/node/**`, `proto/**`, `packages/go/config/**`, agent-contract/spec/roadmap 문서는 수정하지 않는다.
- 실제 ReleaseSink 상태 머신, codec adapter, eager commit 제거, filter registry, Arbiter, recovery coordinator, request rebuilder, observation은 후속 Milestone Task다.
- 외부 OpenAI error envelope는 현재 active contract를 바꾸지 않는다. production descriptor는 SDD가 요구한 안전한 내부 typed 경계만 제공하고 endpoint 직렬화는 closure sibling에서 검증한다.
- raw parser, semantic detector, provider admission/auth/model rewrite를 공통 package에 추가하지 않는다.
- 이 sibling PASS만으로 `event-contract` 완료를 주장하지 않으므로 `Roadmap Targets`를 넣지 않는다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`
- build:
  - closures:
    - scope_closed=true: seven Required가 세 production 파일의 enum/payload/validation/deep-copy 교정으로 한정된다.
    - context_closed=true: SDD S09/S21, exact FAIL log, 세 파일과 dependent ownership만으로 구현 문맥이 닫힌다.
    - verification_closed=true: formatter, package compile, transport 회귀, import inventory로 이 sibling의 성공 여부를 판정할 수 있다.
    - evidence_trusted=true: exact archived review와 현재 source line을 직접 대조했고 실행 전 PASS 출력은 요구하지 않는다.
    - ownership_closed=true: production write set은 `01`, tests는 `03`, final closure는 `02`로 분리돼 있다.
    - decision_closed=true: Milestone/SDD 잠금이 해제됐고 사용자 결정이 남아 있지 않다.
  - grade scores: scope_coupling=1, state_concurrency=0, blast_irreversibility=1, evidence_diagnosis=1, verification_complexity=1
  - route: `local`, `G04`, `PLAN-local-G04.md`
- review:
  - closures:
    - scope_closed=true: Required별 exact source/SDD checkpoint가 고정돼 있다.
    - context_closed=true: 세 파일과 bounded archive evidence를 한 review context에서 대조할 수 있다.
    - verification_closed=true: source invariant와 계획된 compile/import evidence를 결정적으로 확인할 수 있다.
    - evidence_trusted=true: prior false-positive whitespace evidence는 제외했고 raw command output을 stub에 요구한다.
    - ownership_closed=true: review는 product source를 수정하지 않고 이 pair 판정만 소유한다.
    - decision_closed=true: user-review gate 없이 PASS 또는 후속 finding으로 종결할 수 있다.
  - grade scores: scope_coupling=1, state_concurrency=0, blast_irreversibility=1, evidence_diagnosis=2, verification_complexity=1
  - route: `local`, `G05`, `CODE_REVIEW-local-G05.md`

## 구현 체크리스트

- [ ] `REVIEW_API-1` event kind/base disposition/commit state를 exact SDD 값으로 교정하고 response-start status 및 kind별 typed payload를 immutable constructor/accessor와 validation으로 고정한다.
- [ ] `REVIEW_API-2` filter decision/outcome, typed recovery strategy/directive, bounded sanitized evidence, pending/look-behind `EvidenceBatch`를 SDD 모델로 교정하고 모든 mutable 경계를 deep-copy한다.
- [ ] `REVIEW_API-3` failure cause chain과 external terminal descriptor/result를 private bounded storage, 모든 경계 validation, strict success/error 상호 배제로 교정한다.
- [ ] 계획에 명시한 local 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 채우고 review-ready를 보고한 뒤 현재 실행을 종료한다. code-review를 실행하거나 다음 에이전트를 시작하지 않는다.

### [REVIEW_API-1] Exact event lifecycle과 typed payload

- 문제:
  - `packages/go/streamgate/event.go:26-55`가 SDD 밖의 tool result/host terminal event를 만들고 terminal 종류를 분리한다.
  - `packages/go/streamgate/event.go:57-90`이 release/terminal candidate 대신 staged/committed/abandoned를 사용하며 text/reasoning/tool을 `hold`로 돌리고 unknown을 묵인한다.
  - `packages/go/streamgate/event.go:93-142`의 `ResponseStart`는 status code가 없고 공개 header map이 변이 가능하다.
  - `packages/go/streamgate/event.go:144-190`의 generic string payload와 공개 disposition이 kind별 타입 및 base table을 우회한다.
- 해결 방법:
  - event kind는 `response_start|text_delta|reasoning_delta|tool_call_fragment|terminal|provider_error`, base disposition은 `hold|release_candidate|terminal_success_candidate|terminal_error_candidate`만 허용한다.
  - `BaseDispositionOf`는 unknown kind에 오류를 반환하고 constructor/`Validate`는 kind에서 파생한 disposition 외 값을 거부한다. caller가 임의 disposition을 주입할 공개 필드를 없앤다.
  - response-start는 status code, allowlisted headers, channel/timestamp를 private storage에 보관하고 constructor/accessor에서 map을 deep-copy한다.
  - normalized event는 response-start, text delta, reasoning delta, tool-call fragment, terminal, provider error별 typed payload와 전용 constructor를 제공한다. 한 kind에는 해당 payload 하나만 허용하고 generic payload/extra kind를 거부한다.
  - tool fragment와 provider error의 request-local 원문은 typed event 안에서만 유지하고 terminal/observation용 sanitized 타입으로 자동 복제하지 않는다.
- Before (`packages/go/streamgate/event.go:26-90`):

```go
EventKindToolCall          EventKind = "tool_call"
EventKindToolResult        EventKind = "tool_result"
EventKindTerminalSuccess   EventKind = "terminal_success"
BaseDispositionStaged      BaseEventDisposition = "staged"
BaseDispositionCommitted   BaseEventDisposition = "committed"

func BaseDispositionOf(kind EventKind) BaseEventDisposition {
	// unknown과 text/reasoning/tool도 hold로 수렴한다.
}
```

- After (public contract shape):

```go
const (
	EventKindResponseStart    EventKind = "response_start"
	EventKindTextDelta        EventKind = "text_delta"
	EventKindReasoningDelta   EventKind = "reasoning_delta"
	EventKindToolCallFragment EventKind = "tool_call_fragment"
	EventKindTerminal         EventKind = "terminal"
	EventKindProviderError    EventKind = "provider_error"
)

const (
	BaseDispositionHold                     BaseEventDisposition = "hold"
	BaseDispositionReleaseCandidate         BaseEventDisposition = "release_candidate"
	BaseDispositionTerminalSuccessCandidate BaseEventDisposition = "terminal_success_candidate"
	BaseDispositionTerminalErrorCandidate   BaseEventDisposition = "terminal_error_candidate"
)

func BaseDispositionOf(kind EventKind) (BaseEventDisposition, error)
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/event.go`: exact enum/table, private response-start, typed payload union, constructors/accessors/validation
- 테스트 작성: 이 sibling에서는 skip한다. `03+01_event_contract_unit_tests`가 event table, unknown/mismatch, status/header mutation, kind-payload exclusivity 정상/경계 test를 작성한다.

### [REVIEW_API-2] Filter result 모델과 immutable evidence

- 문제:
  - `packages/go/streamgate/filter_contract.go:8-37`에서 decision이 epoch 상태, outcome이 pass/fail로 정의돼 SDD 의미가 반대다.
  - `packages/go/streamgate/filter_contract.go:39-73`의 arbitrary strategy/directive/reason 문자열은 typed recovery와 raw-free 경계를 강제하지 않는다.
  - `packages/go/streamgate/filter_contract.go:76-121`의 자유 `Reason`은 raw text를 담을 수 있고 fingerprint/count/offset 형태가 없다.
  - `packages/go/streamgate/filter_contract.go:124-199`의 batch가 committed look-behind를 누락하고 decision/outcome/recovery를 evidence 입력과 섞는다.
  - `packages/go/streamgate/filter_contract.go:160-186,220-292`가 nested response-start header를 얕게 복사한다.
- 해결 방법:
  - `FilterDecision`은 `pass|observe|violation|fatal|replacement` kind, consumer/filter/rule id, bounded sanitized evidence, optional intent를 가진 private validated value로 만든다.
  - `FilterOutcome`은 `evaluated|evaluation_error|not_applicable_for_epoch|deferred_by_requirement` kind를 표현한다. `evaluated`만 decision을 요구하고 error variant는 sanitized stable code를 요구하며 나머지는 decision/error payload를 금지한다.
  - recovery strategy를 `exact_replay|continuation_repair|schema_repair` enum으로 만들고 exact/continuation/schema별 directive 타입 중 정확히 하나가 strategy와 일치하도록 validation한다. directive에는 raw prompt/output/provider body/auth string을 넣지 않는다.
  - sanitized evidence는 stable descriptor code, fixed/bounded fingerprint, count, offset 같은 제한된 scalar만 제공하고 arbitrary reason/body 필드를 제거한다.
  - `EvidenceBatch`는 events, channel별 pending, channel별 committed look-behind, staged response-start, terminal flag, commit state, captured time만 보유한다. filter 결과는 batch 밖의 `FilterOutcome` 집합으로 유지한다.
  - event payload/headers와 모든 map/slice를 constructor와 accessor 양쪽에서 재귀 deep-copy하고 각 element를 validation한다.
- Before (`packages/go/streamgate/filter_contract.go:8-46,124-138`):

```go
type FilterDecision string
type FilterOutcome string

type RecoveryIntent struct {
	Strategy  string
	Directive string
	Reason    string
	Priority  int
}

type EvidenceBatch struct {
	events         []NormalizedEvent
	channelPending map[string][]NormalizedEvent
	stagedStart    *ResponseStart
	decisions      []FilterDecision
	outcomes       []FilterOutcome
	recoveries     []RecoveryIntent
}
```

- After (public contract shape):

```go
type FilterDecisionKind string
type FilterDecision struct {
	// private validated identity, evidence, optional intent
}

type FilterOutcomeKind string
type FilterOutcome struct {
	// evaluated decision 또는 sanitized evaluation error
}

type RecoveryStrategy string
type RecoveryDirective struct {
	// exact/continuation/schema 중 strategy와 일치하는 typed branch 하나
}

type EvidenceBatch struct {
	// private events, pending, committed look-behind, staged start,
	// terminal flag, commit state, captured time
}
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/filter_contract.go`: decision/outcome variant, typed recovery, bounded sanitized evidence, look-behind batch, recursive validation/deep-copy
  - [ ] `packages/go/streamgate/event.go`: batch deep-copy가 사용할 typed event copy/accessor helper
- 테스트 작성: 이 sibling에서는 skip한다. `03`이 variant 필수/금지 필드, strategy-directive mismatch, raw-free evidence shape, pending/look-behind 및 nested header mutation isolation을 작성한다.

### [REVIEW_API-3] Bounded cause와 strict terminal result

- 문제:
  - `packages/go/streamgate/terminal.go:11-23`의 commit state가 SDD의 transport lifecycle과 다르다.
  - `packages/go/streamgate/terminal.go:71-98`의 slice alias와 `Append`는 길이 5 이상 입력을 한 번만 자르고 invalid cause를 수용한다.
  - `packages/go/streamgate/terminal.go:105-145`의 descriptor가 `type/code/safe message template/param` 대신 내부 stage와 자유 message를 노출한다.
  - `packages/go/streamgate/terminal.go:147-219`가 공개 descriptor/cause storage를 노출하고 success result에 error descriptor/cause가 함께 있는 상태를 허용한다.
- 해결 방법:
  - commit state는 `transport_uncommitted|stream_open|terminal_committed`만 허용하고 모든 batch/sink 결과 validation에서 unknown state를 거부한다.
  - `FailureCauseChain`을 private slice를 가진 struct로 바꾸고 constructor/append/copy/terminal constructor에서 모든 cause를 validate한다. arbitrary-length 입력은 최신 4개만 보존하고 accessor는 복사본만 반환한다.
  - external descriptor는 private `type`, optional `code`, safe message template, optional `param` descriptor를 제공하고 내부 `stage`를 제거한다. stable token/template validation으로 raw stack/provider body/prompt/output/auth 전달 경로를 만들지 않는다.
  - terminal은 별도 success/error constructor 또는 private outcome kind로 생성한다. success는 descriptor/cause를 금지하고 error는 valid descriptor와 bounded chain을 요구하며 모든 accessor가 defensive copy한다.
  - `ReleaseSink`는 typed response-start/release/terminal과 exact commit state만 교환하고 실제 commit 상태 머신은 구현하지 않는다.
- Before (`packages/go/streamgate/terminal.go:11-22,75-87,105-112,150-156`):

```go
CommitStateHold      CommitState = "hold"
CommitStateCommitted CommitState = "committed"

type FailureCauseChain []FailureCause

type ExternalDescriptor struct {
	Code    string
	Message string
	Stage   string
}

type TerminalResult struct {
	Success       bool
	Error         bool
	ExternalDesc  *ExternalDescriptor
	FailureCauses FailureCauseChain
}
```

- After (public contract shape):

```go
const (
	CommitStateTransportUncommitted CommitState = "transport_uncommitted"
	CommitStateStreamOpen           CommitState = "stream_open"
	CommitStateTerminalCommitted    CommitState = "terminal_committed"
)

type FailureCauseChain struct {
	causes []FailureCause
}

type ExternalDescriptor struct {
	// private error type/code/safe message template/param
}

type TerminalResult struct {
	// private mutually-exclusive success/error state and defensive copies
}
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/terminal.go`: exact commit state, private bounded cause chain, safe descriptor, strict terminal constructors/accessors, ReleaseSink validation boundary
  - [ ] `packages/go/streamgate/filter_contract.go`: evaluation error/intent가 terminal raw-free 타입 경계를 우회하지 않도록 연결
- 테스트 작성: 이 sibling에서는 skip한다. `03`이 invalid cause, arbitrary-length latest-four cap, accessor mutation, descriptor validation, success/error mutual exclusion을 작성하고 `02`가 endpoint별 single-error fake를 닫는다.

## 의존 관계 및 구현 순서

1. `REVIEW_API-1`에서 exact event/commit vocabulary와 typed payload를 먼저 고정한다.
2. `REVIEW_API-2`가 해당 event/commit 타입을 사용해 immutable evidence와 filter result를 재구성한다.
3. `REVIEW_API-3`가 filter error/recovery와 공유하는 sanitized cause/terminal 경계를 확정한다.
4. 세 파일이 함께 compile되는 상태에서만 검증한다. 중간에 dependent sibling의 test/fixture를 수정하지 않는다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/go/streamgate/event.go` | REVIEW_API-1, REVIEW_API-2 |
| `packages/go/streamgate/filter_contract.go` | REVIEW_API-2, REVIEW_API-3 |
| `packages/go/streamgate/terminal.go` | REVIEW_API-3 |

## 최종 검증

1. `gofmt -d packages/go/streamgate/event.go packages/go/streamgate/filter_contract.go packages/go/streamgate/terminal.go`
   - 기대 결과: stdout 없음
2. `make proto`
   - 기대 결과: platform-common local profile setup PASS, 생성물 drift/error 없음
3. `go test -count=1 ./packages/go/streamgate`
   - 기대 결과: 새 production 계약 package fresh compile PASS. 직접 test는 dependent sibling 소유이므로 현재 `[no test files]`여도 이 sibling에서는 허용
4. `go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport`
   - 기대 결과: platform-common Edge/Node transport 회귀 PASS
5. `go list -f '{{range .Imports}}{{println .}}{{end}}' ./packages/go/streamgate | LC_ALL=C sort`
   - 기대 결과: standard library import만 출력되고 `iop/apps/`, `iop/proto/`, `iop/packages/go/config` import 없음

검증 결과를 review stub에 기록하고 review-ready를 보고한 뒤 현재 실행을 종료한다. code-review를 실행하거나 다음 에이전트를 시작하지 않는다.
