<!-- task=m-stream-evidence-gate-core/23+22_filter_observation_recovery plan=4 tag=REVIEW_REVIEW_REVIEW_FILTER_OBSERVATION_CLOSURE -->

# Plan - Recovery observation re-entry matrix 폐쇄

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

구현·테스트·증거만 소유한다. 아래 검증을 정확히 실행하고 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션에 실제 변경·출력을 채운 뒤 active pair를 유지하고 리뷰 준비 상태를 보고한다. 차단되면 정확한 blocker, 시도한 명령/출력, 재개 조건만 구현 소유 evidence에 기록한다. 사용자 질문, user-input 도구, `USER_REVIEW.md`, 다음 상태 분류, log archive, `complete.log` 작성은 하지 않는다.

## 배경

네 번째 리뷰에서 snapshot release ordering, failure matrix의 기존 분기, abort-barrier concurrency, post-dispatch attempt correlation과 제출된 검증 명령은 확인됐다. 그러나 계획에 고정된 re-entry 분기가 `TestRecoveryCoordinator_ObservationResultMatrix`에서 빠진 채 exhaustive matrix 완료로 표시됐다. 실제 coordinator의 used-plan rejection과 observation/result equality를 한 case로 닫는다.

## Archive Evidence Snapshot

- 이전 계획: `agent-task/m-stream-evidence-gate-core/23+22_filter_observation_recovery/plan_cloud_G08_3.log`
- 이전 리뷰: `agent-task/m-stream-evidence-gate-core/23+22_filter_observation_recovery/code_review_cloud_G08_3.log`
- 판정: FAIL
- 발견: Required 1, Suggested 0, Nit 0
- 핵심 문제: 계획이 명시한 `unavailable/mismatch/reentry` 중 re-entry가 actual coordinator result matrix와 verbose subtest 목록에 없다.
- 영향 파일: `packages/go/streamgate/filter_observation_test.go`
- 이전 검증: Go 1.26.2에서 targeted result matrix/runtime/concurrency, full package unit·race, gofmt, vet, diff는 통과했다. reviewer의 fresh verbose result-matrix 실행은 14개 subtest만 보여 re-entry evidence 부재를 확인했다.
- Roadmap carryover: 이번 follow-up은 하위 recovery observation evidence closure이며 Milestone Task를 직접 완료하지 않으므로 `Roadmap Targets`를 두지 않는다.

## 분석 결과

### 읽은 파일

- `packages/go/streamgate/recovery_coordinator.go`
- `packages/go/streamgate/filter_observation_test.go`
- `packages/go/streamgate/recovery_coordinator_test.go`
- `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-ops/rules/project/domain/platform-common/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-spec/index.md`
- `agent-contract/index.md`
- `agent-task/m-stream-evidence-gate-core/23+22_filter_observation_recovery/plan_cloud_G08_3.log`
- `agent-task/m-stream-evidence-gate-core/23+22_filter_observation_recovery/code_review_cloud_G08_3.log`

### SDD 기준

- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/stream-evidence-gate-core/SDD.md`, 상태 `[승인됨]`, 잠금 해제.
- S14 / `recovery-coordinator`: 같은 plan re-entry는 다른 strategy 우회나 host side effect 없이 terminal rejection으로 수렴해야 한다. Evidence Map은 re-entry fixture와 cycle당 single plan/dispatch를 요구한다.
- S23 / `recovery-coordinator`: preparation snapshot은 re-entry를 포함한 종료 경로에서 release되고, preparer/dispatch/budget을 추가 실행하지 않아야 한다.
- 이번 checklist는 actual `RecoveryCoordinator.Execute`의 used-plan re-entry row, snapshot release, no-side-effect/usage/closure와 final result-observation cause equality를 한 matrix case에서 검증하도록 S14/S23 evidence를 좁힌다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 `agent-test/local/platform-common-smoke.md`를 읽었다.
- PATH host Go identity를 먼저 기록하고 fresh `-count=1` 및 package `-race`를 사용한다.
- protobuf/config/wire를 바꾸지 않는 test-only 보강이므로 profile의 `make proto`, Edge/Node transport와 full-cycle은 적용하지 않는다.
- 외부 runner/provider/credential/port는 필요 없고 test-rule 유지보수도 필요 없다.

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

- `packages/go/streamgate/recovery_coordinator_test.go`는 same-plan re-entry와 no extra host call을 검증하지만 recovery observation kind/cause/sequence, snapshot release와 final result equality를 같은 fixture에서 검증하지 않는다.
- `packages/go/streamgate/filter_observation_test.go:2011-2094`의 result matrix에는 snapshot/preparer/abort/rebuild/dispatch/success 분기가 있으나 used-plan re-entry case가 없다.
- production `packages/go/streamgate/recovery_coordinator.go:429-446`은 re-entry를 `recovery_plan_rejected`와 cause=`plan_reentry`로 emit하므로 새 case는 production 변경 없이 실제 분기를 검증할 수 있다.

### 심볼 참조

- rename/제거 없음.

### 분할 판단

- 한 table case와 그 exact assertions만 보강하는 compact test-only closure다. 분리할 독립 contract가 없으므로 한 plan으로 유지한다.
- subtask `23+22`의 기존 선행 관계는 변경하지 않는다.

### 범위 결정 근거

- `packages/go/streamgate/recovery_coordinator.go`의 producer, concurrency fixture, runtime timeline과 public API는 이미 fresh 검증을 통과했으므로 수정하지 않는다.
- re-entry 의미, budget, recovery eligibility, config/proto, Edge sink/storage, roadmap와 agent-spec은 바꾸지 않는다.
- actual coordinator path를 호출하며 synthetic observation emit이나 private observation construction으로 대체하지 않는다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`, `finalizer=finalize-task-policy.sh`, `finalizer_mode=pair`.
- build/review closure: scope/context/verification/evidence/ownership/decision 모두 true. capability gap 없음.
- build scores: scope=1, state/concurrency=1, blast=0, evidence=1, verification=1 → G04. review scores도 1/1/0/1/1 → G04.
- `large_indivisible_context=false`; positive loop risks=`temporal_state`, `boundary_contract`, count=2.
- recovery signals: `review_rework_count=4`, `evidence_integrity_failure=true`; build base=`local-fit`, route basis=`recovery-boundary` → `PLAN-cloud-G04.md`.
- review route basis=`official-review` → `CODE_REVIEW-cloud-G04.md`.

