<!-- task=m-iop-agent-cli-runtime/08+06,07_quota_failure plan=1 tag=REVIEW_API -->

# Quota and Typed Failure Policy Review Rework

## For the Implementing Agent

Run every verification command and fill the implementation-owned sections of `CODE_REVIEW-*-G??.md` with actual notes and stdout/stderr. Keep the active pair in place and report ready for review; only the code-review skill may append a verdict, archive files, write `complete.log`, or classify the next state. If blocked, record the exact blocker, attempted command/output, and resume condition in the implementation-owned evidence fields; do not ask the user, call user-input tools, or create control-plane stop files.

## Background

The first review found that the new quota snapshot can be tampered without invalidating its ID, `not_applicable` is absent from S07, and malformed corrupt evidence cannot reliably become a durable work-unit blocker. The manager also accepts a selector-produced final continuation decision instead of invoking the common policy algorithm, so policy order and unused-target history are not enforced by the runtime path. The implementation evidence and authoritative shared-runtime contract remain incomplete.

## Archive Evidence Snapshot

- Prior plan: `agent-task/m-iop-agent-cli-runtime/08+06,07_quota_failure/plan_cloud_G09_0.log`
- Prior review: `agent-task/m-iop-agent-cli-runtime/08+06,07_quota_failure/code_review_cloud_G09_0.log`
- Verdict: `FAIL`
- Findings: 5 Required, 0 Suggested, 0 Nit.
- Required summary:
  - Bind quota snapshot ID to normalized content, allow only safe reason codes, and sanitize corrupt evidence before durable storage.
  - Add S07 `not_applicable` semantics.
  - Make the manager invoke `agentpolicy.DecideContinuation` from policy-source inputs and enforce durable unused-target history.
  - Synchronize `iop.agent-runtime` continuation API/state semantics.
  - Fill all implementation-owned review evidence.
- Affected files: `packages/go/agentprovider/cli/status/quota.go`, `packages/go/agentpolicy/{quota.go,failure_policy.go}`, `packages/go/agenttask/{ports.go,dispatch.go}`, their tests, and the two runtime contracts.
- Reviewer verification:
  - Focused package tests passed: `agentruntime`, CLI status, `agentpolicy`, and `agenttask`.
  - `go test -count=1 -race ./packages/go/agentpolicy ./packages/go/agenttask` passed.
  - `go vet ./packages/go/...`, `go test -count=1 ./packages/go/...`, and `git diff --check` passed.
  - `rg --sort path -n 'RawOutput' packages/go/agentpolicy packages/go/agenttask` returned no matches with exit code 1.
- Roadmap carryover: S07 / `quota-failure` remains incomplete; the Milestone was not modified.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md)
- Task ids:
  - `quota-failure`: typed quota/failure와 policy-only retry/failover
- Completion mode: check-on-pass

## Analysis

### Files Read

- `packages/go/agentprovider/cli/status/quota.go`
- `packages/go/agentprovider/cli/status/quota_test.go`
- `packages/go/agentruntime/status.go`
- `packages/go/agentruntime/failure.go`
- `packages/go/agentruntime/failure_test.go`
- `packages/go/agentconfig/runtime_config.go`
- `packages/go/agentpolicy/decision.go`
- `packages/go/agentpolicy/evaluator.go`
- `packages/go/agentpolicy/quota.go`
- `packages/go/agentpolicy/failure_policy.go`
- `packages/go/agentpolicy/failure_policy_test.go`
- `packages/go/agenttask/ports.go`
- `packages/go/agenttask/dispatch.go`
- `packages/go/agenttask/failure_continuation_test.go`
- `packages/go/agenttask/types.go`
- `packages/go/agenttask/state_machine.go`
- `packages/go/agenttask/manager.go`
- `agent-contract/inner/agent-runtime.md`
- `agent-contract/inner/iop-agent-cli-runtime.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`

