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

# Stream Gate Evidence Tail 상태 불변조건 보완 계획

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

- 구현 체크리스트와 검증 명령을 완료하고 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션에 실제 변경 내용과 stdout/stderr를 기록한다.
- active PLAN/CODE_REVIEW 파일은 유지하고 review-ready만 보고한다. 판정, 로그 rename, `complete.log`, task archive는 code-review 책임이다.
- 막히면 정확한 차단 원인, 시도한 명령과 출력, 재개 조건만 구현 소유 evidence에 기록한다.
- 사용자에게 질문하거나 선택지를 제시하거나 user-input 도구·control-plane stop 파일을 만들거나 다음 상태를 분류하지 않는다.

## 배경

첫 구현은 green test를 만들었지만 epoch와 prepared snapshot을 결속하지 않았고, fragment와 channel pending의 release 경계를 분리하지 못했다. requirement 합성과 event applicability도 binding 순서와 내부 slice 노출에 영향을 받으며, committed cursor와 exact rune look-behind가 빠져 SDD S01/S02를 충족하지 못한다. 이 follow-up은 기존 공개 foundation을 두 소스 파일 안에서 폐쇄하고 dependent commit-boundary 작업이 신뢰할 수 있는 API를 제공한다.

## Archive Evidence Snapshot

- 이전 plan: `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/plan_local_G05_0.log`
- 이전 review: `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/code_review_local_G06_0.log`
- 판정: `FAIL`
- Required:
  - epoch을 검증하지 않는 channel 임의 선택과 mutable pending 기반 confirm을 epoch-bound one-shot snapshot으로 교체한다.
  - fragment를 `Append`에서 channel+tool-call ID별로 누적하고 completed safe prefix만 release한다.
  - requirement의 public hard-bound 구성, deterministic composition, defensive subscription, event applicability, fail-closed UTF-8를 완성한다.
  - committed cursor와 effective evidence-rune look-behind를 구현하고 oversized event도 exact rune bound로 자른다.
- Suggested: 없음
- Nit: 없음
- 영향 파일: `packages/go/streamgate/evidence_tail.go`, `packages/go/streamgate/evidence_tail_test.go`, active review stub.
- 현재 검증 evidence: focused fresh test, package race, vet, gofmt, diff hygiene는 현재 checkout에서 PASS하지만 기존 test가 Required 변형을 assert하지 않아 correctness evidence로 충분하지 않다.
- 환경 evidence: host `go`는 `/config/opt/go/bin/go`의 `go1.26.2`; Edge/Node transport unit은 host GOROOT의 `crypto/internal/fips140cache` 누락으로 setup failure다.
- Roadmap carryover: 이 foundation은 S01/S02 core와 S19 tail overflow signal만 준비한다. attempt cancel→terminal/no-release 통합과 `evidence-tail` Roadmap Task 완료는 dependent `07+01,06_commit_boundary`가 소유하므로 이 plan에는 `Roadmap Targets`를 두지 않는다.
- 구현자는 위 두 task log와 명시된 predecessor `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log` 외의 `agent-task/archive/**`를 탐색하지 않는다.

## 분석 결과

### 읽은 파일

