<!-- task=m-principal-provider-credential-slot-routing/04+03_principal_routes plan=3 tag=REVIEW_REVIEW_API -->

# Managed Principal Route Evidence Recovery

## For the Implementing Agent

Filling implementation-owned sections of `CODE_REVIEW-cloud-G05.md` is mandatory. Run every verification command exactly, paste each command's actual stdout/stderr under its own section, keep the active files in place, and report ready for review. Only code-review may append a verdict, rename logs, write `complete.log`, archive task artifacts, or classify a user-review stop. If blocked, record exact blocker evidence, attempted commands/output, and resume conditions only in implementation-owned fields; do not ask the user, call user-input tools, create control-plane stop files, or classify the next state.

## Background

The second implementation fixed the managed route production wiring, but its tests still erase the projected selector and revision values and do not exercise provider-pool recovery re-entry. The submitted review evidence also assigns outputs to commands that could not have produced them. This follow-up is test-and-evidence only: it must prove the existing binding across initial and recovery admission without changing production behavior or activating projection transport.

## Archive Evidence Snapshot

- Failed pair after review archive: `agent-task/m-principal-provider-credential-slot-routing/04+03_principal_routes/plan_cloud_G08_2.log` and `agent-task/m-principal-provider-credential-slot-routing/04+03_principal_routes/code_review_cloud_G09_2.log`.
- Verdict: FAIL; Required=2, Suggested=0, Nit=0; `review_rework_count=2`, `evidence_integrity_failure=true`.
- Required findings: preserve projected resource selector and route/credential revisions in fixtures; prove adverse-order initial and recovery provider-pool admission with identical trusted binding metadata; cover both local and native managed count-tokens; record only actual command output.
- Affected implementation area: `apps/edge/internal/openai/principal_routes_test.go` and the implementation-owned evidence fields in the new review stub.
- Fresh reviewer verification: formatting, vet, focused tests, race tests, affected packages, full `./apps/edge/...`, dormant-activation, and diff checks pass; the blocker is missing/contradictory evidence, not a reproduced production-code failure.
- Roadmap carryover: this remains a dormant foundation packet with no Roadmap Targets; PASS must not check `model-discovery` or `explicit-selection` before authenticated projection transport activation.

## Analysis

### Files Read

- `apps/edge/internal/authprojection/cache.go`
- `apps/edge/internal/authprojection/cache_test.go`
- `apps/edge/internal/openai/principal.go`
- `apps/edge/internal/openai/routes.go`
- `apps/edge/internal/openai/principal_routes.go`
- `apps/edge/internal/openai/route_resolution.go`
- `apps/edge/internal/openai/dispatch_context.go`
- `apps/edge/internal/openai/chat_handler.go`
- `apps/edge/internal/openai/responses_handler.go`
- `apps/edge/internal/openai/anthropic_handler.go`
- `apps/edge/internal/openai/provider_tunnel.go`
- `apps/edge/internal/openai/stream_gate_runtime.go`
- `apps/edge/internal/openai/principal_routes_test.go`
- `apps/edge/internal/openai/provider_test_support_test.go`
- `apps/edge/internal/service/provider_pool.go`
- `apps/edge/internal/service/provider_resolution.go`

### SDD Criteria

- SDD: `agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md`; status `[승인됨]`, lock released.
- Foundation evidence maps to S06 / `model-discovery` and S07 / `explicit-selection`, with Evidence Map row S04-S08 requiring principal isolation, explicit no-fallback selection, and executable management/routing evidence.
- The checklist preserves distinct public route, internal group, provider resource, credential slot, and revisions, and requires repeated admission evidence. Because secure projection delivery remains dormant, this plan intentionally has no Roadmap Targets.

### Verification Context

- No external verification handoff was supplied. Repository-native sources were `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md`, the edge/testing domain rules, the active pair, the prior exact review log, source/tests above, and the two compatible API contracts.
- Local preflight: Go resolves to `/config/.local/bin/go`; `go version go1.26.2 linux/arm64`; `GOROOT=/config/opt/go`. Package-level tests require no credential, network, remote runner, or provider process.
- Fresh reviewer commands proved the current production code compiles and passes focused/race/affected/full Edge suites. Fresh execution is required with `-count=1`; cached output is not acceptable.
- The dormant managed cache cannot be activated or observed by current field/Ollama smoke, so no external/full-cycle smoke is a valid oracle for this test-only follow-up. Confidence is high once the recording double exercises both admissions and every output block matches its command.

### Test Coverage Gaps

