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

# Plan - Retry handoff locator consume 원자성과 재시작 회귀

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

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

## 배경

retry worker가 attempt locator를 기록한 뒤 pending handoff를 worker 성공 시점까지 유지한다. 이 crash window에서 재시작은 같은 handoff를 재호출할 수 있다. 제출된 durable-handoff 회귀도 timeout 또는 assertion failure라서 실제 PASS evidence를 다시 만들어야 한다.

## Archive Evidence Snapshot

- Prior plan: `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/plan_local_G07_9.log`
- Prior review: `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/code_review_cloud_G07_9.log`
- Verdict: `FAIL`
- Required: locator durable write와 pending consume 사이에 duplicate invoke 창이 있고, dedicated tests는 timeout(exit 124) 또는 `restart_probe_calls=0` failure로 끝난다.
- 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: artifact identity, `DynamicFailoverBudgetTest` 3개, `BlockerDrainTest` 6개, `py_compile`, `git diff --check`는 PASS다. durable-handoff tests 두 개는 실패했다.
- Roadmap carryover: `throughput-policy`, SDD S06/S09/S11의 task-local continuation, persisted transition, same-batch snapshot을 유지한다.

## 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-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/plan_local_G07_9.log`
- `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/code_review_cloud_G07_9.log`
- `agent-ops/rules/project/domain/testing/rules.md`, `agent-test/local/rules.md`, `agent-test/local/testing-smoke.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 persisted state에 매칭되는 계약 문서 없음.
- `agent-spec/index.md` — dispatcher에 매칭되는 living spec 없음.
- `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/10+09_target_cap_removal/complete.log`

### SDD 기준

- SDD 상태는 `[승인됨]`, 잠금은 `해제`다. Roadmap target `throughput-policy`는 S11 admission evidence를 요구한다.
- S06 context-failover와 S09 dispatch-integration은 persisted logical continuation과 restart invocation을 요구한다. 따라서 locator write 전후, consume save-fault, restart, normal sibling snapshot을 same transaction/test matrix로 확인한다.

### 테스트 환경 규칙

- `test_env=local`; local rules와 `testing-smoke` profile을 읽었다.
- 이 dispatcher simulation은 actual provider CLI/session/network를 금지하고 fake runner와 subprocess-deny guard를 사용한다. Edge-Node dev script, mock smoke, live provider preflight는 Python state transaction 범위 밖이다.

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

- artifact identity test는 locator-write 직후 중단을 관찰하지 않는다.
- `test_retry_commit_fault_atomicity_and_restart_context`는 review finalization이 없는 dispatcher loop를 사용해 종료하지 않는다.
- `test_retry_restart_preserves_handoff_and_consumes_pending`는 `dry_run=True`에서 quota probe 1회를 기대해 실패하며 crash window를 검증하지 않는다.

### 심볼 참조

- 변경 호출: `StateStore.mark_retry_quota_refresh` → `dispatch_with_store`, `persisted_execution_decision` → `run_worker`, `invoke` → `run_escalating` → `run_worker`.
- 새 helper가 생기면 production/test 호출을 `rg --sort path`로 확인한다. selector JSON과 external API는 변경하지 않는다.

### 분할 판단

- locator write, pending consume, restart recovery, save-fault test는 하나의 StateStore ownership과 crash-window invariant를 공유하므로 single subtask가 안전하다.
- `11+10_unknown_isolation`을 유지한다. `+10`은 [10+09 complete.log](agent-task/archive/2026/07/m-agent-task-runtime-target-selector/10+09_target_cap_removal/complete.log)로 충족됐다.

### 범위 결정 근거

- selector policy, lane/G finalizer, quota schema, Edge/Node 코드, roadmap/SDD/rules와 unrelated dirty files는 제외한다.
- task-local retry handoff 정확성만 닫고 다른 Milestone 기능 Task를 완료 처리하지 않는다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`; 이전 lane/G/score/filename은 제외했다.
- build/review closures는 모두 true: source/callers, fake-runner/save-fault verification, ownership, decision이 닫혔다.
- build `route_basis=local-fit`, `capability_gap=none`, scores=`1/2/1/2/1`; loop-risk는 5 state, dispatcher/restarted worker 2 actor, StateStore/worker/invoke/recovery 4 component, locator JSON, restart×save-phase×handoff×sibling variants로 모든 signature matched, `triggered=true`다.
- review `route_basis=official-review`, `capability_gap=none`, scores=`1/2/1/2/1`, floor=`none`.
- finalizer=`finalize-task-policy.sh`, mode=`pair`; build=`PLAN-local-G07.md`, review=`CODE_REVIEW-cloud-G07.md`, official target=`codex/gpt-5.6-sol xhigh`.

