<!-- task=m-agent-task-runtime-target-selector/11+10_unknown_isolation plan=7 tag=REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR -->

# Plan - Typed retry evidence와 continuation transaction 원자성

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

구현과 검증을 끝낸 뒤 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 원문 출력으로 채운다. active 파일은 그대로 두고 review 준비 완료만 보고한다. 종결은 code-review skill 전용이다. 차단되면 정확한 원인, 시도한 명령/출력, 재개 조건만 구현 에이전트 소유 evidence에 기록한다. 사용자에게 질문하거나 user-input 도구를 호출하지 않고, control-plane stop file 생성, 다음 상태 분류, archive/log 이동, `complete.log` 또는 roadmap 수정은 하지 않는다.

## 배경

일곱 번째 격리 재검토에서 focused 및 전체 252개 테스트는 통과했지만, 현재 worker decision과 다른 `selected` evidence도 qualified retry intent를 만들고 유효하지 않은 locator에서도 failover decision이 commit되며 intent가 먼저 소비됨을 별도 상태 재현으로 확인했다. terminal pre-loop 분기는 failure class를 잃고, actual dispatcher 회귀는 `{}` locator와 부분 상태 비교만 사용해 이 계약 위반을 놓친다. typed evidence 생성부터 logical context 검증, decision/history/quota commit과 intent exactly-once 소비까지를 하나의 task-local transaction으로 완결한다.

## Archive Evidence Snapshot

- Prior plan: `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/plan_local_G07_6.log`
- Prior review: `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/code_review_cloud_G07_6.log`
- Verdict: `FAIL`
- Required:
  - qualified evidence가 persisted worker decision의 `selected` identity를 검증하지 않고, 이미 소진된 terminal 분기는 `failure_class=None`을 기록한다.
  - decision commit이 locator/logical context 검증보다 먼저 retry marker/context를 지워 selector/context/commit 실패 보존과 exactly-once 소비 계약을 깨뜨린다.
  - actual dispatcher 회귀가 `{}` locator, resume path와 selected target만 검증해 identity mismatch, exact context prompt, 실패 보존 및 정상 sibling 전체 상태 불변을 놓친다.
