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

# Code Review Reference - REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> Fill all implementation-owned sections and the implementation checklist, then leave this active pair in place for the review agent.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only.

## 개요

date=2026-07-26
task=m-agent-task-runtime-target-selector/07+06_context_review_recovery, plan=2, tag=REFACTOR

## 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/isolation 변경의 계획과 범위 경계.
- `code_review_cloud_G07_1.log`: Required — `synthesized_official_review_decision()`이 canonical schema의 `lane`/`grade`/nested `decision`/`quota`를 만들지 않아 class/full suite가 schema validation에서 실패했다. provider command/session/process 신규 실행은 `0/0/0`이었다.
- `plan_local_G08_0.log`, `code_review_cloud_G09_0.log`: historical context만 제공하며 완료 evidence로 재사용하지 않는다.

## 이 파일을 읽는 리뷰 에이전트에게

1. 실제 source와 implementation evidence를 대조한다.
2. 판정 뒤 이 active pair를 `code_review_cloud_G09_2.log` 및 `plan_cloud_G09_2.log`로 아카이브한다.
3. PASS이면 `complete.log`과 task archive를 작성한다. WARN/FAIL이면 code-review protocol의 next filesystem state를 작성하고 `complete.log`는 만들지 않는다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|---|---|
| REFACTOR-5 Canonical fixed official-review recovery decision | [x] |
| TEST-3 Recovery schema and isolation regressions | [x] |

## 구현 체크리스트

