<!-- task=m-principal-provider-credential-slot-routing/05+01,02_management_core plan=5 tag=REVIEW_REVIEW_REVIEW_API -->

# Credential Management Core Security Evidence Closure

## For the Implementing Agent

Filling implementation-owned sections of `CODE_REVIEW-cloud-G05.md` is mandatory. Run every verification command, paste actual output, keep active files in place, and report ready for review; only code-review may finalize, rename logs, write `complete.log`, or archive. If blocked, record exact blocker evidence, attempted commands/output, and resume conditions only in implementation-owned evidence fields; do not ask the user, call user-input tools, create stop files, classify the next state, archive logs, or write `complete.log`.

## Background

The credential management core implementation now passes its focused and regression suites, and source inspection shows the intended token and secret-handling logic. The permanent tests still do not prove several assertions fixed by the active plan: additional-token commit atomicity and raw-token non-persistence, plus create/rotate failure-path zeroization, redaction, and exact no-mutation behavior. This test-only follow-up closes those evidence gaps without changing the dormant service contract or claiming S08 completion.

## Archive Evidence Snapshot

- Current pair after archive: `agent-task/m-principal-provider-credential-slot-routing/05+01,02_management_core/plan_cloud_G06_4.log`, `agent-task/m-principal-provider-credential-slot-routing/05+01,02_management_core/code_review_cloud_G06_4.log`.
- Verdict: FAIL; Required 2, Suggested 0, Nit 0; `review_rework_count=3`, `evidence_integrity_failure=true`.
- Required repairs: prove additional-token generation, digest-only persistence, stable listing, and rejected-issuance atomicity; prove successful and failing create/rotate secret paths zeroize owned buffers, preserve caller buffers, redact errors/logs, and leave exact store state unchanged on failure.
- Fresh reviewer verification: both focused race suites, full credentialstore/credentialops race tests, Control Plane regression tests, predecessor checks, formatting, vet, structural absence, probe absence, and `git diff --check` passed. Source inspection showed that the selected tests do not contain the required assertions.
- Roadmap carryover: this remains a preparatory S08 foundation. PASS must not check `credential-management`; concrete at-rest sealing and confidential Client transport remain later S09/S10 work.

## Analysis

### Files Read

- `apps/control-plane/internal/credentialstore/principal.go`
- `apps/control-plane/internal/credentialstore/principal_test.go`
- `apps/control-plane/internal/credentialstore/projection.go`
- `apps/control-plane/internal/credentialstore/slot.go`
- `apps/control-plane/internal/credentialstore/secret_envelope.go`
- `apps/control-plane/internal/credentialops/service.go`
- `apps/control-plane/internal/credentialops/service_test.go`
- `apps/control-plane/internal/wire/client.go`
- `proto/iop/control.proto`
- `agent-contract/inner/client-control-plane-wire.md`
- `agent-spec/control/control-plane-operations.md`
- `agent-ops/rules/project/domain/control-plane/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/control-plane-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-roadmap/phase/operational-observability-provider-management/PHASE.md`
- `agent-roadmap/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md`
- `agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md`
- `agent-task/m-principal-provider-credential-slot-routing/05+01,02_management_core/plan_local_G07_3.log`
- `agent-task/m-principal-provider-credential-slot-routing/05+01,02_management_core/code_review_cloud_G07_3.log`

### SDD Criteria

- SDD: `agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md`; status approved, lock released, no user review.
- Targeted foundation criterion: S08 / `credential-management`; Evidence Map row S04-S08 requires management authorization, principal isolation, lifecycle revisions, and secret-blind results.
- This packet strengthens only the evidence required to judge the existing preparatory S08 core. `Roadmap Targets` remains omitted because production sealing and confidential remote management required by S09/S10 remain outside this packet.

### Verification Context

- No external verification handoff was supplied. Repository-native evidence came from the local test rules, Go module, current source/tests, approved SDD, Client wire contract, prior exact loop logs, and fresh reviewer commands.
- Preflight: `/config/.local/bin/go`, Go 1.26.2 linux/arm64, `GOROOT=/config/opt/go`, repository root `/config/workspace/iop-s0`, intentional dirty worktree preserved.
- Preconditions: archived `01_principal_store` and `02+01_credential_catalog` each have exactly one `complete.log`.
- Fresh baseline: both focused race suites, full credentialstore/credentialops race tests, Control Plane regression, formatting, vet, structural absence, probe absence, and diff checks exit zero.
- No remote runner, external provider, credential, TLS endpoint, UI, protobuf generation, or full-cycle user flow is required because this packet modifies deterministic package tests only. Confidence: high.