- Suggested: 없음
- Nit: 없음
- Affected files: `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`, `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- Verification evidence: focused 4/12/13/6개와 fresh 전체 252개, `py_compile`, `git diff --check`는 PASS했다. 외부 subprocess deny 상태 재현은 mismatched selected evidence가 qualified이고 누락 locator 뒤 intent가 소비됨을 확인했다.
- Roadmap carryover: `throughput-policy`, SDD S06/S07/S09/S11의 task-local qualified failover, persisted transition, 같은 admission snapshot과 unknown 격리를 유지한다.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-task-runtime-target-selector.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/agent-task-runtime-target-selector.md)
- Task ids:
  - `throughput-policy`: target별 정적 cap 없이 ready task dispatch와 batch quota snapshot 재사용
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/plan_local_G07_6.log`
- `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/code_review_cloud_G07_6.log`
- `agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md`
- `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-ops/rules/common/philosophy.md`
- `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/agent-task-runtime-target-selector.md`
- `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`
- `agent-contract/index.md` — dispatcher에 매칭되는 별도 계약 문서 없음.
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md` — dispatcher에 매칭되는 living spec 없음.

### SDD 및 테스트 환경 기준

- SDD는 `[승인됨]`, SDD 잠금과 Milestone 구현 잠금은 `해제`이며 사용자 결정 항목은 없다.
- 대상은 S11 → `throughput-policy`; S06의 logical context failover, S07의 failure budget, S09의 persisted decision/transition을 retry variant에 함께 적용한다.
- `test_env=local`; dispatcher persisted-state simulation이므로 Edge/Node user-flow, mock smoke, live provider와 외부 CLI profile은 적용하지 않는다.
- provider/session/network/host quota subprocess는 deterministic fake 또는 deny로 고정하고 fresh unittest process, `py_compile`, `git diff --check`를 사용한다.

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

- `mark_retry_quota_refresh`는 evidence `selected`가 현재 decision과 같은지 비교하지 않는다.
- 이미 recovery budget이 소진된 진입 분기는 normalized last failure를 복원하지 못해 qualified terminal evidence를 만들 수 없다.
- `persisted_execution_decision`은 logical context를 준비하기 전 `commit_execution_decision`에서 retry intent를 소비한다.
- actual dispatcher 회귀는 유효한 locator artifact package와 exact continuation prompt를 검증하지 않는다.
- 정상 sibling은 shallow snapshot과 selected만 비교하며 decision/quota/history/marker/context 전체 불변을 보장하지 않는다.

### 심볼 참조와 분할 판단

- rename/remove 없음. 영향 경계는 `StageFailureBudget`, `StateStore.mark_retry_quota_refresh`, `commit_execution_decision`, `persisted_execution_decision`, `build_context_package`, `run_worker`, `run_escalating`, `dispatch_with_store`와 대응 테스트다.
- evidence validator, retry selection/context preparation, StateStore commit/consume는 하나의 transaction이다. 이를 분리하면 깨진 중간 상태를 독립 승인하게 되므로 기존 `11+10_unknown_isolation` 단일 subtask를 유지한다.

### 범위 결정 근거

- selector의 공개 schema/policy/canonical target 목록, global quota cache, target semaphore, reverse failover, generic stderr inference, roadmap/SDD/rules와 `WORK_LOG.md`는 변경하지 않는다.
- 구현은 기존 persisted unused candidate와 `transition="failover"` 계약을 사용하며 dispatcher source와 tests만 수정한다.
- unrelated dirty milestone/SDD 및 parent `WORK_LOG.md` 변경은 보존한다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`; prior lane/grade/score/filename은 중립 입력에서 제외했다.
- build/review closures는 모두 true이고 Milestone 사용자 결정은 없다.
- build `route_basis=local-fit`, scores=`1/2/1/1/2`; loop-risk는 typed evidence→retry intent→selection→context validation→atomic commit/consume의 ordered state, scheduler/worker StateStore actor, failure/success variant product로 `triggered=true`다.
- review `route_basis=official-review`, scores=`1/2/1/1/2`.
- finalizer=`finalize-task-policy.sh`, `finalizer_mode=pair`; build=`local-G07` / `PLAN-local-G07.md`, review=`cloud-G07` / `CODE_REVIEW-cloud-G07.md`, official target=`codex/gpt-5.6-sol xhigh`.

## 구현 체크리스트

- [ ] terminal 두 경로가 canonical failure/locator/selected/work-unit evidence를 만들고 현재 persisted decision/plan과 완전 일치한 qualified evidence만 retry intent로 승인한다.
- [ ] retry selection과 logical context를 먼저 준비한 뒤 decision/history/quota/context 및 intent consume를 단일 commit으로 반영하고 모든 prepare/commit/save 실패에서 pre-state를 보존한다.
- [ ] actual dispatcher 회귀가 유효한 artifact package, exact continuation prompt, mismatch/failure variants, exactly-once 소비와 정상 sibling 전체 상태 불변을 외부 호출 없이 검증한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1] Canonical terminal evidence identity

- 문제: `dispatch.py:604`는 evidence `selected`의 존재만 확인하고 `work_unit_id`만 persisted decision과 비교한다. `dispatch.py:3745`의 pre-loop exhausted 분기는 `failure_class=None`을 기록한다.
- 해결 방법:
  - `StageFailureBudget` 또는 동등한 persisted terminal state에 normalized last `failure_class`, locator와 target identity를 유지해 pre-loop/loop-exhausted 경로가 같은 evidence builder를 사용하게 한다.
  - validator는 role=`worker`, qualified failure class, readable locator identity, selected adapter/target과 work-unit이 현재 worker decision 및 현재 PLAN identity와 모두 정확히 일치할 때만 retry context를 반환한다.
  - generic/incomplete/mismatched/stale evidence는 blocker/budget 정리 후 same-target resume으로 남고 retry marker를 만들지 않는다.