- [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를 기록한다.
- [x] 이 파일의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 구현 에이전트는 이 항목을 변경하거나 체크하지 않는다.

- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 차원별 평가, Required/Suggested/Nit 분류가 일치한다.
- [ ] active `CODE_REVIEW-cloud-G09.md`를 `code_review_cloud_G09_2.log`로 아카이브한다.
- [ ] active `PLAN-cloud-G09.md`를 `plan_cloud_G09_2.log`로 아카이브한다.
- [ ] `.gitignore` Agent-Ops block을 확인한다.
- [ ] PASS이면 `complete.log`를 작성하고 active `.md`를 남기지 않는다.
- [ ] PASS이면 active task directory를 `agent-task/archive/YYYY/MM/m-agent-task-runtime-target-selector/07+06_context_review_recovery/`로 이동한다.
- [ ] PASS이면 runtime completion metadata만 보고하고 roadmap을 직접 수정하지 않는다.
- [ ] PASS split 작업이면 active parent 유지/정리를 확인한다.
- [ ] WARN/FAIL이면 다음 active pair 또는 USER_REVIEW 상태를 작성하고 `complete.log`를 작성하지 않는다.

## 계획 대비 변경 사항

- 계획의 수정 파일 두 개만 변경했다. 이전 plan=1에서 이미 반영된 `SelectorDispatcherIntegrationTest.asyncSetUp()` provider-deny guard와 retry-blocked empty-scan 변경은 보존하고 그 위에 회귀를 추가했다.
- `RouteDecisionPersistenceTest.test_reopen_body_edit_and_generation_reset_preserve_or_reset_pin`의 generation-reset assertion을 canonical nested history 기준으로 갱신했다. 기존에는 review schema error로 해당 assertion까지 도달하지 못했으며, 이번 fix 후 실제 history shape를 검증하도록 한 TEST-3 범위의 보강이다.
- 사용자 지정 격리 조건에 따라 live provider, repo Edge-Node 진단, 보조 E2E smoke, full-cycle 실제 구동은 실행하지 않았다. 모든 검증은 provider binary가 해석되지 않는 `PATH=/usr/bin:/bin` Python simulation으로 수행했다.

## 주요 설계 결정

- active pair는 active PLAN의 route와 `task/plan/tag`를 source of truth로 사용한다. active pair가 없을 때만 최신 verdict review log와 identity가 일치하는 `plan_*.log`를 사용하며, route basename 또는 task identity가 불완전하면 `ExecutionDecisionError`로 fail closed한다.
- synthesized review decision은 policy module의 `official-review-codex` candidate를 사용해 top-level `lane`/`grade`, full candidate, nested `decision`, bounded/unknown `quota`, complete `transition`을 만든다. arbitrary `plan-0` fallback과 flat `rule_id`/`priority`/`quota_snapshot` write를 제거했다.
- `agent_spec_from_decision()`은 selector의 canonical prior-decision/policy identity validation을 재사용한다. persisted canonical review decision은 active/recovery source와 route·identity를 재검증한 뒤 그대로 재사용하고, legacy flat decision은 source 복구가 성공한 경우에만 canonical decision으로 대체한다.
- state history와 locator audit record는 nested `decision`/`quota`를 저장한다. 상태 표시의 `selector_evidence_lines()`만 과거 flat record를 read-only fallback으로 읽는다.
- official review의 qualified cloud failure는 같은 `codex/gpt-5.6-sol xhigh` target으로만 fresh retry한다. selector failover, quota probe, promotion, Pi/local invocation은 수행하지 않는다.

## 리뷰어를 위한 체크포인트

- synthesized fixed review decision이 selector initial/resume schema와 policy identity를 모두 만족하는가.
- legacy recovery source가 matching identity를 사용하고, 불완전한 source에서 fail closed하는가.
- active/recovery/budget/no-progress 실행이 schema error 없이 기존 semantics를 유지하는가.
- tests는 provider-deny PATH와 guard 아래에서 실행되어 실제 provider command/session/process가 0건인가.

## 검증 결과

### focused recovery schema

명령: `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`

```text
test_review_recovery_and_runtime_audit_evidence (__main__.SelectorDispatcherIntegrationTest.test_review_recovery_and_runtime_audit_evidence) ... ------------------------------------------
리뷰재시도: 01_unit
------------------------------------------
task=selector_dispatch_integration/01_unit
model=codex/gpt-5.6-sol xhigh
reason=official-review-fixed-target
failure_class=provider-quota
failure_source=unverified
provider_transport_failure_confirmed=false
locator=/tmp/tmp8oy5r445/attempt-codex/locator.json
retry=1/10
ok

----------------------------------------------------------------------
Ran 1 test in 0.040s

OK
```

검증 범위: active PLAN route 복구, historical review log가 공존하는 active generation, persisted canonical reuse, fixed-Codex same-target recovery, matching archived PLAN legacy recovery, invalid archived route fail-closed, nested history/locator/status evidence, legacy read-only evidence fallback, provider deny.

### integration and budget regressions

명령: `env PATH=/usr/bin:/bin python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest RepetitionLimitTest RouteDecisionPersistenceTest -v`

전체 stdout/stderr: `/tmp/iop-g09-class.log`

```text
test_rejects_tampered_canonical_target_and_selector_load_error (__main__.RouteDecisionPersistenceTest.test_rejects_tampered_canonical_target_and_selector_load_error) ... ok
test_reopen_body_edit_and_generation_reset_preserve_or_reset_pin (__main__.RouteDecisionPersistenceTest.test_reopen_body_edit_and_generation_reset_preserve_or_reset_pin) ... ok
test_resume_keeps_pin_across_kst_boundary (__main__.RouteDecisionPersistenceTest.test_resume_keeps_pin_across_kst_boundary) ... ok

----------------------------------------------------------------------
Ran 15 tests in 5.274s

OK
```

worker→review initial, persisted generation reset, exhausted review budget, review no-progress 10회, failure budget/retry-blocked 경로를 포함해 PASS했다.

### full Python suite

명령: `env PATH=/usr/bin:/bin python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'`

전체 stdout/stderr: `/tmp/iop-g09-full-unittest.log`

```text
..........................................................
----------------------------------------------------------------------
Ran 214 tests in 14.070s

OK
```

### py_compile

명령: `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`

```text
(stdout/stderr 없음, exit 0)
```

전체 stdout/stderr: `/tmp/iop-g09-py-compile.log` (0 bytes).

### diff check

명령: `git diff --check`

```text
(stdout/stderr 없음, exit 0)
```

전체 stdout/stderr: `/tmp/iop-g09-diff-check.log` (0 bytes).

### provider isolation evidence

명령: `env PATH=/usr/bin:/bin sh -c 'for provider_name in pi agy claude codex; do command -v "$provider_name" || true; done'`

```text
(stdout/stderr 없음, exit 0)
```

- provider binary path 출력: 없음 (`/tmp/iop-g09-provider-paths.log`, 0 bytes).
- focused test의 `invoke`/`build_command` deny guard 및 명시 fake review retry assertion: PASS.
- 전체 suite에 표시되는 `pi-sessions`, locator, provider banner는 `/tmp` fixture/fake runner evidence이며 실제 provider process가 아니다.
- real provider command/session/process 신규 실행 수: `0/0/0`.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING]** Fill every implementation-owned section, then leave review-only sections unchanged.

