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

# Plan - Qualified retry intent와 pending continuation 원자화

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

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

## 배경

여섯 번째 리뷰에서도 이전 Required를 닫는 source/test 변경과 구현 evidence가 반영되지 않았다. terminal blocker는 typed evidence 없이 generic failure를 quota failover로 승격하고, retry admission은 현재 시각 정책과 global batch snapshot으로 pinned sibling state를 바꾸며, 저장한 locator를 actual continuation에서 소비하지 않는다. 동일한 1건이 focused와 전체 251개 suite에서 재현되므로 retry intent의 생성·admission·continuation·commit을 task-local 원자 수명으로 완결한다.

## Archive Evidence Snapshot

- Prior plan: `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/plan_local_G07_5.log`
- Prior review: `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/code_review_cloud_G07_5.log`
- Verdict: `FAIL`
- Required:
  - terminal recovery-limit가 typed blocker evidence를 쓰지 않고 `mark_retry_quota_refresh`가 evidence 부재를 `provider-quota`로 기본 처리한다.
  - retry admission이 persisted unused alternate 대신 현재 KST policy candidates를 계산하고 shared snapshot을 모든 worker에 전달하며 retry locator를 actual continuation에 연결하지 않는다.
  - 야간 회귀가 deterministic initial snapshot 없이 실제 quota subprocess를 1회 호출하고 fake runner가 actual worker/escalation 경계를 우회한다.
  - 구현 완료 표, 설계 결정, 계획 대비 변경과 검증 출력이 모두 미작성이다.
- 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: terminal 4개, throughput 12개, focused 13개와 전체 251개에서 같은 1개가 FAIL했다. `BlockerDrainTest` 6개, `py_compile`, `git diff --check`는 PASS였다.
- Roadmap carryover: `throughput-policy`와 SDD S11의 task-local explicit retry, pinned route/history, same-batch quota 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_5.log`
- `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/code_review_cloud_G07_5.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/scripts/select_execution_target.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.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 없음.
- `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/10+09_target_cap_removal/complete.log` — predecessor `10` 완료 확인.

### SDD 기준

- SDD는 `[승인됨]`, SDD 잠금과 Milestone 구현 잠금은 `해제`다.
- 대상은 S11 → `throughput-policy`; Evidence Map은 동시 dispatch와 같은 admission batch quota snapshot 결과를 요구한다.
- S06/S07/S09의 pinned decision, qualified failover, 동일 stage failure budget과 dispatcher invocation 계약을 S11의 task-local retry variant에 함께 적용했다. 따라서 체크리스트는 typed evidence, persisted-unused probe, pending-only handoff, actual continuation, sibling 불변과 deterministic external deny evidence를 하나의 성공 조건으로 둔다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 testing profile `agent-test/local/testing-smoke.md`를 읽었다.
- 변경은 dispatcher 내부 persisted-state simulation이다. Edge/Node user-flow, mock smoke, live provider preflight와 외부 CLI profile은 적용하지 않는다.
- 실제 provider CLI/session/network/host quota subprocess를 호출하지 않고 `invoke`, command builder, selector subprocess와 quota provider를 deterministic fake/deny로 고정한다.
- 검증은 fresh Python unittest process, `py_compile`, `git diff --check`를 사용한다. 캐시된 결과는 허용하지 않는다.

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

- 현재 회귀는 야간 최초 decision에 snapshot을 주입하지 않아 host quota subprocess에 닿는다.
- terminal blocker tests는 `blocker_evidence`를 수동 주입하므로 production `run_escalating`이 evidence를 생성하는지 검증하지 않는다.
- retry dispatcher test는 `run_worker`를 fake로 대체해 locator가 `run_escalating`의 logical continuation prompt로 전달되는지 검증하지 않는다.
- 정상 sibling은 selected target만 비교하며 decision/quota/history/marker/context의 byte-equivalent 불변을 검증하지 않는다.
- generic/incomplete/qualified evidence, selector/context/commit 실패 전후, KST 경계에서 persisted unused candidate와 current policy가 달라지는 조합 검증이 없다.

### 심볼 참조

- rename/remove 없음.
- 영향 경계: `StateStore.mark_retry_quota_refresh`, `commit_execution_decision`, `persisted_execution_decision`, `build_admission_batch_snapshot`, `dispatch_with_store`, `run_worker`, `run_escalating`과 대응 테스트 호출부.

### 분할 판단

- split 정책을 재평가했다. typed evidence, pending admission, continuation package, decision commit과 intent consume는 하나의 retry transaction이며 중간 상태를 별도 PASS로 만들 수 없다.
- production/test는 같은 회귀의 최소 검증 단위이고, API-vs-call-site 또는 별도 domain 경계가 없다. 추가 split은 exactly-once와 sibling 불변을 깨진 중간 상태에서 승인하게 하므로 현재 단일 subtask를 유지한다.
- 디렉터리 의존성 `11+10`의 predecessor `10`은 `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/10+09_target_cap_removal/complete.log`로 충족됐다.

