<!-- task=m-stream-evidence-gate-core/07+01,06_commit_boundary plan=2 tag=REVIEW_API -->

# Stream Gate Commit/Release 불변조건 후속 수정 계획

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

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

## 배경

현재 구현은 fresh/race 테스트를 통과하지만 테스트가 irreversible state와 cursor를 끝까지 단언하지 않아 partial sink error, concurrent terminal, attempt replacement 결함을 놓쳤다. `CommitBoundary`의 attempt-scoped reservation과 sink state reconciliation, `StreamReleaser`의 zero/partial/full confirmation 및 success-terminal gate를 같은 request-scope 불변조건으로 보완한다. S03/S04/S05/S17/S19 완료 evidence는 deterministic ordering/cursor 회귀가 통과한 뒤에만 인정한다.

## Archive Evidence Snapshot

- 현재 계획 로그: `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/plan_local_G06_1.log`
- 현재 리뷰 로그: `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/code_review_local_G07_1.log`
- 판정: `FAIL`
- Required:
  - partial sink 성공 뒤 `ConfirmRelease`가 생략되고 release/confirm 오류 뒤에도 success terminal이 commit된다.
  - boundary sink callback 전에 in-flight reservation이 없어 staged start/terminal 중복과 stale generation state 반영이 가능하다.
  - attempt ID 검증이 빠지고 post-open replacement가 허용돼 selected attempt와 commit state 경계가 깨진다.
  - 테스트가 partial cursor/suffix, concurrent exactly-once, 실제 post-open replace, deterministic overflow cancel→terminal을 단언하지 않는다.
- Suggested: 없음
- Nit: 없음
- 영향 파일: `packages/go/streamgate/commit_boundary.go`, `commit_boundary_test.go`, `stream_release.go`, `stream_release_test.go`.
- 실제 검증:
  - `go test -count=1 ./packages/go/streamgate -run '^Test(CommitBoundary|StreamReleaser)'`, fresh package, race, vet는 PASS했다.
  - `go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport`는 host `/config/opt/go/src/crypto/internal/fips140cache` 누락으로 setup 전에 실패했다.
  - `make proto`, gofmt, diff hygiene, proto generated status는 PASS했다.
- 선행 완료:
  - `agent-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`
  - `agent-task/archive/2026/07/m-stream-evidence-gate-core/06+01_evidence_tail/complete.log`
- 구현자는 위 특정 로그 외의 `agent-task/archive/**`를 넓게 탐색하지 않는다.

