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

# Code Review Reference - REVIEW_REFACTOR

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked, record the exact blocker, attempted commands/output, and resume condition only in implementation-owned evidence fields.
> Do not ask the user directly, present choices, call user-input tools, create control-plane stop files, or classify the next state.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## 개요

date=2026-07-26
task=m-agent-task-runtime-target-selector/08+07_selfcheck_policy, plan=2, tag=REVIEW_REFACTOR

## 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_1.log`, `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/code_review_cloud_G05_1.log`
- Verdict: `FAIL`
- Issue summary: Required 3, Suggested 0, Nit 0 — worker completion이 decision의 `stage`와 현재 `work_unit_id`를 검증하지 않음; 모순된 adapter/execution_class/selfcheck 조합이 restart에서 valid로 처리됨; locator mismatch가 task-local blocker가 아닌 `ExecutionDecisionError`로 전파됨.
- 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 17건, pinned-target integration 1건, 전체 231건, `py_compile`, `git diff --check`는 PASS했다. 추가 reproducer는 `pi + cloud_model + selfcheck_required=False`가 `review`, `agy + local_model`이 `selfcheck`로 진행하고 wrong `stage/work_unit_id`가 `worker_done=True`로 저장되며 locator mismatch 후 `blocked=None`인 예외 전파를 확인했다.
- Roadmap carryover: Milestone Task `selfcheck-policy`, SDD Acceptance Scenario S10과 Evidence Map S10을 계속 대상으로 한다.
- Narrow reread allowed: 정확한 직전 판정 문맥이 필요할 때 위 `plan_local_G05_1.log`와 `code_review_cloud_G05_1.log`만 읽는다.

## 이 파일을 읽는 리뷰 에이전트에게

> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.

각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.

1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G05.md` → `code_review_cloud_G05_2.log`, `PLAN-local-G05.md` → `plan_local_G05_2.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/`로 이동한다. WARN/FAIL이면 code-review skill이 요구하는 다음 filesystem state를 완전히 작성한다.
4. PASS이고 task group이 `m-agent-task-runtime-target-selector`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| REVIEW_REFACTOR-1 Strict completing-decision validator 공유 | [x] |
| REVIEW_REFACTOR-2 Worker completion atomicity와 task-local blocker | [x] |

## 구현 체크리스트

- [x] completing decision의 `stage=worker`, 현재 PLAN 기반 `work_unit_id`, selected adapter/target/execution_class/selfcheck_required를 하나의 strict validator로 검증하고 valid Pi local/required 및 cloud nonlocal/not-required 조합만 허용한다.
- [x] persisted worker decision이 존재하면 그것만 authoritative source로 사용하고 malformed state를 initial decision으로 폴백하지 않으며, normalized decision identity와 성공 locator가 일치할 때만 completion fields를 한 번에 저장한다.
- [x] `run_worker()`가 completion validation 실패를 예외로 전파하지 않고 `worker_done=False`를 유지한 채 task-local `blocked`와 `작업차단` evidence를 기록한다.
- [x] wrong stage/work-unit, 모순 schema, malformed persisted decision, actual `run_worker()` locator mismatch, valid local/cloud restart를 provider-deny 상태의 회귀 테스트로 고정한다.
- [x] focused class와 integration method, 전체 Python suite, `py_compile`, `git diff --check`를 fresh process에서 통과시킨다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

## 코드리뷰 전용 체크리스트

> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-cloud-G05.md`를 `code_review_cloud_G05_2.log`로 아카이브한다.
- [x] active `PLAN-local-G05.md`를 `plan_local_G05_2.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/`를 `agent-task/archive/YYYY/MM/m-agent-task-runtime-target-selector/08+07_selfcheck_policy/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-agent-task-runtime-target-selector`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-agent-task-runtime-target-selector/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이면 code-review skill의 판정에 맞는 다음 filesystem state를 작성하고 `complete.log`를 작성하지 않는다.

## 계획 대비 변경 사항

계획에 명시된 Before/After 코드 스니펫과 구현 간 다음 차이가 있다.

