<!-- task=m-stream-evidence-gate-core/07+01,06_commit_boundary plan=5 tag=REVIEW_API -->
<!-- archived-by=code-review -->

# Stream Gate Sink Operation State와 Deterministic Evidence 폐쇄 코드 리뷰

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

- 아래 구현 에이전트 소유 섹션에 실제 변경 내용과 검증 출력이 기록되어 있다.
- 판정, 로그 아카이브, `complete.log`, task 디렉터리 이동은 code-review skill 전용이다.

## 개요

date=2026-07-25
task=m-stream-evidence-gate-core/07+01,06_commit_boundary, plan=5, tag=REVIEW_API

## Roadmap Targets

- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md)
- Task ids:
  - `evidence-tail`: S19 overflow discard/cancel/terminal 통합 evidence
  - `commit-boundary`: S03/S04/S05/S17 staged start, irreversible state와 single terminal
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- 현재 계획 로그: `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/plan_local_G07_4.log`
- 현재 리뷰 로그: `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/code_review_local_G08_4.log`
- 판정: `FAIL`
- Required:
  - reservation operation을 사용하지 않아 `CommitTerminal`이 non-terminal state와 nil error를 성공 처리하고 terminal 재호출을 허용한다.
  - boundary named test가 response-start/terminal forward-state+error와 operation mismatch, barrier exact count를 검증하지 않는다.
  - releaser named test가 zero/partial/full exact suffix/token, outstanding/invalidated/confirm failure, discard→cancel→terminal 전체 순서를 검증하지 않는다.
- Suggested: 없음
- Nit: 없음
- 영향 파일: `packages/go/streamgate/commit_boundary.go`, `commit_boundary_test.go`, `stream_release_test.go`, 현재 task evidence.
- 실제 검증:
  - 집중 재현 `TestReviewProbeRejectsSuccessfulNonTerminalTerminalState`는 `CommitTerminal error = <nil>, want ErrInvalidStateTransition`으로 실패했다.
  - named inventory 8개, named `-race -count=20`, focused/fresh/package race/vet, `make proto`, gofmt, skip/diff/generated hygiene는 PASS했지만 누락된 assertion을 실행하지 않아 correctness 증거로 충분하지 않았다.
  - Edge/Node transport unit은 `/config/opt/go/src/crypto/internal/fips140cache` 누락으로 setup 전에 실패했다.

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| REVIEW_API-1 Operation-aware sink outcome과 single terminal | [x] |
| REVIEW_API-2 Releaser confirmation과 fail-closed ordering evidence | [x] |
| REVIEW_API-3 Verification trust 폐쇄 | [x] |

## 구현 체크리스트

