<!-- task=m-agent-task-runtime-target-selector/05+04_dispatch_route_source plan=2 tag=REVIEW_REFACTOR -->

# Plan - Dispatcher task-local route source 리뷰 보완

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

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

## 배경

persisted selector decision을 live route source로 연결했지만, 복수 ready task의 dry-run이 마지막 task state를 공유해 work-unit route pin을 잘못 표시한다. 또한 구현 검증이 helper 직접 호출에 머물고 제거 대상 `route_agent()`가 남아 실제 worker/review invocation 계약의 완료 근거가 부족하다. 두 Required finding을 같은 dispatcher 경계와 회귀 테스트에서 닫는다.

## Archive Evidence Snapshot

- Prior task: `agent-task/m-agent-task-runtime-target-selector/05+04_dispatch_route_source`
- Prior plan: `agent-task/m-agent-task-runtime-target-selector/05+04_dispatch_route_source/plan_local_G08_1.log`
- Prior review: `agent-task/m-agent-task-runtime-target-selector/05+04_dispatch_route_source/code_review_cloud_G09_1.log`
- Verdict: FAIL
- Findings: Required 2, Suggested 0, Nit 0.
- 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 2 tests, full Python 198 tests, `py_compile`, `git diff --check`는 PASS했지만 복수 ready task 재현에서 주간 AGY로 고정된 첫 task가 야간 dry-run에 Laguna로 출력됐다.
- Roadmap carryover: SDD S05/S09의 task generation route pin과 dispatcher invocation audit를 보완하되 이 child PASS만으로 Milestone Task 완료를 체크하지 않는다.

## 분석 결과

### 읽은 파일

- `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/skills/project/orchestrate-agent-task-loop/SKILL.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-test/local/rules.md`
- `agent-ops/rules/common/philosophy.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md`
- `agent-contract/index.md`
- `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/04+03_failover_budget/complete.log`
- `agent-task/m-agent-task-runtime-target-selector/05+04_dispatch_route_source/plan_local_G08_1.log`
- `agent-task/m-agent-task-runtime-target-selector/05+04_dispatch_route_source/code_review_cloud_G09_1.log`

### SDD 기준

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`, 상태 `[승인됨]`, 잠금 해제.
- 대상 Acceptance Scenario: S05 `route-pin`, S09 `dispatch-integration` 중 task-local persisted decision의 dry-run/worker/review 소비 경계.
- Evidence Map S05의 persisted route resume/restart와 S09의 worker/review invocation audit를 복수 task 격리, 실제 `run_worker()`/`run_review()` spec 전달, 무상태 dry-run 검증으로 역산한다.
- 이 follow-up은 분할 child의 Required finding만 닫으므로 `Roadmap Targets`를 두지 않고 후속 통합 task의 최종 evidence에 넘긴다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`를 읽었다.
- agent-ops Python dispatcher에 매칭되는 `agent-test/local/*.md` profile은 없다. 현재 checkout의 Python unittest manifest, `py_compile`, deterministic `rg`, `git diff --check`를 fallback으로 사용하며 test-rule 유지보수는 필요하지 않다.
- provider subprocess는 `run_escalating` mock과 임시 workspace/state로 대체하고 실제 provider 호출은 하지 않는다.
- fresh-process 전체 suite를 사용하며 cache output은 허용하지 않는다.

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

- 단일 task dry-run만 있어 복수 ready task의 서로 다른 persisted state 격리가 검증되지 않는다.
- `test_worker_and_review_initial_invocation_uses_selector`가 `persisted_execution_decision()`만 직접 호출해 `run_worker()`/`run_review()`가 해당 spec을 실행 경계로 전달하는지 증명하지 않는다.
- 제거 대상으로 명시된 `route_agent()`가 남았지만 stale symbol inventory 검증이 없다.

### 심볼 참조

- 제거 대상 `route_agent()` 정의: `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:1048`.
- `rg --sort path -n "route_agent" agent-ops/skills/project/orchestrate-agent-task-loop` 결과 production/test call site는 없고 정의만 남아 있다.

### 분할 판단

- split 정책을 다시 평가했다. 현재 task path는 `m-agent-task-runtime-target-selector/05+04_dispatch_route_source`이며 predecessor `04+03_failover_budget`는 `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/04+03_failover_budget/complete.log`로 충족된다.
- 두 finding은 동일한 dispatcher route-source 경계와 동일 테스트 class를 수정하는 하나의 bug-fix unit이다. production 수정과 필수 회귀 테스트를 분리하면 독립 PASS가 불가능하고, 새 API·도메인·외부 환경 경계도 없어 추가 split은 인위적이다.

### 범위 결정 근거