- `packages/go/streamgate/evidence_tail.go`
- `packages/go/streamgate/evidence_tail_test.go`
- `go.mod`
- `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-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-spec/index.md`
- `agent-contract/index.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-task/m-stream-evidence-gate-core/06+01_evidence_tail/plan_local_G05_0.log`
- `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/code_review_local_G06_0.log`
- `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`
- `.gitignore`

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`
- 상태: `[승인됨]`, SDD 잠금 `해제`, 사용자 리뷰 `없음`
- 대상 Acceptance Scenario:
  - S01 / `evidence-tail`: 200/500 rune, bounded pending+committed look-behind, cross-boundary evidence, replace reset와 continuation cursor preserve.
  - S02 / `evidence-tail`: valid Korean UTF-8 chunk의 Unicode rune 경계.
  - S19 / `evidence-tail`: terminal-gate hard bound의 tail-side fail-closed/no-release signal. attempt cancel과 terminal integration은 dependent `07` 범위다.
- Evidence Map의 S01/S02가 effective rune look-behind, cursor recovery, Unicode boundary 회귀를 요구하므로 `REVIEW_API-2`의 checklist와 검증에 직접 포함했다.
- S19는 fragment/terminal hard-bound overflow가 release snapshot을 만들지 않는 assertion까지만 이 plan이 제공하고, Roadmap completion evidence는 dependent task로 넘긴다.

### 테스트 환경 규칙

- `test_env`: local
- `agent-test/local/rules.md`: 존재하며 전체를 읽었다.
- matching profile: `agent-test/local/platform-common-smoke.md`를 읽었다.
- 적용 기준: PATH에서 처음 해석되는 host `go`만 사용하고 `GOTOOLCHAIN`이나 별도 바이너리로 우회하지 않는다. fresh focused test, package race, vet, gofmt, proto diff hygiene를 사용한다.
- current preflight:
  - runner/workdir: local checkout `/config/workspace/iop`
  - host Go: `/config/.local/bin/go` → `/config/opt/go/bin/go`, `go1.26.2 linux/arm64`, `GOROOT=/config/opt/go`
  - dirty state: 이 Milestone의 여러 active task와 agent-ops 변경이 공존하므로 구현자는 이 task의 두 streamgate 파일과 task-local evidence만 수정한다.
  - source sync: 현재 checkout의 untracked evidence-tail 두 파일이 plan source of truth다.
  - external host/service/credential/port: 없음
- 현재 fresh focused/race/vet/gofmt/diff hygiene는 PASS했다.
- profile의 Edge/Node transport unit은 `crypto/internal/fips140cache is not in std` setup failure가 재현됐다. 이 package-only 변경의 결정적 검증은 streamgate focused/race/vet이며, transport 명령은 host 설치 blocker를 그대로 기록하는 보조 회귀 evidence다. host 설치를 task 범위에서 우회하거나 수정하지 않는다.
- proto/config/wire와 사용자 실행 entrypoint를 바꾸지 않으므로 Edge-Node full-cycle은 적용하지 않는다.

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

- 기존 requirement test는 서로 다른 mode의 우선순위만 보며 같은 mode threshold/bound 순서 반전, public max-buffer override, defensive-copy mutation을 검증하지 않는다.
- 기존 append test는 비구독 event와 observe-only/no-hold invalid UTF-8을 검증하지 않는다.
- 기존 prepared release test는 pending rune 수를 epoch ID처럼 넘겨 잘못된 epoch, multi-channel, post-prepare append, overlapping prepared token, prepared snapshot보다 큰 confirm을 놓친다.
- 기존 fragment test는 `RegisterFragment`를 별도 호출하고 각 ID를 한 event만 보며 interleaved incomplete ID의 release 격리와 per-ID bound를 검증하지 않는다.
- 기존 look-behind test는 pending 수만 확인하며 committed cursor, effective evidence window, oversized single-event rune slicing을 검증하지 않는다.

### 심볼 참조

- 현재 production call site: 없음. `rg --sort path` 결과 새 evidence-tail public symbol은 이 source/test와 dependent task plan 문서에서만 참조된다.
- 변경 후보: `RegisterFragment`는 `Append`의 단일 state-owner 계약으로 흡수한 뒤 제거한다. 현재 call site는 `packages/go/streamgate/evidence_tail_test.go`뿐이며 함께 갱신한다.
- 기존 default constructor는 유지하고 explicit `max_buffer_runes`를 받는 public constructor variant를 추가해 dependent task의 source compatibility를 지킨다.
- 새 third-party dependency는 없으며 `go.mod` 변경은 필요 없다.
- 매칭되는 active agent-spec/agent-contract 구현 문서는 없다. 외부 API, wire, config schema는 바꾸지 않는다.

### 분할 판단

- split decision policy를 routed filename 선택 전에 적용했다.
- shared task group: `m-stream-evidence-gate-core`
- 현재 subtask: `06+01_evidence_tail`; predecessor `01`은 `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`로 충족됐다.
- requirement composition, epoch/prepared snapshot, fragment safe prefix와 cursor/look-behind는 모두 같은 `EvidenceTail` pending entry와 epoch record를 공유한다. 별도 plan으로 나누면 같은 두 파일의 state representation을 경쟁적으로 바꾸고 한 불변조건을 다른 plan이 다시 작성하므로 독립 review 단위가 아니다.
- dependent `07+01,06_commit_boundary`의 sink progress/attempt cancel/terminal integration과 `08+02,05,06_filter_registry`의 registry/policy ownership은 기존 sibling 경계로 유지한다.

### 범위 결정 근거

- 수정 write-set은 `packages/go/streamgate/evidence_tail.go`, `packages/go/streamgate/evidence_tail_test.go`, active `CODE_REVIEW-*.md` evidence다.
- `ReleaseSink`, `CommitBoundary`, attempt cancel, terminal codec, concrete registry/policy, Edge/Node adoption은 sibling 소유이므로 구현하지 않는다.
- roadmap, SDD, agent-spec, agent-contract, proto/config, sibling task 파일을 수정하지 않는다.
- raw output을 observation/log/cross-request state에 복제하지 않고 request-local cloned event와 bounded rune evidence만 유지한다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`
- build:
  - closures: scope/context/verification/evidence/ownership/decision 모두 `true`
  - 근거: 두 source/test 파일과 SDD S01/S02/S19 tail invariant, deterministic 검증, sibling 책임이 닫혔고 사용자 결정이 없다.
  - scores: scope coupling 1, state/concurrency 2, blast/irreversibility 1, evidence diagnosis 1, verification complexity 1
  - result: `local`, `G06`, `PLAN-local-G06.md`