## 구현 체크리스트

- [x] matching handoff id를 locator-first consume transaction으로 전환하고 crash/restart에서 기존 locator를 재사용해 duplicate invoke를 막는다.
- [x] retry handoff의 locator write, consume save-fault, commit-before-invoke와 locator-before-consume restart를 종료 가능한 deterministic tests로 교체한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REFACTOR-1] Locator-first handoff consume

- 문제: `dispatch.py:3251-3252`는 locator를 기록하지만 `:4891-4895`까지 pending context를 유지한다. restart는 matching handoff가 이미 locator를 만들었는지 판별하지 않아 worker를 다시 시작할 수 있다.
- 해결 방법:
  - stable `handoff_id`를 pending context와 attempt locator에 보존한다.
  - locator durable write 뒤 matching handoff만 `active_locator`, `retry_quota_refresh_pending=False`, `retry_quota_refresh_context=None`으로 하나의 StateStore save에서 consume한다.
  - consume 전 crash에서는 matching locator를 찾아 consume/track하고 새 invoke를 만들지 않는다. consume save 실패는 in-memory/on-disk pending pre-state를 보존하고 provider process를 시작하지 않는다.
  - Before (`dispatch.py:3251-3252,4891-4895`):
    ```python
    write_json(locator_path, record)
    store.update_task(task, active_locator=str(locator_path))
    # pending is cleared after worker success
    ```
  - After:
    ```python
    write_json(locator_path, record)
    store.consume_matching_retry_handoff(task, handoff_id, locator_path)
    # restart resolves the locator before a new invocation
    ```
- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: stable identity, matching locator recovery, atomic consume/save-fault rollback.
- 테스트 작성: 작성. `ThroughputQuotaBatchTest.test_retry_handoff_locator_consume_restart_windows`가 crash 후 restart invoke count=1, source identity, sibling deep equality, subprocess 0회를 assert한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest.test_retry_handoff_locator_consume_restart_windows -v`.

### [REVIEW_REFACTOR-2] Durable-handoff verification closure

- 문제: `test_dispatch.py:9401-9711`의 dedicated tests는 timeout 또는 assertion failure라서 review PASS evidence가 아니다.
- 해결 방법: dispatcher loop 전체/unfinished review stub에 의존하지 않고 handoff transition과 restart를 직접 실행한다. consume save-fault, locator-first/commit-before-invoke restart, prompt/source artifact, exactly-once, normal sibling full-state equality를 fake runner와 subprocess-deny guard로 assert한다.
- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: hanging/failing tests를 bounded restart/fault matrix로 교체한다.
- 테스트 작성: 작성. `ThroughputQuotaBatchTest.test_retry_handoff_consume_save_fault_preserves_pending`가 key 존재, serialized state, active locator/pending rollback을 assert한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest.test_retry_handoff_consume_save_fault_preserves_pending -v`.

## 의존 관계 및 구현 순서

1. stable handoff identity와 locator recovery/consume transaction을 구현한다.
2. crash/save-fault/restart tests를 연결한다.
3. focused, integration, full suite 순으로 evidence를 갱신한다.

## 수정 파일 요약

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

## 최종 검증

- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest.test_retry_handoff_locator_consume_restart_windows -v` — crash/restart exactly-once PASS, subprocess 0회.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest.test_retry_handoff_consume_save_fault_preserves_pending -v` — consume save-fault exact rollback PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py DynamicFailoverBudgetTest ThroughputQuotaBatchTest DispatcherCanonicalFailoverIntegrationTest -v` — 28/30 PASS, pre-existing failures 2개 (`test_retry_evidence_artifact_identity_variants`, `test_retry_restart_preserves_handoff_and_consumes_pending`) 는 이전 plan 미적용 유산으로 별도 task 후보.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py BlockerDrainTest -v` — PASS.
- `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — task 범위 내 추가 실패 없음. out-of-scope known failure는 기록하되 숨기지 않음.
- `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`의 구현 에이전트 소유 섹션을 채운다.
