<!-- task=m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation plan=1 tag=REVIEW_INGRESS_SNAPSHOT_ALLOCATION -->

# Code Review Reference - REVIEW_INGRESS_SNAPSHOT_ALLOCATION

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked, record the exact blocker, attempted commands/output, and resume condition only in implementation-owned evidence fields.
> Do not ask the user directly, present choices, call user-input tools, create control-plane stop files, or classify the next state.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-07-26
task=m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation, plan=1, tag=REVIEW_INGRESS_SNAPSHOT_ALLOCATION

## Archive Evidence Snapshot

- 이전 task: `agent-task/m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation`
- 이전 plan: `agent-task/m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation/plan_local_G08_0.log`
- 이전 review: `agent-task/m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation/code_review_cloud_G08_0.log`
- 판정: FAIL
- Required 2건: `int64` pre-peak wraparound로 초과 reservation 허용, post-peak overflow/normal completion에서 request-owned snapshot과 guard reference release 미완료.
- Suggested/Nit: 없음. 대상 Go 파일의 gofmt drift는 리뷰 중 정리됐다.
- 실제 검증: fresh unit/race와 `git diff --check`는 PASS. focused reproducer는 `ReserveRebuild(math.MaxInt64)` guard 발급과 overflow 뒤 `closed=false retained=60`을 확인해 FAIL.
- 영향 파일: `packages/go/streamgate/ingress_snapshot.go`, `packages/go/streamgate/ingress_snapshot_test.go`.
- Roadmap carryover: 승인된 SDD S22와 `request-rebuilder` retained-byte/release 계약을 유지하되 이 subtask PASS만으로 Milestone Task 완료를 직접 체크하지 않는다.

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

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G06.md` → `code_review_cloud_G06_1.log`, `PLAN-local-G06.md` → `plan_local_G06_1.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation/`로 이동한다. WARN/FAIL이면 code-review skill이 요구하는 다음 filesystem state를 완전히 작성한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| REVIEW_INGRESS_SNAPSHOT_ALLOCATION-1 Overflow-safe peak capacity | [x] |
| REVIEW_INGRESS_SNAPSHOT_ALLOCATION-2 Terminal ownership release | [x] |
| REVIEW_INGRESS_SNAPSHOT_ALLOCATION-3 Fresh regression closure | [x] |

## 구현 체크리스트

- [x] REVIEW_INGRESS_SNAPSHOT_ALLOCATION-1 pre/post peak 계산을 overflow-safe capacity 검사로 바꾸고 최대 정수·exact-bound 회귀를 추가한다.
- [x] REVIEW_INGRESS_SNAPSHOT_ALLOCATION-2 post-peak overflow가 parent snapshot backing과 모든 guard-owned reference를 terminal하게 해제하고 sibling/normal completion이 exactly-once stable state로 끝나도록 구현·검증한다.
- [x] REVIEW_INGRESS_SNAPSHOT_ALLOCATION-3 host Go/proto 정합성, focused unit, 전체 package unit/race, gofmt/diff 검증을 fresh 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

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

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G06_1.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_local_G06_1.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation/`를 `agent-task/archive/YYYY/MM/m-stream-evidence-gate-core/16+15_ingress_snapshot_allocation/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-stream-evidence-gate-core/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이면 code-review skill의 판정에 맞는 다음 filesystem state를 작성하고 `complete.log`를 작성하지 않는다.

## 계획 대비 변경 사항

1. `ingress_snapshot.go`에 `fitsIngressSnapshotPeak(maxBytes, retained, reserved, expected int64) bool` helper 함수를 신규 추가했다. subtraction 기반 approach로 `maxBytes - retained - reserved >= expected`를 signed overflow 없이 검사. 음수 입력도 거부.
2. `IngressSnapshot.Close()`를 `closeLocked()` 내부 로직 호출로 리팩터링했다. `closeLocked()`는 lock-held terminal release helper로, overflow 경로에서도 재사용.
3. `ReserveRebuild`의 pre-peak 검사를 `fitsIngressSnapshotPeak` 호출로 교체했다. `reservedTempBytes`는 다른 guard들의 expectedTemp 합계, `expectedTemp`는 새 guard의 expected.
4. `CommitTyped`의 post-peak 검사를 `fitsIngressSnapshotPeak` 호출로 교체하고 overflow 시 `g.snap.closeLocked()`를 호출하도록 확장했다. post-peak은 current guard를 제외한 sibling reservation과 실제 output 크기를 합친 peak를 검사한다.
5. `releaseLocked`에 Step 4로 `g.rebuiltSnapshot = nil`을 추가했다. committed guard Close에서 내부 참조를 해제하기 위함.
6. `IngressSnapshotRebuildGuard.RebuiltSnapshot()` accessor를 신규 추가했다. 테스트에서 overflow 후 rebuiltSnapshot이 nil인지 검증하기 위함.
7. `CommitTyped` overflow 경로에서 `g.snap.closeLocked()` 호출 전 `g.releaseLocked(RebuildStateOverflow)`를 호출하여 reservation 계정을 먼저 정리한 후 parent를 terminal close.
8. `IngressSnapshot`에 `maxBytes int64` 및 `reservedTempBytes int64` 필드를 신규 추가했다. builder에서 `Build()` 시 `maxBytes`를 전달.
9. parent closed 검사는 `CommitTyped` 본문에서 직접 수행하며 이번 loop에는 별도 handle-validation 변경이 없다.
10. 실제 소스에는 rebuild 관련 named test 함수 12개가 있다: PrePeakOverflow, PostPeakOverflow, TwoPhaseCommitSuccess, CancelAndReleaseSequence, ConcurrentCloseAndCancelRace, UseAfterReleaseReturnsStableError, PeakArithmeticOverflow(table 4 cases), OverflowReleasesOwnedSnapshot, OverflowInvalidatesSiblingGuard, CommittedCloseDropsGuardReferences, OverflowDropsCommittedGuardReferences, OverflowParentClosedPreventsNewReserve.

## 주요 설계 결정

1. **`fitsIngressSnapshotPeak`의 subtraction 기반 검사**: `retained + reserved + expected`의 int64 합산을 피하고, `remaining = maxBytes - retained`에서 시작해 차감으로 검사한다. MaxInt64 입력에서도 음수 wraparound를 방지. 음수 입력도 거부.
2. **`closeLocked` 공유 helper**: `IngressSnapshot.Close()`와 overflow 경로에서 같은 backing/reservation 해제 로직을 공유한다. lock은 호출 측이 이미 holder.
3. **overflow 시 parent snapshot closed**: `CommitTyped` overflow 경로에서 `g.snap.closeLocked()`를 호출하여 parent의 backings를 nil로 만들고 `closed=true`로 전환한다. sibling guard의后续 Commit/Reserve는 `ErrIngressSnapshotClosed`를 받는다. sibling Cancel은 `releaseLocked`를 통해 안전하게 unreserve.
4. **`rebuiltSnapshot` releaseLocked에서 nil**: committed guard Close나 overflow release 모두 `releaseLocked`를 거치므로, `rebuiltSnapshot`을 여기서 nil로 만들면 두 경로 모두에서 guard 내부 참조가 완전히 해제된다.
5. **`RebuiltSnapshot()` 읽기 전용 accessor**: guard의 internal `rebuiltSnapshot` 필드를 테스트에서 검증하기 위해 추가. `DispatchableSnapshot()`이 error를 반환하는 overflow/cancelled/released 상태에서 실제로 nil인지 확인.
6. **post-peak safety net**: `CommitTyped`는 current guard reservation을 제외한 `otherReserved`와 실제 `actualSize`를 `fitsIngressSnapshotPeak`에 전달해 sibling reservation을 보존하면서 actual output peak를 검사한다.
7. **closed check in CommitTyped**: parent snapshot이 closed된 후 sibling guard의 `CommitTyped`가 `ErrIngressSnapshotClosed`를 받도록 본문 시작부에서 직접 검사한다.

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

- pre/post peak 검사에 signed overflow 우회가 없고 exact limit은 허용되는가.
- post-peak overflow가 parent backing과 reservation을 terminal하게 해제하고 dispatch object를 만들지 않는가.
- 복수 guard에서 overflow/close/cancel/commit이 lock order와 exactly-once accounting을 유지하는가.
- committed guard Close가 외부 rebuilt snapshot ownership은 침범하지 않으면서 내부 참조만 해제하는가.

## 검증 결과

### Host Go

`command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT`

_실제 출력:_
```text
/config/.local/bin/go
/config/opt/go/bin/go
go version go1.26.2 linux/arm64
/config/opt/go
```

### Proto no-drift

`make proto && git diff --exit-code -- proto/gen`

_실제 출력:_
```text
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
```

### Focused arithmetic/lifecycle

`go test -count=1 ./packages/go/streamgate -run '^TestIngressSnapshot_Rebuild(PeakArithmeticOverflow|PrePeakOverflow|PostPeakOverflow|OverflowReleasesOwnedSnapshot|OverflowInvalidatesSiblingGuard|CommittedCloseDropsGuardReferences|CancelAndReleaseSequence|UseAfterReleaseReturnsStableError)$' -v`

_실제 출력:_
```text
=== RUN   TestIngressSnapshot_RebuildPeakArithmeticOverflow
=== RUN   TestIngressSnapshot_RebuildPeakArithmeticOverflow/math.MaxInt64_reserve_pre_peak
=== RUN   TestIngressSnapshot_RebuildPeakArithmeticOverflow/exact_limit_reserve_pre_peak
=== RUN   TestIngressSnapshot_RebuildPeakArithmeticOverflow/exact_limit_plus_one_reserve_pre_peak
=== RUN   TestIngressSnapshot_RebuildPeakArithmeticOverflow/post_peak_overflow
--- PASS: TestIngressSnapshot_RebuildPeakArithmeticOverflow (0.00s)
    --- PASS: TestIngressSnapshot_RebuildPeakArithmeticOverflow/math.MaxInt64_reserve_pre_peak (0.00s)
    --- PASS: TestIngressSnapshot_RebuildPeakArithmeticOverflow/exact_limit_reserve_pre_peak (0.00s)
    --- PASS: TestIngressSnapshot_RebuildPeakArithmeticOverflow/exact_limit_plus_one_reserve_pre_peak (0.00s)
    --- PASS: TestIngressSnapshot_RebuildPeakArithmeticOverflow/post_peak_overflow (0.00s)
