<!-- task=m-agent-task-runtime-target-selector/04+03_failover_budget plan=12 tag=REVIEW_API -->

# KST canonical failover와 completing-target selfcheck 보완

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

구현과 테스트를 완료한 뒤 모든 검증 명령을 실행하고 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션에 실제 변경 내용과 stdout/stderr, exit code를 채운다. active PLAN/CODE_REVIEW 파일은 그대로 두고 리뷰 준비 완료만 보고한다. 최종 판정, 로그 아카이브, `complete.log`, 다음 상태 분류는 code-review skill 소유다. 차단되면 구현 소유 evidence 필드에 정확한 blocker, 시도한 명령과 출력, 재개 조건만 기록하며 사용자에게 질문하거나 user-input 도구·control-plane stop 파일을 만들지 않는다.

## 배경

KST 주야간 1차 target 선택은 반영됐지만 `local-G07~G08` 정책은 시간대마다 후보가 하나뿐이어서 정규 Gemini↔Laguna failover를 실행할 수 없다. dispatcher는 selector의 failover 전이를 호출하지 않고 실제 invocation이 아닌 초기 persisted decision으로 failure budget을 기록하며, selfcheck도 실제 완료 target이 아니라 정적 lane/grade로 판별한다. 최신 전체 테스트도 야간 Laguna 변경과 오래된 정적 기대가 충돌해 179개 중 2건 실패한다.

## Archive Evidence Snapshot

- 선행 완료: `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/03+01,02_route_pin_state/complete.log` — route pin/state predecessor PASS.
- 직전 계획: `agent-task/m-agent-task-runtime-target-selector/04+03_failover_budget/plan_local_G08_11.log`.
- 직전 리뷰: `agent-task/m-agent-task-runtime-target-selector/04+03_failover_budget/code_review_cloud_G08_11.log` — FAIL, Required 5 / Suggested 0 / Nit 0.
- 영향 파일: `execution_target_policy.py`, `select_execution_target.py`, `dispatch.py`와 세 대응 테스트 파일.
- 검증 evidence: policy 5 tests PASS, selector 집중 7 tests PASS, budget helper 3 tests PASS, 전체 179 tests는 2 failures, `py_compile`/`git diff --check` PASS, SDD 후보 순서 재현 FAIL.
- 로드맵 carryover: S02/S06/S07/S10과 `time-route`, `context-failover`, `failure-budget`, `selfcheck-policy`가 미완료다.

## 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:
  - `time-route`: local-G07~G08 KST 주야간 최초 target
  - `context-failover`: Gemini↔Laguna 단방향 logical context failover
  - `failure-budget`: target 전환 전후 동일 stage 10회 실패 예산
  - `selfcheck-policy`: 실제 worker 완료 target 기반 selfcheck
- Completion mode: check-on-pass

## 분석 결과

### 읽은 파일

- `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/scripts/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`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- `agent-test/local/rules.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`, `agent-spec/index.md` — 이 runtime 범위에 매칭되는 별도 계약/spec 문서 없음.

