<!-- task=m-stream-evidence-gate-core/14+13_recovery_execution plan=2 tag=REVIEW_REVIEW_RECOVERY_EXECUTION -->

# Plan - Recovery winner contributor evidence 종결

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

이 plan은 S14 winner contributor assertion과 검증 evidence 정정만 소유한다. 아래 검증을 실행하고 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션에 실제 변경 내용과 stdout/stderr를 기록한 뒤 active 파일을 그대로 두고 review-ready로 보고한다. 막히면 정확한 blocker, 시도한 명령/출력, 재개 조건만 구현 소유 evidence에 남긴다. 사용자에게 질문하거나 user-input 도구를 호출하거나 control-plane stop 파일을 만들거나 다음 상태를 분류하지 않는다. log archive, `complete.log`, verdict와 task archive는 code-review 스킬 전용이다.

## 배경

S14 seam fixture는 두 violation을 실제 Arbiter와 Coordinator에 연결하고 cycle당 host side effect 하나를 검증한다. 그러나 계획이 필수로 요구한 winner consumer/filter/rule의 최종 `RecoveryPlan` contributor 보존 assertion이 없고 실제 Arbiter 결과를 동등한 값으로 재구성한다. production 동작을 바꾸지 않고 기존 fixture를 직접 연결·검증해 마지막 evidence 공백을 닫는다.

## Archive Evidence Snapshot