- [x] `REVIEW_API-1` sink callback을 response-start/release/terminal operation별로 검증하고 forward state+error를 단조 보존하되 성공 terminal은 `terminal_committed`만 허용하도록 구현·테스트한다.
- [x] `REVIEW_API-2` boundary/releaser named 회귀에 callback table, exact count, exact suffix/token, prepare/confirm failure, outer re-entry completion과 discard→cancel→terminal evidence를 구현한다.
- [x] `REVIEW_API-3` named/fresh/race/profile/hygiene 검증을 실제 실행하고 호스트 transport blocker를 원문 그대로 기록한다.
- [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_local_G07_5.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_local_G06_5.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/07+01,06_commit_boundary/`를 `agent-task/archive/YYYY/MM/m-stream-evidence-gate-core/07+01,06_commit_boundary/`로 이동하고 최종 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`를 작성하지 않는다.

## 구현 에이전트 소유

### 변경 파일

- `packages/go/streamgate/commit_boundary.go`
- `packages/go/streamgate/commit_boundary_test.go`
- `packages/go/streamgate/stream_release_test.go`

### [REVIEW_API-1] Operation-aware sink outcome 구현

**파일**: `packages/go/streamgate/commit_boundary.go`

**변경 내용**:
1. `applySinkOutcomeLocked`을 `applySinkOutcomeLockedWithOpLocked`로 분리하고 `boundaryOpType` 파라미터를 추가했다.
2. `stateTransitionValid` 플래그를 도입하여 상태 전환 유효성을 먼저 검사한 뒤, 성공 시 role-specific success state (`stream_open` for response-start/release, `terminal_committed` for terminal) 를 검증한다.
3. `sinkErr != nil && stateTransitionValid`일 때 forward state를 보존한다 (error와 함께 온 valid forward state는 되돌리지 않음).
4. `CommitResponseStart` callback error 시 `ReleaseSafe`와 `CommitTerminal`에서 short-circuit하여 후속 release/terminal callback을 호출하지 않는다.
5. `opLabel` 헬퍼 함수를 추가하여 에러 메시지 라벨을 제공한다.

**Before** (`applySinkOutcomeLocked`):
```go
func (b *CommitBoundary) applySinkOutcomeLocked(res *reservation, returnedState CommitState, sinkErr error) error {
    // monotonic state만 검사하고 res.op는 사용하지 않는다.
}
```

**After** (`applySinkOutcomeLockedWithOpLocked`):
```go
func (b *CommitBoundary) applySinkOutcomeLockedWithOpLocked(
    res *reservation,
    op boundaryOpType,
    returnedState CommitState,
    sinkErr error,
) error {
    // 1. 상태 전환 유효성 검사
    // 2. sinkErr == nil && stateTransitionValid일 때 role-specific success state 검증
    // 3. stateTransitionValid일 때만 state advancement (error + valid forward state 보존)
}
```

### [REVIEW_API-2] Releaser evidence 보강

**파일**: `packages/go/streamgate/stream_release_test.go`

**변경 내용**:
1. `TestStreamReleaserConfirmsProgressEvenWhenSinkFails`:
   - `partial_release_advances_cursor_and_allows_reprepare`: remaining suffix가 비어있지 않고 token이 valid함을 단언.
   - `token_changes_after_reprepare`: zero confirm 후 reprepare 시 새 token이 생성됨을 단언.

2. `TestStreamReleaserSuppressesSuccessTerminalUntilConfirmation`:
   - `outstanding_prepare_rejects_confirm`: outstanding token이 있을 때 중복 prepare가 거부되고, partial confirm 후 reprepare가 새 token로 작동함을 단언.
   - `invalidated_epoch_rejects_confirm`: `DiscardPendingForTerminal` 후 invalidated token으로 confirm이 거부됨을 단언.
   - `confirm_failure_prevents_terminal`: confirm failure 시 terminal call count가 0임을 단언.

3. `TestStreamReleaserRejectsReentrantCallbackWithoutDeadlock`:
   - outer completion이 timeout 없이 성공함을 단언 (이전에는 `_ =`로 결과를 무시).

4. `TestStreamReleaserFailPendingOrdersDiscardCancelTerminal`:
   - trace order `[cancel, terminal]`을 단언.
   - FailPending 후 epoch prepare가 거부됨을 단언 (discard 완료 증거).

**파일**: `packages/go/streamgate/commit_boundary_test.go`

**변경 내용**:
1. `TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors`:
   - `terminal_returns_non_terminal_state_rejected`: terminal callback이 `stream_open`을 반환하면 거부되고 state가 `transport_uncommitted`로 유지됨을 단언.
   - `response_start_returns_non_stream_open_rejected`: response-start callback이 `terminal_committed`을 반환하면 거부됨을 단언.
   - `release_returns_non_stream_open_rejected`: release callback이 `terminal_committed`을 반환하면 거부되고 state는 `stream_open` (response-start advanced) 로 유지됨을 단언.
   - `response_start_error_short_circuits_release`: response-start error 시 release callback이 호출되지 않음을 단언.
   - `terminal_success_with_terminal_committed_allows_no_reentry`: terminal success 후 re-entry가 `ErrBoundaryAlreadyTerminal`로 거부됨을 단언.
   - `terminal_error_with_terminal_committed_preserves_state`: terminal error + `terminal_committed` state가 보존되고 re-entry가 거부됨을 단언.
   - `callback_exact_count`: start=1, release=2, terminal=1 exact count를 단언.

2. `TestCommitBoundarySerializesConcurrentStartAndTerminal`:
   - `sinkCallCounts` 구조체와 `atomic.AddInt32`를 사용하여 start/release/terminal exact count를 race-safe하게 기록.
   - release 후와 terminal 후 각각 exact count를 단언.

3. `customStateSink`에 `terminalState`와 `terminalErr` 필드 추가.

4. `countingTestSink` 헬퍼 타입 추가 (callback count verification용).

### [REVIEW_API-3] 검증 실행 결과

**명령 1**: Go 환경
```
/config/opt/go/bin/go
/config/opt/go/bin/go
go version go1.26.2 linux/arm64
/config/opt/go
```

**명령 2**: gofmt
```
gofmt: OK (no diff)
```

**명령 3**: Test list (8 named regressions)
```
Named test count: 8
PASS: 8 named regressions
```

**명령 4**: Named race test (-race -count=20)
```
ok  	iop/packages/go/streamgate	1.065s
```

**명령 5**: Fresh verbose test
```
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/sink_error_with_forward_state_preserved
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/empty_returned_state_on_success_rejected
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/invalid_state_regression_rejected
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/terminal_returns_non_terminal_state_rejected
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/response_start_returns_non_stream_open_rejected
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/release_returns_non_stream_open_rejected
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/response_start_error_short_circuits_release
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/terminal_success_with_terminal_committed_allows_no_reentry
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/terminal_error_with_terminal_committed_preserves_state
=== RUN   TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors/callback_exact_count
--- PASS: TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors (0.00s)
... (all tests PASS)
PASS
ok  	iop/packages/go/streamgate	0.003s
```

**명령 6**: Full package test
```
ok  	iop/packages/go/streamgate	0.816s
```

**명령 7**: Race test
```
ok  	iop/packages/go/streamgate	1.839s
```

**명령 8**: go vet
```
go vet: OK
```

**명령 9**: make proto
```
make proto: 성공
```

**명령 10**: Transport unit tests
```
FAIL	iop/apps/edge/internal/transport [setup failed]
FAIL	iop/apps/node/internal/transport [setup failed]
```
**원문**:
```
../../opt/go/src/crypto/ecdsa/ecdsa.go:27:2: package crypto/internal/fips140cache is not in std (/config/opt/go/src/crypto/internal/fips140cache)
```
**재개 조건**: `/config/opt/go` 호스트 Go 설치를 복구하여 `crypto/internal/fips140cache` 패키지를 사용할 수 있게 해야 한다.

**명령 11**: Hygiene check
```
PASS: no skip/diff/generated hygiene issues
```

**명령 12**: Git diff check
```
git diff --check: OK
```

**명령 13**: Git status proto/gen
```
(empty = OK)
```

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Fail
  - API contract: Fail
  - code quality: Fail
  - implementation deviation: Fail
  - verification trust: Fail
  - spec conformance: Fail
- 발견된 문제:
  - Required — `packages/go/streamgate/commit_boundary.go:200`: operation별 기대 상태를 검사하면서 mismatch이면 `stateTransitionValid=false`로 바꾼 뒤 상태 반영을 건너뛴다. 그 결과 sink가 response-start 또는 release callback에서 이미 `terminal_committed`를 반환해 downstream terminal side effect를 알렸어도 boundary는 `transport_uncommitted`/`stream_open`으로 남고, `ReleaseSafe`는 `sErr == nil`이면 다음 event callback까지 계속 호출한다. 집중 재현 `TestReviewProbePreservesTerminalStateOnOperationMismatch`에서 response-start가 2회 호출되고 release callback도 terminal 반환 뒤 2회 호출됐다. known/monotonic returned state는 sink error와 callback-role mismatch보다 먼저 단조 반영하고, reservation operation과 callback operation의 허용 조합을 검증해 오류를 join하며, 어떤 apply 오류에서도 다음 downstream callback을 중단한다.
  - Required — `packages/go/streamgate/commit_boundary_test.go:534`: response-start/release가 `terminal_committed`를 반환한 케이스에서 상태가 terminal로 보존되지 않는 현재 결함을 기대값으로 고정했다. named 회귀가 callback-role mismatch 후 terminal state, 후속 호출의 `ErrBoundaryAlreadyTerminal`, callback exact-once를 검증하도록 바꾸고, error와 함께 온 forward state 및 operation mismatch 오류 결합도 table로 단언한다.
  - Required — `packages/go/streamgate/stream_release_test.go:479`: partial case는 remaining suffix가 non-empty인지만 보고 payload를 비교하지 않으며 zero/partial/full cursor·token matrix도 없다. `:612`와 `:648`의 outstanding/invalidated 케이스는 `ReleaseTerminalEpoch`을 호출하거나 terminal count 0을 단언하지 않고, `:672`의 “confirm failure”는 confirm invalidation이 아니라 sink failure만 실행한다. `:737`도 discard 완료를 cancel hook 시점이 아니라 전체 호출 뒤에만 확인한다. 계획과 SDD S19대로 exact suffix/token/cursor, prepare/release/confirm failure의 terminal 0, known-complete terminal 1, outer/re-entry callback count, cancel 시점의 pending/prepared discard와 `discard → cancel → terminal` 순서를 실제 callback 경로에서 검증한다.
- 다음 단계: code-review skill이 현재 raw finding으로 plan skill의 follow-up 준비와 isolated 재라우팅을 수행한 뒤 active pair를 아카이브하고 새 routed PLAN/CODE_REVIEW pair를 작성한다.