- `makeTestProjection` hard-codes `ResourceSelector: "default"` and replaces both revisions with the projection generation, so explicit selector and trusted revision assertions are absent.
- Chat, Responses, and Messages success cases record one selected candidate, not an adverse candidate set, and do not assert all four binding metadata fields.
- `TestManagedRoutePredicateSurvivesRecovery` calls a predicate directly once; it does not construct and submit a recovery admission.
- Managed count-tokens covers only the local `TokenCounter`; the native provider-pool fallback is absent.
- The active review evidence assigns package-test output to `mkdir`, contract-search output to `gofmt`, and an extra package to a one-package test command.

### Symbol References

- None. This follow-up changes no production symbol or public API.

### Split Judgment

- Keep one compact test packet. Fixture fidelity, surface success, recovery re-entry, and evidence fidelity are one verification oracle; splitting would allow a partial PASS without proving the frozen binding.
- Runtime predecessor `03+01,02_projection_auth` is satisfied by `agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/03+01,02_projection_auth/complete.log`.

### Scope Rationale

- Modify no production Go file, contract, spec, roadmap, Control Plane wire/store, connector/runtime activation, credential lease, secret delivery, provider queue accounting, or provider auth injection.
- Reuse existing test service interfaces and fixtures inside `principal_routes_test.go`; change shared `provider_test_support_test.go` only if the required adverse-order recorder cannot remain local to the managed-route test file.

### Final Routing

- `status=routed`, `evaluation_mode=isolated-reassessment`, finalizer=`finalize-task-policy.sh`, pair mode.
- Build closures are all true; scores `1+1+0+2+1=G05`; base=`local-fit`, route=`recovery-boundary`, lane=`cloud`, canonical file=`PLAN-cloud-G05.md`.
- Review closures are all true; scores `1+1+0+2+1=G05`; route=`official-review`, lane=`cloud`, adapter=`codex`, model=`gpt-5.6-sol`, reasoning=`xhigh`, canonical file=`CODE_REVIEW-cloud-G05.md`.
- `large_indivisible_context=false`; positive loop risks=`temporal_state`, `boundary_contract`, `variant_product` (3); `review_rework_count=2`; `evidence_integrity_failure=true`; recovery boundary matched; no capability gap.

## Implementation Checklist

- [ ] Preserve projected resource selector, route revision, and credential revision in the managed test fixture, then assert distinct public route, internal model group, provider resource, credential slot, and all trusted binding metadata on successful Chat, Responses, and Messages dispatch.
- [ ] Replace helper-only recovery coverage with adverse-order initial and recovery provider-pool admissions that reject alternates, preserve the same predicate/internal key/metadata, cover local and native managed count-tokens, and retain generation-swap/no-fallback cases.
- [ ] Run fresh formatting, vet, focused, race, affected-package, full Edge, dormant-activation, and diff verification, recording only each command's actual stdout/stderr in its own review section.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_REVIEW_API-1] Restore fixture fidelity and surface assertions

**Problem:** `apps/edge/internal/openai/principal_routes_test.go:44-46` replaces `ResourceSelector`, `RouteRevision`, and `CredentialRevision`. The success cases at lines 342-416 therefore cannot prove the explicit provider binding and trusted revisions they configure.

**Solution:** Copy the three fields from each `authprojection.Route`. Use four distinct values (`route-public`, `catalog-internal`, `provider-resource`, `credential-slot`) plus non-generation route/credential revisions. For Chat, Responses, and Messages, assert the recorded `Run` and `Tunnel` templates use the internal group, explicit provider, public model echo, and the exact trusted route/slot metadata after caller spoof attempts. Add a managed native count-tokens fallback beside the existing local counter case.

Before (`apps/edge/internal/openai/principal_routes_test.go:37-47`):

```go
proj.Routes = append(proj.Routes, &iop.ProjectedPrincipalRoute{
    RouteId: r.RouteID, PrincipalRef: r.PrincipalRef,
    ResourceSelector: "default",
    RouteRevision: gen, CredentialRevision: gen,
})
```

After:

```go
proj.Routes = append(proj.Routes, &iop.ProjectedPrincipalRoute{
    RouteId: r.RouteID, PrincipalRef: r.PrincipalRef,
    ResourceSelector: r.ResourceSelector,
    RouteRevision: r.RouteRevision, CredentialRevision: r.CredentialRevision,
})
```

**Modified Files and Checklist:**

- [ ] `apps/edge/internal/openai/principal_routes_test.go`: preserve projected fields; add spoof-resistant distinct-identity assertions for Chat, Responses, Messages, local count-tokens, and native count-tokens.

**Test Strategy:** Update the managed surface tests and add `TestManagedProjectionFixturePreservesBindingFacts`, `TestManagedSurfacesUseDistinctBinding`, and `TestManagedCountTokensLocalAndNativeBinding`. Assert provider-pool request fields and all `iop_route_*` / `iop_credential_*` metadata values; do not accept status-only evidence.