- Prior task: `agent-task/m-stream-evidence-gate-core/14+13_recovery_execution`
- Archived plan: `agent-task/m-stream-evidence-gate-core/14+13_recovery_execution/plan_local_G04_1.log`
- Archived review: `agent-task/m-stream-evidence-gate-core/14+13_recovery_execution/code_review_cloud_G04_1.log`
- Verdict: FAIL
- Findings: Required 1, Suggested 0, Nit 0.
- Required evidence gap: `TestRecoveryCoordinatorTwoViolationsSinglePlan`의 winner contributor 블록이 `PlanID`만 확인해 `c.winner/a.recovery/r.winner` 보존을 검증하지 않는다.
- Affected file: `packages/go/streamgate/recovery_coordinator_test.go`.
- Verification evidence: host Go `/config/.local/bin/go` -> `/config/opt/go/bin/go`, Go `1.26.2`, `GOROOT=/config/opt/go`; focused, package unit/race, 20회 focused 반복과 `git diff --check`는 통과했다. 비-verbose focused 명령의 실제 출력은 `ok iop/packages/go/streamgate 0.033s`이며 이전 verbose 형태 기록은 현재 명령과 일치하지 않아 reviewer fresh output으로 정정됐다.
- Roadmap carryover: `recovery-coordinator`; S20 abort-timeout evidence는 충족됐고 S14 winner contributor evidence만 남았다.
- Narrow reread allowed when exact prior context is needed: 위 archived plan/review 두 파일만 읽는다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md`
- Milestone link: [Stream Evidence Gate Core](agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/stream-evidence-gate-core.md)
- Task ids:
  - `recovery-coordinator`: Recovery Coordination과 Request Rebuild coordinator
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.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/14+13_recovery_execution/plan_local_G04_1.log`
- `agent-task/m-stream-evidence-gate-core/14+13_recovery_execution/code_review_cloud_G04_1.log`
- `agent-task/m-stream-evidence-gate-core/14+13_recovery_execution/plan_cloud_G09_0.log`
- `agent-task/m-stream-evidence-gate-core/14+13_recovery_execution/code_review_cloud_G09_0.log`
- `agent-task/archive/2026/07/m-stream-evidence-gate-core/13+11,12_recovery_plan_contract/complete.log`
- `packages/go/streamgate/recovery_coordinator_test.go`
- `packages/go/streamgate/recovery_coordinator.go`
- `packages/go/streamgate/recovery_plan.go`
- `packages/go/streamgate/recovery_plan_test.go`
- `packages/go/streamgate/decision_arbiter.go`

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`; 상태 `[승인됨]`, 잠금 해제, 사용자 리뷰 없음.
- 대상 Task: `recovery-coordinator`.
- S14 Acceptance Scenario는 같은 epoch의 두 retryable violation이 하나의 plan/idempotency key/dispatch로 수렴하고 선택 결과가 coordinator plan에 연결돼야 한다. Evidence Map은 simultaneous intent와 cycle당 one plan/dispatch assertion을 요구한다.
- S20 abort timeout/failure의 no-overlapping-live-attempt evidence는 `TestRecoveryCoordinatorAbortTimeoutBlocksDownstream`과 fresh unit/race 실행으로 충족됐다.
- 구현 checklist는 S14 winner contributor 보존 하나만 역산하고, final verification은 named fixture와 전체 unit/race로 기존 S14/S20 evidence를 함께 보존한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 `agent-test/local/platform-common-smoke.md`를 읽었다.
- host PATH의 Go 정체를 먼저 기록하고 검증 중 toolchain을 바꾸지 않는다. fresh evidence가 필요하므로 Go test는 `-count=1`을 사용한다.
- profile의 `make proto`, Edge/Node transport unit과 full-cycle은 proto/config/wire 변경용이다. 이번 test-only assertion은 production 또는 사용자 실행 경로를 바꾸지 않아 적용하지 않는다.
- fallback verification source는 현재 package test layout, 승인 SDD S14/S20 Evidence Map과 이전 리뷰의 재현 명령이다. 외부 서비스, Docker, port, secret은 필요 없고 테스트 규칙 유지보수도 필요 없다.

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

- 실제 `Arbitrate` winner와 coordinator의 단일 abort/rebuild/dispatch: 기존 fixture가 커버한다.
- winner contributor의 consumer/filter/rule 보존: `RecoveryPlan.Contributors()` assertion이 없어 미커버이며 이번 plan에서 추가한다.
- S20 abort deadline 뒤 zero downstream/usage, snapshot release, binding 유지: 기존 fixture가 커버하며 변경하지 않는다.
- production behavior 변경: 없음.

### 심볼 참조

- renamed/removed symbol: 없음.
- 새 API/dependency/import: 없음.

### 분할 판단

- split decision policy를 먼저 적용했다.
- 변경은 기존 split subtask의 한 test 함수에서 직접 Arbiter value 전달과 contributor assertion을 추가하는 단일 evidence fix다. API/호출부, domain, ownership, 별도 검증 경계가 없고 분리하면 같은 fixture와 package 회귀를 중복하므로 추가 split을 하지 않는다.
- subtask `14+13_recovery_execution`의 predecessor `13`은 `agent-task/archive/2026/07/m-stream-evidence-gate-core/13+11,12_recovery_plan_contract/complete.log`의 PASS로 충족됐다.

### 범위 결정 근거

- 수정 허용: `packages/go/streamgate/recovery_coordinator_test.go`의 `TestRecoveryCoordinatorTwoViolationsSinglePlan`과 active review evidence fields만.
- 제외: `recovery_coordinator.go`, `recovery_plan.go`, `decision_arbiter.go`, S20 fixture, roadmap, SDD, contract/config, agent-spec, 다른 subtask, task-group `WORK_LOG.md`. production correctness/API defect가 없고 현재 Required는 test assertion 하나다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`.
- finalizer: `finalize-task-policy.sh`; finalizer_mode: `pair`.
- build closures: `scope_closed=true`(한 fixture의 contributor assertion), `context_closed=true`(test와 public contributor/arbiter/coordinator 경계 확인), `verification_closed=true`(named/package/race/diff 명령), `evidence_trusted=true`(fresh 실행과 20회 반복), `ownership_closed=true`(test file과 active task evidence만 소유), `decision_closed=true`(Milestone 잠금 해제, 결정 필요 없음).
- build route_basis: `local-fit`; capability_gap: `none`; none floor: `none`.
- build grade_scores: `scope_coupling=1`, `state_concurrency=1`, `blast_irreversibility=0`, `evidence_diagnosis=0`, `verification_complexity=1`; grade `G03`.
- build loop-risk observations:
  - ordered_transitions: `state_count=5`, adverse paths=`winner_contributor_misbinding`; 실제 Arbiter→plan→abort→rebuild→dispatch 흐름이다.
  - concurrent_consistency: `actor_count=1`; 새 concurrency/lock/race 제약은 없다.
  - boundary_contract: `component_count=3`, `consumer_count=1`; Arbiter winner와 RecoveryCoordinator/RecoveryPlan contributor의 immutable identity 연결이다.
  - structured_interpretation: mechanisms/hazards 없음.
  - variant_product: `independent_axis_count=1`, `combination_verification_required=false`.
  - matched signatures: `temporal_state`, `boundary_contract`; triggered `true`이나 route/grade에는 사용하지 않았다.
- build output: `PLAN-local-G03.md`.
- review closures: scope/context/verification/evidence/ownership/decision 모두 `true`; official reviewer가 S14 checklist, direct arbitration input, contributor assertion과 fresh output을 독립 대조할 수 있다.
- review route_basis: `official-review`; capability_gap: `none`; none floor: `none`.
- review grade_scores: `scope_coupling=1`, `state_concurrency=1`, `blast_irreversibility=0`, `evidence_diagnosis=1`, `verification_complexity=1`; grade `G04`.
- review output: `CODE_REVIEW-cloud-G04.md`; official target Codex `gpt-5.6-sol` xhigh.
- finalizer 출력과 canonical filenames가 일치한다.

## 구현 체크리스트

- [x] REVIEW_REVIEW_RECOVERY_EXECUTION-1 실제 `Arbitrate` 결과를 coordinator에 직접 전달하고 최종 plan contributor가 winner `c.winner/a.recovery/r.winner` 하나인지 assertion한다.
- [x] REVIEW_REVIEW_RECOVERY_EXECUTION-2 focused test, streamgate unit/race, gofmt/symbol/diff 검증을 fresh execution으로 수행하고 실제 stdout/stderr를 그대로 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_RECOVERY_EXECUTION-1] S14 winner contributor assertion