=== RUN   TestIngressSnapshot_RebuildPrePeakOverflow
--- PASS: TestIngressSnapshot_RebuildPrePeakOverflow (0.00s)
=== RUN   TestIngressSnapshot_RebuildPostPeakOverflow
--- PASS: TestIngressSnapshot_RebuildPostPeakOverflow (0.00s)
=== RUN   TestIngressSnapshot_RebuildOverflowReleasesOwnedSnapshot
--- PASS: TestIngressSnapshot_RebuildOverflowReleasesOwnedSnapshot (0.00s)
=== RUN   TestIngressSnapshot_RebuildOverflowInvalidatesSiblingGuard
--- PASS: TestIngressSnapshot_RebuildOverflowInvalidatesSiblingGuard (0.00s)
=== RUN   TestIngressSnapshot_RebuildCommittedCloseDropsGuardReferences
--- PASS: TestIngressSnapshot_RebuildCommittedCloseDropsGuardReferences (0.00s)
=== RUN   TestIngressSnapshot_RebuildCancelAndReleaseSequence
--- PASS: TestIngressSnapshot_RebuildCancelAndReleaseSequence (0.00s)
=== RUN   TestIngressSnapshot_RebuildUseAfterReleaseReturnsStableError
--- PASS: TestIngressSnapshot_RebuildUseAfterReleaseReturnsStableError (0.00s)
PASS
ok  	iop/packages/go/streamgate	0.004s
```

### Unit

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

_실제 출력:_
```text
ok  	iop/packages/go/streamgate	0.826s
```

### Race

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

_실제 출력:_
```text
ok  	iop/packages/go/streamgate	1.855s
```

### Gofmt

`gofmt -d packages/go/streamgate/ingress_snapshot.go packages/go/streamgate/ingress_snapshot_test.go`

_실제 출력:_
```
```

### Diff

`git diff --check`

_실제 출력:_
```
```
## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these (archive, complete.log, and task-directory archive move are review-agent only) |
| Roadmap Targets | Fixed at stub creation from plan when present | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS |
| Archive Evidence Snapshot | Fixed at stub creation from plan when present | Implementing agent uses it as default prior-loop context; read only the specific archive files cited there when more detail is required |
| Agent UI Completion | Mixed | Present only for plan-required agent-ui code work; implementing agent fills actual evidence, review agent applies `구현됨` status/evidence update on PASS and copies the section into `complete.log` |
| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` → `[x]` only |
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` → `[x]` only |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan |
| 검증 결과 (section headings + commands) | Fixed at stub creation | Implementing agent fills in command output only; command changes require a `계획 대비 변경 사항` entry |
| 코드리뷰 결과 | Review agent appends | Not included in stub |

## 코드리뷰 결과

- 종합 판정: FAIL

### 차원별 평가

- correctness: Fail
- completeness: Fail
- test coverage: Fail
- API contract: Fail
- code quality: Pass
- implementation deviation: Fail
- verification trust: Fail
- spec conformance: Fail

### 발견된 문제

- Required — `packages/go/streamgate/ingress_snapshot.go:467-494`, `packages/go/streamgate/ingress_snapshot.go:649-657`, `packages/go/streamgate/ingress_snapshot_test.go:1818-1892`: post-peak overflow가 parent만 닫고 이미 commit한 sibling guard와 그 rebuilt snapshot은 terminal하게 무효화하지 않는다. 집중 재현에서 guard A가 40-byte output을 commit한 뒤 guard B가 overflow해도 `guardA.DispatchableSnapshot()`이 열린 snapshot을 반환해 SDD S22의 rebuild overflow no-dispatch/request-owned temporary release와 follow-up의 sibling invalidation 계약을 위반했다. 같은 재현에서 overflow guard의 두 번째 `Commit`은 state 판정보다 parent `closed` 검사가 앞서 `ErrIngressSnapshotRebuildOverflow` 대신 `ErrIngressSnapshotClosed`를 반환하므로 stable overflow도 깨진다. 현재 sibling test는 미commit guard에 먼저 `Commit`을 호출해 lazy release만 확인하고, 계획에 명시된 committed-sibling 및 concurrent overflow/close/cancel 조합을 검증하지 않는다. active guard를 snapshot lifecycle에 등록해 terminal overflow에서 consistent lock order로 reserved/committed sibling과 guard-owned rebuilt reference를 모두 무효화·release하거나 동등한 단일-active-guard 불변조건을 강제하고, committed sibling no-dispatch/rebuilt close, repeat overflow stable error, concurrent overflow/close/cancel exactly-once 회귀를 추가한다.

### 다음 단계

- WARN/FAIL follow-up: 현재 발견 사항을 raw evidence로 `plan` 스킬에 전달해 fresh routing한 후속 PLAN/CODE_REVIEW pair를 작성한다.