### 범위 결정 근거

- `select_execution_target.py`의 공개 schema, policy matrix와 canonical target 목록은 변경하지 않는다. dispatcher가 persisted candidate/evidence를 검증하고 기존 `transition="failover"` 입력을 사용한다.
- global quota cache, target semaphore, reverse failover, generic stderr 추론, 새 route 정책, runtime notification은 범위 밖이다.
- unrelated dirty worktree, roadmap, domain rules, sibling task artifacts와 dispatcher-owned `WORK_LOG.md`는 수정하지 않는다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`; prior route/grade/score/filename은 중립 입력에서 제외했다.
- build/review closures: `scope_closed=true`, `context_closed=true`, `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`.
- closure basis: source line과 재현 테스트로 scope/context를 고정했고, deterministic fake/deny 명령으로 verification/evidence를 닫았으며, task-local state와 구현 소유권이 명확하고 Milestone 결정 필요가 없다.
- build `route_basis=local-fit`, `capability_gap=none`; scores `scope_coupling=1`, `state_concurrency=2`, `blast_irreversibility=1`, `evidence_diagnosis=1`, `verification_complexity=2`.
- loop-risk: ordered states=`terminal blocker→retry intent→snapshot→continuation→commit/consume`, actors=`scheduler+worker StateStore`, components=`terminal recovery+admission+selector+runner`, variants=`qualified/generic × blocked/normal × KST boundary × commit failure/success`; matched=`temporal_state,concurrent_consistency,boundary_contract,variant_product`, `triggered=true`이며 route 점수에는 영향 없음.
- review `route_basis=official-review`, `capability_gap=none`; 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 blocker가 canonical role/failure class/locator/selected/work-unit identity를 typed evidence로 기록하고 qualified complete evidence만 failover intent로 만든다.
- [ ] persisted unused alternate만 batch probe하고 fresh snapshot/locator/context를 pending worker에만 전달해 successful decision commit 뒤 exactly once 소비한다.
- [ ] actual dispatcher→run_worker→run_escalating 회귀에서 KST 경계, external deny, transition/continuation/commit과 정상 sibling 전체 state 불변을 검증하고 focused/전체 suite를 통과한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1] Typed terminal evidence와 qualified retry intent

- 문제: `dispatch.py:597-604`는 evidence가 없으면 blocker 문자열을 추론한 뒤 `provider-quota`를 기본값으로 쓰고, `dispatch.py:3717`, `dispatch.py:3787`의 terminal write는 blocker 문자열만 저장한다.
- Before (`dispatch.py:597`):

```python
failure_class = blocker_evidence.get("failure_class")
if not failure_class:
    failure_class = "provider-quota"
```

- 해결 방법:
  - invocation 실패마다 normalized `role`, `failure_class`, `locator`, current worker `selected`, `work_unit_id`를 terminal evidence builder 입력으로 유지하고 recovery-limit write 두 곳에서 `blocker_evidence`를 함께 저장한다.
  - `mark_retry_quota_refresh`는 blocker text를 해석하지 않는다. evidence의 role이 worker이고 failure class가 `QUALIFIED_FAILOVER_FAILURES`이며 locator와 selected/work-unit이 현재 persisted worker decision과 일치할 때만 `retry_quota_refresh_pending/context`를 만든다.
  - generic/incomplete/mismatched evidence는 blocker와 budget만 clear하고 same-target resume으로 남기며 failover marker를 만들지 않는다.
- After:

```python
retry_context = validated_retry_context(value, blocker_evidence)
value["retry_quota_refresh_pending"] = retry_context is not None
value["retry_quota_refresh_context"] = retry_context
```

- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: terminal evidence builder와 두 recovery-limit write를 연결한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: strict retry evidence validation과 same-target fallback을 구현한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: production terminal qualified/generic/incomplete/mismatch variant와 task-local state를 검증한다.
- 테스트 작성: 작성. `DynamicFailoverBudgetTest`에서 실제 `run_escalating` terminal 결과를 retry 입력으로 사용하고 generic/incomplete evidence가 failover marker를 만들지 않음을 assertion한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py DynamicFailoverBudgetTest ThroughputQuotaBatchTest.test_retry_blocked_scopes_to_blocked_worker_and_refreshes_pinned_alternate -v` — 전부 PASS, provider/selector subprocess 호출 0회.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2] Persisted-unused admission과 continuation commit

- 문제: `dispatch.py:1726-1729`는 retry에도 current-time policy를 계산하고, `dispatch.py:5531-5539`는 aggregate snapshot을 모든 worker에 전달한다. `run_worker`는 retry context locator를 읽지 않아 `run_escalating(initial_resume_locator=...)`에 전달하지 않으며 `commit_execution_decision`은 continuation 준비 전에 intent를 지운다.
- Before (`dispatch.py:1726`, `dispatch.py:5531`):

