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

# Plan - 실제 완료 target 기반 selfcheck

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

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

## 배경

현재 selfcheck 여부는 task의 정적 local route 성격에 기대고 있어 failover 후 실제 완료 target과 어긋날 수 있다. 이 작업은 worker 성공을 만든 decision을 완료 evidence로 고정하고, 그 target의 local/cloud 성격만으로 selfcheck를 결정한다.

## 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

## 분석 결과

### 읽은 파일

- `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/scripts/select_execution_target.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- `agent-test/local/rules.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-spec/index.md`
- `agent-contract/index.md`

### SDD 기준

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`, 상태 `[승인됨]`, 잠금 해제.
- 대상 Acceptance Scenario: S10 → `selfcheck-policy`.
- Evidence Map S10 행의 completing-target stage evidence를 따라 Gemini→Laguna 완료 selfcheck, Laguna→Gemini/cloud 완료 미실행, pinned target 재사용을 구현 체크리스트와 집중 테스트에 반영했다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`가 존재하며 끝까지 읽었다.
- agent-ops Python dispatcher에 매칭되는 `agent-test/local/*.md` profile은 없다. 현재 checkout의 Python test manifest를 fallback 근거로 삼아 fresh-process `unittest`, `py_compile`, `git diff --check`를 사용하며 test-rule 유지보수는 필요하지 않다.
- fake runner로 worker/selfcheck invocation spec을 포착하고 실제 provider는 호출하지 않는다.
- 계획 시점 전체 Python suite 기준선은 169 tests PASS다.

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

- dispatcher selfcheck 판단이 `completed_spec.local_pi`와 정적 route 정보에 의존한다.
- failover 뒤 실제 성공 target의 `execution_class`를 완료 state에 고정해 쓰지 않는다.
- local selfcheck가 새 initial selector decision을 만들지 않고 성공 target을 그대로 재사용하는지 검증하지 않는다.

### 심볼 참조

- `task_requires_selfcheck()` 정의 `dispatch.py:1008`과 유일 call-site `task_stage()`(`dispatch.py:1091`)를 completing decision 기반 helper로 교체한다.
- `run_worker()` 완료 기록 `dispatch.py:3450-3458`과 `run_selfcheck()`의 정적 route call `dispatch.py:3468`을 갱신한다. `run_selfcheck` 자체는 rename/remove하지 않는다.

### 분할 판단

- split 정책을 평가했으며 selfcheck completion evidence와 scheduling/target reuse가 같은 state transition을 공유해 원본 pair를 유지한다.
- 전체 topology는 `03 → 04 → 05 → 06 → 07 → 08 → 09 → 10 → 11 → 12`다.
- 현재 predecessor `07+06_context_review_recovery`는 active plan만 있고 `complete.log`가 없어 미충족이다.
- 이 task 뒤 admission batch, target cap 제거, unknown 격리를 순서대로 진행하고 최종 audit가 `08`과 `11`을 소비한다.

### 범위 결정 근거

- selector route matrix와 failover eligibility는 변경하지 않는다.
- selfcheck는 worker와 별도 stage budget/lifecycle을 유지하되 route를 새로 평가하지 않는다.
- review 실행 정책은 공식 Codex 고정을 그대로 보존한다.
- `agent-spec/index.md`와 `agent-contract/index.md`에 매칭되는 활성 selector/dispatcher spec/contract가 없으므로 승인 SDD, 코드와 테스트를 기준으로 삼는다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`
- finalizer=`finalize-task-policy.sh`, finalizer_mode=`pair`; build/review status=`routed`.
- build closures: `scope_closed=true`(승인 SDD와 이 subtask 경계가 고정됨), `context_closed=true`(명시된 source/test 범위를 한 local 작업에서 유지 가능), `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`.
- review closures: `scope_closed=true`, `context_closed=true`(동일 source/test 및 구현 evidence로 판정 가능), `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`.
- build route_basis=`local-fit`; capability_gap=`none`.
- build loop-risk audit: matched signatures=`temporal_state`; 이 기록은 lane/G를 바꾸지 않는다.
- build scores(scope_coupling/state_concurrency/blast_irreversibility/evidence_diagnosis/verification_complexity)=`1/1/1/0/1`, final=`local-G04`, filename=`PLAN-local-G04.md`.
- review route_basis=`official-review`; official execution=`codex/gpt-5.6-sol xhigh`; capability_gap=`none`.
- review scores(scope_coupling/state_concurrency/blast_irreversibility/evidence_diagnosis/verification_complexity)=`1/1/1/1/1`, final=`cloud-G05`, filename=`CODE_REVIEW-cloud-G05.md`.

## 구현 체크리스트

- [x] worker 성공 state가 실제 completing decision, target, execution_class를 보존한다.
- [x] selfcheck는 completing decision의 `execution_class=local_model`일 때만 정확히 한 번 scheduling된다.
- [x] local selfcheck가 새 selector 평가 없이 completing target과 같은 adapter/target을 재사용한다.
- [x] Gemini→Laguna, Laguna→Gemini, cloud 완료와 restart 회귀 테스트가 정책을 고정한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 구현 항목

### [REFACTOR-1] Completing decision 저장

- 문제: `dispatch.py:3450-3458`은 locator의 CLI/model과 `local_pi`만 기록해 failover 뒤 실제 selector completing decision을 selfcheck 판단의 authoritative evidence로 제공하지 않는다.
- 해결 방법:

```python
# Before: agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:3450
completed_spec = agent_spec_from_locator(locator) or spec
store.update_task(
    task,
    worker_done=True,
    worker_cli=completed_spec.cli,
    worker_model=completed_spec.model,
    selfcheck_done=not completed_spec.local_pi,
)
```

```python
# After
state.mark_worker_done(
    task,
    completing_decision=decision,
    execution_class=decision["selected"]["execution_class"],
)
```

  decision identity와 stage를 검증한 뒤 성공 locator와 같은 target만 기록한다. restart 시에도 이 완료 evidence를 보존한다.
- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: worker completion state schema와 validator.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: success target/state 일치 회귀.
- 테스트 작성: `test_dispatch.py`의 `CompletingTargetSelfcheckTest`에서 fake success locator와 persisted decision으로 initial/failover completing target 및 identity mismatch fail-closed를 검증한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — completion state case가 PASS해야 한다.

### [REFACTOR-2] Selfcheck scheduling과 target 재사용

- 문제: `dispatch.py:1008-1009,1091`은 task lane/G로 scheduling하고 `dispatch.py:3468`은 정적 route를 다시 계산해 실제 cloud 완료에 불필요한 selfcheck를 만들거나 local 완료 target을 바꿀 수 있다.
- 해결 방법:

```python
# Before: agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:1008
def task_requires_selfcheck(task: Task) -> bool:
    return task.lane == "local" and task.grade is not None and task.grade <= 8
```

```python
# After
def completing_decision_requires_selfcheck(state: dict[str, Any]) -> bool:
    return state["completing_decision"]["selected"]["execution_class"] == "local_model"
```

  persisted completing decision에서 `AgentSpec`을 복원한다. selfcheck stage state/budget은 worker와 별도지만 selector `initial`/`failover`와 quota probe를 호출하지 않는다.
- 수정 파일 및 체크리스트:
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`: scheduling 조건과 `run_selfcheck` spec source.
  - [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: target 재사용과 no-selfcheck matrix.
- 테스트 작성: `CompletingTargetSelfcheckTest`에서 Gemini→Laguna는 Laguna selfcheck 1회, Laguna→Gemini와 모든 cloud 완료는 0회, selector/probe call 0회, restart 후 중복 실행 없음을 fake runner로 검증한다.
- 중간 검증: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — target/no-selfcheck/restart case가 PASS해야 한다.

## 의존 관계 및 구현 순서

1. `07+06_context_review_recovery`의 archived `complete.log`가 PASS여야 한다.
2. REFACTOR-1 완료 evidence를 REFACTOR-2가 소비한다.
3. 이 task PASS 후 `09+08_admission_quota_batch`를 시작하며, `08`과 `11`이 모두 PASS해야 `12+08,11_audit_closure`를 시작한다.

## 수정 파일 요약

| 파일 | 항목 |
|---|---|
| `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py` | REFACTOR-1, REFACTOR-2 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` | REFACTOR-1, REFACTOR-2 |

## 최종 검증

- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — completion/selfcheck matrix 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/tests/test_dispatch.py` — exit 0.
- `git diff --check` — 출력 없음.

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