# Complete - m-stream-evidence-gate-core/13+11,12_recovery_plan_contract

## 완료 일시

2026-07-26

## 요약

Dispatchable rebuilt request의 Core 전용 생성 권한, managed allowance 및 required-capability binding을 4회 리뷰 루프에서 닫았으며 최종 판정은 PASS다.

## 루프 이력

| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_cloud_G09_0.log` | `code_review_cloud_G09_0.log` | FAIL | sibling ingress snapshot 의존성과 post-rebuild allowance 확정 순서 결함을 확인했다. |
| `plan_local_G08_1.log` | `code_review_cloud_G08_1.log` | FAIL | 확정 allowance가 실제 dispatchable request에 결합되지 않는 문제를 확인했다. |
| `plan_local_G07_2.log` | `code_review_cloud_G07_2.log` | FAIL | 공개 final request 생성자 우회와 required-capability mismatch 승인 문제를 확인했다. |
| `plan_local_G07_3.log` | `code_review_cloud_G07_3.log` | PASS | finalizer sole factory, exact capability binding, dispatcher 관찰 회귀와 독립 검증을 확인했다. |

## 구현/정리 내용

- Exported `NewRebuiltRequest`를 제거하고 유효한 `RebuiltRequest` 생성 경로를 `RecoveryPlan.FinalizeRebuiltRequest` 내부의 package-private factory로 제한했다.
- finalizer가 plan/idempotency identity와 required capabilities의 immutable exact snapshot을 대조한 뒤 Core 계산 allowance를 final request에 결합하도록 했다.
- 성공 dispatcher의 identity/allowance/capabilities와 capability mismatch zero result, managed exhaustion, preparation 및 fault-request lifecycle 회귀를 갱신했다.

## 최종 검증

- `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT` - PASS; `/config/.local/bin/go` → `/config/opt/go/bin/go`, `go1.26.2`, `GOROOT=/config/opt/go`.
- `gofmt -l packages/go/streamgate/recovery_plan.go packages/go/streamgate/recovery_plan_test.go` - PASS; 출력 없음.
- `go test -count=1 ./packages/go/streamgate -run 'Test(ManagedTrajectoryPostRebuildFinalization|RebuiltRequestDraftLifecycleAndIdentity|RebuiltRequestFinalizationAuthorityAndCapabilities|RecoveryPlanDefensiveCopiesAndPreparationContract|RecoveryRequestSnapshotRefBounds|RecoveryHostSeamsAndRawFreeReferences)'` - PASS; `ok iop/packages/go/streamgate 0.002s`.
- `go test -count=1 ./packages/go/streamgate` - PASS; `ok iop/packages/go/streamgate 0.827s`.
- `go test -race -count=1 ./packages/go/streamgate` - PASS; `ok iop/packages/go/streamgate 1.862s`.
- `if rg --sort path -n '\bNewRebuiltRequest\b' packages/go/streamgate/recovery_plan.go packages/go/streamgate/recovery_plan_test.go; then exit 1; fi` - PASS; 출력 없음.
- `if rg --sort path -n '\bWithManagedRebuiltRequest\b' packages/go/streamgate/recovery_plan.go packages/go/streamgate/recovery_plan_test.go; then exit 1; fi` - PASS; 출력 없음.
- `if rg --sort path -n '\b(IngressSnapshot|ErrIngressSnapshotLimitExceeded)\b' packages/go/streamgate/recovery_plan.go packages/go/streamgate/recovery_plan_test.go; then exit 1; fi` - PASS; 출력 없음.
- `git diff --check` - PASS; 출력 없음.
- `go doc iop/packages/go/streamgate.NewRebuiltRequest` - PASS(expected absence); exported symbol이 없음을 확인했다.

## 잔여 Nit

- `packages/go/streamgate/recovery_plan_test.go:807`, `packages/go/streamgate/recovery_plan_test.go:815`의 mismatch `recordingDispatcher` no-call assertion은 실행 경로에 연결되지 않아 자명하다. coordinator dispatch 경로가 생기면 실제 no-call 검증으로 대체하거나 제거할 수 있다.

## 후속 작업

- 없음
