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

# Stream Gate evidence-tail 최종 회귀 증거 정합성 계획

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

이 follow-up은 production 동작을 바꾸는 작업이 아니다. `packages/go/streamgate/evidence_tail_test.go`의 남은 assertion·fixture·주석만 고치고 아래 명령을 fresh 실행한다. 완료한 항목만 체크한 뒤 active `CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션에 실제 변경과 stdout/stderr를 채우고 멈춘다. active pair, log, `complete.log`, USER_REVIEW 분류와 task archive는 코드리뷰 에이전트 소유다. 막히면 구현 소유 evidence에 시도한 명령, 실제 출력, 재개 조건만 기록하고 사용자 질문·user-input tool·control-plane stop 파일을 만들지 않는다.

## 배경

strict fragment partial-confirm과 ordered reprepare 자체는 통과하지만 최종 cleanup 회귀가 `b`만 검사하고 실제 코드와 반대인 `a` 잔존 주석을 남겼다. Korean exact suffix fixture도 trailing content가 전부 같은 rune이라 잘못된 시작 위치를 구별하지 못한다. 또한 직전 “full relevant” 정규식은 테스트를 0개 실행했으므로 실제 prefix/package 회귀 출력으로 검증 신뢰를 복구해야 한다.

## Archive Evidence Snapshot

- 직전 계획: `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/plan_local_G04_6.log`
- 직전 리뷰: `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/code_review_local_G05_6.log`
- 판정: `FAIL`
- Required:
  - final fragment confirm 뒤 `fragmentState["a"]`와 `fragmentState["b"]`가 모두 제거되는지 증명하고 실제 동작과 반대인 주석을 고친다.
  - 위치별로 구별되는 Hangul fixture로 2/200/500 exact trailing suffix를 증명한다.
  - 0-test 정규식을 실제 prefix/package test 명령으로 교체하고 fresh stdout을 기록한다.
- Suggested/Nit: 없음.
- 영향 파일: `packages/go/streamgate/evidence_tail_test.go`와 active review evidence.
- 현재 검증 evidence:
  - focused test, package 전체 test, corrected prefix test, race, vet, gofmt/hygiene는 PASS했다.
  - 직전 full-relevant 정규식은 `ok ... [no tests to run]`으로 재현됐다.
  - transport unit은 host `/config/opt/go`의 `crypto/internal/fips140cache` 누락으로 setup failure다.
- Roadmap carryover: 이 subtask는 S01/S02 evidence를 준비하지만 `evidence-tail` Task 완료 체크는 dependent `07+01,06_commit_boundary`가 소유하므로 `Roadmap Targets`를 두지 않는다.
- 구현 에이전트는 위 두 task log와 선행 완료 근거 `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log` 외의 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-ops/rules/common/rules-agent-spec.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/code-review/SKILL.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/finalize-task-routing/SKILL.md`
- `agent-ops/skills/common/plan/templates/review-stub-template.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.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-task/m-stream-evidence-gate-core/06+01_evidence_tail/plan_local_G04_6.log`
- `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/code_review_local_G05_6.log`
- `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`
- `packages/go/streamgate/evidence_tail.go`
- `packages/go/streamgate/evidence_tail_test.go`
- `packages/go/streamgate/event.go`의 `NormalizedEvent`/`ReleaseEvent` constructor·accessor 구간
- `packages/go/streamgate/filter_contract.go`의 `cloneNormalizedEvent` 구간