## 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`: predecessor S01/S02 evidence와 S19 overflow cancel/terminal 통합
  - `commit-boundary`: staged response-start, irreversible release state와 single terminal
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `packages/go/streamgate/commit_boundary.go`
- `packages/go/streamgate/commit_boundary_test.go`
- `packages/go/streamgate/stream_release.go`
- `packages/go/streamgate/stream_release_test.go`
- `packages/go/streamgate/terminal.go`
- `packages/go/streamgate/evidence_tail.go`
- `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/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-task/archive/2026/07/m-stream-evidence-gate-core/01_event_contract_types/complete.log`
- `agent-task/archive/2026/07/m-stream-evidence-gate-core/06+01_evidence_tail/complete.log`
- `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/plan_local_G06_1.log`
- `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/code_review_local_G07_1.log`
- `.gitignore`

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`
- 상태: `[승인됨]`; SDD/Milestone 잠금 `해제`, 결정 필요 `없음`.
- `S03` / `commit-boundary`: staged start와 terminal-before-evidence는 safe outcome 하나만 commit한다.
- `S04` / `commit-boundary`: idle timeout은 pending release 없이 terminal error만 commit한다.
- `S05` / `commit-boundary`: stream-open 뒤 rollback/exact/schema replacement를 금지한다.
- `S17` / `commit-boundary`: original attempt start를 숨기고 selected retry start/output만 한 번 노출한다.
- `S19` / `evidence-tail`: overflow는 partial/start release 없이 cancel 뒤 terminal error로 끝낸다.
- Evidence Map의 no eager commit/single terminal, pending-tail no-release, strategy matrix, selected attempt, fail-closed ordering을 구현 체크리스트와 최종 race/ordering/cursor 검증으로 역산했다.

### 테스트 환경 규칙

- `test_env`: local.
- `agent-test/local/rules.md`와 `agent-test/local/platform-common-smoke.md`를 읽었다.
- host toolchain: `/config/.local/bin/go` → `/config/opt/go/bin/go`, `go1.26.2 linux/arm64`, `GOROOT=/config/opt/go`.
- 적용 명령: `make proto`, focused/fresh package test, race, vet, Edge/Node transport unit, diff/generated hygiene.
- 새 동시성·ordering 증거는 cache를 허용하지 않아 `-count=1`과 concurrency stress의 `-count=20`을 사용한다.
- transport unit은 host GOROOT source 누락으로 setup 전에 차단된다. 우회하지 않고 원문과 `/config/opt/go` 복구 조건을 기록한다. production transport adapter는 변경하지 않으므로 package focused/race가 코드 판정의 결정 증거다.
- 외부 runner/service/secret/port는 필요 없고 test-rule 유지보수도 필요 없다.

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

- response-start 성공 뒤 첫 body 실패에서 boundary state가 `stream_open`으로 보존되는 assertion이 없다.
- sink가 error와 함께 반환한 valid forward state, unknown state, regression state 표가 없다.
- partial release error 뒤 tail cursor/suffix 재prepare와 zero confirmation token 해제 assertion이 없다.
- prepare/release/confirm 실패에서 success terminal이 억제되는 assertion이 없다.
- concurrent release/terminal/replacement가 같은 start/terminal을 한 번만 호출하는 barrier fixture가 없다.
- wrong/missing attempt ID와 실제 post-open `ReplaceUncommittedAttempt` rejection assertion이 없다.
- overflow test가 `t.Skip` 가능하며 attempt start, cancel count, cancel-before-terminal order를 검증하지 않는다.
- callback 재진입 시 blocking deadlock 대신 deterministic conflict를 반환하는 assertion이 없다.

### 심볼 참조

- rename/remove 없음.
- 수정 public API: `CommitBoundary`, `StreamReleaser`, `ReleaseProgress`, `ReplaceUncommittedAttempt`.
- production call site는 아직 없고 현재 참조는 신규 source/test와 task evidence뿐이다.
- `ReleaseSink`는 `terminal_test.go`와 `consumer_contract_test.go`의 fake 구현이 기존 contract를 검증한다.
- 매칭되는 active agent-spec/agent-contract 문서는 없으며 외부 API/wire/config/event schema는 변경하지 않는다.
- 새 dependency는 추가하지 않고 Go 표준 라이브러리만 사용한다.

### 분할 판단

- split decision policy를 파일명 선택 전에 평가했다.
- boundary reservation/state와 tail confirmation/terminal은 같은 sink callback의 partial progress와 generation을 공유해 한쪽만 수정하면 cursor 또는 exactly-once가 다시 깨진다.
- 테스트도 동일 barrier sink/canceller fixture로 두 component의 ordering을 함께 증명한다.
- production transport adapter rollout은 별도 ownership이며 범위에서 제외했다. 따라서 현재 subtask 하나를 유지하는 것이 더 안전하다.
- predecessor `01`과 `06`은 위 두 archived `complete.log`로 충족됐다.

### 범위 결정 근거

- 수정 범위는 네 신규 source/test 파일과 현재 review evidence다.
- `terminal.go`, `evidence_tail.go`, `event.go`, `filter_contract.go`의 기존 public 계약은 변경하지 않고 소비한다.
- Edge/OpenAI handler, production `ReleaseSink`/`AttemptCanceller`, coordinator/arbiter/recovery budget, config/proto/API는 후속 consumer adoption 범위다.
- transport profile의 host Go 설치 복구는 repository source 변경 범위가 아니다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`
- build:
  - closures: `scope_closed=true`, `context_closed=true`, `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`
  - closure basis: 네 source/test 파일과 SDD 불변조건으로 scope가 닫히고, 재현 가능한 코드 경로와 focused/race 명령이 있으며 사용자 결정이 없다.
  - scores: `scope_coupling=2`, `state_concurrency=2`, `blast_irreversibility=1`, `evidence_diagnosis=1`, `verification_complexity=1`
  - result: lane `local`, grade `G07`, filename `PLAN-local-G07.md`
- review:
  - closures: `scope_closed=true`, `context_closed=true`, `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`
  - closure basis: misleading passing tests와 actual state/cursor 경로를 함께 대조해야 하지만 필요한 code/test/log가 bounded하고 deterministic barrier/stress 검증으로 판정 가능하다.
  - scores: `scope_coupling=2`, `state_concurrency=2`, `blast_irreversibility=1`, `evidence_diagnosis=2`, `verification_complexity=1`
  - result: lane `local`, grade `G08`, filename `CODE_REVIEW-local-G08.md`