### Test Coverage Gaps

- `TestAdditionalTokenIssueAndList` does not assert projection-generation increments, rejected-issuance non-mutation, exact digest-only persistence for each additional raw token, or stable list order and metadata.
- `TestServiceZeroizesOwnedProviderSecret` observes retained buffers only after successful create/rotate and does not assert the caller-owned input remains unchanged.
- `TestServiceSecretHandlingFailureIsBlindAndDoesNotMutate` exercises failing-sealer and unknown-key behavior only for create, while its failing sealer discards the owned slice. It does not cover failed rotate, invalid-envelope variants, failure-path zeroization, or exact slot envelope/revision/history/generation preservation.

### Symbol References

- No production symbol is renamed or removed.
- Test fixture changes remain local to `principal_test.go` and `service_test.go`; production callers and imports are unchanged.

### Split Judgment

- Keep one packet: the two test files close one review evidence-integrity boundary for the same credential management core. Both focused suites and the final package regression must pass together before the existing implementation can be trusted.
- Runtime predecessors 01 and 02 remain satisfied by their unique archived `complete.log` files.

### Scope Rationale

- Modify only `principal_test.go` and `service_test.go`; current source inspection does not justify a production change.
- Do not change credentialstore/service APIs, protobuf, ClientServer, Dart, CLI, config, server wiring, contracts, schema, concrete encryption/key loading, remote management, or roadmap state.
- If a new assertion exposes a production defect, stop and record the exact failure instead of expanding this test-only packet silently.

### Final Routing

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

## Dependencies and Execution Order

1. Archived predecessors `01_principal_store` and `02+01_credential_catalog` remain complete.
2. Strengthen the store token evidence, then complete the service secret-failure matrix and run the combined regression.

## Implementation Checklist

- [ ] Strengthen additional-token store evidence for exact projection generation, digest-only persistence, stable ordered metadata, and no mutation on rejected issuance.
- [ ] Complete create/rotate secret success and failure evidence for owned-buffer zeroization, caller-buffer preservation, stable redaction, and exact store no-mutation behavior.
- [ ] Run fresh focused race, full package race, Control Plane regression, predecessor, formatting, vet, structural-absence, probe-absence, and diff verification.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_REVIEW_REVIEW_API-1] Make additional-token persistence evidence exact

**Problem:** `apps/control-plane/internal/credentialstore/principal_test.go:716-753` verifies only successful issuance, principal identity, a three-row count, and a missing-principal error. It does not prove the plan-required generation bump, digest-only persistence, stable ordering/status metadata, or transaction non-mutation on rejection.

**Solution:** Expand `TestAdditionalTokenIssueAndList` to snapshot `ProjectionGeneration` before and after each operation, derive the expected SHA-256 digest from each returned raw token, inspect each persisted token row, and compare the entire ordered list against initial/additional token refs and statuses. Snapshot token count and generation before the missing-principal attempt and assert both remain unchanged.

Before (`apps/control-plane/internal/credentialstore/principal_test.go:725-748`):

```go
tok1, err := store.CreateToken(ctx, issuedP.Principal.ID)
// ...
list, err := store.ListTokens(ctx, issuedP.Principal.ID)
if len(list) != 3 {
    t.Fatalf("ListTokens count: got %d want 3", len(list))
}
```

After:

```go
generationBefore, err := store.ProjectionGeneration(ctx)
tok1, err := store.CreateToken(ctx, issuedP.Principal.ID)
generationAfter, err := store.ProjectionGeneration(ctx)
// Assert generationAfter == generationBefore+1, exact digest-only persistence,
// deterministic list order/statuses, and unchanged count/generation on rejection.
```

**Modified Files and Checklist:**

- [ ] `apps/control-plane/internal/credentialstore/principal_test.go`: make `TestAdditionalTokenIssueAndList` assert generation, digest-only rows, order/status metadata, and rejected-issuance atomicity.

**Test Strategy:** Update the existing test rather than add overlapping cases. Use the store's durable `ProjectionGeneration`, direct test-owned DB inspection, and SHA-256 derivation from both one-time raw tokens. Assert no raw token occurs in any returned/persisted field and the failed missing-principal call changes neither rows nor generation.

**Verification:** `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 -race ./apps/control-plane/internal/credentialstore -run 'AdditionalTokenIssueAndList'` exits 0.

### [REVIEW_REVIEW_REVIEW_API-2] Complete secret failure-path evidence