- review:
  - closures: scope/context/verification/evidence/ownership/decision 모두 `true`
  - 근거: source-level invariant와 새 regression/race test로 판정 가능하며, green legacy test와 실패한 work-log evidence의 불일치는 명시적으로 재검증할 수 있다.
  - scores: scope coupling 1, state/concurrency 2, blast/irreversibility 1, evidence diagnosis 2, verification complexity 1
  - result: `local`, `G07`, `CODE_REVIEW-local-G07.md`

## 구현 체크리스트

- [ ] `REVIEW_API-1` public hard-bound constructor, deterministic strongest composition, defensive subscription copy, subscribed event applicability와 fail-closed UTF-8를 구현하고 순서 반전·bound matrix·mutation·비구독 회귀를 통과시킨다.
- [ ] `REVIEW_API-2` epoch-bound one-shot prepared snapshot, overlapping/stale confirm 방지, committed cursor와 exact evidence-rune look-behind를 구현하고 multi-channel·post-prepare append·partial/full confirm·oversized event·recovery 회귀를 통과시킨다.
- [ ] `REVIEW_API-3` fragment state를 `Append`가 channel+tool-call ID별로 누적·bounded 관리하고 completed contiguous safe prefix만 epoch/release snapshot에 결속하도록 구현해 interleaved ID·multi-fragment·overflow 회귀를 통과시킨다.
- [ ] 호스트 `go` 기준 fresh focused/race/vet, proto/diff hygiene와 transport setup 결과를 실제 출력으로 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_API-1] Requirement 합성과 event applicability 폐쇄

- 문제:
  - `packages/go/streamgate/evidence_tail.go:125-201`의 public constructor는 hard bound override를 표현하지 못한다.
  - `packages/go/streamgate/evidence_tail.go:389-410`은 같은 mode의 threshold/bound를 합성하지 않아 binding 순서에 따라 결과가 달라진다.
  - `packages/go/streamgate/evidence_tail.go:498-500`은 내부 subscribed-kind slice를 그대로 노출한다.
  - `packages/go/streamgate/evidence_tail.go:690-714`은 subscribed kind를 검사하지 않고 no-hold 경로에서 UTF-8 validation보다 먼저 Ready를 반환한다.