- 수정 파일:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: canonical builder/validator와 terminal 두 경로를 연결한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: qualified/generic/incomplete/selected/work-unit/locator mismatch 및 두 terminal 경로를 table test한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py DynamicFailoverBudgetTest ThroughputQuotaBatchTest.test_retry_evidence_identity_variants -v` — 전부 PASS, 외부 subprocess 0회.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2] Prepare-context-first atomic commit

- 문제: `dispatch.py:1587`은 context 검증 전 retry fields를 지우고 `dispatch.py:4581`은 locator 문자열만 continuation에 전달한다.
- 해결 방법:
  - persisted unused alternate selection은 side effect 없는 prepare 결과로 만들고 previous/next spec과 validated retry locator를 함께 반환한다.
  - `build_context_package`로 locator/workspace/task/PLAN/raw/normalized artifact를 검증하고 exact logical/native continuation context를 준비한 뒤에만 commit한다.
  - decision/history/quota update와 retry marker/context/evidence 소비를 하나의 copied task-state update 및 atomic JSON replace로 저장한다. selector/context/commit/save 예외에서는 in-memory/on-disk pre-state를 유지하거나 복원한다.
  - 준비한 context와 locator를 첫 `run_escalating` 호출에 전달하고 성공 commit 이후 재진입에서는 같은 intent를 다시 소비하지 않는다.
- 수정 파일:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: prepare/validate/commit 경계를 도입하고 `run_worker`/`run_escalating` handoff를 연결한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: selector/context/commit/save 실패 pre-state와 성공 exactly-once를 검증한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest -v` — 전부 PASS.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-3] Contract-complete dispatcher regression

- 문제: `test_dispatch.py:9132`의 `{}` locator는 logical context 계약을 만족하지 않고, assertion은 resume locator와 정상 sibling selected에 그친다.
- 해결 방법:
  - 실제 locator record, `stream.log`, `normalized-output.log`, PLAN/workspace/task identity를 만드는 fixture를 사용한다.
  - `dispatch_with_store→run_worker→run_escalating→invoke` 경로에서 exact probe, transition, context prompt 필드, resume locator, history/commit 1회와 intent 소비 1회를 검증한다.
  - selected/work-unit/locator mismatch와 selector/context/commit/save failure matrix에서 blocked task pre-state를 deep equality로 비교하고, 정상 sibling의 decision/quota/history/marker/context를 전체 deep copy로 비교한다.
  - selector/provider/CLI subprocess는 deny하고 현재 focused/전체 suite raw 결과를 active review에 기록한다.
- 수정 파일:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: contract-complete actual dispatcher regression을 추가한다.
  - [ ] `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/CODE_REVIEW-cloud-G07.md`: 구현 evidence를 완성한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest SelectorDispatcherIntegrationTest.test_context_budget_and_retry_blocked_lifecycle -v` — 전부 PASS.

## 의존 관계 및 구현 순서

1. item 1에서 신뢰 가능한 terminal evidence와 strict identity를 고정한다.
2. item 2에서 prepare-context-first commit/consume transaction을 구현한다.
3. item 3에서 actual dispatcher failure/success matrix와 제출 evidence를 완성한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1, REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1, REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2, REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-3 |

## 최종 검증

- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py DynamicFailoverBudgetTest ThroughputQuotaBatchTest.test_retry_evidence_identity_variants -v` — terminal/evidence variant PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest -v` — retry transaction 및 isolation PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest SelectorDispatcherIntegrationTest.test_context_budget_and_retry_blocked_lifecycle -v` — actual dispatcher/continuation PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py BlockerDrainTest -v` — 독립 branch drain PASS.
- `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — fresh 전체 suite PASS.
- `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.

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