**Verification:** `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 ./apps/edge/internal/authprojection ./apps/edge/internal/openai -run 'ManagedProjectionFixture|ManagedSurfacesUseDistinctBinding|ManagedCountTokensLocalAndNative|MetadataSpoof|ExplicitSelector'` passes.

### [REVIEW_REVIEW_API-2] Prove provider-pool recovery re-entry and evidence fidelity

**Problem:** `apps/edge/internal/openai/principal_routes_test.go:277-305` tests only a composed predicate function. No test submits an initial provider-pool request and a real recovery admission with adverse candidate order, so predicate/key/metadata retention is not executable evidence. The active review's command/output blocks are also mismatched.

**Solution:** Add a test-local recording `runService` double that receives ordered candidate lists, evaluates each request's `AcceptCandidate`, records the accepted `ProviderPoolDispatchRequest`, and fails if an alternate provider/profile/model is admitted. Build the recovery request through the production Chat or tunnel recovery admission builder, submit it a second time with reversed adverse order, and compare the internal group, explicit provider, predicate decisions, and all trusted metadata byte-for-byte. Keep the fake deterministic and credential/network free. In the new review stub, paste only raw output from the exact command heading; silent commands must show an empty block and explicit exit status.

**Modified Files and Checklist:**

- [ ] `apps/edge/internal/openai/principal_routes_test.go`: replace helper-only recovery with two actual provider-pool submissions using adverse candidate sequences and frozen binding assertions.
- [ ] `agent-task/m-principal-provider-credential-slot-routing/04+03_principal_routes/CODE_REVIEW-cloud-G05.md`: fill only actual implementation notes and command-specific raw verification output.

**Test Strategy:** Add `TestManagedRecoveryReentersProviderPoolWithFrozenBinding`. The initial order must put wrong slot/provider, wrong profile, and wrong model before the valid candidate; recovery must reverse the adverse order. Require exactly two submissions, one accepted candidate each, identical model-group key and trusted metadata, and zero legacy/global fallback. Run it under `-race`.

**Verification:** `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -race -count=1 ./apps/edge/internal/authprojection ./apps/edge/internal/openai -run 'ManagedRecoveryReentersProviderPool|ManagedSurfacesUseDistinctBinding|ManagedCountTokensLocalAndNative|GenerationSwap|NoFallback'` passes.

## Modified Files Summary

| File | Items |
|------|-------|
| `apps/edge/internal/openai/principal_routes_test.go` | REVIEW_REVIEW_API-1, REVIEW_REVIEW_API-2 |
| `agent-task/m-principal-provider-credential-slot-routing/04+03_principal_routes/CODE_REVIEW-cloud-G05.md` | REVIEW_REVIEW_API-1, REVIEW_REVIEW_API-2 |

## Final Verification

Run from `/config/workspace/iop-s0`. Every Go test is fresh (`-count=1`); paste actual stdout/stderr only under the matching review command.

1. `test "$(find agent-task/archive -type f -path '*/m-principal-provider-credential-slot-routing/03+01,02_projection_auth/complete.log' -print | wc -l)" -eq 1` — exactly one predecessor completion exists; exit 0.
2. `test -z "$(gofmt -d apps/edge/internal/openai/principal_routes_test.go)"` — the modified test file is formatted; exit 0 with no stdout.
3. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go vet ./apps/edge/internal/authprojection ./apps/edge/internal/openai ./apps/edge/internal/service` — no vet findings.
4. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 ./apps/edge/internal/authprojection ./apps/edge/internal/openai -run 'ManagedProjectionFixture|ManagedSurfacesUseDistinctBinding|ManagedCountTokensLocalAndNative|ManagedRecoveryReentersProviderPool|MetadataSpoof|ExplicitSelector|GenerationSwap|NoFallback'` — focused binding/surface/recovery fixtures pass.
5. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -race -count=1 ./apps/edge/internal/authprojection ./apps/edge/internal/openai -run 'ManagedSurfacesUseDistinctBinding|ManagedCountTokensLocalAndNative|ManagedRecoveryReentersProviderPool|GenerationSwap|NoFallback'` — focused race fixtures pass.
6. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 ./apps/edge/internal/authprojection ./apps/edge/internal/openai ./apps/edge/internal/service` — affected package suites pass.
7. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 ./apps/edge/...` — full Edge regression suite passes.
8. `if rg --sort path -n 'PrincipalProjection' apps/control-plane/internal/wire/edge_server.go apps/edge/internal/controlplane/connector.go apps/edge/internal/bootstrap/runtime.go; then exit 1; else exit 0; fi` — unauthenticated runtime remains dormant; exit 0 with no stdout.
9. `git diff --check` — no whitespace errors.

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