- 해결 방법:
  - 기존 default constructor는 `NewFilterHoldRequirementRollingWithMaxBuffer`, `NewFilterHoldRequirementTerminalGateWithMaxBuffer`, `NewFilterHoldRequirementFragmentGateWithMaxBuffer`에 위임한다. 각 variant는 마지막 인자로 `maxBufferRunes int`를 받는다. rolling은 `max_buffer_runes >= evidence_runes`를 강제하고 terminal/fragment도 public hard bound range를 검증한다.
  - channel 합성은 subscribed kind union과 mode priority를 유지하되 같은 rolling mode의 evidence threshold는 max, 모든 blocking hard bound는 min으로 합성한다. trigger가 양립하지 않거나 합성 hard bound가 threshold에 못 미치면 plan compile error로 거부한다.
  - `SubscribeKinds`와 requirement/binding accessor는 defensive copy를 반환한다.
  - `Append`는 event 자체와 UTF-8을 먼저 검증하고, channel subscription/trigger applicability를 판정한 뒤에만 pending에 넣는다. 비구독 event는 hold state를 변경하지 않고 Ready/not-held 결과로 처리한다.
- Before (`evidence_tail.go:406-410`):

```go
existing, exists := plan.blockingRequirements[ch]
if !exists || strongerMode(req.Mode(), existing.Mode()) {
	plan.blockingRequirements[ch] = req
}
```

- After:

```go
merged, err := mergeBlockingRequirement(existing, req)
if err != nil {
	return evidencePlan{}, err
}
plan.blockingRequirements[ch] = merged
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/evidence_tail.go`: explicit-bound constructor, matrix validation, deterministic merge, defensive copy, applicability helper
  - [ ] `packages/go/streamgate/evidence_tail_test.go`: order reversal, same-mode threshold/bound, incompatible bound, accessor mutation, unsubscribed event, no-hold invalid UTF-8
- 테스트 작성:
  - `TestFilterHoldRequirementValidatesPublicBoundMatrix`: default/override/min/max/reachable threshold를 검증한다.
  - `TestEvidencePlanComposesDeterministicallyAndDefensively`: binding 순서 반전 결과와 returned slice mutation isolation을 검증한다.
  - `TestEvidenceTailAppliesSubscriptionsAfterFailClosedValidation`: 비구독 event 무상태와 observe/no-hold invalid UTF-8 거부를 검증한다.
- 중간 검증:
  - `go test -count=1 ./packages/go/streamgate -run '^Test(FilterHoldRequirementValidatesPublicBoundMatrix|EvidencePlanComposesDeterministicallyAndDefensively|EvidenceTailAppliesSubscriptionsAfterFailClosedValidation)$'`
  - 기대 결과: PASS, cached output 불허

### [REVIEW_API-2] Epoch snapshot, cursor와 exact look-behind

- 문제:
  - `packages/go/streamgate/evidence_tail.go:864-902`는 epoch을 조회하지 않고 map iteration으로 pending channel을 선택하며 token에 snapshot identity가 없다.
  - `packages/go/streamgate/evidence_tail.go:908-957`은 prepared event 수가 아니라 현재 pending 길이로 confirm하고 post-prepare append/overlapping token을 commit할 수 있다.
  - `packages/go/streamgate/evidence_tail.go:949-953`은 look-behind를 hard buffer로 trim하며 release cursor를 구현하지 않는다.
  - `packages/go/streamgate/evidence_tail.go:1084-1111`은 마지막 event 하나가 bound보다 커도 whole event를 남긴다.
