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

# Plan - cloud completion test fixture 단일화

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

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

## 배경

valid cloud validation/commit/restart 회귀는 추가됐지만, invalid 경로가 class-level canonical table과 factory를 소비하지 않고 adapter/target 표와 decision dict를 반복한다. 계획 체크리스트와 실제 source of truth를 일치시켜 다음 adapter 또는 decision field 변경 때 valid/invalid 행렬이 함께 갱신되도록 한다.

## 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_G03_5.log`, `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/code_review_cloud_G03_5.log`
- Verdict: `FAIL`
- Issue summary: Required 1, Suggested 0, Nit 0 — valid cloud 행렬은 통과하지만 invalid commit/restart 경로가 canonical `_CLOUD_CASES`와 decision factory를 재사용하지 않아 계획의 단일 source of truth 기준을 충족하지 못했다.
- Affected files: `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- Verification evidence: focused 24건, pinned-target integration 1건, 전체 238건, `py_compile`, `git diff --check`는 모두 fresh process에서 PASS했다.
- Roadmap carryover: Milestone Task `selfcheck-policy`, SDD Acceptance Scenario S10과 Evidence Map S10을 계속 대상으로 한다.
- Narrow reread allowed: 정확한 직전 판정 문맥이 필요할 때 위 `plan_local_G03_5.log`와 `code_review_cloud_G03_5.log`만 읽는다.

## 분석 결과

### 읽은 파일

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md`
- `agent-contract/index.md`
- `agent-roadmap/current.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-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/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/PLAN-local-G03.md`
- `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/CODE_REVIEW-cloud-G03.md`
- `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/plan_local_G03_4.log`
- `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/code_review_cloud_G03_4.log`

### SDD 기준

- SDD는 `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`, 상태 `[승인됨]`, 잠금 `해제`다.
- 대상은 Acceptance Scenario S10과 Evidence Map S10이며 Milestone Task id는 `selfcheck-policy`다.
- S10의 cloud completion selfcheck 생략 evidence를 세 adapter의 valid/invalid validation, completion commit, restart 행렬로 유지하되 이번 follow-up은 그 행렬의 test fixture 단일화만 수행한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 `agent-test/local/testing-smoke.md`를 읽었다.
- dispatcher unit/integration simulation은 실제 provider를 실행하지 않으므로 기존 `invoke`/`build_command` provider-deny guard를 유지한다.
- test-only fixture refactor로 사용자 실행 경로와 production dispatcher를 바꾸지 않으므로 Edge-Node full-cycle, mock smoke, live provider preflight는 적용하지 않는다.
- fresh Python `unittest`, `py_compile`, deterministic `rg --sort path`, `git diff --check`를 검증 기준으로 사용한다.

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

- 세 adapter의 valid validation/commit/restart와 invalid validation/no-commit/blocked 동작은 현재 focused 24건과 pinned-target integration에 포함되어 있다.
- 남은 공백은 동작 variant가 아니라 동일 case/factory가 모든 행렬의 단일 source of truth인지에 대한 source 구조다. inline `cloud_cases =` 제거를 deterministic `rg`와 코드리뷰로 확인한다.

### 심볼 참조

- production symbol rename/remove는 없다.
- test helper `make_cloud_decision`의 호출부는 같은 `CompletingTargetSelfcheckTest` 내부 validation, completion commit, restart matrix뿐이다.

### 분할 판단

- split 정책을 먼저 평가했다. 한 test class의 class-level tuple과 helper signature를 바꾸고 같은 class의 중복 fixture를 치환하는 단일 test-only 원자 변경이다.
- API/foundation, 다중 domain, 별도 검증 profile, 독립 산출물 경계가 없고 분할하면 동일 class를 동시에 수정하므로 기존 `08+07_selfcheck_policy` 단일 subtask를 유지한다.
- dependency prefix `08+07`은 선행 `07` 완료 뒤 시작된 기존 task-local review loop이며 새 dependency를 추가하지 않는다.

### 범위 결정 근거

