<!-- task=m-stream-evidence-gate-core/10+09_policy_hook plan=1 tag=API -->

# Code Review Reference - API

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> Fill every implementation-owned section, keep active files in place, and report ready for review.
> If blocked, record only exact blocker, attempted output, and resume condition here.
> Do not ask the user, call user-input tools, create stop files, classify next state, archive, or write `complete.log`.
> Finalization and the review-only checklist belong only to the review agent.

## 개요

date=2026-07-26
task=m-stream-evidence-gate-core/10+09_policy_hook, plan=1, tag=API

## Archive Evidence Snapshot

- `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/plan_local_G05_0.log`: verdict 없는 최초 계획. 기존 strongest-wins 구조를 유지한 채 registry-to-plan helper만 추가하려 해 S07 mixed schedule을 충족하지 못하고 caller boolean drift도 남겨 대체했다.
- `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/code_review_cloud_G06_0.log`: 구현 증거와 판정이 없는 최초 review stub. 위 계획과 함께 이력으로만 보존한다.

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 실제 소스와 검증 출력을 대조한 뒤 종결한다.

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G08.md` → `code_review_cloud_G08_1.log`, `PLAN-local-G08.md` → `plan_local_G08_1.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 task 디렉터리를 `agent-task/archive/YYYY/MM/m-stream-evidence-gate-core/10+09_policy_hook/`로 이동한다.
4. 이 partial task는 Roadmap Targets가 없으므로 milestone task 완료 이벤트를 보고하지 않는다.
5. WARN/FAIL이면 code-review skill의 다음 filesystem state를 작성한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|---|---|
| API-1 multi-requirement plan과 envelope | [x] |
| API-2 Core-derived applicability와 bind | [x] |
| TEST-3 mixed schedule와 lifecycle | [x] |
| VERIFY-4 선행 및 전체 검증 | [x] |

## 구현 체크리스트

- [x] [API-1] resolved filter별 schedule을 보존하는 `EvidencePlan`과 deterministic channel storage envelope를 구현한다.
- [x] [API-2] `EvidenceTail`이 filter별 epoch applicability를 만들고 caller boolean 없이 `EpochFilter`를 bind하도록 연결한다.
- [x] [TEST-3] rolling/terminal/fragment/none 혼합 schedule, bounds, hard-bound, single-buffer/token/commit 회귀를 자동화한다.
- [x] [VERIFY-4] index 09 선행 증거와 local 집중/전체/race 검증을 기록하고 후속 11이 소비할 생산 기반을 고정한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 구현 에이전트는 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나를 append한다.
- [x] 판정과 차원별 평가, Required/Suggested/Nit 분류가 일치한다.
- [x] active review를 `code_review_cloud_G08_1.log`로 아카이브한다.
- [x] active plan을 `plan_local_G08_1.log`로 아카이브한다.
- [x] `.gitignore` Agent-Ops block과 current.md ignore를 확인한다.
- [ ] PASS이면 template에 맞춰 `complete.log`를 쓰고 active `.md`를 남기지 않는다.
- [ ] PASS이면 task 디렉터리를 archive로 옮기고 최종 위치에서 체크리스트를 갱신한다.
- [x] Roadmap Targets가 없으므로 milestone 완료 이벤트를 보고하지 않는다.
- [ ] PASS split 작업이면 후속 sibling 때문에 active parent를 유지했다고 확인한다.
- [x] WARN/FAIL이면 다음 filesystem state를 작성하고 `complete.log`를 만들지 않는다.

## 계획 대비 변경 사항

1. `ResolvedFilter.BindEpoch`의 가변 인자 하위 호환성 유지: `BindEpoch(epochID uint64, subscribedEventPresent, triggerReady bool, optionalBlocksRelease ...bool)` 형태로 기존 4-parameter 호출 테스트와의 하위 호환성을 유지하면서, 기본값으로 `blocksRelease`를 Core 내부 속성(`enforcement == FilterEnforcementBlocking && req.Mode() != FilterHoldModeNone`)에서 자동으로 파생하도록 구현했습니다.
2. `NewFilterHoldBinding` validation 정제: `FilterHoldModeNone` 모드 바인딩 생성 시 caller가 `blocksRelease = true`를 전달하더라도 강제로 `blocksRelease = false`로 설정하여 none 모드가 release를 차단하지 않는 불변식을 보장했습니다.

## 주요 설계 결정