## 섹션 소유권

| Section | Owner | Note |
|---|---|---|
| Header, 개요, Roadmap Targets, Archive Evidence Snapshot | Fixed at stub creation | Implementing agent must not modify. |
| 구현 항목별 완료 여부, 구현 체크리스트 | Implementing agent | Check only after actual implementation/evidence. |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check. |
| 계획 대비 변경 사항, 주요 설계 결정, 검증 결과 | Implementing agent | Record actual source and output only. |
| 코드리뷰 결과 | Review agent appends | Not present in stub. |

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail — log-only official-review recovery가 논리적 최신 archive 순번이 아니라 파일 mtime으로 source generation을 선택해 과거 work unit을 재개할 수 있다.
  - completeness: Fail — active/canonical recovery는 구현됐지만 여러 archived loop가 공존할 때 latest verdict/PLAN을 결정적으로 복구한다는 필수 경계가 닫히지 않았다.
  - test coverage: Fail — 기존 회귀는 현재 loop log를 나중에 생성한 단일 mtime 순서만 다루며, archive suffix 순서와 mtime이 반대인 경우를 검증하지 않는다.
  - API contract: Fail — archive suffix가 정의하는 loop 순서 대신 filesystem metadata가 `work_unit_id`, lane, grade의 source of truth가 되어 SDD S09/S12의 persisted identity/audit 계약을 위반한다.
  - code quality: Pass — canonical decision 생성·검증과 nested audit consumer 자체에는 추가 Required/Suggested 문제가 없다.
  - implementation deviation: Fail — 계획은 최신 verdict review log와 matching PLAN 복구를 요구했지만 실제 선택 기준은 archive 순번이 아닌 mtime이다.
  - verification trust: Pass — provider-deny focused/class/full suite와 정적 검증은 재실행 결과가 제출 evidence와 일치했고, 별도 임시 fixture가 누락 경계를 결정적으로 재현했다.
  - spec conformance: Fail — SDD S09의 review recovery identity 및 S12의 추적 가능한 audit source가 checkout/copy 후에도 결정적이어야 하나 mtime 변화에 따라 달라진다.
- 발견된 문제:
  - Required — `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:792`: `latest_verdict_log()`가 `code_review_*.log`를 `st_mtime`으로 정렬하고 가장 최근 mtime 한 건만 판정한다. archive protocol의 suffix는 loop마다 전역 count로 증가하지만 mtime은 checkout, copy, touch로 바뀔 수 있어, 논리적 최신 `_1`보다 과거 `_0`의 mtime이 크면 `official_review_plan_source()`가 과거 matching PLAN과 `plan-0` identity를 선택한다. 재현 fixture에서 기대 source `plan_cloud_G09_1.log` 대신 `plan_local_G08_0.log`가 선택됐다. verdict가 있는 canonical review log만 대상으로 archive numeric suffix의 최댓값을 선택하고, 반대 mtime 순서를 고정한 회귀 테스트를 추가해야 한다.
- 다음 단계: FAIL — `latest_verdict_log()`의 최신성 기준을 canonical archive suffix로 바꾸고, archived loop 두 개의 suffix와 mtime 순서를 반대로 만든 fixture에서 최신 PLAN route/work-unit이 복구되는지 provider-deny focused/full suite로 재검증한다.
- 리뷰 검증 evidence:
  - `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` — 1 test PASS.
  - `env PATH=/usr/bin:/bin python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest RepetitionLimitTest RouteDecisionPersistenceTest -v` — 15 tests PASS.
  - `env PATH=/usr/bin:/bin python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — 214 tests 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` — exit 0, 출력 없음.
  - reversed-mtime archived-loop reproducer — `logical_latest=plan_cloud_G09_1.log`, actual `selected_source=plan_local_G08_0.log`, actual `selected_identity=group/01_unit::plan-0::tag-OLD`.
  - provider binary path 출력 없음; real provider command/session/process 신규 실행 수 `0/0/0`.