- `dispatch.py` production validator/completion/stage 로직은 변경하지 않는다.
- 새 test method를 추가하지 않고 기존 24개 focused method의 fixture source만 단일화한다.
- selector route, quota/failover, failure budget, runtime skill, 중앙 관리 `agent-ops/rules/common/**`와 `agent-ops/skills/common/**`, roadmap/SDD/contract/spec, `WORK_LOG.md`, sibling task와 다른 dirty 파일은 범위에서 제외한다.
- agent-spec과 agent-contract index에는 dispatcher test fixture 구조에 매칭되는 living 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의 중복 위치와 치환 방식이 확정됐고 focused/full suite 및 source-shape 명령으로 판정 가능하며 외부 결정이 없다. 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: existing validator/commit/task_stage tests}`; `concurrent_consistency={actor_count: 1, constraints: [], evidence: isolated StateStore subtests}`; `boundary_contract={component_count: 3, consumer_count: 3, constraints: [single fixture source, adapter/class/selfcheck invariants], evidence: validation/commit/restart consumers}`; `structured_interpretation={mechanisms: [nested persisted selected dict fixture], hazards: [duplicated table, duplicated decision shape], evidence: current inline definitions}`; `variant_product={independent_axis_count: 3, combination_verification_required: true, evidence: adapter × validity × 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.make_cloud_decision()`이 `execution_class` variant를 만들 수 있게 하고 validation, valid/invalid `_mark_worker_done()`, valid/invalid restart matrix가 모두 class-level `_CLOUD_CASES`와 이 factory를 소비하도록 바꾸며 inline `cloud_cases =`/중복 decision dict를 제거한다.
- [x] source-shape 검색, focused class, pinned-target integration, 전체 Python suite, `py_compile`, `git diff --check`를 fresh process에서 통과시킨다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 구현 항목

### [REVIEW_TEST-1] Canonical cloud fixture 단일화

- 문제: `test_dispatch.py:412`의 factory는 `execution_class="cloud_model"`을 고정한다. `test_dispatch.py:1115-1127`, `1370-1392`, `1416-1439`, `1466-1488`은 invalid decision 또는 세 adapter 표를 다시 만들어 계획의 “한 번만 정의”와 “같은 case table” 기준을 위반한다.
- 해결 방법: factory에 `execution_class` 기본 인자를 추가하고 `selfcheck_required=False`는 유지한다. validation, invalid no-commit, malformed restart, class mismatch restart와 기존 valid commit/restart가 모두 `self._CLOUD_CASES`를 순회하고 factory로 decision을 만든다. `cloud_cases` 지역 alias와 adapter/target literal list를 제거한다.

Before (`test_dispatch.py:412`, `1370-1392`):

```python
@classmethod
def make_cloud_decision(cls, adapter: str, target: str) -> dict:
    return {"selected": {"adapter": adapter, "target": target,
                         "execution_class": "cloud_model",
                         "selfcheck_required": False}, ...}

cloud_cases = [("agy", "..."), ("claude", "..."), ("codex", "...")]
bad_decision = {"selected": {"adapter": adapter, "target": target,
                              "execution_class": "local_model",
                              "selfcheck_required": False}, ...}
```

After:

```python
@classmethod
def make_cloud_decision(
    cls, adapter: str, target: str, execution_class: object = "cloud_model",
) -> dict:
    return {"selected": {"adapter": adapter, "target": target,
                         "execution_class": execution_class,
                         "selfcheck_required": False}, ...}

for adapter, target in self._CLOUD_CASES:
    valid_decision = self.make_cloud_decision(adapter, target)
    invalid_decision = self.make_cloud_decision(adapter, target, "local_model")
```

- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: helper signature를 variant-aware로 만들고 모든 cloud validation/commit/restart fixture를 `_CLOUD_CASES`와 helper로 통일한다.
- 테스트 작성: 새 test method는 추가하지 않는다. 기존 `test_completing_decision_validation_matrix`, `test_mark_worker_done_rejects_cloud_decision_with_local_execution_class`, `test_restart_with_malformed_completed_state_blocks_not_selfcheck`, `test_restart_with_cloud_local_mismatch_blocks`, valid commit/restart method의 assertion을 유지하면서 fixture 생성만 단일화한다.
- 중간 검증: `! rg --sort path -n '^[[:space:]]+cloud_cases[[:space:]]*=' agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` — inline cloud table alias가 없어야 한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — 24개 test method와 모든 subtest PASS.

## 수정 파일 요약

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

## 최종 검증

1. `rg --sort path -n '_CLOUD_CASES|make_cloud_decision' agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` — class-level table/factory 정의와 모든 matrix 참조를 결정적 순서로 확인한다.
2. `! rg --sort path -n '^[[:space:]]+cloud_cases[[:space:]]*=' agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` — 중복 inline table alias 없음.
3. `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — canonical valid/invalid cloud validation/commit/restart matrix 전체 PASS.
4. `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest.test_completing_target_controls_selfcheck_and_reuses_pin -v` — local/cloud completing-target integration PASS.
5. `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — 전체 dispatcher suite fresh process PASS.
6. `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.
7. `git diff --check` — whitespace error 없음.

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