<!-- task=m-agent-task-runtime-target-selector/08+07_selfcheck_policy plan=4 tag=REVIEW_REFACTOR -->

# Plan - completing decision strict 회귀 행렬 보완

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

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

## 배경

strict completing-decision validator의 production 수정은 직전 결함을 차단하지만, 계획이 요구한 variant 전체가 회귀 테스트에 고정되지 않았다. cloud adapter 세 종류와 selected string field 세 종류를 table-driven evidence로 완성하고, 잘못된 input shape로 우연히 통과하는 직접 validator assertion을 보정한다.

## 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:
  - `selfcheck-policy`: 실제 worker 완료 target의 local/cloud 성격으로 selfcheck 결정
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- Task: `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/`
- Prior loop artifacts: `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/plan_local_G05_3.log`, `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/code_review_cloud_G05_3.log`
- Verdict: `FAIL`
- Issue summary: Required 1, Suggested 0, Nit 0 — 필수 regression matrix가 `agy`와 adapter/execution_class 일부 변형만 검증하고 non-string target, `claude|codex` 모순 조합, 올바른 direct validator input을 누락했다.
- Affected files: `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- Verification evidence: focused 22건, pinned-target integration 1건, 전체 236건, `py_compile`, `git diff --check`는 PASS했으나 누락 variant가 suite에 존재하지 않았다.
- Roadmap carryover: Milestone Task `selfcheck-policy`, SDD Acceptance Scenario S10과 Evidence Map S10을 계속 대상으로 한다.
- Narrow reread allowed: 정확한 직전 판정 문맥이 필요할 때 위 `plan_local_G05_3.log`와 `code_review_cloud_G05_3.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`
- `agent-spec/index.md`
- `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-task/archive/2026/07/m-agent-task-runtime-target-selector/07+06_context_review_recovery/complete.log`
- `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/plan_local_G05_3.log`
- `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/code_review_cloud_G05_3.log`

### SDD 기준

- SDD 경로는 `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`, 상태는 `[승인됨]`, SDD 잠금은 해제 상태다.
- 대상은 Acceptance Scenario S10과 Evidence Map S10이며 Milestone Task id는 `selfcheck-policy`다.
- 실제 worker 완료 target이 local일 때만 pinned target으로 selfcheck하고 cloud completion은 생략한다는 기준을 valid/invalid adapter-class matrix, completion commit, restart fail-closed assertion과 최종 검증에 반영한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 매칭 profile `agent-test/local/testing-smoke.md`를 읽고 적용한다.
- 외부 provider process를 시작하지 않는 dispatcher unit/integration simulation이며 `CompletingTargetSelfcheckTest`의 `invoke`/`build_command` provider-deny guard를 유지한다.
- fresh Python `unittest`, `py_compile`, `git diff --check`를 사용한다. 원격 checkout, runtime port, secret, 외부 runner가 필요하지 않아 non-local preflight와 Edge-Node/full-cycle smoke는 적용하지 않는다.

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

- `test_completing_decision_validation_matrix`는 `agy + local_model + False`만 거부하고 `claude`, `codex`의 같은 모순 조합을 검증하지 않는다.
- non-string selected field는 adapter와 execution_class만 확인하고 target을 누락한다.
- `_spec_from_completing_decision()` 직접 assertion은 decision 전체가 아닌 `selected` 하위 dict를 전달해 cloud class 불변식이 아닌 selected-schema 오류로 통과한다.
- `_mark_worker_done()`와 restart fail-closed 회귀는 `agy` 한 종류만 다루며 valid cloud commit 조합 전체를 table-driven evidence로 고정하지 않는다.

### 심볼 참조

- rename/remove 대상은 없다.
- 검증 대상 call path는 `_spec_from_completing_decision()` -> `_validated_completing_decision()` -> `_completing_decision_is_valid()`, `_mark_worker_done()`, `task_stage()`다.

### 분할 판단

- split 정책을 먼저 평가했다. 이번 follow-up은 `test_dispatch.py`의 한 test class 안에서 동일 fixture/provider-deny guard로 같은 validator 계약을 보완하는 test-only 원자 단위다.
- API/foundation 변경, 다중 domain, 별도 verification profile, 독립 배포 가능한 산출물이 없고 테스트를 분리하면 동일 행렬을 중복 구성하므로 기존 `08+07_selfcheck_policy` 단일 subtask를 유지한다.
- predecessor `07+06_context_review_recovery`는 `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/07+06_context_review_recovery/complete.log`의 PASS로 충족됐다.

### 범위 결정 근거

- `dispatch.py` production validator는 현재 strict type/class/selfcheck 조합을 올바르게 차단하므로 변경하지 않는다.
- selector route matrix, quota/failover, failure budget, runtime skill, 중앙 관리 `agent-ops/rules/common/**`와 `agent-ops/skills/common/**`, Milestone/SDD/contract/spec 문서는 변경하지 않는다.
- `WORK_LOG.md`, sibling task, repo의 기존 dirty/untracked 파일, 실제 provider 실행은 범위에서 제외한다.
- agent-spec index에는 dispatcher orchestration과 매칭되는 living spec이 없어 별도 spec 갱신 대상이 아니다.

### 최종 라우팅

- evaluation mode=`isolated-reassessment`; finalizer=`finalize-task-policy.sh`; finalizer mode=`pair`; missing evidence=`[]`; blocked reason=`null`.
- build closures=`scope/context/verification/evidence/ownership/decision 모두 true`; 근거는 단일 test class와 Required variant가 확정됐고, focused/full suite를 재현했으며, test-only ownership과 사용자 결정 부재가 확인됐다는 점이다. route basis=`local-fit`; capability gap=`none`; scores=`scope_coupling 1, state_concurrency 0, blast_irreversibility 0, evidence_diagnosis 1, verification_complexity 1`; final=`local-G03`; filename=`PLAN-local-G03.md`.
- build loop-risk snapshot: `ordered_transitions={state_count: 3, adverse_paths: [validation reject, completion no-commit, restart blocked], evidence: validator/commit/task_stage tests}`; `concurrent_consistency={actor_count: 1, constraints: [], evidence: isolated StateStore subtests}`; `boundary_contract={component_count: 3, consumer_count: 3, constraints: [selected exact type, adapter/class/selfcheck immutability], evidence: validator/commit/restart consumers}`; `structured_interpretation={mechanisms: [nested persisted selected schema], hazards: [wrong input shape, type variant], evidence: direct validator assertion}`; `variant_product={independent_axis_count: 3, combination_verification_required: true, evidence: adapter × selected field × consumption path}`. matched signatures=`temporal_state, boundary_contract, structured_interpretation, variant_product`; triggered=`true`.
- review closures=`scope/context/verification/evidence/ownership/decision 모두 true`; route basis=`official-review`; capability gap=`none`; scores=`1/0/0/1/1`; final=`cloud-G03`; filename=`CODE_REVIEW-cloud-G03.md`; execution=`codex/gpt-5.6-sol xhigh`.
- repetition/signature 기반 lane/G floor=`none`; universal cloud floor=`none`; capability-gap floor=`none`.

## 구현 체크리스트

- [x] `CompletingTargetSelfcheckTest`의 validation matrix를 table-driven으로 정리해 `agy|claude|codex`의 valid `cloud_model + False`와 invalid `local_model + False`, adapter/target/execution_class의 non-string 변형을 모두 검증하고 direct validator에 전체 decision shape를 전달한다.
- [x] 같은 cloud case table로 `_mark_worker_done()` completion commit과 `task_stage()` restart 경로가 valid cloud는 review로, 모순 조합은 worker completion 미저장 및 blocked로 fail closed 되는지 provider-deny 상태에서 검증한다.
- [x] focused class, pinned-target integration, 전체 Python suite, `py_compile`, `git diff --check`를 fresh process에서 통과시킨다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 구현 항목

### [REVIEW_REFACTOR-1] Strict schema와 cloud adapter 회귀 행렬 완성

- 문제: `test_dispatch.py:1095-1152`는 cloud/local 모순을 `agy` 하나로만 확인하고 non-string target을 누락하며, line 1152의 direct call은 잘못된 input shape로 다른 validation error를 확인한다. `test_dispatch.py:1311-1434`의 completion/restart 회귀도 `agy`만 다뤄 계획의 모든 cloud adapter evidence가 닫히지 않는다.
- 해결 방법: canonical cloud case `(adapter, target)` 표와 decision factory를 test class에 두고 validation, direct spec extraction, `_mark_worker_done()`, `task_stage()` subtest에서 재사용한다. 각 adapter의 valid `cloud_model + False`는 normalized spec/commit/review를 확인하고 invalid `local_model + False`는 validator raise/no commit/restart blocked를 확인한다. selected exact-type matrix는 adapter, target, execution_class 각각에 non-string 값을 주입한다.

Before (`test_dispatch.py:1095-1152`):

```python
cloud_with_local_class = {
    "selected": {"adapter": "agy", "target": "Gemini 3.6 Flash (Medium)",
                 "execution_class": "local_model", "selfcheck_required": False},
}
self.assertFalse(dispatch._completing_decision_is_valid(...))
with self.assertRaises(dispatch.ExecutionDecisionError):
    dispatch._spec_from_completing_decision(cloud_with_local_class["selected"])
```

After:

```python
for adapter, target in cloud_cases:
    with self.subTest(adapter=adapter):
        invalid = make_decision(adapter, target, "local_model", False)
        self.assertFalse(dispatch._completing_decision_is_valid(
            task, {"completing_decision": invalid}
        ))
        with self.assertRaises(dispatch.ExecutionDecisionError):
            dispatch._spec_from_completing_decision(invalid)
for field, invalid_value in non_string_selected_cases:
    with self.subTest(field=field):
        self.assertFalse(dispatch._completing_decision_is_valid(...))
```

- 수정 파일 및 체크리스트:
  - [x] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: shared cloud case/factory와 validation/commit/restart subtest matrix를 추가하고 잘못된 direct input을 보정한다.
- 테스트 작성: 작성한다. `test_completing_decision_validation_matrix`, `test_mark_worker_done_rejects_cloud_decision_with_local_execution_class`, `test_restart_with_cloud_local_mismatch_blocks`를 table-driven으로 확장하고 valid cloud commit/review assertion을 같은 provider-deny class에 추가한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — 모든 strict schema/cloud adapter variant PASS.

## 의존 관계 및 구현 순서

1. shared cloud case/decision factory로 validation matrix와 direct validator input을 먼저 보정한다.
2. 같은 table을 completion commit과 restart fail-closed 회귀에 재사용한다.
3. 전체 검증 후 review stub의 구현 에이전트 소유 섹션만 채운다.

## 수정 파일 요약

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

## 최종 검증

1. `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — strict completion validation/commit/restart matrix 전체 PASS.
2. `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest.test_completing_target_controls_selfcheck_and_reuses_pin -v` — valid local/cloud completing target integration PASS.
3. `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — 전체 dispatcher suite PASS; cached output은 사용하지 않고 fresh Python process 결과를 기록한다.
4. `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` — syntax PASS.
5. `git diff --check` — whitespace error 없음.

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