<!-- task=m-agent-task-runtime-target-selector/02+01_quota_input plan=0 tag=API -->

# Code Review Reference - API

> **[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-25
task=m-agent-task-runtime-target-selector/02+01_quota_input, plan=0, tag=API

## 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:
  - `quota-input`: Go usage checker 기반 required-cap quota snapshot과 selector admission
- Completion mode: check-on-pass

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

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

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

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

---

## 구현 항목별 완료 여부

| 항목 | 완료 여부 |
|------|---------|
| API-1 Required-cap quota snapshot 정규화 | [x] |
| API-2 Hidden iop-node quota-probe JSON command | [x] |
| API-3 Selector S04 black-box 연결 | [x] |

## 구현 체크리스트

- [x] 기존 `UsageStatus`의 overall/model remaining을 required cap set에 맞춰 `available|exhausted|unknown` snapshot으로 정규화한다.
- [x] raw output을 노출하지 않는 hidden `iop-node quota-probe` JSON command를 추가하고 checker/parse 오류를 `unknown` evidence로 반환한다.
- [x] overall/model cap 0·양수·누락·충돌, local unbounded, unknown work-unit 1회 admission을 Go와 selector black-box 테스트로 검증한다.
- [ ] Go preflight를 재실행하고 `go test -count=1 ./apps/node/internal/adapters/cli/status ./apps/node/cmd/node` 및 selector 테스트를 통과시킨다. 호스트 Go 표준 라이브러리의 `crypto/internal/fips140cache` 누락으로 두 Go package가 setup 단계에서 차단됐다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다.

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

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

- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G09_0.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G07_0.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/02+01_quota_input/`를 `agent-task/archive/YYYY/MM/m-agent-task-runtime-target-selector/02+01_quota_input/`로 이동하고 최종 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`를 작성하지 않는다.

## 계획 대비 변경 사항

- `unknown`의 1회 admission은 selector의 최초 결정 후 `resume`이 persisted decision을 그대로 재사용하는 경계로 black-box 검증했다. 실제 admission batch 상태와 실행 결과에 따른 exhausted 갱신은 plan의 범위 제외인 dispatcher integration Epic에서 소유한다.
- selector 기본 probe source를 실제 hidden command 명칭인 `iop-node quota-probe`로 갱신했다.

## 주요 설계 결정

- `QuotaSnapshot`은 selector가 읽는 `targets[].adapter/target/status`를 포함하고, required cap별 normalized remaining evidence와 deterministic snapshot ID를 추가한다. `UsageStatus.RawOutput`과 checker error 원문은 직렬화하지 않는다.
- overall은 `DailyLimit`의 remaining percent를, model cap은 `model_usage_*` metadata의 case-insensitive exact-name match와 used percent를 사용한다. confirmed 0은 missing/invalid evidence보다 먼저 `exhausted`로 수렴한다.
- hidden command는 `--target`, `--command`, 반복 `--required-cap`, 선택 `--checked-at`만 받으며 command basename으로 selector adapter를 정규화한다. fake checker 주입으로 외부 CLI 실행 없이 schema/error 경로를 검증한다.

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

- required cap 하나의 confirmed 0이 누락 cap보다 우선해 exhausted가 되는가
- 모든 required cap 양수일 때만 available이고 누락·충돌·parse/checker 실패는 unknown인가
- raw PTY output, secret, generic stderr가 quota evidence JSON에 노출되거나 exhausted 판정에 쓰이지 않는가
- hidden command가 existing Go checker를 호출하며 parser를 Python/command에서 복제하지 않는가
- local target은 probe를 호출하지 않고 unbounded/not_applicable이며 unknown은 work unit별 1회만 admission되는가
- predecessor `01_selector_contract` evidence와 S04 black-box schema가 일치하는가

## 검증 결과

### Go 환경 프리플라이트

명령:

```bash
command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT
```

실제 stdout/stderr:

```text
/config/.local/bin/go
/config/opt/go/bin/go
go version go1.26.2 linux/arm64
/config/opt/go
```

### API-1 중간 검증

명령:

```bash
go test -count=1 ./apps/node/internal/adapters/cli/status
```

실제 stdout/stderr:

```text
FAIL iop/apps/node/internal/adapters/cli/status [setup failed]
# iop/apps/node/internal/adapters/cli/status
../../opt/go/src/crypto/ecdsa/ecdsa.go:27:2: package crypto/internal/fips140cache is not in std (/config/opt/go/src/crypto/internal/fips140cache)
FAIL
```

재개 조건: `/config/opt/go`의 표준 라이브러리 source를 go1.26.2 설치와 일치하도록 복구한 뒤 같은 명령을 재실행한다.

### API-2 중간 검증

명령:

```bash
go test -count=1 ./apps/node/cmd/node
```

실제 stdout/stderr:

```text
FAIL iop/apps/node/cmd/node [setup failed]
# iop/apps/node/cmd/node
../../opt/go/src/crypto/ecdsa/ecdsa.go:27:2: package crypto/internal/fips140cache is not in std (/config/opt/go/src/crypto/internal/fips140cache)
FAIL
```

재개 조건: `/config/opt/go`의 표준 라이브러리 source를 go1.26.2 설치와 일치하도록 복구한 뒤 같은 명령을 재실행한다.

### API-3 중간 검증

명령:

```bash
python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_execution_target*.py'
```

실제 stdout/stderr:

```text
python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_execution_target*.py'
.....
----------------------------------------------------------------------
Ran 5 tests in 0.000s

OK

python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py -v
----------------------------------------------------------------------
Ran 30 tests in 0.413s

OK
```

### 최종 검증

명령:

```bash
go test -count=1 ./apps/node/internal/adapters/cli/status ./apps/node/cmd/node
python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_execution_target*.py'
```

실제 stdout/stderr:

```text
go test -count=1 ./apps/node/internal/adapters/cli/status ./apps/node/cmd/node
FAIL iop/apps/node/internal/adapters/cli/status [setup failed]
FAIL iop/apps/node/cmd/node [setup failed]
../../opt/go/src/crypto/ecdsa/ecdsa.go:27:2: package crypto/internal/fips140cache is not in std (/config/opt/go/src/crypto/internal/fips140cache)

python3 -m unittest discover -s agent-ops/skills/project/orchestrate-agent-task-loop/tests -p 'test_execution_target*.py'
Ran 5 tests in 0.000s
OK

python3 agent-ops/skills/project/orchestrate-agent-task-loop/tests/test_select_execution_target.py -v
Ran 30 tests in 0.413s
OK

git diff --check
exit 0
```

Go 검증은 호스트 설치 차단으로 아직 통과하지 못했다. 외부 provider/credential을 호출하지 않았다.

---

> **[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
  - completeness: Fail
  - test coverage: Fail
  - API contract: Fail
  - code quality: Fail
  - implementation deviation: Fail
  - verification trust: Fail
  - spec conformance: Fail
- 발견된 문제:
  - Required — `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/select_execution_target.py:455`: quota가 첫 후보를 `exhausted`/`ineligible`로 판정해도 `selected`는 무조건 `decision.candidates[0]`을 반환한다. 주간 `local-G07`에서 Gemini가 exhausted이고 Laguna가 eligible인 재현에서도 exhausted Gemini가 선택되어 SDD S04의 admission 계약을 위반한다. 첫 eligible 후보를 선택하고, eligible 후보가 없을 때는 exhausted target을 선택하지 않는 결정적 no-eligible 결과를 반환하며 두 경로를 회귀 테스트로 고정해야 한다.
  - Required — `apps/node/internal/adapters/cli/status/quota.go:148`: `strconv.ParseFloat` 결과의 유한성을 확인하지 않아 `NaN%`가 범위 검사에서 빠지고 `available`로 분류된다. 이어지는 JSON 인코딩은 NaN을 지원하지 않아 hidden probe가 `unknown` snapshot 대신 실패한다. `math.IsNaN`/`math.IsInf`를 거부하고 overall/model 양쪽 비유한 percent가 `unknown`으로 수렴하는 테스트를 추가해야 한다.
  - Required — `apps/node/cmd/node/quota_probe.go:37`: Cobra의 required flag 표시는 명시적으로 전달된 빈 `--target=`/`--command=` 값을 막지 않으므로 selector가 거부하는 빈 target 또는 비정상 adapter snapshot을 출력할 수 있다. checker 호출 전에 두 값을 trim·non-empty 검증하고 selector-compatible 입력 오류 테스트를 추가해야 한다.
  - Required — `agent-task/m-agent-task-runtime-target-selector/02+01_quota_input/CODE_REVIEW-cloud-G09.md:55`: 필수 fresh Go 검증이 구현 및 리뷰 양쪽에서 `crypto/internal/fips140cache is not in std` setup 실패로 끝나 API-1/API-2의 컴파일과 회귀를 신뢰할 수 없다. `/config/opt/go` 표준 라이브러리를 go1.26.2 바이너리와 일치하도록 복구한 뒤 지정된 두 패키지 테스트를 `-count=1`로 통과시켜 실제 출력을 기록해야 한다.
- 다음 단계: FAIL 후속을 plan 스킬의 `prepare-follow-up` 모드와 격리 재라우팅으로 준비한다.