## 구현 체크리스트

- [ ] REVIEW_REVIEW_REVIEW_FILTER_OBSERVATION_CLOSURE-1 actual coordinator result matrix에 used-plan re-entry의 exact rejection row, snapshot/no-side-effect barrier와 result equality를 추가하고 fresh package 검증을 통과한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_REVIEW_FILTER_OBSERVATION_CLOSURE-1] Actual re-entry result row

- 문제: `packages/go/streamgate/filter_observation_test.go:2011-2094`의 table은 `agent-task/m-stream-evidence-gate-core/23+22_filter_observation_recovery/plan_cloud_G08_3.log:132`가 고정한 re-entry 분기를 포함하지 않는다. 따라서 generic equality assertion이 `packages/go/streamgate/recovery_coordinator.go:429-446`의 used-plan rejection에 적용되지 않고, S14/S23의 re-entry/no-side-effect/snapshot lifetime evidence도 이 matrix에서 비어 있다.
- 해결 방법: result-matrix case setup에 실행 전 plan ledger를 priming하는 명시적 fixture field/helper를 추가하고 continuation input과 snapshot을 사용해 same plan을 재실행한다. expected row는 sequence 1의 `recovery_plan_rejected`, cause=`plan_reentry` 한 개이며 snapshot release 한 번, `PreviousAttemptClosed=false`, usage 0, abort/prepare/rebuild/dispatch 0을 기존 exact assertions로 검증한다.

Before (`packages/go/streamgate/filter_observation_test.go:2027`):

```go
{
    name: "preparer snapshot mismatch", strategy: RecoveryStrategyContinuationRepair,
    // re-entry case 없음
},
```

After:

```go
{
    name: "plan reentry", strategy: RecoveryStrategyContinuationRepair,
    snapshot: &coordinatorPreparationSnapshot{ref: "snapshot.reentry"},
    setup: func(in *RecoveryCycleInput) { in.PreparerID = "preparer.matrix" },
    primeUsedPlan: true,
    wantErr: ErrRecoveryPlanReentry,
    wantRows: []observationRow{{kind: ObservationKindRecoveryPlanRejected, causes: []string{"plan_reentry"}}},
    wantCalls: []string{"snapshot.release:snapshot.reentry"},
},
```

- 수정 파일 및 체크리스트:
  - [ ] `packages/go/streamgate/filter_observation_test.go`: actual coordinator matrix에 used-plan re-entry fixture와 exact expected row/side-effect evidence를 추가한다.
- 테스트 작성: 작성. `TestRecoveryCoordinator_ObservationResultMatrix/plan_reentry`가 actual `Execute` path, result/observation cause equality, contiguous sequence, snapshot single release, zero host side effect/usage와 previous-attempt-open 상태를 검증한다.
- 중간 검증: `go test -count=1 -v ./packages/go/streamgate -run '^TestRecoveryCoordinator_ObservationResultMatrix$'` 출력에 `plan_reentry` subtest가 나타나고 PASS해야 한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `packages/go/streamgate/filter_observation_test.go` | REVIEW_REVIEW_REVIEW_FILTER_OBSERVATION_CLOSURE-1 |

## 최종 검증

- `command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT`
- `rg --sort path -n 'name: "plan reentry"|"plan_reentry"' packages/go/streamgate/filter_observation_test.go`
- `go test -count=1 -v ./packages/go/streamgate -run '^TestRecoveryCoordinator_ObservationResultMatrix$'`
- `go test -count=1 ./packages/go/streamgate`
- `go test -race -count=1 ./packages/go/streamgate`
- `test -z "$(gofmt -l packages/go/streamgate/filter_observation_test.go)"`
- `go vet ./packages/go/streamgate/`
- `git diff --check`