```python
pol_dec = policy_mod.select_policy(
    stage="worker", lane=lane, grade=grade, evaluated_at=admission_time
)
future = asyncio.create_task(run_worker(workspace, store, task, quota_snapshot=batch_snapshot))
```

- 해결 방법:
  - retry candidate key는 persisted decision의 canonical candidates와 used/promotion history에서 아직 사용하지 않은 ordered alternate만 추출한다. `admission_time`은 probe timestamp로만 사용한다.
  - scheduler는 새 initial worker와 retry-pending worker에만 batch snapshot을 전달한다. persisted ordinary resume/review/selfcheck와 정상 sibling에는 전달하지 않는다.
  - `run_worker`는 validated retry locator와 previous/next spec으로 logical context package를 만든 뒤 decision/history commit을 수행하고, commit 성공 시에만 marker/context/evidence를 exactly once 지운다. selector/context/commit 예외에서는 기존 decision/history와 retry intent를 보존한다.
  - committed locator/context를 `run_escalating` 최초 continuation에 전달한다. same-Pi native resume와 cross-adapter logical context를 혼동하지 않는다.
- After:

```python
snapshot = batch_snapshot if worker_needs_admission_snapshot(state, task) else None
retry = prepare_retry_continuation(store, task, snapshot)
success, locator = await run_escalating(
    workspace, store, task, "worker", retry.spec,
    initial_resume_locator=retry.locator,
    initial_context=retry.context,
)
```

- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: persisted-unused key derivation과 task-local snapshot handoff를 구현한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: logical continuation 준비, commit-success consume와 failure preservation을 연결한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: KST 경계, exact alternate probe, locator/context, selector/context/commit 실패와 sibling full-state 불변을 검증한다.
- 테스트 작성: 작성. blocked Laguna만 Gemini alternate를 1회 probe하고 normal sibling의 full task state가 byte-equivalent이며 ordinary resume probe가 0회임을 검증한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest -v` — 전부 PASS.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-3] Deterministic actual dispatcher evidence와 제출 완결

- 문제: `test_dispatch.py:9040-9044`의 야간 최초 selection은 deterministic snapshot이 없어 host quota subprocess에 닿고, `test_dispatch.py:9082-9085`는 `run_worker`를 fake로 교체해 actual continuation을 검증하지 않는다. active review의 구현 소유 섹션도 비어 있었다.
- Before (`test_dispatch.py:9082`):

```python
async def fake_run_worker(ws, st, task, resume_locator=None, quota_snapshot=None):
    dispatch.persisted_execution_decision(st, task, stage="worker", quota_snapshot=quota_snapshot)
```

- 해결 방법:
  - 야간 Laguna initial decision에 고정 snapshot/evaluated_at을 주입한다.
  - `dispatch_with_store(..., retry_blocked=True)`와 실제 `run_worker`/`run_escalating`을 통과시키되 `invoke`를 deterministic success fake로 두고 build command, selector subprocess, quota provider 외부 호출을 deny한다.
  - exact probe key/count, continuation prompt/locator, transition/history 1회, intent consume 1회, blocked/normal state 전후 전체 equality와 ordinary/new-generation variants를 assertion한다.
  - 구현 후 active review의 완료 표, 체크리스트, 계획 대비 변경, 설계 결정과 각 명령의 원문 stdout/stderr/exit code를 채운다.
- After:

```python
with patch.object(dispatch, "invoke", side_effect=fake_invoke), external_deny_guards():
    result = await dispatch.dispatch_with_store(args, workspace, store)
self.assertEqual(result, 0)
self.assertEqual(normal_state_after, normal_state_before)
```

- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: deterministic initial snapshot과 actual dispatcher/worker/escalation 회귀를 구현한다.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: external deny, exact transition/locator/commit과 full sibling invariant를 assertion한다.
  - [ ] `agent-task/m-agent-task-runtime-target-selector/11+10_unknown_isolation/CODE_REVIEW-cloud-G07.md`: 구현 소유 evidence를 완성한다.
- 테스트 작성: 작성. production provider/session/network/subprocess는 실행하지 않는다.
- 중간 검증: `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와 qualified intent를 만든다.
2. item 2에서 intent를 persisted-unused admission, context, decision commit/consume에 연결한다.
3. item 3에서 actual dispatcher regression과 제출 evidence를 고정한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-1, 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_REFACTOR-1, REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_REFACTOR-2, 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_blocked_scopes_to_blocked_worker_and_refreshes_pinned_alternate -v` — typed terminal variants와 scoped retry PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest -v` — pending snapshot lifecycle와 unknown 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 retry/throughput 경로 PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py BlockerDrainTest -v` — 독립 branch drain 6개 PASS.
- `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — fresh process 전체 Python 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`의 구현 에이전트 소유 섹션을 채운다.