### SDD 기준

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`, 상태 `[승인됨]`, 잠금 해제.
- S02 → `time-route`: 06:59:59, 07:00:00, 22:59:59, 23:00:00 KST의 initial target과 후보 순서를 REVIEW_API-1 및 최종 검증에 반영한다.
- S06 → `context-failover`: 주간 Gemini→Laguna, 야간 Laguna→quota-available Gemini, qualified failure만 전환, logical context, no bounce를 REVIEW_API-2에 반영한다.
- S07 → `failure-budget`: primary/alternate가 동일 stage 10회 예산을 공유하고 성공 때만 초기화되는 lifecycle을 REVIEW_API-3에 반영한다.
- S10 → `selfcheck-policy`: Gemini→Laguna 완료만 pinned Laguna selfcheck를 실행하고 Laguna→Gemini 및 cloud 완료는 생략하는 lifecycle을 REVIEW_API-3에 반영한다.
- Evidence Map의 경계 matrix, transition evidence, stage counter evidence, stage evidence를 각 집중 테스트와 전체 suite의 PASS 조건으로 고정한다.

### 테스트 환경 규칙

- `test_env=local`.
- `agent-test/local/rules.md`가 존재해 전체를 읽었다. 이 agent-ops Python runtime 범위에 매칭되는 별도 profile route는 없어 profile 문서를 적용하지 않는다.
- fallback verification source는 repository Python unittest layout, `py_compile`, `git diff --check`, 승인 SDD Acceptance/Evidence Map이다.
- 외부 runner, provider 호출, 장기 실행 환경을 사용하지 않으므로 비-local preflight는 해당 없음이다.
- test-rule 유지보수 작업이 아니며 현재 local rule이 구조적으로 유효하므로 create-test/update-test는 필요하지 않다.

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

- KST 경계 1차 target: policy/selector 테스트가 부분 커버하지만 후보가 하나인 상태를 정답으로 둔다.
- canonical failover: selector 테스트가 cloud decision에 Codex 후보를 수동 삽입하므로 Gemini/Laguna 정책을 실행하지 않는다.
- dispatcher failover/context: `build_context_package` helper만 직접 호출하며 실제 failure→다음 invocation 경로가 없다.
- failure budget: helper가 임의 target을 직접 기록하고 generic Pi 반복만 실행해 실제 primary→alternate audit를 검증하지 않는다.
- selfcheck: completing Laguna decision을 만들고 재사용하는 dispatcher 통합 테스트가 없다.
- 전체 회귀: `TaskStageTest.test_local_route_grade_boundaries`가 야간에도 G07/G08=Gemini라고 가정해 현재 2건 실패한다.

### 심볼 참조

- rename/remove 없음.
- 변경 call sites: `select_policy`는 selector와 두 policy/selector 테스트가 소비한다. `_failover`는 `select_execution_target`이 호출한다. `select_execution_decision`/`persisted_execution_decision`은 `route_agent`, worker/selfcheck/review entry와 route persistence 테스트가 소비한다. `task_requires_selfcheck`는 `task_stage`가 호출한다. `StageFailureBudget`은 `run_escalating`과 budget 테스트가 소비한다.

### 분할 판단

- split decision policy를 파일 선택 전에 평가했다. 이 디렉터리는 `04+03_failover_budget`이므로 predecessor `03`은 `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/03+01,02_route_pin_state/complete.log`로 충족됐다.
- 정책 후보 순서, selector 전이, persisted decision, 실제 invocation 예산, completing-target selfcheck는 하나의 work-unit lifecycle과 동일 상태 schema를 함께 바꾼다. API와 call-site를 분리하면 중간 pair가 실행 불가능하고 같은 테스트 fixture를 중복 소유하므로 기존 dependent subtask 안의 단일 plan이 안전하다.
- 외부 소유권·독립 배포·별도 위험 프로필 경계는 없고, 테스트만 별도 sibling으로 떼어도 production slice를 독립 검증할 수 없다.

### 범위 결정 근거

- official review route, cloud lane grade matrix, G01~G06/G09~G10 worker 정책은 변경하지 않는다.
- quota probe를 새로 실행하거나 외부 quota API를 추가하지 않고 기존 `quota_snapshot` tri-state 입력만 사용한다.
- legacy recovery 재분류와 process liveness/work-log archive 경로는 canonical Gemini/Laguna 전환에 필요한 최소 call site 외에는 수정하지 않는다.
- `agent-ops/rules/common/**`, `agent-ops/skills/common/**`, roadmap/SDD 문서는 구현 범위에서 제외한다.

### 최종 라우팅

- `evaluation_mode=isolated-reassessment`, `finalizer=finalize-task-policy.sh`, `finalizer_mode=pair`.
- Build closures: scope/context/verification/evidence/ownership/decision 모두 `true`. 근거는 승인 SDD S02/S06/S07/S10, 전체 source/test/diff, local 재현 명령, 단일 dispatcher 소유 상태다.
- Build scores: scope_coupling=2, state_concurrency=2, blast_irreversibility=1, evidence_diagnosis=2, verification_complexity=1. `route_basis=local-fit`, capability gap=none, lane=`local`, grade=`G08`, filename=`PLAN-local-G08.md`.
- Build loop-risk: temporal_state=true(초기·resume·failover·성공·terminal), concurrent_consistency=true(dispatcher/state persistence의 atomic snapshot), boundary_contract=true(policy/selector/dispatcher와 두 consumer 이상), structured_interpretation=false, variant_product=true(시간대×failure×quota×completing target). `triggered=true`; unknown 없음.
- Review closures: scope/context/verification/evidence/ownership/decision 모두 `true`.
- Review scores: scope_coupling=2, state_concurrency=2, blast_irreversibility=1, evidence_diagnosis=2, verification_complexity=1. `route_basis=official-review`, lane=`cloud`, grade=`G08`, filename=`CODE_REVIEW-cloud-G08.md`, target=`codex/gpt-5.6-sol xhigh`.
- grade floor 및 capability-gap 승격: none. 반복 횟수와 직전 route는 평가 입력이나 점수에 사용하지 않았다.

## 구현 체크리스트

- [ ] REVIEW_API-1 KST 네 경계의 canonical Gemini/Laguna 후보 순서와 selector 회귀 테스트를 구현한다.
- [ ] REVIEW_API-2 qualified failure의 단방향 selector failover, persisted transition, logical context 다음 invocation을 구현한다.
- [ ] REVIEW_API-3 실제 invocation target/transition 기준 stage budget과 completing-target selfcheck lifecycle을 구현한다.
- [ ] REVIEW_API-4 정적 route 기대를 시간 명시 matrix로 교체하고 집중·전체 검증을 통과한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

### [REVIEW_API-1] Canonical KST 후보 순서

#### 문제

`execution_target_policy.py:93-109`는 시간대별 1차 target을 고른 뒤 `candidates=(target,)`만 반환한다. 따라서 주간 Gemini 실패 시 Laguna, 야간 Laguna 실패 시 quota-available Gemini라는 S06 전이를 selector가 수행할 후보가 없다.

```python
# Before: execution_target_policy.py:93-109
if grade <= 8:
    time_window = _kst_time_window(evaluated_at)
    # ... target 하나 선택 ...
    return PolicyDecision(
        # ...
        candidates=(target,),
    )
```

#### 해결 방법

시간대에 따라 같은 두 canonical target의 우선순위만 바꾸고, initial은 첫 eligible target을 선택하도록 유지한다. 두 후보가 모두 canonical set에 남으므로 KST 경계를 넘은 resume/failover decision 검증도 현재 시각에 의해 거부되지 않는다.

```python
# After
if time_window == "kst-day-[07:00,23:00)":
    candidates = (AGY_GEMINI_MEDIUM, PI_LAGUNA)
else:
    candidates = (PI_LAGUNA, AGY_GEMINI_MEDIUM)
return PolicyDecision(..., candidates=candidates)
```

#### 수정 파일 및 체크리스트

- [ ] `scripts/execution_target_policy.py`: 두 target 후보 순서와 reason/time window를 고정한다.
- [ ] `tests/test_execution_target_policy.py`: G07/G08 네 경계에서 두 후보 전체 순서를 검증한다.
- [ ] `tests/test_select_execution_target.py`: initial selected, rank 1/2, quota eligibility와 canonical failover를 실제 local plan으로 검증한다.

#### 테스트 작성

작성한다. `ExecutionTargetPolicyTests.test_local_g07_g08_candidate_order_uses_kst_boundaries`와 `SelectorRouteMatrixTests.test_local_g07_g08_use_kst_boundary_candidate_order`가 네 경계에서 adapter+target 순서를 검증한다. `SelectorFailoverContractTests`는 수동 Codex 후보 fixture를 제거하고 주간/야간 local-G08 decision을 사용한다.

#### 중간 검증

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_execution_target_policy.py
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py SelectorRouteMatrixTests SelectorFailoverContractTests -v
```

예상 결과: 모든 테스트 PASS, exit 0. 주간 후보는 `agy Gemini Medium → pi Laguna`, 야간 후보는 역순이다.

### [REVIEW_API-2] Dispatcher failover와 logical context 연결

#### 문제

`dispatch.py:1099-1118`은 prior decision 유무로 `initial|resume`만 선택한다. `run_escalating`의 qualified cloud failure는 `dispatch.py:3187-3214`에서 legacy `promoted_spec`으로 전환되며 selector `failover`, decision history, `build_context_package`가 실제 다음 invocation에 연결되지 않는다.

```python
# Before: dispatch.py:1112-1118
return selector.select_execution_target(
    _decision_file(task, stage),
    transition="resume" if prior_decision is not None else "initial",
    prior_decision=prior_decision,
    quota_snapshot=quota_snapshot,
)
```

#### 해결 방법

selector bridge와 persistence helper가 명시적 `transition` 및 `failure_class`를 받고 decision/history를 원자적으로 갱신하게 한다. worker의 qualified failure에서 현재 decision을 failover하고 다음 `AgentSpec`을 만든 뒤, `build_context_package`의 PLAN/locator/normalized output/raw log/workspace 경로를 다음 adapter의 continuation prompt에 넣는다. cross-adapter 전환은 native session을 전달하지 않고, generic failure·반복 횟수만으로는 failover하지 않으며 used candidate로 bounce를 막는다. 야간 Gemini quota가 exhausted이면 `no_failover_candidate`로 해당 task만 차단한다.

```python
# After
next_decision = persisted_execution_decision(
    store,
    task,
    stage="worker",
    transition="failover",
    failure_class=failure,
)
context = build_context_package(
    workspace, task, locator,
    previous_spec=spec,
    next_spec=agent_spec_from_decision(next_decision),
)
```

#### 수정 파일 및 체크리스트

- [ ] `scripts/select_execution_target.py`: canonical candidate quota 상태를 보존하고 failed cloud target만 quota evidence에 따라 exhausted 처리한다.
- [ ] `scripts/dispatch.py`: selector bridge/persistence에 failover 인자를 연결하고 transition history를 갱신한다.
- [ ] `scripts/dispatch.py`: logical context package를 다음 invocation prompt에 연결하고 cross-adapter native resume을 차단한다.
- [ ] `tests/test_select_execution_target.py`: qualified/unqualified, quota unavailable, unknown-once, no-bounce를 실제 Gemini/Laguna 후보로 검증한다.
- [ ] `tests/test_dispatch.py`: 주간·야간 failure→alternate invocation의 spec, prompt context, persisted transition을 통합 검증한다.

#### 테스트 작성

작성한다. `DispatcherCanonicalFailoverIntegrationTest.test_day_gemini_failure_continues_on_laguna_with_logical_context`, `test_night_laguna_failure_continues_on_available_gemini`, `test_night_gemini_quota_exhaustion_blocks_without_bounce`, `test_generic_failure_stays_on_same_target`를 추가한다. 실제 locator fixture는 PLAN, normalized-output.log, stream.log, workspace identity를 포함한다.

#### 중간 검증

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py SelectorFailoverContractTests -v
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py DispatcherCanonicalFailoverIntegrationTest -v
```

예상 결과: 모든 전환 테스트 PASS, exit 0. cross-adapter continuation은 logical context만 사용하고 이전 target으로 bounce하지 않는다.

### [REVIEW_API-3] 실제 invocation budget과 completing-target selfcheck

#### 문제

`dispatch.py:3062-3066`은 실패한 `spec`이 아니라 persisted decision의 기존 `selected`와 transition을 budget audit에 기록한다. `dispatch.py:1157-1158`과 `task_stage:1239-1242`는 selfcheck를 정적 lane/grade로 판별해 Gemini→Laguna 완료와 Laguna→Gemini 완료를 구분하지 못한다.

```python
# Before: dispatch.py:3062-3066
recovery_failures += 1
selected = state["execution_decisions"][role]["selected"]
transition = state["execution_decisions"][role]["transition"]["trigger"]
recovery_failures = stage_budget.record_failure(
    target=selected, transition=transition
)
```

#### 해결 방법

각 invoke 직전에 active decision/spec/transition을 일치시켜 보관하고 그 snapshot으로 실패를 기록한다. primary 1회와 alternate 9회가 reopen 뒤에도 같은 `work_unit_id|worker` key를 공유하며 10번째에 terminal block하고, 성공 때만 reset한다. worker 성공 시 실제 completing spec의 local/cloud 성격과 pinned worker decision을 state에 저장한다. `task_stage`는 이 완료 evidence로 selfcheck를 예약하고, `run_selfcheck`는 저장된 Laguna decision을 resume하여 새 initial route를 평가하지 않는다.

```python
# After
failure_target = current_decision["selected"]
failure_transition = current_decision["transition"]["trigger"]
count = stage_budget.record_failure(
    target=failure_target,
    transition=failure_transition,
)
store.update_task(
    task,
    worker_selfcheck_required=completed_spec.local_pi,
)
```

#### 수정 파일 및 체크리스트

- [ ] `scripts/dispatch.py`: invocation snapshot의 실제 target/transition으로 `StageFailureBudget`을 기록한다.
- [ ] `scripts/dispatch.py`: worker 완료 target의 `local_pi`와 pinned decision을 persisted state에 남긴다.
- [ ] `scripts/dispatch.py`: `task_stage`/`run_selfcheck`가 completing-target evidence와 resume decision을 사용하게 한다.
- [ ] `tests/test_dispatch.py`: primary 1 + alternate 9, stage 분리, success reset, last_target/last_transition audit를 검증한다.
- [ ] `tests/test_dispatch.py`: Gemini→Laguna만 Laguna selfcheck, Laguna→Gemini와 cloud 완료는 selfcheck 생략을 검증한다.

#### 테스트 작성

작성한다. `DynamicFailoverBudgetTest.test_primary_then_alternate_share_ten_failure_budget_across_reopen`이 실제 decision lifecycle과 audit 필드를 검증한다. `DispatcherCanonicalFailoverIntegrationTest.test_completing_target_controls_selfcheck_and_reuses_pin`이 세 completing-target case와 transition history의 no-new-initial을 검증한다.

#### 중간 검증

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py DynamicFailoverBudgetTest DispatcherCanonicalFailoverIntegrationTest -v
```

예상 결과: 모든 테스트 PASS, exit 0. worker stage counter만 10에 도달하며 `last_target`은 alternate이고 Laguna 완료 case만 selfcheck로 전이한다.

### [REVIEW_API-4] 회귀 기대와 전체 evidence 정합성

#### 문제

`test_dispatch.py:261-281`은 현재 시각을 고정하지 않은 채 local G07/G08을 항상 Gemini라고 기대한다. 최신 전체 suite는 야간 Laguna 선택과 이 기대가 충돌해 G07/G08 두 subtest가 실패한다.

```python
# Before: test_dispatch.py:261-281
expected = {
    7: ("agy", "Gemini 3.6 Flash (Medium)", False),
    8: ("agy", "Gemini 3.6 Flash (Medium)", False),
}
spec = dispatch.route_agent(task)
```

#### 해결 방법

정적 grade matrix는 시간 독립 grade만 유지하고, G07/G08은 명시적 KST day/night `evaluated_at`을 selector bridge에 주는 별도 matrix로 검증한다. 집중 테스트 후 전체 unittest discovery, py_compile, diff check를 실행해 SDD와 회귀 suite가 동시에 통과하는지 확인한다.

```python
# After
for evaluated_at, expected in kst_cases:
    decision = dispatch.select_execution_decision(
        task, stage="worker", evaluated_at=evaluated_at
    )
    assert decision["selected"] == expected
```

#### 수정 파일 및 체크리스트

- [ ] `tests/test_dispatch.py`: 정적 grade matrix에서 시간 의존 G07/G08 기대를 분리한다.
- [ ] `tests/test_dispatch.py`: 명시적 KST day/night decision과 completing-target lifecycle을 검증한다.
- [ ] `tests/test_execution_target_policy.py`: canonical 후보 순서 경계 기대를 유지한다.
- [ ] `tests/test_select_execution_target.py`: selector initial/failover 기대를 canonical 후보와 일치시킨다.

#### 테스트 작성

작성한다. `TaskStageTest.test_local_route_grade_boundaries`는 시간 독립 grade만 검증하고, G07/G08은 `test_local_g07_g08_route_uses_explicit_kst_boundaries`에서 고정 `evaluated_at`별 initial target을 검증한다. 기존 집중 테스트와 새 integration test를 전체 discovery에 포함한다.

#### 중간 검증

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py TaskStageTest -v
python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'
```

예상 결과: 전체 suite PASS, exit 0. 현재 179개를 줄이지 않으며 새 회귀 테스트만 증가한다.

## 의존 관계 및 구현 순서

1. REVIEW_API-1에서 canonical 후보 순서와 selector matrix를 먼저 고정한다.
2. REVIEW_API-2가 그 decision 계약을 dispatcher failover와 logical context에 연결한다.
3. REVIEW_API-3이 실제 invocation audit와 completing-target selfcheck를 연결한다.
4. REVIEW_API-4가 오래된 정적 기대를 제거하고 전체 회귀를 닫는다.

선행 subtask `03+01,02_route_pin_state`는 archive `complete.log`로 충족됐으며, 이 active subtask 안에 추가 runtime dependency는 없다.

## 수정 파일 요약

| 파일 | 구현 항목 |
|---|---|
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/execution_target_policy.py` | REVIEW_API-1 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/select_execution_target.py` | REVIEW_API-1, REVIEW_API-2 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py` | REVIEW_API-2, REVIEW_API-3 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_execution_target_policy.py` | REVIEW_API-1, REVIEW_API-4 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py` | REVIEW_API-1, REVIEW_API-2, REVIEW_API-4 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` | REVIEW_API-2, REVIEW_API-3, REVIEW_API-4 |

## 최종 검증

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_execution_target_policy.py
```

예상 결과: PASS, exit 0.

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py SelectorRouteMatrixTests SelectorFailoverContractTests -v
```

예상 결과: PASS, exit 0.

```bash
python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py TaskStageTest RouteDecisionPersistenceTest DynamicFailoverBudgetTest DispatcherCanonicalFailoverIntegrationTest -v
```

예상 결과: PASS, exit 0.

```bash
python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'
python3 -m py_compile 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/scripts/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 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py
git diff --check
```

예상 결과: 전체 unittest PASS, compile/diff check exit 0. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.