## 구현 체크리스트

- [ ] `REVIEW_API-1` attempt-scoped in-flight reservation, sink 반환 state의 검증·단조 반영, response-start/terminal exactly-once와 uncommitted-only atomic replacement를 구현·테스트한다.
- [ ] `REVIEW_API-2` zero/partial/full release를 error 여부와 무관하게 정확히 confirm하고, release/confirm 성공 뒤에만 success terminal을 commit하며 callback 중 serializer lock을 노출하지 않도록 구현·테스트한다.
- [ ] `REVIEW_API-3` cursor/suffix, sink state/error, wrong attempt, concurrent/re-entrant operation, deterministic idle/overflow cancel→terminal을 검증하는 회귀를 작성하고 fresh/race/profile 검증을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_API-1] Boundary reservation, state와 attempt ownership

- 문제:
  - `commit_boundary.go:108-121`은 stage attempt를 검증하지 않고 `128-199`, `208-264`는 callback 전에 mutex를 풀면서 operation reservation을 남기지 않는다.
  - response-start가 실제 commit돼도 첫 body가 실패하면 state가 uncommitted로 남고, error와 함께 반환된 forward state와 unknown/regression state를 일관되게 처리하지 않는다.
  - `272-287`은 post-open replacement를 허용하고 `newAttemptID`를 사용하지 않는다.
- 해결 방법:
  - state mutex 아래에 request generation과 single in-flight reservation을 둔다. mutating operation은 current attempt/generation을 검증하고 reservation을 획득한 뒤 mutex 없이 sink callback을 실행하며, 완료 시 같은 reservation/generation에만 결과를 적용한다. concurrent/re-entrant operation은 stable conflict error로 즉시 실패해 callback deadlock과 duplicate call을 막는다.
  - sink 반환 `CommitState`를 항상 validate하고 state rank를 단조 반영한다. response-start 성공 또는 forward state 관찰 즉시 `stream_open`을 보존하고, error와 함께 반환된 valid forward state도 반영한다. unknown/regression은 stable contract error로 반환하되 이미 관찰한 forward state를 되돌리지 않는다.
  - 모든 stage/release/terminal/replace에 exact current attempt 검증을 적용한다. replacement는 `transport_uncommitted`에서만 old ID를 검증하고 new ID를 같은 transition에서 active attempt로 확정하며 staged start/confirmed state를 reset한다.
- Before (`packages/go/streamgate/commit_boundary.go:136-157`):

```go
b.mu.Lock()
// snapshot
currentState := b.state
b.mu.Unlock()
```

- After (`packages/go/streamgate/commit_boundary.go`):

```go
b.mu.Lock()
reservation, err := b.reserveLocked(operationRelease, attemptID)
b.mu.Unlock()
// sink callback without b.mu
b.mu.Lock()
err = b.finishLocked(reservation, returnedState, sinkErr)
b.mu.Unlock()
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/commit_boundary.go`: reservation/generation, exact attempt validation, monotonic state helper, staged-start lifecycle, terminal/replacement guard, unused public error 정리
  - [ ] `packages/go/streamgate/commit_boundary_test.go`: start/body/terminal state+error table, missing/wrong attempt, concurrent start/terminal, callback state access/conflict, actual post-open replace rejection
- 테스트 작성:
  - `TestCommitBoundaryPreservesReturnedStateAcrossSinkErrors`
  - `TestCommitBoundaryRejectsWrongOrMissingAttempt`
  - `TestCommitBoundarySerializesConcurrentStartAndTerminal`
  - `TestCommitBoundaryRejectsPostOpenReplacement`
- 중간 검증:
  - `go test -race -count=20 ./packages/go/streamgate -run '^TestCommitBoundary(PreservesReturnedStateAcrossSinkErrors|RejectsWrongOrMissingAttempt|SerializesConcurrentStartAndTerminal|RejectsPostOpenReplacement)$'`
  - 기대 결과: PASS, duplicate sink call/deadlock/race 없음.

### [REVIEW_API-2] Progress confirmation과 terminal gate

- 문제:
  - `stream_release.go:83-91`은 boundary가 partial progress와 error를 함께 반환하면 confirmation 전에 종료한다.
  - `109-126`은 prepare/release/confirm 실패를 구분하지 않고 success terminal을 commit한다.
  - `101-127`, `154-191`은 releaser mutex를 sink/canceller callback 동안 잡아 re-entrant callback이 deadlock할 수 있다.
