<!-- task=m-agent-task-runtime-target-selector/10+09_target_cap_removal plan=1 tag=REVIEW_REFACTOR -->

# Plan - 제거된 semaphore 인자 테스트 호출 계약 정리

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

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

## 배경

target별 정적 semaphore를 production 경로에서 제거했지만 테스트 11곳이 옛 semaphore dict를 `run_worker`/`run_selfcheck`의 네 번째 positional 인자로 계속 전달한다. 새 함수 계약에서는 그 위치가 `resume_locator`이므로 mock 중심 테스트가 잘못된 locator를 허용한 채 통과한다. 별도로 retry 테스트의 독립 semaphore/`locked()` 관찰은 제거된 정책과 연결되지 않아 dead evidence가 됐다.

## Archive Evidence Snapshot

- 직전 보관 계획: `agent-task/m-agent-task-runtime-target-selector/10+09_target_cap_removal/plan_local_G07_0.log`
- 직전 보관 리뷰: `agent-task/m-agent-task-runtime-target-selector/10+09_target_cap_removal/code_review_cloud_G07_0.log`
- 직전 판정: `FAIL`
- finding 요약: Required=1, Suggested=0, Nit=0. 제거된 semaphore dict가 11개 테스트 호출에서 `resume_locator`로 오인되고, 독립 semaphore의 `locked()` assertion은 정책 제거 뒤 dead evidence다.
- 영향 파일: `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- 검증 증거: `ThroughputQuotaBatchTest` 5개, `BlockerDrainTest` 6개, 전체 244개 테스트와 `py_compile`, `git diff --check`는 통과했지만 전체 suite 출력에 `locator={'pi:ornith:35b': <...Semaphore...>}`가 나타나 기존 PASS evidence의 계약 검증 신뢰가 깨졌다.
- 좁은 재열람 허용: 구현과 리뷰에서 prior-loop 상세가 필요하면 위 두 보관 로그만 다시 읽는다.

## 분석 결과

### 읽은 파일

- `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatch.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`
- `agent-test/local/rules.md`
- `agent-test/local/testing-smoke.md`
- `agent-roadmap/sdd/automation-runtime-bridge/agent-task-runtime-target-selector/SDD.md`

### SDD 기준

- 승인된 SDD Acceptance Scenario S11은 독립적인 동일 target task의 정적 cap 없는 admission을 요구한다.
- 이 후속 계획은 S11 production 동작을 바꾸거나 roadmap task 완료를 주장하지 않는다. Evidence Map의 test-suite 근거가 실제 새 호출 계약을 사용하도록 복구한다.

### 테스트 환경 규칙

- `test_env=local`; `agent-test/local/rules.md`와 연결된 `testing-smoke.md`를 읽었다.
- `testing-smoke.md`의 full-cycle 조건인 `scripts/dev/**` 또는 사용자 flow 변경은 이번 한 파일 테스트 호출 정리에 해당하지 않는다. 실제 provider 호출은 기존 test deny guard/fake 정책을 유지하고 repository Python suite로 검증한다.
- 결정적 검증은 AST 호출 형태 점검, 영향 class 묶음, 기존 throughput/blocker 회귀, fresh-process 전체 suite, `py_compile`, `git diff --check` 순서로 닫는다.

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

- mock이 `resume_locator`의 타입/의미를 소비하지 않는 경로에서는 제거된 네 번째 dict 인자가 있어도 테스트가 통과한다.
- retry sleep 테스트의 별도 semaphore는 production 실행과 연결되지 않아 `locked()` assertion이 항상 의미 없는 값을 관찰한다.

### 심볼 참조

- 네 번째 positional 인자가 남은 호출은 `test_dispatch.py:550,617,712,783,958,1581,3845,4181,4251,6464,7635`의 `run_worker`/`run_selfcheck`다.
- dead evidence는 `test_dispatch.py:4037-4067`의 `semaphore`, `semaphore.locked()`, `all(not locked ...)`다.
- production 계약은 `run_worker(workspace, store, task, resume_locator=None, quota_snapshot=None)`와 `run_selfcheck(workspace, store, task, resume_locator=None)`이며 선택 인자를 유지해야 할 때는 의미가 드러나는 keyword를 사용한다.

### 분할 판단

- 기존 `10+09_target_cap_removal` split child 안의 단일 test 파일과 단일 Required finding이다. 별도 child로 더 나누면 같은 호출 계약 검증을 중복하므로 이 generation에서 함께 수정한다.
- 선행 의존성 `agent-task/archive/2026/07/m-agent-task-runtime-target-selector/09+08_admission_quota_batch/complete.log`의 PASS는 확인됐다.

### 범위 결정 근거

- `test_dispatch.py`의 stale 인자와 dead assertion만 수정한다.
- `dispatch.py` production 동작, quota/admission 알고리즘, dependency readiness, task blocker, state/work-log lock, roadmap/SDD, 다른 active sibling은 변경하지 않는다.

### 최종 라우팅

- evaluation_mode: `isolated-reassessment`; 이전 lane/G와 실패 횟수는 입력에서 제외했다.
- build/review closures: `scope_closed=true`, `context_closed=true`, `verification_closed=true`, `evidence_trusted=true`, `ownership_closed=true`, `decision_closed=true`.
- build route_basis=`local-fit`; capability_gap=`none`; loop-risk matched signatures=`boundary_contract`, triggered=`true`.
- build scores(scope_coupling/state_concurrency/blast_irreversibility/evidence_diagnosis/verification_complexity)=`1/1/0/2/1`, final=`local-G05`, filename=`PLAN-local-G05.md`.
- review route_basis=`official-review`; official execution=`codex/gpt-5.6-sol xhigh`.
- review scores(scope_coupling/state_concurrency/blast_irreversibility/evidence_diagnosis/verification_complexity)=`1/1/0/2/1`, final=`cloud-G05`, filename=`CODE_REVIEW-cloud-G05.md`.

## 구현 체크리스트

- [x] 제거된 semaphore dict를 전달하는 `run_worker`/`run_selfcheck` 호출 11곳을 현재 함수 계약에 맞춘다.
- [x] production 경로와 무관한 retry semaphore/`locked()` dead evidence를 제거하고 retry 횟수·sleep 횟수 검증은 보존한다.
- [x] `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 원문으로 채운다.

## 구현 항목

### [REVIEW_REFACTOR-1] 테스트 호출 계약과 검증 신뢰 복구 ✓

- 문제: 제거된 semaphore dict가 네 번째 positional 인자로 남아 `resume_locator`로 전달되고, 독립 semaphore 관찰은 production 정책을 검증하지 않는다.
- 해결 방법:

```python
# Before
await dispatch.run_worker(workspace, store, task, {"pi": asyncio.Semaphore(1)})
```

```python
# After
await dispatch.run_worker(workspace, store, task)
```

  실제 locator 또는 quota가 필요한 호출만 `resume_locator=`/`quota_snapshot=` keyword로 표현한다. retry 테스트에서는 `sleep_observations`에 delay만 기록하고 호출 횟수·sleep 횟수 assertion을 유지한다.
- 수정 파일 및 체크리스트:
  - [x] `agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py`: 11개 stale 호출과 dead semaphore assertion 정리.
- 테스트 작성: 새 production 동작 테스트를 추가하지 않는다. 기존 영향 테스트들이 현재 호출 계약으로 같은 상태 전이와 failure budget 결과를 보이는지 재실행하고 AST 검사로 네 번째 positional 호출 재발을 결정적으로 차단한다.
- 중간 검증: 아래 AST 검사와 영향 class 묶음이 모두 PASS해야 한다.

## 수정 파일 요약

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

## 최종 검증

- `python3 - <<'PY'`로 `test_dispatch.py` AST를 읽어 `run_worker`/`run_selfcheck` call의 positional arg 수가 3을 넘는 위치가 없음을 assert한다.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py CompletingTargetSelfcheckTest ReviewRetryTest RepetitionLimitTest RouteDecisionPersistenceTest SelectorDispatcherIntegrationTest -v` — 영향 호출/상태 전이 회귀 PASS.
- `python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py ThroughputQuotaBatchTest BlockerDrainTest -v` — S11 admission과 독립 branch drain 회귀 PASS.
- `python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_*.py'` — fresh-process 전체 suite PASS이며 semaphore dict가 locator로 출력되지 않는다.
- `python3 -m py_compile agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_dispatch.py` — exit 0.
- `git diff --check` — 출력 없음.

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