**Problem:** `apps/control-plane/internal/credentialops/service_test.go:856-985` proves retained-slice clearing only on successful create/rotate. `failingSealer` discards its input, and the failure test covers only create for both an injected error and unknown key, so failed rotate zeroization, caller ownership, redaction, and exact no-mutation behavior remain untested.

**Solution:** Replace the separate success-only retaining and discard-only failing fixtures with retaining sealers that can return either a valid envelope, an injected sensitive error, or invalid/unknown-key envelopes. Exercise create and rotate for every applicable outcome. After each return, assert the retained service-owned slice is zeroed, the caller slice is unchanged, returned errors/logs exclude plaintext/error/key sentinels, and failed operations preserve slot count or the existing slot's revision, envelope, revision-history count, and projection generation exactly.

Before (`apps/control-plane/internal/credentialops/service_test.go:922-927`):

```go
type failingSealer struct {
    err error
}

func (f *failingSealer) Seal(_ context.Context, _ []byte, _ SecretContext) (credentialstore.SecretEnvelope, error) {
    return credentialstore.SecretEnvelope{}, f.err
}
```

After:

```go
type retainingSealer struct {
    retained []byte
    envelope credentialstore.SecretEnvelope
    err      error
}

func (r *retainingSealer) Seal(_ context.Context, plaintext []byte, _ SecretContext) (credentialstore.SecretEnvelope, error) {
    r.retained = plaintext
    return r.envelope, r.err
}
```

**Modified Files and Checklist:**

- [ ] `apps/control-plane/internal/credentialops/service_test.go`: add a deterministic create/rotate matrix for successful, failing-sealer, invalid-envelope, and unknown-key outcomes with zeroization, caller ownership, redaction, and no-mutation assertions.

**Test Strategy:** Strengthen `TestServiceZeroizesOwnedProviderSecret` and `TestServiceSecretHandlingFailureIsBlindAndDoesNotMutate`. Use unique provider, sealer-error, ciphertext, nonce, AAD, key-id, and version sentinels; capture logs; and snapshot store slot/revision/envelope/history/generation state before every failure. Keep all fixtures package-local and deterministic.

**Verification:** `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 -race ./apps/control-plane/internal/credentialops -run 'ZeroizesOwnedProviderSecret|SecretHandlingFailureIsBlindAndDoesNotMutate'` exits 0.

## Modified Files Summary

| File | Items |
|------|-------|
| `apps/control-plane/internal/credentialstore/principal_test.go` | REVIEW_REVIEW_REVIEW_API-1 |
| `apps/control-plane/internal/credentialops/service_test.go` | REVIEW_REVIEW_REVIEW_API-2 |
| `agent-task/m-principal-provider-credential-slot-routing/05+01,02_management_core/CODE_REVIEW-cloud-G05.md` | REVIEW_REVIEW_REVIEW_API-1, REVIEW_REVIEW_REVIEW_API-2 |

## Final Verification

Run from `/config/workspace/iop-s0`; fresh Go results are required and cached output is not acceptable.

1. `test "$(find agent-task/archive -type f -path '*/m-principal-provider-credential-slot-routing/01_principal_store/complete.log' -print | wc -l)" -eq 1 && test "$(find agent-task/archive -type f -path '*/m-principal-provider-credential-slot-routing/02+01_credential_catalog/complete.log' -print | wc -l)" -eq 1` — both predecessors remain uniquely complete.
2. `mkdir -p .cache/go-build .cache/go-cache` — workspace-local Go temp/cache paths exist.
3. `test -z "$(gofmt -d apps/control-plane/internal/credentialstore/principal_test.go apps/control-plane/internal/credentialops/service_test.go)"` — no Go formatting drift.
4. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go vet ./apps/control-plane/internal/credentialstore ./apps/control-plane/internal/credentialops` — no vet findings.
5. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 -race ./apps/control-plane/internal/credentialstore ./apps/control-plane/internal/credentialops` — all store/service lifecycle, security, and race tests pass.
6. `GOTMPDIR=/config/workspace/iop-s0/.cache/go-build GOCACHE=/config/workspace/iop-s0/.cache/go-cache go test -count=1 ./apps/control-plane/...` — the Control Plane regression suite passes.
7. `if rg --sort path -n 'message[[:space:]]+.*(Bootstrap|CredentialOperation)|AddRequestListenerTyped.*Credential' proto/iop/control.proto apps/control-plane/internal/wire/client.go; then exit 1; else exit 0; fi` — no plaintext Client management operation exists.
8. `test ! -e apps/control-plane/internal/credentialops/reviewer_probe_test.go` — no reviewer probe remains.
9. `git diff --check` — no whitespace errors.

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