- `execution_target_policy.py`, `select_execution_target.py`의 selector 정책, quota/failover/budget, selfcheck/throughput sibling 범위는 변경하지 않는다.
- dispatcher live worker/review selector 연결 자체는 유지하고 task-local dry-run state 읽기, dead helper 제거, 해당 invocation evidence만 보완한다.
- 현재 agent-spec/agent-contract index에는 agent-task selector/dispatcher에 매칭되는 활성 spec/contract 문서가 없어 승인 SDD와 코드·테스트를 기준으로 삼는다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`; route-free current findings와 실제 재현만 입력으로 사용했다.
- finalizer=`finalize-task-policy.sh`, finalizer_mode=`pair`; build/review status=`routed`.
- build closures: `scope_closed=true`(두 Required와 두 파일로 고정), `context_closed=true`(dispatcher/state/test evidence가 한 task에 들어옴), `verification_closed=true`(복수 task 재현·실제 invocation·전체 suite), `evidence_trusted=true`(현재 checkout에서 실패 재현 및 198 tests PASS를 직접 확인), `ownership_closed=true`(task-local source/test만 수정), `decision_closed=true`(사용자 결정 없음).
- review closures: `scope_closed=true`, `context_closed=true`, `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`.
- build route_basis=`local-fit`; capability_gap=`none`; grade floor=`none`.
- build loop-risk observations: `ordered_transitions.state_count=2`(initial/resume), `concurrent_consistency.actor_count=2`(복수 ready task의 state 격리), `boundary_contract.component_count=3`(StateStore/selector/dispatcher)와 consumer 3(worker/review/dry-run), `structured_interpretation.mechanisms=[]`, `variant_product.independent_axis_count=3`(task/stage/persisted 여부). matched signatures=`concurrent_consistency,boundary_contract,variant_product`; 이는 route에 영향을 주지 않는다.
- build scores(scope_coupling/state_concurrency/blast_irreversibility/evidence_diagnosis/verification_complexity)=`1/1/1/2/2`, final=`local-G07`, filename=`PLAN-local-G07.md`.
- review route_basis=`official-review`; capability_gap=`none`; grade floor=`none`; execution=`codex/gpt-5.6-sol xhigh`.
- review scores(scope_coupling/state_concurrency/blast_irreversibility/evidence_diagnosis/verification_complexity)=`1/1/1/2/2`, final=`cloud-G07`, filename=`CODE_REVIEW-cloud-G07.md`.

## 구현 체크리스트

- [ ] 복수 ready task의 dry-run이 각 task의 persisted decision/quota snapshot을 읽고 state/history를 변경하지 않도록 수정하고 경계 회귀를 통과시킨다.
- [ ] worker/review initial 경계를 `run_worker()`/`run_review()` 호출로 검증하고 `route_agent()` 정의와 모든 stale reference를 제거한다.
- [ ] focused integration, 전체 Python suite, `py_compile`, deterministic symbol scan과 `git diff --check`를 통과시킨다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_REFACTOR-1] Task-local dry-run과 live invocation evidence 종결

- 문제: `dispatch.py:4563`은 dry-run 출력 루프에서 직전 분류 루프의 마지막 `state`를 재사용한다. `test_dispatch.py:6060`은 helper만 직접 호출하며 `dispatch.py:1048`의 제거 대상 `route_agent()` 정의가 남아 계획 완료와 SDD S05/S09 evidence를 충족하지 못한다.
- 해결 방법:

```python
# Before: agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:4559
for task in tasks:
    if task.name in ready_by_name:
        decisions = state.get("execution_decisions", {})
```

```python
# After
for task in tasks:
    if task.name in ready_by_name:
        preview_state = store.peek_task_state(task)
        decisions = preview_state.get("execution_decisions", {})
```

  quota snapshot도 같은 `preview_state`에서 읽는다. `route_agent()`는 삭제한다. 테스트는 주간 pinned AGY task와 야간 initial Laguna task를 동시에 dry-run해 서로 다른 model 출력과 두 state/history 불변을 확인하고, `run_escalating`을 mock한 `run_worker()`/`run_review()` 호출이 stage별 selector `AgentSpec`을 전달하고 decision을 저장하는지 확인한다.
- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: dry-run task-local state snapshot 사용과 dead `route_agent()` 제거.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: 복수 ready task state 격리와 실제 worker/review invocation 회귀.
- 테스트 작성: `SelectorDispatcherIntegrationTest`에 복수 task/day→night dry-run regression과 mock runner 기반 worker/review invocation test를 작성한다. 단일 task 무상태 검증은 보존한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest -v` — 복수 task route 격리, worker/review spec 전달, dry-run state/history 불변이 PASS해야 한다.

## 의존 관계 및 구현 순서

1. predecessor `04+03_failover_budget`는 `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/04+03_failover_budget/complete.log`로 충족됐다.
2. task-local dry-run state를 수정하고 dead helper를 제거한 뒤 실제 invocation/복수 task 회귀를 갱신한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `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 |

## 최종 검증

- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest -v` — task-local dry-run과 실제 worker/review invocation 회귀 PASS.
- `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — fresh-process 전체 suite PASS; cache output은 허용하지 않는다.
- `python3 -m py_compile agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py agent-ops/skills/project/orchestrate-agent-task-loop/scripts/execution_target_policy.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_execution_target_policy.py agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py` — exit 0.
- `! rg --sort path -n "route_agent" agent-ops/skills/project/orchestrate-agent-task-loop` — 제거된 helper 참조가 없어야 한다.
- `git diff --check` — 출력 없음.

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