- 문제: `packages/go/streamgate/recovery_coordinator_test.go:966`은 실제 Arbiter 결과를 `NewArbitrationResult`로 재구성하고, `packages/go/streamgate/recovery_coordinator_test.go:1010`의 winner contributor 블록은 `PlanID`만 검사한다. `RecoveryPlan.Contributors()`의 consumer/filter/rule이 잘못돼도 fixture가 통과한다.
- 해결 방법:

```go
// Before: packages/go/streamgate/recovery_coordinator_test.go:966
intentCopy := *arbitration.RecoveryIntent()
arbCopy, err := NewArbitrationResult(/* copied fields */)
input := RecoveryCycleInput{Arbitration: arbCopy, /* ... */}

// After: actual Arbiter value and exact contributor identity
input := RecoveryCycleInput{Arbitration: arbitration, /* ... */}
contributors := plan.Contributors()
if len(contributors) != 1 ||
	contributors[0].ConsumerID() != "c.winner" ||
	contributors[0].FilterID() != "a.recovery" ||
	contributors[0].RuleID() != "r.winner" {
	t.Fatalf("plan contributors = %v, want c.winner/a.recovery/r.winner", contributors)
}
```

- 수정 파일 및 체크리스트:
  - [x] `packages/go/streamgate/recovery_coordinator_test.go`: 수동 `arbCopy` 블록을 제거하고 `Arbitration: arbitration`을 직접 전달한다.
  - [x] `plan.Contributors()` 길이와 `ConsumerID/FilterID/RuleID`를 정확히 assertion한다.
  - [x] 기존 plan/abort/rebuild/dispatch 1회, usage, re-entry assertions를 유지한다.
- 테스트 작성: 새 test는 추가하지 않고 기존 `TestRecoveryCoordinatorTwoViolationsSinglePlan`을 강화한다. fixture의 assertion goal은 실제 Arbiter winner identity가 coordinator plan contributor 하나로 보존되는 것이다.
- 중간 검증: `go test -count=1 ./packages/go/streamgate -run '^TestRecoveryCoordinatorTwoViolationsSinglePlan$'` — PASS.

### [REVIEW_REVIEW_RECOVERY_EXECUTION-2] Fresh evidence 정합성

- 문제: 직전 review의 focused command는 `-v`가 없는데 verbose test lines를 기록해 명령과 stdout이 일치하지 않았다. 코드 정합성은 fresh unit/race로 확인됐지만 최종 evidence는 실제 명령 출력 그대로 남겨야 한다.
- 해결 방법: host Go 정체, gofmt, S14/S20 focused tests, package unit/race, deterministic symbol inventory와 diff check를 순서대로 다시 실행한다. 출력은 요약하거나 재구성하지 않고 review stub의 대응 섹션에 그대로 기록한다.
- 수정 파일 및 체크리스트:
  - [x] repo-local 임시 도구나 생성물을 만들지 않는다.
  - [x] 각 명령의 실제 stdout/stderr를 대응 `검증 결과` 섹션에 그대로 기록한다.
  - [x] 명령을 바꾸면 `계획 대비 변경 사항`에 대체 명령과 이유를 먼저 기록한다.
- 테스트 작성: 별도 test는 추가하지 않는다. 강화한 S14 fixture와 기존 S20 fixture가 regression evidence다.
- 중간 검증: `gofmt -l packages/go/streamgate/recovery_coordinator_test.go` — 출력 없음.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/go/streamgate/recovery_coordinator_test.go` | REVIEW_REVIEW_RECOVERY_EXECUTION-1 |
| `CODE_REVIEW-cloud-G04.md` 구현 소유 evidence fields | REVIEW_REVIEW_RECOVERY_EXECUTION-2 |

## 최종 검증

- `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT` — host Go 정체가 local rule과 일치한다.
- `gofmt -l packages/go/streamgate/recovery_coordinator_test.go` — 출력 없음.
- `go test -count=1 ./packages/go/streamgate -run 'TestRecoveryCoordinator(TwoViolationsSinglePlan|AbortTimeoutBlocksDownstream)'` — 두 fixture PASS.
- `go test -count=1 ./packages/go/streamgate` — PASS.
- `go test -race -count=1 ./packages/go/streamgate` — PASS.
- `rg --sort path -n 'Arbitration: +arbitration|contributors := plan\.Contributors\(\)|ConsumerID\(\).*c\.winner|FilterID\(\).*a\.recovery|RuleID\(\).*r\.winner' packages/go/streamgate/recovery_coordinator_test.go` — direct seam과 contributor assertions가 출력된다.
- `git diff --check` — 출력 없음.

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

## 의존 관계 및 구현 순서

REVIEW_REVIEW_RECOVERY_EXECUTION-1 assertion을 먼저 반영한 뒤 REVIEW_REVIEW_RECOVERY_EXECUTION-2 fresh evidence를 기록한다. predecessor `13`은 위 archived `complete.log`로 충족됐다.