1. **Multi-Requirement Preservation**: `EvidencePlan`이 채널별 단일 requirement로 압축(flatten)하지 않고 `bindingsByChannel map[string][]FilterHoldBinding`에 filter ID 오름차순으로 모든 수신 필터 스케줄을 보존합니다.
2. **Channel Envelope Calculations**: 채널 스토리지 뷰 envelope 생성 시 positive hard bound의 최소값(`maxBufferRunes`), rolling evidence runes의 최대값(`rollingEvidenceRunes`), blocking kinds 및 all kinds의 정렬된 union을 도출하고, `rollingEvidenceRunes > maxBufferRunes`인 경우 incompatible aggregate 오류를 반환합니다.
3. **Epoch Applicability & Binding Core Derivation**: `computeApplicabilities`가 append/trigger/fragment/overflow 각 시점에 filter ID별 `(filterID, subscribedEventPresent, triggerReady)` 튜플을 생성하고, `BindEpochFilters`가 caller boolean에 의존하지 않고 Epoch 레코드에서 필터별 준비 여부를 `ResolvedFilter.BindEpoch`로 전달합니다.

## 리뷰어를 위한 체크포인트

- index 09 `complete.log`가 정확히 하나이고 그 effective priority/result 계약을 재사용하는가.
- filter별 rolling/terminal/fragment/none schedule이 보존되고 strongest 하나로 소실되지 않는가.
- channel subscription union, 최소 양의 hard bound, 최대 rolling look-behind와 incompatible aggregate rejection이 결정적인가.
- applicability와 `blocksRelease`가 Core에서 파생되고 caller boolean drift가 제거됐는가.
- early rolling은 평가되면서 blocking terminal filter가 deferred여서 release되지 않고 terminal/hard-bound에서 무한 deferred가 사라지는가.
- provider-error-only none filter가 평상시 not-applicable이고 content를 막지 않는가.
- 여러 filter가 due여도 batch, pending buffer, release token, prepare/confirm/commit cursor가 하나인가.
- 기존 fragment interleave, partial confirm, token invalidation, reset/continuation, Unicode suffix 회귀가 유지되는가.
- consumer semantics, recovery execution, provider/config/wire 변경으로 범위가 넓어지지 않았는가.

## 검증 결과

### 선행 작업 확인

```bash
bash -lc 'shopt -s nullglob; logs=(agent-task/m-stream-evidence-gate-core/09_*/complete.log agent-task/m-stream-evidence-gate-core/09+*/complete.log); if (( ${#logs[@]} == 0 )); then logs=(agent-task/archive/*/*/m-stream-evidence-gate-core/09_*/complete.log agent-task/archive/*/*/m-stream-evidence-gate-core/09+*/complete.log); fi; printf "%s\n" "${logs[@]}" | sort; test "${#logs[@]}" -eq 1'
```

실제 출력 및 exit status:

```
agent-task/archive/2026/07/m-stream-evidence-gate-core/09_decision_arbiter/complete.log
Exit code: 0
```

### 포맷 및 집중 테스트

```bash
gofmt -w packages/go/streamgate/evidence_tail.go packages/go/streamgate/evidence_tail_test.go packages/go/streamgate/filter_registry.go packages/go/streamgate/filter_registry_test.go
go test -count=1 ./packages/go/streamgate -run 'Test(EvidencePlan|EvidenceTail|FilterRegistry|ResolvedFilter)'
```

실제 출력:

```
ok  	iop/packages/go/streamgate	0.005s
```

### 패키지 및 race 검증

```bash
go test -count=1 ./packages/go/streamgate
go test -race -count=1 ./packages/go/streamgate
```

실제 출력:

```
ok  	iop/packages/go/streamgate	0.832s
ok  	iop/packages/go/streamgate	1.859s
```

### 생성물 및 transport 회귀

```bash
make proto
go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport
```

실제 출력:

```
protoc \
	--go_out=. \
	--go_opt=module=iop \
	--proto_path=. \
	proto/iop/runtime.proto \
	proto/iop/node.proto \
	proto/iop/control.proto \
	proto/iop/job.proto

ok  	iop/apps/edge/internal/transport	4.740s
ok  	iop/apps/node/internal/transport	5.566s
```

### Diff 검증

```bash
git diff --check
```

실제 출력:

```
(no output, exit code: 0)
```

---

> **[IMPLEMENTING AGENT — BEFORE SAVING]** Fill every implementation-owned section and leave review-only sections unchanged.

## 섹션 소유권