1. `_completing_decision_is_valid` 시그니처가 `(state)`에서 `(task, state)`로 변경되었다. plan은 `task` 파라미터 추가만 언급했지만, 이에 따라 `task_stage()` 호출부도 함께 수정했다.
2. `_mark_worker_done`에서 `initial_decision` 파라미터는 유지하되, persisted `execution_decisions["worker"]`가 없으면 폴백 대신 `ExecutionDecisionError`를 raise하도록 변경했다. plan의 "authoritative source로 선택" 지침을 strict fail-closed로 해석한 결과이다.
3. `_mark_worker_done` 내부의 adapter/target/CLI/model 수동 검증 로직을 `_validated_completing_decision` + `_require_same_runtime_identity` 두 헬퍼로 분리했다. plan이 `_spec_from_completing_decision` 재사용을 지시했으므로, `_spec_from_completing_decision`이 이미 adapter/target/class/selfcheck_required 정규화를 수행하므로 중복 검증을 제거했다.
4. `run_worker`에서 `_mark_worker_done` 호출을 `try/except ExecutionDecisionError`로 감싸 `worker_done=False` + `blocked` + `작업차단` banner로 변환한다. plan의 After 코드와 동일 방향이다.
5. `run_selfcheck`에서 `_spec_from_completing_decision(completing)` 대신 `_validated_completing_decision(task, completing)`을 사용한다. plan의 "same contract" 지시에 따른 것이다.

## 주요 설계 결정

1. **strict validator 공유 계약**: `_validated_completing_decision(task, decision)`은 `stage == "worker"`, `work_unit_id == work_unit_id_from_file(task.plan)`, `_spec_from_completing_decision` 정규화를 하나의 원자 계약으로 통합한다. `task_stage()`, `_mark_worker_done()`, `run_selfcheck()`가 모두 이 계약을 소비하므로, completing-state 소비 경로가 모두 동일한 기준으로 차단/진행을 결정한다.
2. **폴백 제거**: persisted `execution_decisions["worker"]`가 없으면 initial_decision으로 폴백하지 않고 즉시 차단한다. 이는 malformed persisted state가 speculative initial decision으로 silent revert되는 이전 회귀를 수정한다.
3. **runtime identity 추가 검증**: `_require_same_runtime_identity(expected_spec, worker_cli, worker_model)`으로 completed locator의 CLI/model이 completing decision spec과 일치하는지 추가로 확인한다. locator mismatch 시 task-local blocker로 변환되어 coroutine 예외가 scheduler로 전파되지 않는다.
4. **단일 commit**: validator 통과 후 `worker_done`, `worker_cli`, `worker_model`, `completing_decision`, `execution_class`, `selfcheck_done`, `blocked=None`을 단일 `update_task()`로 commit한다.

## 리뷰어를 위한 체크포인트

- worker completion과 restart scheduler가 동일한 validator로 `stage`, 현재 PLAN `work_unit_id`, adapter/class/selfcheck 조합을 검증하는가.
- persisted worker decision key가 존재하지만 malformed이면 valid initial decision으로 폴백하지 않는가.
- success locator와 normalized completing target mismatch가 coroutine 예외가 아니라 task-local blocker가 되고 completion fields는 commit되지 않는가.
- valid Pi local/required와 cloud nonlocal/not-required는 각각 selfcheck/review로 수렴하며 selector/quota/provider 실제 호출은 발생하지 않는가.

## 검증 결과

### CompletingTargetSelfcheckTest

명령: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v`

```
Ran 19 tests in 0.101s
OK
```

19건 전체 PASS. 신규 tests: `test_completing_decision_validation_matrix`(stage/work-unit/boolean 모순 9 case), `test_mark_worker_done_does_not_fallback_from_malformed_persisted_worker_decision`, `test_run_worker_completion_mismatch_blocks_task_without_raise`.

### pinned target integration

명령: `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest.test_completing_target_controls_selfcheck_and_reuses_pin -v`

```
Ran 1 test in 0.212s
OK
```

local pinned selfcheck, cloud skip selfcheck, cloud G07 skip selfcheck 3 case 모두 PASS.

### 전체 Python suite

명령: `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'`

```
Ran 233 tests in 14.770s
OK
```

233건 전체 PASS. regression 없음.

### py_compile

명령: `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`

```
py_compile OK
```

exit code 0, stderr empty.

### diff check

명령: `git diff --check`

```
(no output)
```

