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

# Storage Envelope Mutation-proof 회귀 후속 계획

## 이 파일을 읽는 구현 에이전트에게

`CODE_REVIEW-cloud-G03.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채우는 것이 필수 최종 단계다. 아래 테스트 수정과 검증을 수행하고 실제 notes/stdout/stderr/exit status를 기록한 뒤 active 파일을 유지하고 리뷰 준비 완료를 보고한다. 차단되면 구현 소유 evidence 필드에 정확한 blocker, 시도한 명령/출력, 재개 조건만 기록한다. 사용자에게 질문하거나 user-input 도구를 호출하거나 control-plane stop 파일을 만들거나 다음 상태를 분류하거나 로그 archive/`complete.log` 작성을 수행하지 않는다. 최종화는 code-review skill 전용이다.

## 배경

직전 후속은 exact-set malformed 행렬과 storage-envelope lifecycle을 추가했고 fresh focused/package/race/proto/transport 검증도 통과했다. 그러나 lifecycle fixture의 첫 80 rune과 마지막 80 rune이 같아 잘못된 prefix trim도 통과하며, mixed plan의 대표 mode가 `terminal_gate`인지 직접 검증하지 않는다. 이 후속은 같은 테스트 함수만 mutation-resistant하게 보강한다.

## Archive Evidence Snapshot

- `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/plan_local_G04_3.log`, `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/code_review_cloud_G04_3.log`: `FAIL`(Required 1, Suggested 0, Nit 0). periodic 100-rune fixture가 prefix/suffix 방향 회귀를 구분하지 못하고 representative `terminal_gate` mode assertion이 없다.
- 영향 범위는 `packages/go/streamgate/evidence_tail_test.go`의 `TestMultiRequirementPolicyHookStorageEnvelope/runtimeStorageEnvelopeLifecycle` 하나다. 리뷰 재검증에서 focused/package/race, `make proto`, Edge/Node transport, `gofmt -d`, `git diff --check`는 fresh PASS했다.
- 선행 의존성은 `agent-task/archive/2026/07/m-stream-evidence-gate-core/09_decision_arbiter/complete.log` 하나로 충족된다. Roadmap Targets는 없고 `policy-hook` 완료 판정은 후속 `11+09,10_policy_hook_contract`에 유지된다.

## 분석 결과

### 읽은 파일

- `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/plan_local_G04_3.log`
- `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/code_review_cloud_G04_3.log`
- `agent-task/m-stream-evidence-gate-core/10+09_policy_hook/code_review_cloud_G08_2.log`
- `packages/go/streamgate/evidence_tail.go`
- `packages/go/streamgate/evidence_tail_test.go`
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md`
- `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`
- `agent-spec/index.md`
- `agent-contract/index.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`

### SDD 기준

- SDD `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`는 `[승인됨]`, 잠금 `해제`, 사용자 리뷰 없음이다.
- 대상 Acceptance Scenario는 `S07`, Milestone Task는 `policy-hook`이다. Evidence Map `S07`은 rolling/terminal/fragment mixed-mode composition과 channel-bound test, strongest bounded requirement/single buffer assertion을 요구한다.
- 따라서 체크리스트는 mixed rolling+terminal plan의 representative mode, compiled 1500/80 storage envelope, 한 buffer/token/commit cursor, 정확한 trailing 80-rune suffix를 같은 lifecycle에서 증명하도록 구성한다. 이 partial은 Roadmap Targets 없이 후속 completion evidence만 보강한다.

### 테스트 환경 규칙

- `test_env=local`. `agent-test/local/rules.md`와 매칭 profile `agent-test/local/platform-common-smoke.md`를 읽었다. blank/skeleton, 누락 route, `<확인 필요>` 값은 없다.
- 현재 checkout `/config/workspace/iop-s0`에서 PATH 첫 Go(`command -v go`, resolved path, version, GOROOT)를 기록하고 `-count=1` fresh focused/package/race를 사용한다.
- profile의 quick check에 따라 `make proto`, Edge/Node transport, `gofmt -d`, `git diff --check`를 실행한다. proto/wire와 사용자 실행 경로는 수정하지 않으므로 외부 service, live provider, full-cycle runtime은 적용하지 않는다.

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