- 해결 방법:
  - pending을 monotonic sequence가 있는 internal entry로 관리하고 epoch record에 channel, exact safe-prefix sequence/snapshot, prepared 상태를 고정한다.
  - `PrepareRelease(epochID)`는 known ready epoch만 one-shot token record로 만들고 channel별 overlapping prepared token을 거부한다. `ConfirmRelease`는 token snapshot prefix와 `ReleasedEvents` upper bound를 검증해 current pending의 동일 sequence만 commit한다.
  - partial confirm은 token을 소비하되 같은 epoch의 unreleased suffix를 재-prepare할 수 있게 record를 갱신하고, full confirm/replace/terminal은 epoch과 token을 폐기한다.
  - channel별 committed cursor는 sink-confirmed event 수만 증가시킨다. replace는 초기화하고 continuation은 cursor/look-behind를 보존한다.
  - rolling look-behind는 `evidence_runes` 이하의 Unicode suffix가 되도록 oversized single event도 rune boundary에서 잘라 defensive snapshot으로 보존한다.
- Before (`evidence_tail.go:864-875`):

```go
var channel string
var found bool
for ch, cs := range t.channelState {
	if len(cs.pendingEvents) > 0 {
		channel = ch
		found = true
		break
	}
}
```

- After:

```go
epoch, ok := t.epochs[epochID]
if !ok || epoch.consumed || t.preparedByChannel[epoch.channel] != "" {
	return PreparedRelease{}, errInvalidPreparedEpoch
}
record := newPreparedRecord(epoch, t.pendingPrefix(epoch))
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/evidence_tail.go`: sequenced pending entries, epoch/prepared records, one-shot validation, committed cursor accessor, rune-exact trim, recovery invalidation
  - [ ] `packages/go/streamgate/evidence_tail_test.go`: unknown/stale epoch, multi-channel, append-after-prepare, overlapping prepare, over-confirm, partial reprepare, cursor transitions, oversized Korean event
- 테스트 작성:
  - `TestEvidenceTailBindsPreparedReleaseToEpochSnapshot`: multi-channel map order와 post-prepare append가 snapshot 밖임을 검증한다.
  - `TestEvidenceTailRejectsOverlappingAndOversizedConfirmation`: concurrent prepared token과 prepared count 초과 confirm을 거부한다.
  - `TestEvidenceTailPreservesCursorAndExactRuneLookBehind`: partial/full confirm cursor, exact rune suffix, replace/continuation 차이를 검증한다.
- 중간 검증:
  - `go test -race -count=1 ./packages/go/streamgate -run '^TestEvidenceTail(BindsPreparedReleaseToEpochSnapshot|RejectsOverlappingAndOversizedConfirmation|PreservesCursorAndExactRuneLookBehind)$'`
  - 기대 결과: PASS, race 없음, cached output 불허

### [REVIEW_API-3] Fragment safe-prefix와 per-ID bound

- 문제:
  - `packages/go/streamgate/evidence_tail.go:770-832`는 `Append`와 별도 `RegisterFragment`를 요구하고 같은 ID의 후속 fragment를 누적하지 않는다.
  - completed ID를 fragment map에서 즉시 지우지만 epoch은 그 ID의 event snapshot을 보존하지 않는다.
  - `PrepareRelease`가 channel pending 전체를 반환해 interleaved incomplete tool call까지 노출할 수 있다.
- 해결 방법:
  - `Append`가 `ToolCallFragment.ID`를 추출해 channel+ID keyed fragment state와 channel ordered pending entry를 원자적으로 갱신한다. `RegisterFragment`는 제거하고 유일한 state mutation 경로를 유지한다.
  - per-ID rune count와 channel total에 hard bound를 적용하며 overflow는 pending/epoch/release를 만들지 않는다.
  - `CompleteFragment`는 ID를 completed로 표시하고 channel pending의 앞에서부터 completed ID에 속한 contiguous safe prefix만 epoch snapshot으로 고정한다. incomplete ID 뒤 event는 같은 ID가 complete여도 다음 epoch까지 보류한다.
  - confirm된 entry만 fragment state에서 제거하고, duplicate/unknown completion은 trigger하지 않는다.
- Before (`evidence_tail.go:819-829`):

```go
if _, exists := cs.fragmentState[toolCallID]; !exists {
	runes := runeCountForEvent(event)
	cs.fragmentState[toolCallID] = &fragmentState{
		toolCallID: toolCallID,
		events:     []NormalizedEvent{cloneNormalizedEvent(event)},
		runes:      runes,
	}
}
```