### SDD Criteria

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`; status `[승인됨]`, lock `해제`.
- Target: S07 / `quota-failure`.
- Acceptance: available/exhausted/unknown/not-applicable evidence, immutable isolated snapshots, declared-policy-only retry/failover, and unknown as a work-unit blocker.
- Evidence Map: quota parser, runtime observation, isolation, and failover tests; PASS must provide snapshot/failure transition evidence in `Roadmap Completion`.
- These criteria require tamper rejection, explicit not-applicable behavior, durable safe blocker evidence, actual common-policy invocation, unused candidate history, and manager integration tests.

### Test Environment Rules

- `test_env=local`.
- Read `agent-test/local/rules.md` and matched `agent-test/local/platform-common-smoke.md`.
- Applied preflight (`command -v go`, `go version`, `go env GOROOT`, worktree status), focused fresh package tests, race tests for state transitions, `go vet ./packages/go/...`, full shared-package tests, formatting, deterministic searches, and `git diff --check`.
- No external service or credential is required. No current user executable instantiates this standalone manager path, so field/full-cycle smoke belongs to S14 and is not required for this repair.

### Test Coverage Gaps

- Existing tests cover basic available retry, exhausted failover, unknown/stale/corrupt blockers, failure budget, and omission of failure message/metadata.
- Missing: snapshot content/ID tampering, arbitrary reason-code rejection, explicit not-applicable, malformed corrupt identity through manager persistence, and source-slice mutation.
- Missing: manager integration that calls `DecideContinuation`; current tests fabricate the final decision and do not prove reused-candidate rejection over multiple failed attempts.
- Missing: authoritative contract conformance search and filled implementation evidence.

### Symbol References

- `FailureContinuationSelector`, `FailureContinuation`, and `Continue` occur in `packages/go/agenttask/ports.go`, `packages/go/agenttask/dispatch.go`, and `packages/go/agenttask/failure_continuation_test.go`.
- `DecideContinuation` currently occurs only in `packages/go/agentpolicy/failure_policy.go` and its unit tests; the repaired production call must be in `packages/go/agenttask/dispatch.go`.
- No dependency manifest change is needed.

### Split Judgment

- Keep one plan: quota normalization and manager continuation form one S07 fail-closed invariant, and manager PASS evidence depends on the exact observation and decision types.
- Predecessor `06` is satisfied by `agent-task/archive/2026/07/m-iop-agent-cli-runtime/06+05_config_registry/complete.log`.
- Predecessor `07` is satisfied by `agent-task/archive/2026/07/m-iop-agent-cli-runtime/07+06_target_policy/complete.log`.

### Scope Rationale

- Include only shared quota normalization, common policy decision inputs, manager continuation persistence, tests, and authoritative runtime contracts.
- Exclude provider transport/parser redesign beyond quota snapshot validation, standalone CLI wiring, Edge provider-pool behavior, config schema expansion, project logs/UI, and S08/S09/S14/S19 work.

### Final Routing

- `evaluation_mode=isolated-reassessment`; `finalizer=finalize-task-policy.sh`, mode `pair`.
- Build closures: scope/context/verification/evidence/ownership/decision are all closed; no capability gap.
- Build scores: scope=2, state=2, blast=2, evidence=2, verification=1; grade `G09`.
- Build: base/final basis `grade-boundary`, lane `cloud`, filename `PLAN-cloud-G09.md`.
- `large_indivisible_context=false`.
- Positive loop risks: `temporal_state`, `boundary_contract`, `variant_product`; count=3.
- Recovery signals: `review_rework_count=1`, `evidence_integrity_failure=true`; recovery boundary matched but does not replace grade-boundary.
- Review closures are closed; scores 2/2/2/2/1; route `official-review`, `cloud G09`, Codex `gpt-5.6-sol` xhigh, filename `CODE_REVIEW-cloud-G09.md`.

## Implementation Checklist

- [ ] Validate quota snapshot content integrity and durable reason codes, and sanitize invalid evidence into a secret-free corrupt work-attempt observation.
- [ ] Represent `not_applicable` explicitly through status normalization and retry/failover decisions while unknown, stale, and corrupt evidence remain blocking.
- [ ] Make `agenttask.Manager` invoke `agentpolicy.DecideContinuation` from policy-source inputs, derive used targets from durable attempt history, and reject fabricated, reused, or over-budget continuations.
- [ ] Add snapshot-tamper, unsafe-reason, not-applicable, malformed-observation, multi-failure unused-candidate, and budget regression tests.
- [ ] Synchronize authoritative runtime contracts and run focused, race, vet, full shared-package, search, formatting, and diff checks.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Seal and sanitize quota evidence

**Problem:** `packages/go/agentpolicy/quota.go:85-115` checks only the syntax of `SnapshotID`; changing target status, caps, time, or reasons leaves the snapshot valid. Lines 145-146 then reject a malformed ID even when normalization marked it corrupt, preventing durable typed-blocker persistence. `QuotaState` at lines 17-21 omits S07 `not_applicable`.

**Solution:** Make CLI status own a strict `ValidateQuotaSnapshot` check whose digest covers schema/source, checked time, target, sorted cap evidence, and allowlisted reason codes. Emit `not_applicable` for an empty declared cap set with a stable reason code. Agentpolicy must validate before projection, replace invalid input with a canonical secret-free corrupt observation, expose a sanitizer for untrusted invocation observations, and treat not-applicable as quota-neutral for a policy-declared retry or candidate.

Before (`packages/go/agentpolicy/quota.go:85`):

```go
observation := QuotaObservation{
    SnapshotID: snapshot.SnapshotID,
    Reasons:    cloneStrings(snapshot.ReasonCodes),
    Validity:   ObservationCorrupt,
}
```

After:

```go
if err := status.ValidateQuotaSnapshot(snapshot); err != nil {
    return CorruptQuotaObservation()
}
observation := projectValidatedQuota(snapshot)
```

**Modified Files and Checklist:**

- [ ] `packages/go/agentprovider/cli/status/quota.go`: content-bound validation, safe reason registry, and not-applicable normalization.
- [ ] `packages/go/agentprovider/cli/status/quota_test.go`: tamper/reason/not-applicable matrices.
- [ ] `packages/go/agentpolicy/quota.go`: sanitized corrupt projection and explicit not-applicable.
- [ ] `packages/go/agentpolicy/failure_policy.go`: not-applicable decision semantics.
- [ ] `packages/go/agentpolicy/failure_policy_test.go`: immutable projection, tamper, sanitizer, and not-applicable tests.

**Test Strategy:** Add `TestValidateQuotaSnapshotRejectsTampering`, `TestNormalizeQuotaSnapshotNotApplicable`, `TestNormalizeQuotaObservationSanitizesCorruptEvidence`, and `TestDecideContinuationNotApplicable`. Mutate every integrity-covered field after snapshot creation, inject a secret-like unknown reason, mutate input slices after normalization, and assert no input diagnostic enters encoded observation state.

**Verification:**

```bash
go test -count=1 -run 'Test(ValidateQuotaSnapshotRejectsTampering|NormalizeQuotaSnapshotNotApplicable|NormalizeQuotaObservationSanitizesCorruptEvidence|DecideContinuationNotApplicable)$' ./packages/go/agentprovider/cli/status ./packages/go/agentpolicy
```

Expected: all named tests pass.

### [REVIEW_API-2] Put the common policy decision in the manager path

**Problem:** `packages/go/agenttask/ports.go:146-159` lets a selector return a finished action and target. `dispatch.go:389-470` never calls `DecideContinuation`, while the test at `failure_continuation_test.go:48-55` fabricates that decision. Ordered eligibility, used-target exclusion, and failure policy are therefore not enforced by the common runtime path.

**Solution:** Replace the final-decision return port with a policy-source result containing declared failure policy plus ordered candidate quota/target inputs. Manager supplies the exact current target, durable attempted-target history, normalized observation, and pending budget to `agentpolicy.DecideContinuation`; only then may it resolve the returned identity to the current target or an exact supplied candidate. Invalid observation input is first canonicalized to a secret-free corrupt observation and persisted as a typed blocker. Keep attempt observations as the durable used-route history and add a two-failure failover case proving the first alternate cannot be reused.

Before (`packages/go/agenttask/ports.go:146`):

```go
type FailureContinuation struct {
    Decision agentpolicy.ContinuationDecision
    Target   *ExecutionTarget
}
```

After:

```go
type FailureContinuationPolicy struct {
    Policy     agentpolicy.FailurePolicy
    Candidates []FailureContinuationCandidate
}
```

**Modified Files and Checklist:**

- [ ] `packages/go/agenttask/ports.go`: policy-source input contract; no caller-supplied final decision.
- [ ] `packages/go/agenttask/dispatch.go`: sanitize evidence, derive used history, call `DecideContinuation`, map exact target, and persist blocker/history atomically.
- [ ] `packages/go/agenttask/failure_continuation_test.go`: real policy invocation, malformed evidence, multi-failure unused-candidate, and budget cases.

**Test Strategy:** Replace fabricated decisions with declared policy/candidate fixtures. Add `TestFailureContinuationUsesCommonPolicyAndSkipsUsedCandidate` and `TestFailureContinuationMalformedObservationBecomesTypedBlocker`; assert invocation counts, target order, attempt IDs, durable observations, blockers, and absence of secret diagnostics.

**Verification:**

```bash
go test -count=1 -run 'TestFailureContinuation(UsesCommonPolicyAndSkipsUsedCandidate|MalformedObservationBecomesTypedBlocker|UnknownAndBudgetBlockWork)$' ./packages/go/agenttask
```

Expected: manager tests pass and production `dispatch.go` calls `agentpolicy.DecideContinuation`.

### [REVIEW_API-3] Synchronize contracts and completion evidence

**Problem:** `agent-contract/inner/agent-runtime.md:94-101` documents only the failure codec, while the standalone contract assigns retry/failover ownership to the shared runtime. The active review evidence was entirely blank.

**Solution:** Add the observation schema, content integrity, not-applicable, policy-source/manager decision boundary, used-route history, budget, typed blockers, and no-diagnostic rules to `iop.agent-runtime`. Mark S07 source/evidence status accurately in the standalone contract. After fresh verification, fill every implementation-owned review section without modifying review-only fields.

**Modified Files and Checklist:**

- [ ] `agent-contract/inner/agent-runtime.md`: authoritative shared observation/continuation contract.
- [ ] `agent-contract/inner/iop-agent-cli-runtime.md`: S07 implementation source and evidence ownership pointers.
- [ ] `agent-task/m-iop-agent-cli-runtime/08+06,07_quota_failure/CODE_REVIEW-cloud-G09.md`: completion, decisions, deviations, and actual output.

**Test Strategy:** No separate document-only test. Contract claims are checked by focused behavior tests and deterministic symbol searches; review evidence must contain actual command output.

**Verification:**

```bash
rg --sort path -n 'not_applicable|DecideContinuation|failure_budget_exhausted|unused' packages/go/agentprovider/cli/status packages/go/agentpolicy packages/go/agenttask agent-contract/inner/agent-runtime.md agent-contract/inner/iop-agent-cli-runtime.md
```

Expected: code, tests, and both contracts expose consistent S07 anchors.

## Modified Files Summary

| File | Item |
|---|---|
| `packages/go/agentprovider/cli/status/quota.go` | REVIEW_API-1 |
| `packages/go/agentprovider/cli/status/quota_test.go` | REVIEW_API-1 |
| `packages/go/agentpolicy/quota.go` | REVIEW_API-1 |
| `packages/go/agentpolicy/failure_policy.go` | REVIEW_API-1 |
| `packages/go/agentpolicy/failure_policy_test.go` | REVIEW_API-1 |
| `packages/go/agenttask/ports.go` | REVIEW_API-2 |
| `packages/go/agenttask/dispatch.go` | REVIEW_API-2 |
| `packages/go/agenttask/failure_continuation_test.go` | REVIEW_API-2 |
| `agent-contract/inner/agent-runtime.md` | REVIEW_API-3 |
| `agent-contract/inner/iop-agent-cli-runtime.md` | REVIEW_API-3 |
| `agent-task/m-iop-agent-cli-runtime/08+06,07_quota_failure/CODE_REVIEW-cloud-G09.md` | REVIEW_API-3 |

## Dependencies and Execution Order

1. Predecessor `06+05_config_registry` is complete at `agent-task/archive/2026/07/m-iop-agent-cli-runtime/06+05_config_registry/complete.log`.
2. Predecessor `07+06_target_policy` is complete at `agent-task/archive/2026/07/m-iop-agent-cli-runtime/07+06_target_policy/complete.log`.
3. Implement REVIEW_API-1 before REVIEW_API-2 so manager tests consume the final safe observation contract.
4. Synchronize contracts and evidence after behavior and verification are final.

## Final Verification

```bash
command -v go && go version && go env GOROOT
gofmt -d packages/go/agentprovider/cli/status/quota.go packages/go/agentprovider/cli/status/quota_test.go packages/go/agentpolicy/quota.go packages/go/agentpolicy/failure_policy.go packages/go/agentpolicy/failure_policy_test.go packages/go/agenttask/ports.go packages/go/agenttask/dispatch.go packages/go/agenttask/failure_continuation_test.go
go test -count=1 ./packages/go/agentruntime ./packages/go/agentprovider/cli/status ./packages/go/agentpolicy ./packages/go/agenttask
go test -count=1 -race ./packages/go/agentpolicy ./packages/go/agenttask
go vet ./packages/go/...
go test -count=1 ./packages/go/...
rg --sort path -n 'DecideContinuation\\(' packages/go/agentpolicy packages/go/agenttask
if rg --sort path -n 'RawOutput' packages/go/agentpolicy packages/go/agenttask; then exit 1; else test $? -eq 1; fi
git diff --check
```

Expected: preflight resolves Go, formatting emits no diff, all focused/race/full tests and vet pass, production `agenttask` calls `DecideContinuation`, no `RawOutput` reference exists in durable policy/task packages, and the diff check is clean. Fresh `-count=1` output is required.

After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.