- 해결 방법:
  - releaser도 state mutex 아래 in-flight reservation을 획득한 뒤 mutex를 풀고 tail→boundary→tail cycle을 단독 수행한다. callback 재진입은 `ErrReleaserSerializerConflict`로 즉시 실패한다.
  - `ReleaseEpoch`은 zero/partial/full progress 모두 `ConfirmRelease`해 prepared token을 닫고 cursor를 실제 sink 성공 수와 맞춘다. release와 confirm error는 `errors.Join` 또는 동등한 stable wrapping으로 손실 없이 반환한다.
  - fully confirmed epoch을 request-local로 기록한다. `ReleaseTerminalEpoch`은 known-complete epoch만 direct terminal을 허용하고, otherwise remaining suffix release와 confirmation이 모두 성공한 뒤에만 success terminal을 commit한다. 오류 시 progress를 반환하고 terminal은 commit하지 않는다.
  - `FailPending`은 error terminal만 받고 discard→cancel→terminal 순서를 보장한다. cancel failure cause는 attempt ID를 rule id로 넣지 않고 bounded stable code만 append한다.
- Before (`packages/go/streamgate/stream_release.go:82-91`):

```go
prog, err := r.boundary.ReleaseSafe(ctx, attemptID, releaseEvents)
if err != nil {
	return prog, err
}
return prog, r.tail.ConfirmRelease(prepared.Token(), confirmation)
```

- After (`packages/go/streamgate/stream_release.go`):

```go
prog, releaseErr := r.boundary.ReleaseSafe(ctx, attemptID, releaseEvents)
confirmErr := r.tail.ConfirmRelease(
	prepared.Token(),
	ReleaseConfirmation{ReleasedEvents: prog.ReleasedEvents()},
)
return prog, errors.Join(releaseErr, confirmErr)
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/stream_release.go`: reservation, zero/partial/full confirmation, completed epoch tracking, success terminal gate, error-terminal validation, bounded cancel cause
  - [ ] `packages/go/streamgate/stream_release_test.go`: cursor/suffix reprepare, release/confirm failure terminal suppression, callback conflict/no deadlock, cancel ordering
- 테스트 작성:
  - `TestStreamReleaserConfirmsProgressEvenWhenSinkFails`
  - `TestStreamReleaserSuppressesSuccessTerminalUntilConfirmation`
  - `TestStreamReleaserRejectsReentrantCallbackWithoutDeadlock`
  - `TestStreamReleaserFailPendingOrdersDiscardCancelTerminal`
- 중간 검증:
  - `go test -race -count=20 ./packages/go/streamgate -run '^TestStreamReleaser(ConfirmsProgressEvenWhenSinkFails|SuppressesSuccessTerminalUntilConfirmation|RejectsReentrantCallbackWithoutDeadlock|FailPendingOrdersDiscardCancelTerminal)$'`
  - 기대 결과: PASS, cursor/suffix/terminal count와 call order가 deterministic하게 일치.

### [REVIEW_API-3] SDD fixture와 verification trust 폐쇄

- 문제:
  - `commit_boundary_test.go:157-183`과 `stream_release_test.go:141-209`은 partial progress count만 보고 boundary/tail cursor를 확인하지 않는다.
  - `commit_boundary_test.go:312-371`은 wrong attempt 성공을 허용하고 실제 replace를 post-open에서 호출하지 않는다.
  - `stream_release_test.go:427-469`은 overflow를 skip할 수 있고 attempt/cancel ordering을 확인하지 않는다.
- 해결 방법:
  - 기존 이름만 유지하는 약한 테스트를 보강하거나 위 regression test로 대체한다. barrier sink와 ordered canceller는 channel/atomic을 사용해 callback 진입을 증명하고 timeout으로 hang을 실패 처리한다.
  - zero/partial/full마다 sink count, boundary state, committed cursor, remaining suffix와 reprepare token을 함께 단언한다.
  - terminal-gate hard bound 또는 deterministic fixture로 overflow를 반드시 발생시키고 `t.Skip`을 제거한다. start/release 0, cancel 1, terminal 1, cancel-before-terminal을 확인한다.
  - actual test inventory, fresh/race/vet, local profile와 no-skip/diff/generated hygiene를 기록한다.
- Before (`packages/go/streamgate/stream_release_test.go:451-453`):

```go
if !overflowed {
	t.Skip("expected overflow signal not generated with current configuration")
}
```