`agent-spec/index.md`와 `agent-contract/index.md`에는 evidence-tail 내부 release lifecycle에 매칭되는 living spec/contract가 없다. 승인 SDD, 코드와 테스트를 기준으로 삼는다.

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`
- 상태: `[승인됨]`, SDD 잠금 `해제`, 사용자 리뷰/결정 항목 없음.
- S01 / `evidence-tail`: pending/look-behind bound와 partial/full confirm 뒤 정확한 state cleanup evidence가 필요하다.
- S02 / `evidence-tail`: Korean multi-byte content의 Unicode rune boundary가 exact content로 보존돼야 한다.
- Evidence Map S01/S02가 양쪽 fragment state cleanup, 위치별 구별 가능한 Korean 2/200/500 suffix와 fresh package 검증을 이 plan의 checklist로 결정했다.
- S19 overflow 동작은 현재 production 변경이 없고 기존 회귀가 통과하므로 이 follow-up에서 수정하지 않는다.

### 테스트 환경 규칙

- `test_env`: `local`
- `agent-test/local/rules.md`: 존재하며 전체를 읽었다.
- 매칭 profile: `agent-test/local/platform-common-smoke.md`
- toolchain: `/config/.local/bin/go` → `/config/opt/go/bin/go`, `go1.26.2 linux/arm64`, `GOROOT=/config/opt/go`.
- fresh 검증은 `-count=1`을 사용한다. focused `-v`, corrected prefix `-v`, package 전체, race, vet, gofmt, scoped diff/proto/ignored-error/forbidden-symbol 검사를 실행한다.
- proto/config/wire source는 바꾸지 않으므로 `make proto` 대신 generated tree 비변경을 확인한다.
- transport unit은 같은 host toolchain으로 실행한다. `crypto/internal/fips140cache` setup failure가 지속되면 성공으로 바꾸지 말고 실제 stderr와 `/config/opt/go` 복구 후 재실행 조건을 기록한다.

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

- fragment lifecycle은 `[B1,A2]` strict partial, exact `[A2]` reprepare, final confirm까지 실행하지만 final `a` cleanup assertion이 없다.
- Korean test는 length/full-text comparison은 있으나 trailing fixture가 같은 rune이라 잘못된 suffix offset을 구별하지 못한다.
- `callerMutationIsolation`은 generic text look-behind slice mutation을 증명한다. Korean bound별 subtest도 첫 반환 element를 교체한 뒤 exact suffix 재조회를 수행해 직전 통합 checklist를 직접 닫는다.
- 직전 full-relevant 정규식은 테스트를 선택하지 않는다. corrected prefix와 package 전체 명령은 현재 checkout에서 실제 test를 실행해 PASS했다.

### 심볼 참조

- rename/delete/public signature 변경 없음.
- production caller는 아직 없고 `EvidenceTail` 직접 call site는 같은 package test다.

### 분할 판단

- split decision policy를 재평가했다.
- fragment assertion, Korean fixture와 검증 명령 수정은 모두 같은 `evidence_tail_test.go`와 같은 evidence-tail closure를 공유하는 test-only 보완이다.
- API/call-site, domain/ownership, 배포, 외부 검증 경계가 없고 하나를 분리해도 독립 production `complete.log` 가치가 없다. 추가 split은 같은 파일 경쟁과 중복 검증만 만들므로 현재 subtask의 단일 plan을 유지한다.
- 디렉터리의 predecessor `01_event_contract_types`는 `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`로 충족됐다.

### 범위 결정 근거

- 허용 write-set: `packages/go/streamgate/evidence_tail_test.go`와 이 task 디렉터리의 active implementation evidence.
- `packages/go/streamgate/evidence_tail.go`는 read-only 검증 대상이다. 새 failing assertion이 production defect를 직접 증명할 때만 blocker evidence를 남기며 이 plan에서 임의 수정하지 않는다.
- roadmap/SDD/spec/contract/proto/config, sibling task, dispatcher-owned `WORK_LOG.md`, 다른 official review와 unrelated dirty worktree를 수정하지 않는다.

### 최종 라우팅

- evaluation mode: `isolated-reassessment`
- 중립 scratch 입력은 현재 누락 assertion, 구별 불가능한 Korean suffix, 0-test 출력, 단일 test-file write-set, 실제 package/race/transport 출력과 ownership만 포함했고 이전 route-bearing 값은 제외했다.
- build closures: scope/context/verification/evidence/ownership/decision 모두 `true`.
- build scores: scope coupling `0`, state/concurrency `1`, blast/irreversibility `0`, evidence/diagnosis `1`, verification complexity `1`.
- build formatter output: lane `local`, grade `G03`, filename `PLAN-local-G03.md`.
- review closures: scope/context/verification/evidence/ownership/decision 모두 `true`.
- review scores: scope coupling `1`, state/concurrency `1`, blast/irreversibility `0`, evidence/diagnosis `2`, verification complexity `1`.
- review formatter output: lane `local`, grade `G05`, filename `CODE_REVIEW-local-G05.md`.

## 구현 체크리스트

- [x] `[REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1]` final fragment confirm 뒤 `a`/`b` state, pending과 cursor의 bounded cleanup을 정확한 주석과 assertion으로 증명한다.
- [x] `[REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-2]` 위치별로 구별되는 Hangul fixture로 2/200/500 exact release/suffix와 mutation-isolated requery를 증명한다.
- [x] `[REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-3]` 실제 test를 선택하는 focused/prefix/package/race/vet/hygiene/transport 명령을 fresh 실행하고 stdout/stderr를 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1] Fragment cleanup assertion 정합성

**문제**

- `packages/go/streamgate/evidence_tail_test.go:3937-3947`은 final suffix confirm 뒤 `fragmentState["b"]`만 검사한다.
- 같은 구간의 `a` state 잔존 설명은 `evidence_tail.go:1623-1634`의 absolute confirmed end와 반대다.

**해결 방법**

- `[A1]` full confirm → `[B1,A2]` strict partial 1 → exact `[A2]` reprepare → final full confirm 1 순서는 유지한다.
- final confirm 직후 `fragmentState["a"]`와 `fragmentState["b"]`가 모두 없음을 검사한다.
- pending length 0과 cursor 3 assertion을 유지한다.
- `a`가 다음 confirm까지 남는다는 주석을 제거하고 final suffix confirm에서 absolute seq 2가 제거된다는 사실로 고친다.
- 모든 lifecycle/accessor error check를 유지한다.

**수정 파일 및 체크리스트**

- [x] `packages/go/streamgate/evidence_tail_test.go`: `a`/`b` cleanup assertion과 정확한 lifecycle 주석

**테스트 작성**

- 기존 `TestEvidenceTailFragmentCompletionPreservesOtherChannels/interleavedFragmentABExpandsSafePrefixAfterConfirm`만 보강한다.
- 새 파일이나 production 수정은 하지 않는다.

**중간 검증**

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

기대 결과: strict partial/reprepare/final confirm과 `a`/`b` bounded cleanup subtest가 실제 이름과 함께 PASS한다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-2] Distinct Korean suffix와 copy evidence

**문제**

- `packages/go/streamgate/evidence_tail_test.go:4268-4269`는 앞 두 rune만 다르고 검증 대상 trailing content는 전부 `가`다.
- `packages/go/streamgate/evidence_tail_test.go:4337-4350`은 반환 slice를 바꾸지 않고 재조회해 해당 subtest의 defensive-copy 설명을 증명하지 않는다.

**해결 방법**

- `tc.runes` 길이의 fixture를 각 index가 구별되는 유효 Hangul syllable로 만든다. 예: `koreanRunes[i] = rune(0xAC00 + i%11172)`.
- release는 전체 `koreanText`, look-behind는 `string(koreanRunes[len(koreanRunes)-tc.bound:])`와 직접 비교한다.
- 첫 `EffectiveLookBehind`의 `lb[0]`을 다른 유효 `NormalizedEvent`로 교체한 뒤 재조회하여 원 exact suffix가 유지되는지 확인한다.
- mutation용 event constructor와 모든 accessor error를 즉시 검사한다.
- 같은-rune 전제의 loop와 사용되지 않는 `wantTail` field를 제거한다.

**수정 파일 및 체크리스트**

- [x] `packages/go/streamgate/evidence_tail_test.go`: distinct Hangul fixture, exact suffix, mutation/requery assertion과 stale helper 제거

**테스트 작성**

- 기존 `TestEvidenceTailPreservesExactKoreanSuffixContent`의 2/200/500 table만 보강한다.
- 각 case가 잘못된 whole-rune offset과 accessor alias를 구별하는지 assertion한다.

**중간 검증**

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

기대 결과: 2/200/500 subtest가 distinct exact suffix와 mutation-isolated requery를 실제 이름과 함께 PASS한다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-3] Fresh verification 신뢰 복구

**문제**

- 직전 `-run '^Test(FilterHoldRequirement|EvidencePlan|EvidenceTail)$'`는 prefix test를 선택하지 않아 `[no tests to run]`이었다.
- 구현 evidence는 이 출력을 34개 하위 테스트 PASS로 잘못 기록했다.

**해결 방법**

- prefix 검증은 끝 anchor를 제거한 `-run '^Test(FilterHoldRequirement|EvidencePlan|EvidenceTail)'`와 `-v`를 사용해 실제 test 이름을 출력한다.
- 별도로 `/config/.local/bin/go test -count=1 ./packages/go/streamgate`를 실행한다.
- 실제 stdout/stderr를 요약하거나 재구성하지 않고 active review에 그대로 기록한다.
- transport setup failure가 지속되면 stderr와 host Go 복구 조건을 그대로 기록한다.

**수정 파일 및 체크리스트**

- [x] `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/CODE_REVIEW-local-G05.md`: 실제 fresh 명령과 stdout/stderr

**테스트 작성**

- 새 test는 추가하지 않는다. 기존 test 선택 정규식과 evidence 기록을 교정한다.

**중간 검증**

```bash
/config/.local/bin/go test -count=1 -v ./packages/go/streamgate -run '^Test(FilterHoldRequirement|EvidencePlan|EvidenceTail)'
/config/.local/bin/go test -count=1 ./packages/go/streamgate
```

기대 결과: prefix 명령이 실제 test/subtest 이름을 출력하고 package 전체가 cached output 없이 PASS한다.

## 의존 관계 및 구현 순서

1. fragment cleanup assertion과 주석을 고친다.
2. distinct Korean fixture와 mutation/requery assertion을 고친다.
3. corrected fresh 명령 전체를 실행하고 active review evidence를 채운다.

선행 `01_event_contract_types`는 `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`로 충족됐다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/go/streamgate/evidence_tail_test.go` | API-1, API-2 |
| `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/CODE_REVIEW-local-G05.md` | API-3와 구현 evidence |

## 최종 검증

```bash
command -v go
readlink -f "$(command -v go)"
go version
go env GOROOT
/config/.local/bin/go test -count=1 -v ./packages/go/streamgate -run '^(TestEvidenceTailRepreparesOnlyUnconfirmedSnapshotSuffix|TestEvidenceTailFragmentCompletionPreservesOtherChannels|TestEvidenceTailPreservesExactKoreanSuffixContent)$'
/config/.local/bin/go test -count=1 -v ./packages/go/streamgate -run '^Test(FilterHoldRequirement|EvidencePlan|EvidenceTail)'
/config/.local/bin/go test -count=1 ./packages/go/streamgate
/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 'A2 entry.*persists|will be removed on the next confirm|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/prefix/package/race/vet/gofmt/diff/proto/ignored-error/forbidden-symbol 검사는 실제 test를 실행해 PASS한다. Transport unit은 PASS가 원칙이며, 동일 host GOROOT setup failure가 지속되면 실제 stderr와 `/config/opt/go` 복구 후 재실행 조건을 기록하고 다른 toolchain으로 우회하지 않는다. cached test output은 허용하지 않는다.

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