- After:

```go
fragment := cs.fragmentState[toolCallID]
fragment.entries = append(fragment.entries, entry.sequence)
fragment.runes += entry.runes
cs.pendingEntries = append(cs.pendingEntries, entry)
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/evidence_tail.go`: append-owned fragment state, completion marker, contiguous safe-prefix epoch, per-ID/channel bound, confirm cleanup
  - [ ] `packages/go/streamgate/evidence_tail_test.go`: multi-fragment same ID, interleaved A/B completion order, safe-prefix partial release, per-ID overflow, duplicate completion
- 테스트 작성:
  - `TestEvidenceTailFragmentsReleaseOnlyCompletedSafePrefix`: A/B interleave에서 A completion이 incomplete B event를 release하지 않음을 검증한다.
  - `TestEvidenceTailAccumulatesAndBoundsFragmentByToolCall`: 같은 ID의 여러 fragment 누적과 limit+1 no-release를 검증한다.
- 중간 검증:
  - `go test -race -count=1 ./packages/go/streamgate -run '^TestEvidenceTail(FragmentsReleaseOnlyCompletedSafePrefix|AccumulatesAndBoundsFragmentByToolCall)$'`
  - 기대 결과: PASS, race 없음, cached output 불허

## 의존 관계 및 구현 순서

1. predecessor `01_event_contract_types`는 `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`로 충족됐다.
2. `REVIEW_API-1`로 immutable compiled requirement를 확정한다.
3. `REVIEW_API-2`의 sequenced pending/epoch record를 도입한 뒤 `REVIEW_API-3`이 같은 entry model에 fragment ID completion을 결속한다.
4. 이 subtask가 PASS/complete된 뒤에만 directory dependency에 따라 `07+01,06_commit_boundary`와 `08+02,05,06_filter_registry`가 이 API를 소비한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/go/streamgate/evidence_tail.go` | REVIEW_API-1, REVIEW_API-2, REVIEW_API-3 |
| `packages/go/streamgate/evidence_tail_test.go` | REVIEW_API-1, REVIEW_API-2, REVIEW_API-3 |
| `agent-task/m-stream-evidence-gate-core/06+01_evidence_tail/CODE_REVIEW-local-G07.md` | 구현 결과와 실제 검증 출력 |

## 최종 검증

1. `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT`
   - 기대 결과: PATH의 host `go`, 실제 경로, version, GOROOT 기록
2. `gofmt -d packages/go/streamgate/evidence_tail.go packages/go/streamgate/evidence_tail_test.go`
   - 기대 결과: stdout 없음
3. `go test -count=1 ./packages/go/streamgate -run '^Test(FilterHoldRequirement|EvidencePlan|EvidenceTail)'`
   - 기대 결과: 기존+신규 evidence-tail 회귀 PASS, cached output 불허
4. `go test -race -count=1 ./packages/go/streamgate`
   - 기대 결과: 전체 package PASS, race 없음, cached output 불허
5. `go vet ./packages/go/streamgate`
   - 기대 결과: PASS, stdout 없음
6. `make proto`
   - 기대 결과: 성공, proto 생성물 추가 diff 없음
7. `go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport`
   - 기대 결과: host Go가 복구됐으면 PASS. 현재 `crypto/internal/fips140cache is not in std` setup failure가 계속되면 우회하지 않고 실제 stdout/stderr와 host Go 설치 복구 조건을 기록한다.
8. `git diff --check -- packages/go/streamgate proto/gen/iop`
   - 기대 결과: stdout 없음
9. `git status --short -- proto/gen/iop`
   - 기대 결과: stdout 없음
10. `rg -n --sort path 'RegisterFragment|tokenToChannel|prepared-[%]d' packages/go/streamgate`
    - 기대 결과: 제거 대상 production symbol/legacy token map 없음. intentional test assertion이 있으면 위치와 사유 기록

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