- exact-set malformed set은 기존 `TestMultiRequirementPolicyHookExactSetBinding`이 resolved empty/subset/extra/duplicate와 applicability missing/extra/duplicate를 검증하므로 추가 변경이 없다.
- storage lifecycle은 runtime hard bound, rolling window, token, cursor, pending empty, 80-rune 길이를 검증하지만 periodic fixture 때문에 suffix 방향 회귀를 검출하지 못한다.
- mixed fixture에서 `BlockingRequirement("ch").Mode()`를 단언하지 않아 strongest representative mode 회귀를 검출하지 못한다.

### 심볼 참조

none. 심볼 추가·삭제·변경이 없다.

### 분할 판단

split decision policy를 평가했다. 변경은 한 테스트 함수 안의 fixture와 두 assertion으로 같은 ownership, 같은 lifecycle, 같은 focused 검증을 공유한다. API/call-site, 도메인, 선행 작업, 별도 위험 profile 경계가 없고 분리하면 동일 fixture와 검증만 중복하므로 단일 plan이 더 안전하다. 디렉터리의 encoded predecessor 09는 archived `complete.log`로 충족된다.

### 범위 결정 근거

- 포함: `packages/go/streamgate/evidence_tail_test.go`의 `runtimeStorageEnvelopeLifecycle`와 active plan/review evidence.
- 제외: `evidence_tail.go`, `filter_registry.go`, 다른 tests, proto/생성물, contract/spec/roadmap, dispatcher-owned `agent-task/m-stream-evidence-gate-core/WORK_LOG.md`. 생산 동작과 계약은 현재 fresh 검증 대상이지만 수정 대상이 아니다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`; finalizer: `finalize-task-policy.sh`; finalizer_mode: `pair`.
- build closures: scope/context/verification/evidence/ownership/decision 모두 `true`. 한 테스트 함수, 구체적인 mutation case, 현재 checkout에서 재현 가능한 명령, 단일 파일 소유권, 외부 결정 없음으로 닫힌다.
- build grade scores: scope_coupling=0, state_concurrency=1, blast_irreversibility=0, evidence_diagnosis=1, verification_complexity=1, 합계 G03. route_basis=`local-fit`, capability_gap=`none`, none floor=`none`, lane=`local`, filename=`PLAN-local-G03.md`.
- build loop-risk: ordered_transitions state_count=4/adverse_paths=0, concurrent actor_count=0, boundary component_count=2/consumer_count=1, structured mechanisms 없음, variant axes=2(position-sensitive suffix, representative mode)이며 조합 검증이 필요하다. matched signature=`variant_product`, triggered=`true`; signature는 route에 영향을 주지 않았다.
- review closures: scope/context/verification/evidence/ownership/decision 모두 `true`. archived finding, source assertion, fresh output을 독립 대조할 수 있다.
- review grade scores: scope_coupling=0, state_concurrency=1, blast_irreversibility=0, evidence_diagnosis=1, verification_complexity=1, 합계 G03. route_basis=`official-review`, capability_gap=`none`, none floor=`none`, lane=`cloud`, target=`Codex gpt-5.6-sol xhigh`, filename=`CODE_REVIEW-cloud-G03.md`.

## 구현 체크리스트

- [x] [REVIEW_REVIEW_REVIEW_API-1] storage lifecycle fixture를 위치별로 구분되는 100-rune 입력으로 바꾸고 representative terminal mode와 exact trailing 80-rune suffix를 단언한다.
- [x] [VERIFY-2] focused/package/race/proto/transport를 fresh 실행하고 formatting/diff evidence를 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_REVIEW_API-1] Mutation-resistant storage lifecycle

문제: `packages/go/streamgate/evidence_tail_test.go:4737-4814`의 `strings.Repeat("ABCDEFGHIJ", 10)`은 첫 80 rune과 뒤 80 rune이 같다. suffix 대신 prefix를 보존하는 mutant도 현재 equality를 통과하며, 계획이 요구한 representative `terminal_gate` mode assertion도 없다.

해결 방법:

Before (`packages/go/streamgate/evidence_tail_test.go:4756`):

```go
text := strings.Repeat("ABCDEFGHIJ", 10)
// ...
runes := []rune(text)
expected := string(runes[len(runes)-80:])
```

After:

```go
sourceRunes := make([]rune, 100)
for i := range sourceRunes {
	sourceRunes[i] = rune(0x4E00 + i)
}
text := string(sourceRunes)
prefix80 := string(sourceRunes[:80])
expected := string(sourceRunes[20:])
if prefix80 == expected {
	t.Fatal("fixture must distinguish leading and trailing 80 runes")
}

