<!-- task=m-stream-evidence-gate-core/06+01_evidence_tail plan=6 tag=REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API -->

# Stream Gate evidence-tail 회귀 증거 폐쇄 계획

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

이 follow-up은 production 동작을 다시 설계하는 작업이 아니다. 현재 `ConfirmRelease`의 absolute fragment sequence 수정은 유지하고, 직전 리뷰에서 빠진 public 회귀 증거만 `packages/go/streamgate/evidence_tail_test.go`에서 보완한다. 아래 두 항목과 fresh 검증을 모두 완료한 뒤 active `CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 채우고 멈춘다.

## 배경

직전 구현은 `confirmedEndSeq := targetEpoch.snapStartSeq + n`으로 fragment state를 정리하도록 production 코드를 수정했고 focused/full/race/vet 검증도 통과했다. 그러나 fragment 회귀가 snapshot 전체를 confirm하면서 이를 partial이라고 부르고 있으며, post-prepare append 배제와 Korean suffix 회귀도 length/repeated-rune assertion만 사용한다. 따라서 green test가 active plan의 exact lifecycle/content 요구를 모두 증명하지 못한다.

## Archive Evidence Snapshot

- 직전 계획: `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/plan_local_G06_5.log`
- 직전 리뷰: `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/code_review_local_G07_5.log`
- 이 두 파일은 이번 follow-up의 유일한 prior-loop archive evidence다.
- 구현 에이전트는 추가 과거 로그나 `agent-task/archive/**`를 탐색하지 않는다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md`
- `agent-contract/index.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`
- `packages/go/streamgate/evidence_tail.go`
- `packages/go/streamgate/evidence_tail_test.go`
- `packages/go/streamgate/event.go`의 event constructor/accessor
- `packages/go/streamgate/filter_contract.go`의 `cloneNormalizedEvent`
- 위 Archive Evidence Snapshot의 두 파일

### 기준

- SDD S01은 pending/look-behind bound와 recovery 보존을, S02는 Korean rune boundary 보존을, S19는 overflow fail-closed를 요구한다.
- 현재 production 변경은 `ConfirmRelease`에서 absolute sequence를 유지하며 확인된 range만 제거한다. 직전 fresh focused/full/race/vet 결과에서 별도 production 결함은 재현되지 않았다.
- API/wire signature 변경과 신규 dependency는 없다. 이번 follow-up에 매칭되는 living `agent-spec` 또는 `agent-contract` 문서는 없다.

### 테스트 환경 규칙

- local 검증은 저장소가 지정한 `/config/.local/bin/go`를 사용한다.
- test cache를 피하기 위해 deterministic test에 `-count=1`을 사용한다.
- race, vet, gofmt, scoped diff/proto/forbidden-symbol 검사를 실행한다.
- transport package는 동일 toolchain으로 실행하고, host GOROOT의 `crypto/internal/fips140cache` 누락이 계속되면 setup failure와 복구 조건을 그대로 기록한다.

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

- `TestEvidenceTailFragmentCompletionPreservesOtherChannels/interleavedFragmentABExpandsSafePrefixAfterConfirm`의 첫 snapshot은 길이 1이고 `ReleasedEvents: 1`이므로 partial confirm이 아니다.
- `TestEvidenceTailRepreparesOnlyUnconfirmedSnapshotSuffix/postPrepareAppendExcludedFromReprepare`는 reprepare 길이만 검사하여 원 snapshot의 정확한 payload/order와 extra event 배제를 구별하지 못한다.
- `TestEvidenceTailPreservesExactKoreanSuffixContent`는 두 distinct prefix 뒤 동일 rune을 반복하고 release/suffix 길이만 검사하여 정확한 원문 및 rune-boundary suffix를 구별하지 못한다.
- 같은 Korean 회귀에서 반환 slice를 변형한 뒤 재조회하는 defensive-copy 증거가 없다.

### 심볼 참조

- public symbol rename/delete는 없다.
- `EffectiveLookBehind`는 `[]NormalizedEvent` defensive copy를 반환하므로 첫 조회 slice의 element를 교체하고 두 번째 조회의 exact text가 유지되는지 확인할 수 있다.
- `ReleaseEvents`, `AsTextDelta`, `AsToolCallFragment`, `ConfirmRelease`의 기존 public 계약만 사용한다.

### 분할 판단

두 항목은 같은 `EvidenceTail` release/confirm lifecycle과 같은 test file을 공유한다. 별도 production 변경이나 독립 배포 단위가 없으므로 한 follow-up plan으로 유지한다. 선행 `01_event_contract_types`의 완료 evidence는 이미 직전 loop에서 확인됐으며 새 의존성은 없다.

### 범위 결정 근거

- 허용 write-set: `packages/go/streamgate/evidence_tail_test.go`와 이 task 디렉터리의 active review artifact.
- `packages/go/streamgate/evidence_tail.go`는 검증 대상이지만 새 실패가 현재 production defect를 직접 증명하지 않는 한 수정하지 않는다.
- unrelated dirty worktree, 다른 official review artifact, roadmap/spec/contract/generated proto는 수정하지 않는다.
- 이 subtask는 roadmap checkbox를 소유하지 않는다. 후속 `07+01,06_commit_boundary`가 evidence-tail 완료 경계를 통합한다.

### 최종 라우팅

기존 lane/grade/filename/archive basename을 제외한 중립 snapshot에서 재평가했다.

- Build score: scope coupling 0, state/concurrency 2, blast/irreversibility 0, evidence/diagnosis 1, verification complexity 1.
- Formatter stdout:

```text
target=build
lane=local
grade=G04
filename=PLAN-local-G04.md
```

- Review score: scope coupling 1, state/concurrency 2, blast/irreversibility 0, evidence/diagnosis 1, verification complexity 1.
- Formatter stdout:

```text
target=review
lane=local
grade=G05
filename=CODE_REVIEW-local-G05.md
```

## 구현 체크리스트

- [ ] `[REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1]` fragment snapshot에서 strict partial confirm, exact suffix reprepare, full confirm과 bounded state cleanup을 증명한다.
- [ ] `[REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-2]` post-prepare append 배제와 Korean release/suffix/copy를 exact content로 증명한다.
- [ ] focused/full/race/vet/gofmt/hygiene/transport 명령을 fresh 실행하고 실제 출력을 기록한다.
- [ ] `CODE_REVIEW-local-G05.md`의 구현 항목별 완료 여부, 구현 체크리스트, 변경 사항, 설계 결정, 검증 결과를 모두 채운다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1] Genuine fragment partial-confirm 회귀

**문제**

- 현재 `[A1]` snapshot에 `ReleasedEvents: 1`을 적용하는 단계는 full confirm이다.
- 따라서 non-zero absolute sequence를 포함한 multi-event fragment snapshot에서 `0 < ReleasedEvents < len(snapshot)`인 경로와 reprepare cleanup을 실행하지 않는다.

**해결 방법**

- 기존 interleaved A/B subtest에서 `[A1]`의 최초 confirm은 유지한다.
- B complete 뒤 exact `[B1,A2]` snapshot에 `ReleasedEvents: 1`을 적용하여 실제 partial confirm을 만든다.
- reprepare 결과가 exact `[A2]` 하나이고 이미 confirmed된 `[B1]`이 다시 나오지 않는지 `AsToolCallFragment`로 확인한다.
- 남은 `[A2]`를 full confirm한 뒤 `fragmentState["a"]`, `fragmentState["b"]`가 모두 제거되고 pending/cursor가 기대 상태인지 확인한다.
- 모든 constructor, append, complete, prepare, accessor, confirm error를 즉시 검사한다.

**수정 파일**

- `packages/go/streamgate/evidence_tail_test.go`

**중간 검증**

```bash
/config/.local/bin/go test -count=1 ./packages/go/streamgate -run '^TestEvidenceTailFragmentCompletionPreservesOtherChannels$'
```

기대 결과: exact `[B1,A2]` → partial confirm 1 → exact `[A2]` reprepare → full confirm 1 lifecycle과 bounded fragment cleanup이 PASS한다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-2] Reprepare/Korean exact evidence

**문제**

- post-prepare append 회귀는 길이 3만 확인한다.
- Korean 회귀는 반복 tail과 rune 길이만 확인하며 defensive-copy 재조회도 없다.

**해결 방법**

- post-prepare append subtest에서 최초 세 payload를 ordered want slice로 보관하고 reprepare된 세 event를 `AsTextDelta`로 변환하여 payload와 순서를 모두 비교한다.
- extra payload가 결과에 없다는 사실을 exact ordered comparison으로 증명한다.
- Korean fixture는 각 index가 구별되는 Hangul rune sequence를 만들어 2/200/500 bound를 검증한다.
- release text는 전체 `koreanText`와 직접 비교한다.
- look-behind text는 `want := string(koreanRunes[len(koreanRunes)-tc.bound:])`와 직접 비교한다.
- 첫 `EffectiveLookBehind` 반환 slice의 element를 교체한 뒤 재조회하여 원 exact suffix가 유지되는지 확인한다.
- 모든 public accessor의 error를 즉시 검사한다.

**수정 파일**

- `packages/go/streamgate/evidence_tail_test.go`

**중간 검증**

```bash
/config/.local/bin/go test -count=1 ./packages/go/streamgate -run '^(TestEvidenceTailRepreparesOnlyUnconfirmedSnapshotSuffix|TestEvidenceTailPreservesExactKoreanSuffixContent)$'
```

기대 결과: post-snapshot append가 exact content 기준으로 제외되고, 2/200/500 Korean suffix와 defensive copy가 모두 PASS한다.

## 의존 관계 및 구현 순서

1. genuine fragment partial-confirm 회귀를 먼저 작성하고 production 수정 없이 통과하는지 확인한다.
2. reprepare exact ordered content assertion을 추가한다.
3. Korean fixture와 exact release/suffix/copy assertion을 추가한다.
4. fresh 검증 전체를 실행하고 active review evidence를 채운다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/go/streamgate/evidence_tail_test.go` | 두 follow-up 항목의 test evidence |
| `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/CODE_REVIEW-local-G05.md` | 구현 체크, 변경/evidence와 실제 검증 출력 |

## 최종 검증

```bash
command -v go
readlink -f "$(command -v go)"
go version
go env GOROOT
/config/.local/bin/go test -count=1 ./packages/go/streamgate -run '^(TestEvidenceTailRepreparesOnlyUnconfirmedSnapshotSuffix|TestEvidenceTailFragmentCompletionPreservesOtherChannels|TestEvidenceTailPreservesExactKoreanSuffixContent)$'
/config/.local/bin/go test -count=1 ./packages/go/streamgate -run '^Test(FilterHoldRequirement|EvidencePlan|EvidenceTail)'
/config/.local/bin/go test -race -count=1 ./packages/go/streamgate
/config/.local/bin/go vet ./packages/go/streamgate
gofmt -d packages/go/streamgate/evidence_tail.go packages/go/streamgate/evidence_tail_test.go
git diff --check -- packages/go/streamgate agent-task/m-stream-evidence-gate-core/06+01_evidence_tail
git status --short -- proto/gen/iop
if awk '
/^func TestEvidenceTailRepreparesOnlyUnconfirmedSnapshotSuffix/ { on = 1 }
/^func TestEvidenceTailFragmentCompletionCreatesSafePrefixEpoch/ { on = 0 }
/^func TestEvidenceTailFragmentCompletionPreservesOtherChannels/ { on = 1 }
/^func TestEvidenceTailTerminalGateConfiguredTrigger/ { on = 0 }
/^func TestEvidenceTailPreservesExactKoreanSuffixContent/ { on = 1 }
on { print FNR ":" $0 }
' packages/go/streamgate/evidence_tail_test.go |
	rg -n '(, _ :=|, _ =|^[0-9]+:[[:space:]]*tail\.(Append|ConfirmRelease|CompleteFragment)\()'; then
	exit 1
fi
! rg -n --sort path 't\.Skip|RegisterFragment|tokenToChannel' packages/go/streamgate/evidence_tail.go packages/go/streamgate/evidence_tail_test.go
/config/.local/bin/go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport
```

기대 결과: focused/full/race/vet/gofmt/diff/proto/ignored-error/forbidden-symbol 검사는 PASS하고 cached test output은 없다. Transport unit은 PASS가 원칙이며, 동일 host GOROOT 누락이 지속되면 실제 setup failure와 `/config/opt/go` 복구 후 재실행 조건을 기록한다. 다른 toolchain으로 우회하지 않는다.

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