exit code 0, whitespace error 없음.

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

## 섹션 소유권

| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these (archive, complete.log, and task-directory archive move are review-agent only) |
| Roadmap Targets | Fixed at stub creation from plan when present | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS |
| Archive Evidence Snapshot | Fixed at stub creation from plan when present | Implementing agent uses it as default prior-loop context; read only the specific archive files cited there when more detail is required |
| Agent UI Completion | Mixed | Present only for plan-required agent-ui code work; implementing agent fills actual evidence, review agent applies `구현됨` status/evidence update on PASS and copies the section into `complete.log` |
| 구현 항목별 완료 여부 (item names) | Fixed at stub creation | Implementing agent checks `[ ]` → `[x]` only |
| 구현 체크리스트 (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` → `[x]` only |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan |
| 검증 결과 (section headings + commands) | Fixed at stub creation | Implementing agent fills in command output only; command changes require a `계획 대비 변경 사항` entry |
| 코드리뷰 결과 | Review agent appends | Not included in stub |

## 코드리뷰 결과

- 종합 판정: FAIL

### 차원별 평가

| 차원 | 평가 | 근거 |
|------|------|------|
| Correctness | Fail | cloud adapter의 `local_model + selfcheck_required=False` completing decision이 valid로 처리되어 restart가 잘못된 selfcheck 단계로 진입한다. |
| Completeness | Fail | 계획이 요구한 valid cloud nonlocal/not-required 조합만 허용하는 strict validator가 완성되지 않았다. |
| Test coverage | Fail | focused 19건과 전체 233건은 통과하지만 cloud adapter와 `local_model`의 모순 조합 및 selected scalar type coercion을 고정하지 않는다. |
| API contract | Pass | 외부 API와 agent-contract 변경은 없으며 dispatcher 내부 persisted-state 계약 범위다. |
| Code quality | Pass | 대상 변경에서 디버그 출력, 잔여 TODO, 죽은 코드는 발견되지 않았다. |
| Implementation deviation | Fail | 구현 체크리스트의 “valid Pi local/required 및 cloud nonlocal/not-required 조합만 허용” 요구와 실제 validator가 불일치한다. |
| Verification trust | Fail | 보고된 명령은 재실행에서도 통과했지만 최소 재현이 테스트가 다루지 않는 completion-state 위반을 확인했다. |
| Spec conformance | Fail | SDD S10의 cloud completion은 selfcheck를 생략해야 한다는 경계가 모순된 persisted class에서 fail closed 되지 않는다. |

### 발견된 문제

- Required — `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:1179`, `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py:1211`, `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py:990`: `_spec_from_completing_decision()`은 selected scalar를 `str()`로 강제 변환하고 cloud branch에서 `selfcheck_required=False`만 확인해 `agy + local_model + False`를 valid로 받아들인다. focused reproducer에서 `_completing_decision_is_valid=True`, `_mark_worker_done()` 후 `worker_done=True`, `execution_class=local_model`, restart `task_stage=selfcheck`를 확인했다. 이는 현재 PLAN의 strict 조합 요구와 SDD S10을 위반한다. adapter/target/execution_class를 강제 변환 없이 non-empty string으로 검증하고 Pi는 `local_model + True`, `agy|claude|codex`는 `cloud_model + False`만 허용하라. validation matrix를 모든 cloud adapter의 `local_model + False` 및 non-string selected field 변형으로 확장하고, invalid state가 completion commit이나 selfcheck 진입 없이 task-local fail-closed 되는 경계를 검증하라.

### 검증 재실행

- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest -v` — PASS, 19건.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py SelectorDispatcherIntegrationTest.test_completing_target_controls_selfcheck_and_reuses_pin -v` — PASS, 1건.
- `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — PASS, 233건.
- `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` — PASS.
- `git diff --check` — PASS.
- focused reproducer — `validator_accepts_cloud_adapter_local_class=True`, `worker_done=True`, `execution_class=local_model`, `selfcheck_done=False`, restart `task_stage=selfcheck`를 확인했다.

### 다음 단계

- FAIL: 위 Required 1건을 같은 task path의 follow-up PLAN에서 strict selected schema와 cloud execution-class 회귀로 수정하고 fresh routing된 review pair로 다시 검토한다.