- After (`packages/go/streamgate/stream_release_test.go`):

```go
if !overflowed {
	t.Fatal("expected deterministic overflow signal")
}
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/commit_boundary_test.go`: required state/attempt/concurrency assertions
  - [ ] `packages/go/streamgate/stream_release_test.go`: required cursor/suffix/terminal/order assertions와 `t.Skip` 제거
  - [ ] `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/CODE_REVIEW-local-G08.md`: 실제 명령 출력과 blocker 기록
- 테스트 작성:
  - REVIEW_API-1/2의 regression을 작성하고 기존 weak cases가 같은 불변조건을 중복 없이 보강하도록 정리한다.
- 중간 검증:
  - `! rg --sort path -n 't\\.Skip\\(' packages/go/streamgate/commit_boundary_test.go packages/go/streamgate/stream_release_test.go`
  - `go test -count=1 -v ./packages/go/streamgate -run '^Test(CommitBoundary|StreamReleaser)'`
  - 기대 결과: skip 없음, 대상 테스트 이름과 subtest가 출력되며 PASS.

## 의존 관계 및 구현 순서

1. `REVIEW_API-1`로 boundary reservation/state/attempt ownership을 먼저 고정한다.
2. `REVIEW_API-2`가 해당 boundary progress를 tail confirmation/terminal에 연결한다.
3. `REVIEW_API-3`이 S03/S04/S05/S17/S19와 최종 profile evidence를 폐쇄한다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `packages/go/streamgate/commit_boundary.go` | REVIEW_API-1 |
| `packages/go/streamgate/commit_boundary_test.go` | REVIEW_API-1, REVIEW_API-3 |
| `packages/go/streamgate/stream_release.go` | REVIEW_API-2 |
| `packages/go/streamgate/stream_release_test.go` | REVIEW_API-2, REVIEW_API-3 |
| `agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary/CODE_REVIEW-local-G08.md` | REVIEW_API-3 evidence |

## 최종 검증

1. `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT`
   - 기대 결과: PATH host Go와 실제 경로/GOROOT 기록.
2. `gofmt -d packages/go/streamgate/commit_boundary.go packages/go/streamgate/commit_boundary_test.go packages/go/streamgate/stream_release.go packages/go/streamgate/stream_release_test.go`
   - 기대 결과: stdout 없음.
3. `go test -race -count=20 ./packages/go/streamgate -run '^Test(CommitBoundary(PreservesReturnedStateAcrossSinkErrors|RejectsWrongOrMissingAttempt|SerializesConcurrentStartAndTerminal|RejectsPostOpenReplacement)|StreamReleaser(ConfirmsProgressEvenWhenSinkFails|SuppressesSuccessTerminalUntilConfirmation|RejectsReentrantCallbackWithoutDeadlock|FailPendingOrdersDiscardCancelTerminal))$'`
   - 기대 결과: PASS, race/deadlock/duplicate 없음.
4. `go test -count=1 -v ./packages/go/streamgate -run '^Test(CommitBoundary|StreamReleaser)'`
   - 기대 결과: 대상 test/subtest가 실제로 열거되고 PASS.
5. `go test -count=1 ./packages/go/streamgate`
   - 기대 결과: PASS.
6. `go test -race -count=1 ./packages/go/streamgate`
   - 기대 결과: PASS, race 없음.
7. `go vet ./packages/go/streamgate`
   - 기대 결과: PASS, stdout 없음.
8. `make proto`
   - 기대 결과: 성공, proto 생성물 추가 diff 없음.
9. `go test -count=1 ./apps/edge/internal/transport ./apps/node/internal/transport`
   - 기대 결과: PASS. 동일 host GOROOT setup failure면 우회 없이 원문/exit code와 `/config/opt/go` 복구 조건 기록.
10. `! rg --sort path -n 't\\.Skip\\(' packages/go/streamgate/commit_boundary_test.go packages/go/streamgate/stream_release_test.go`
    - 기대 결과: stdout 없음, exit code 0.
11. `git diff --check -- packages/go/streamgate/commit_boundary.go packages/go/streamgate/commit_boundary_test.go packages/go/streamgate/stream_release.go packages/go/streamgate/stream_release_test.go agent-task/m-stream-evidence-gate-core/07+01,06_commit_boundary proto/gen/iop`
    - 기대 결과: stdout 없음.
12. `git status --short -- proto/gen/iop`
    - 기대 결과: stdout 없음.

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