<!-- task=m-agent-task-runtime-target-selector/07+06_context_review_recovery plan=2 tag=REFACTOR -->

# Plan - Official review recovery decision canonicalization

## 배경

`plan=1`은 dispatcher simulation의 실제 provider escape를 차단했지만, 공식 리뷰의 legacy recovery decision이 selector contract와 달라 class/full suite가 model invocation 전에 실패했다. `synthesized_official_review_decision()`은 `lane`, `grade`, nested `decision`, canonical `quota`를 생략하고 이전 flat `rule_id`/`priority`/`quota_snapshot`만 반환한다. 따라서 `agent_spec_from_decision()`과 resume validation이 recovery review를 소비할 수 없다.

이 후속은 사용자 지정 cloud-G09 작업이다. 테스트와 검증은 provider command/session/process를 만들지 않는 simulation으로만 수행한다. 실제 작업 에이전트는 dispatcher가 선택한 cloud Codex만 사용하며 Pi 또는 다른 local model을 호출하지 않는다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-task-runtime-target-selector.md`
- Task ids: `context-failover`, `failure-budget`, `dispatch-integration`, `audit-tests`
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- `plan_local_G07_1.log`: provider-deny guard와 state-only retry-blocked test를 구현한 직전 계획. production dispatcher schema 변경은 명시적으로 범위 밖이었다.
- `code_review_cloud_G07_1.log`: 공식 cloud-G09 review의 FAIL evidence. `dispatch.py:1189` synthesized decision의 canonical schema 누락이 Required이며, focused test는 PASS했지만 class는 1 failure/1 error, full suite는 3 failures/2 errors였다. provider command/session/process 신규 실행은 `0/0/0`이었다.
- `plan_local_G08_0.log`와 `code_review_cloud_G09_0.log`: 이전 context/review recovery 범위의 historical evidence. 중단된 Pi fixture 실행 또는 과거 PASS 출력은 이번 완료 근거로 재사용하지 않는다.

## 분석 결과

### 계약 경계

- `select_execution_target.py` initial/resume decision은 `schema_version`, `work_unit_id`, `stage`, `lane`, `grade`, `selected`, canonical candidate list, nested `decision`, `quota`, `transition`을 가진다.
- `agent_spec_from_decision()`은 nested `decision.evaluated_at`과 `lane`/`grade`로 policy target을 재검증한다.
- review policy는 lane/grade와 무관하게 `official-review-codex` / `codex:gpt-5.6-sol` 하나만 선택한다. legacy recovery는 이 fixed target을 유지하되 quota probe나 failover를 시작하지 않아야 한다.
- state history, status, locator evidence는 flat legacy field가 아니라 canonical nested `decision`/`quota`를 읽어야 한다. 필요한 경우 기존 persisted legacy record를 read-only fallback으로만 표시하고, 새 synthesized record에는 legacy flat schema를 저장하지 않는다.

### route/source 복구

- active pair가 있으면 active PLAN route와 work-unit identity를 우선한다.
- active pair가 없는 legacy recovery는 verdict review log와 identity가 같은 archived plan log에서 route와 work-unit identity를 복원한다.
- route 또는 identity를 신뢰성 있게 복원할 수 없으면 fabricated default (`plan-0`, 임의 lane/grade) 대신 fail closed한다.

### 테스트 환경

`agent-test/local/rules.md`의 Python simulation 절차를 적용한다. 모든 test command는 `PATH=/usr/bin:/bin`로 실행해 provider CLI가 해석되지 않게 하고, `SelectorDispatcherIntegrationTest`의 invoke/build-command deny guard를 유지한다. fixture의 문자열이나 temporary locator에 `pi`가 나타나더라도 실제 provider process evidence로 해석하지 않는다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`, `finalizer=finalize-task-policy.sh`, `finalizer_mode=pair`.
- build: `route_basis=grade-boundary`, `risk_triggered=true`, scores=`2/2/2/1/2`, `cloud-G09`, `PLAN-cloud-G09.md`.
- review: `route_basis=official-review`, scores=`2/2/2/1/2`, `cloud-G09`, `CODE_REVIEW-cloud-G09.md`, `codex/gpt-5.6-sol xhigh`.

## 구현 체크리스트

- [x] official-review recovery가 canonical selector decision shape와 fixed-Codex policy identity를 생성·재사용하도록 `dispatch.py`를 수정한다.
- [x] active/recovery route·work-unit 복구와 canonical evidence consumer를 구현해 fabricated default 및 legacy flat-field write를 제거한다.
- [x] success/recovery/budget/no-progress paths를 포함한 dispatcher regression을 provider-deny 아래에서 보강한다.
- [x] focused/class/full unittest, `py_compile`, `git diff --check`, provider command/session/process `0/0/0` evidence를 CODE_REVIEW에 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 변경과 출력으로 채운다.

## 구현 항목

### [REFACTOR-5] Canonical fixed official-review recovery decision

- 수정 파일: `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`
- `synthesized_official_review_decision()`과 호출 경계를 정리한다. policy-owned review candidate와 selected target, `lane`/`grade`, KST-aware nested `decision`, bounded/unknown fixed-review `quota`, complete `transition`을 canonical selector schema로 반환한다.
- active pair와 matching archived pair에서 identity/route를 복원한다. 불완전한 legacy record는 fail closed하고 arbitrary default로 실행하지 않는다.
- review recovery는 Codex fixed policy를 유지하며 quota probe, failover, promotion, local provider 실행을 시작하지 않는다.
- `selector_evidence_lines()`와 persisted history/locator/status consumer가 nested `decision`/`quota`를 기준으로 audit fields를 보존하도록 맞춘다.

### [TEST-3] Recovery schema and isolation regressions

- 수정 파일: `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- active review, archived legacy recovery, persisted resume를 대상으로 full decision shape와 policy validation을 assert한다.
- review no-progress limit, exhausted review budget, worker→review initial flow, generation reset이 schema error 없이 기존 semantics를 보존하는지 회귀한다.
- test suite의 invoke/build-command fail-fast guard를 유지하고, review recovery test에서 real provider command/session/process가 0건임을 확인한다.

## 의존 관계 및 구현 순서

1. recovery plan source에서 route/work-unit을 fail-closed로 추출한다.
2. canonical fixed review decision과 evidence consumer를 구현한다.
3. recovery/initial/budget regression을 보강한다.
4. provider-deny PATH에서 focused, class, full suite와 static validation을 실행하고 evidence를 작성한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py` | REFACTOR-5 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` | TEST-3 |

## 최종 검증

- `env PATH=/usr/bin:/bin python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest.test_review_recovery_and_runtime_audit_evidence -v` — canonical recovery decision과 provider deny PASS.
- `env PATH=/usr/bin:/bin python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest RepetitionLimitTest RouteDecisionPersistenceTest -v` — review/budget/generation regression PASS.
- `env PATH=/usr/bin:/bin python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — fresh full suite PASS.
- `env PATH=/usr/bin:/bin python3 -m py_compile agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` — exit 0.
- `git diff --check` — 출력 없음.
- 위 모든 command 동안 real provider command/session/process=`0/0/0`을 확인한다.

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