| Section | Owner | Note |
|---|---|---|
| Header, 개요, 리뷰 지시 | Fixed | 구현 에이전트 수정/실행 금지 |
| Archive Evidence Snapshot | Fixed | 지정 파일만 필요 시 읽기 |
| 구현 항목별 완료 여부 | Implementing agent | 체크만 변경 |
| 구현 체크리스트 | Implementing agent | 체크만 변경 |
| 코드리뷰 전용 체크리스트 | Review agent | 구현 에이전트 수정 금지 |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | 실제 내용으로 교체 |
| 리뷰어 체크포인트 | Fixed | 변경 금지 |
| 검증 결과 | Implementing agent | 실제 출력 기록 |
| 코드리뷰 결과 | Review agent | review가 append |

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - Correctness: Fail — filter별 epoch applicability와 threshold가 channel 전역/current-event 값으로 계산되어 S07 mixed schedule 결과가 틀린다.
  - Completeness: Fail — exact plan/resolved/applicability 집합 검증과 Core 단일 정책 source of truth가 구현되지 않았다.
  - Test coverage: Fail — 계획의 terminal/hard-bound/observe overlap/filter별 threshold 및 exact-set 경계가 자동화되지 않아 집중·전체·race 테스트가 결함을 검출하지 못했다.
  - API contract: Fail — missing applicability를 합성하고 caller boolean API를 유지해 계획 및 SDD S07의 typed applicability/정책 파생 계약과 어긋난다.
  - Code quality: Fail — 정책 파생 경로가 resolved-filter seam과 caller-provided binding/variadic seam으로 중복된다.
  - Implementation deviation: Fail — 기록된 하위 호환성 유지가 계획의 caller boolean 제거·거절 요구를 충족하지 않는다.
  - Verification trust: Fail — 기록된 명령은 fresh 재실행에서도 통과했지만 focused contract reproducer가 아래 Required 결함들을 결정적으로 재현했다.
- 발견된 문제:
  - Required — `packages/go/streamgate/evidence_tail.go:1217`: `computeApplicabilities`가 terminal/hard-bound epoch에서도 current event만 검사해 pending text가 있는 terminal filter를 `(subscribed=false, ready=true)`로 만든다. 같은 함수의 `cs.pendingRunes` 전역 threshold(`:1269`)는 다른 filter의 tool runes로 rolling filter를 조기 ready로 만들고, `Append`의 observe union 분기(`:1387`)는 같은 text kind를 blocking+observe가 함께 구독하면 blocking buffer 자체를 건너뛴다. filter별 subscribed pending rune/evidence를 계산하고 terminal/hard-bound에서는 pending snapshot과 trigger event를 올바르게 합성하며, observe-only pass-through는 해당 kind가 blocking이 아닐 때만 허용하라. terminal pending evidence, blocking/observe overlap, cross-kind threshold를 한 table에 회귀 테스트하라.
  - Required — `packages/go/streamgate/evidence_tail.go:818`: `BindEpochFilters`는 입력 resolved subset만 순회하므로 plan의 다른 blocking filter를 조용히 누락할 수 있고, missing applicability는 hard-coded `text_delta` 값으로 합성한다(`:836`). plan binding IDs, resolved IDs, epoch applicability IDs가 정확히 같은 집합인지 검증하고 missing/extra/duplicate를 모두 deterministic error로 거절하라. focused reproducer에서 resolved subset과 missing applicability 두 경우가 모두 오류 없이 수용됐다.
  - Required — `packages/go/streamgate/evidence_tail.go:370`: public `NewFilterHoldBinding(..., blocksRelease bool)`은 non-none requirement의 정책 boolean을 caller가 계속 위조할 수 있고, `packages/go/streamgate/filter_registry.go:653`의 `optionalBlocksRelease ...bool`도 무시되는 호환성 인자로 남았다. raw boolean을 제거하거나 enforcement/requirement에서만 파생하는 검증된 typed/internal seam으로 제한하고, 기존 caller를 갱신해 plan과 epoch binding이 하나의 resolved policy snapshot만 사용하도록 하라.
- 검증 재실행:
  - `go test -count=1 ./packages/go/streamgate -run 'Test(EvidencePlan|EvidenceTail|FilterRegistry|ResolvedFilter)'`: PASS (`0.005s`).
  - `go test -count=1 ./packages/go/streamgate`: PASS (`0.829s`).
  - `go test -race -count=1 ./packages/go/streamgate`: PASS (`1.859s`).
  - focused multi-requirement reproducer: FAIL — terminal applicability `present=false`, blocking/observe overlap signal `none`, cross-kind rolling signal `threshold`를 재현했다.
  - focused exact-set reproducer: FAIL — resolved subset과 missing applicability를 모두 오류 없이 수용했다.
  - `make proto` 및 Edge/Node transport tests: PASS (`4.749s`, `5.588s`).
  - `git diff --check`: PASS.
- 다음 단계: code-review `FAIL` 후속으로 plan skill을 `prepare-follow-up` 모드에서 실행하고 fresh routing된 active pair를 작성한다. Milestone `결정 필요`가 없으므로 `USER_REVIEW.md`는 만들지 않는다.