representative, err := plan.BlockingRequirement("ch")
if err != nil || representative.Mode() != FilterHoldModeTerminalGate {
	t.Fatalf("representative mode want terminal_gate, got %s (err=%v)", representative.Mode(), err)
}
```

- 100개 위치별 고유 Unicode rune을 사용해 leading/trailing 80이 다름을 fixture guard로 보장한다.
- 기존 runtime `maxBufferRunes=1500`, `effectiveEvidenceRunes=80`, terminal trigger, one prepared event/token, cursor=1, pending=0 단언을 유지한다.
- `BlockingRequirement("ch")`가 `terminal_gate` representative임을 직접 단언하고 confirm 뒤 look-behind가 `sourceRunes[20:]`와 정확히 같은지 확인한다.

수정 파일 및 체크리스트:

- [x] `packages/go/streamgate/evidence_tail_test.go`: 기존 lifecycle sub-test의 fixture와 assertions만 보강한다.

테스트 작성:

- 경로/이름: `packages/go/streamgate/evidence_tail_test.go`, `TestMultiRequirementPolicyHookStorageEnvelope/runtimeStorageEnvelopeLifecycle`.
- fixture: 100개 position-distinct Unicode rune, rolling 80/max 2000, terminal/max 1500.
- assertion: representative terminal mode, runtime 1500/80 envelope, one token/event/commit, exact trailing 80 rune, leading-prefix mutant rejection.

중간 검증:

```bash
gofmt -d packages/go/streamgate/evidence_tail_test.go
go test -count=1 ./packages/go/streamgate -run '^TestMultiRequirementPolicyHookStorageEnvelope/runtimeStorageEnvelopeLifecycle$' -v
```

예상: formatting diff가 없고 mutation-resistant lifecycle sub-test가 fresh PASS한다.

### [VERIFY-2] Fresh 전체 검증과 evidence

문제: 기존 명령은 모두 통과했지만 periodic fixture 아래 결과라 exact suffix 방향의 신뢰 근거가 아니었다.

해결 방법: 수정된 fixture를 포함해 focused/package/race/proto/transport와 diff를 현재 checkout에서 fresh 실행한다. Go test cache 출력은 허용하지 않는다.

수정 파일 및 체크리스트:

- [x] `CODE_REVIEW-cloud-G03.md`: 실제 명령 출력과 exit status를 기록한다.

테스트 작성: VERIFY 전용 새 테스트/파일은 만들지 않는다. 위 existing sub-test 보강을 실행한다.

중간 검증:

```bash
go test -count=1 ./packages/go/streamgate -run '^TestMultiRequirementPolicyHook(ExactSetBinding|StorageEnvelope)$'
go test -count=1 ./packages/go/streamgate
```

예상: exact-set과 storage-envelope focused 집합 및 package suite가 fresh PASS한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/go/streamgate/evidence_tail_test.go` | REVIEW_REVIEW_REVIEW_API-1, VERIFY-2 |
| `CODE_REVIEW-cloud-G03.md` | VERIFY-2 evidence |

## 최종 검증

```bash
command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT
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'
gofmt -d packages/go/streamgate/evidence_tail_test.go
go test -count=1 ./packages/go/streamgate -run '^TestMultiRequirementPolicyHook(ExactSetBinding|StorageEnvelope)$'
go test -count=1 ./packages/go/streamgate
go test -race -count=1 ./packages/go/streamgate
make proto
go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport
git diff --check
```

예상: host Go identity와 유일한 09 dependency가 확인되고 formatting/focused/package/race/proto/transport/diff가 모두 fresh PASS한다.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
