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

# Plan - Canonical archive suffix recovery hardening

## 배경

`plan=3`는 archived official-review recovery를 mtime 대신 numeric suffix 최댓값으로 바꿨다. 그러나 review 결과, `REVIEW_LOG_RE`와 `PLAN_LOG_RE`가 leading-zero suffix를 허용해 canonical archive count가 아닌 `_099` review 또는 `_010` PLAN log가 정상 source를 덮을 수 있음이 재현됐다.

사용자 지시에 따라 이 후속의 worker와 review는 모두 `cloud-G09` Codex만 사용한다. Pi 또는 다른 local model의 command, session, process를 호출하거나 재개하지 않는다. 모든 Python 검증은 provider binary가 없는 `PATH=/usr/bin:/bin` simulation에서 실행한다.

## 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_cloud_G09_3.log`: numeric latest verdict selection과 reversed-mtime recovery를 구현한 직전 계획.
- `code_review_cloud_G09_3.log`: FAIL Required. `_099` verdict review가 `_10`보다 선택되며, `_010` PLAN은 canonical `_10` PLAN보다 mtime 우선으로 matching source가 된다. 두 parser와 matching PLAN 후보를 canonical ASCII decimal filename으로 fail closed 해야 한다.
- `plan_cloud_G09_2.log`, `code_review_cloud_G09_2.log`: mtime source-selection 결함과 numeric ordering의 선행 근거.
- `plan_local_G07_1.log`, `code_review_cloud_G07_1.log`: 이전 local/Pi 시도와 provider-deny guard의 진단 근거이며 어떤 경우에도 resume source가 아니다.

## 분석 결과

### archive identity 계약

- archive suffix는 전역 증가 counter의 canonical ASCII decimal 표기만 허용한다: `0|[1-9][0-9]*`.
- review와 PLAN filename matcher는 모두 이를 적용한다. leading zero, non-ASCII digit, extra suffix, non-regular file은 candidate가 될 수 없다.
- `latest_verdict_log()`는 canonical regular review verdict 중 suffix가 가장 큰 log를 선택한다.
- `matching_plan_log()`는 선택된 review와 header identity가 일치하는 canonical regular PLAN log만 후보로 하고, 그 밖의 archive는 fail closed 한다.
- active pair 우선순위와 fixed official-review Codex policy는 변경하지 않는다.

### 테스트 환경

`agent-test/local/rules.md`를 적용한다. focused/class/full unittest와 compile은 `PATH=/usr/bin:/bin`에서 실행한다. existing `invoke`/`build_command` provider-deny guard를 유지하고, real provider command/session/process 수가 `0/0/0`임을 기록한다.

### 최종 라우팅

- 사용자 지정 route override: build=`cloud-G09`, review=`cloud-G09`.
- build file: `PLAN-cloud-G09.md`.
- review file: `CODE_REVIEW-cloud-G09.md`, `codex/gpt-5.6-sol xhigh`.
- 자동 local-fit 결과는 이 사용자 지정 route override를 대체하지 않는다.

## 구현 체크리스트

- [ ] `PLAN_LOG_RE`와 `REVIEW_LOG_RE` suffix를 canonical ASCII decimal로 제한한다.
- [ ] `matching_plan_log()`가 canonical regular PLAN filename만 matching identity 후보로 허용하게 한다.
- [ ] leading-zero review/PLAN과 reversed mtime이 정상 `_10` recovery source를 덮지 못하는 regression을 추가한다.
- [ ] focused/class/full unittest, `py_compile`, `git diff --check`, provider command/session/process `0/0/0` evidence를 기록한다.
- [ ] CODE_REVIEW 구현 에이전트 소유 섹션을 실제 변경과 출력으로 채운다.

## 구현 항목

### [REFACTOR-7] Canonical archive count parsing

- 수정 파일: `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`
- `PLAN_LOG_RE`와 `REVIEW_LOG_RE`의 numeric suffix를 `0|[1-9][0-9]*`로 제한한다.
- `matching_plan_log()`가 `PLAN_LOG_RE.fullmatch(path.name)`와 `path.is_file()`을 통과한 identity-matching archive만 선택하도록 보강한다.
- `latest_verdict_log()`의 numeric newest selection, active pair precedence, decision schema를 보존한다.

### [TEST-5] Leading-zero archive recovery regression

- 수정 파일: `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- 기존 reversed-mtime recovery fixture에 verdict가 있는 `_099` review와 identity-matching `_010` PLAN candidate를 추가한다.
- canonical `_10` review/PLAN이 선택되고 leading-zero filename이 regex와 recovery source에서 배제되는지 assert한다.
- provider-deny guard의 invocation/command count가 0인지 유지한다.

## 의존 관계 및 구현 순서

1. review/PLAN matcher의 canonical ASCII decimal suffix 규칙을 구현한다.
2. matching PLAN 후보 filter를 canonical regular file로 보강한다.
3. leading-zero와 reversed-mtime archive fixture로 recovery identity를 고정한다.
4. provider-deny validation과 static checks를 실행하고 evidence를 작성한다.

## 수정 파일 요약

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

## 최종 검증

- `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`
- `env PATH=/usr/bin:/bin python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest RepetitionLimitTest RouteDecisionPersistenceTest -v`
- `env PATH=/usr/bin:/bin python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'`
- `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`
- `git diff --check`
- 모든 검증 동안 real provider command/session/process=`0/0/0`.

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