<!-- task=m-principal-provider-credential-slot-routing/08+03,04,07_secure_delivery plan=6 tag=REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API milestone-task=secure-transport,credential-lease,adapter-injection,revocation -->

# Context-aware Projection Batch Admission Follow-up

## For the Implementing Agent

Filling the implementation-owned sections of `CODE_REVIEW-cloud-G06.md` is mandatory. Implement the item below, run every verification command exactly, paste actual notes and stdout/stderr into the review artifact, keep both active files in place, and report ready for review. Final verdicts, log archives, `complete.log`, task moves, user-review classification, and control-plane stop files belong only to the code-review workflow. If blocked, record the exact blocker, attempted commands/output, and resume condition only in implementation-owned evidence; do not ask the user or classify the next state.

## Background

Concurrent per-Edge projection sends and client-close cancellation now bound an active batch. Batch serialization still uses an unconditional mutex acquisition, so a refresh queued behind a mutation broadcast cannot observe cancellation and can delay `EdgeServer.Stop`. This follow-up makes admission to the serialized batch context-aware without changing projection content or per-client fan-out.

## Archive Evidence Snapshot

- `plan_cloud_G07_5.log` and `code_review_cloud_G07_5.log`: current-pair predicted archives; verdict `FAIL` with 1 Required, 0 Suggested, and 0 Nit findings. Planned focused, wire race, package, process, vet, diff, and secret guards passed on fresh review, except one unrelated connector stop assertion that passed a focused race run 20 times and the full affected race retry. A reviewer reproducer proved that a canceled `broadcastProjection` remained blocked behind `broadcastMu` beyond 200ms.
- `plan_cloud_G10_4.log` and `code_review_cloud_G10_4.log`: prior fan-out finding. The current source satisfies concurrent per-client delivery and closes/drains stalled sends, but not context-aware batch admission.
- `agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/03+01,02_projection_auth/complete.log`, `agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/04+03_principal_routes/complete.log`, and `agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/07+01,02,05_secret_material/complete.log`: projection, route-binding, and secret-at-rest predecessors remain satisfied.

## Analysis

### Files Read

- `apps/control-plane/internal/wire/edge_server.go`
- `apps/control-plane/internal/wire/edge_server_test.go`
- `apps/control-plane/cmd/control-plane/server.go`
- `/config/workspace/proto-socket/go/communicator.go`
- `/config/workspace/proto-socket/go/base_client.go`
- `/config/workspace/proto-socket/go/tcp_client.go`
- `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-contract/inner/control-plane-edge-wire.md`
- `agent-spec/control/control-plane-operations.md`
- `agent-task/m-principal-provider-credential-slot-routing/08+03,04,07_secure_delivery/PLAN-cloud-G07.md`
- `agent-task/m-principal-provider-credential-slot-routing/08+03,04,07_secure_delivery/CODE_REVIEW-cloud-G07.md`

### SDD Criteria

- SDD: `agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md`; status approved and lock released.
- First-line Milestone tasks remain `secure-transport,credential-lease,adapter-injection,revocation`.
- Acceptance S02 requires refresh before expiry; S10-S13 require authenticated delivery and current generation/revision fencing through lease acquisition, adapter admission, and revocation.
- Evidence Map S09-S13 requires TLS, lease, upstream-auth, revocation-order, and secret-scan evidence. The implementation checklist adds a deterministic cancellation-at-batch-admission regression and retains the secure-delivery race and process evidence for those rows.

### Verification Context

- No external handoff was supplied. Repository-native evidence came from the active pair, approved SDD, current source/tests, the local proto-socket dependency, and fresh reviewer execution.
- Fresh focused fan-out and wire race commands passed. Shared packages, Control Plane/Edge/Node packages, the three-process secure-delivery target, vet, diff, and secret guard passed. The affected race packet passed on retry; its single earlier `TestConnectorStopClosesConnection` failure did not reproduce in 20 focused race runs.
- A reviewer-only test held the batch mutex, called `broadcastProjection` with a cancellable context, canceled it, and failed after the call remained blocked for 200ms. The temporary test file was removed.
- Verification stays in the current checkout with `GOCACHE=/config/tmp/gocache-secure-delivery`, `GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery`, and `TMPDIR=/config/workspace/.gotmp-iop-secure-delivery`. No external runner, credential, or user authorization is required.
- Confidence: high. The blocking edge is the unconditional `sync.Mutex.Lock`, and the reviewer reproducer exercises it directly.

### Test Coverage Gaps

- Existing tests cover independently attempted Edges, stalled-response deadlines, active-refresh cancellation, responsive/rejecting clients, mutation broadcasts, and shutdown after an in-flight send.
- No checked-in test covers caller cancellation or refresh shutdown while batch admission is queued behind another serialized broadcast.

### Symbol References

- None. No public or existing symbol needs renaming or removal; the fix may replace the private batch-lock field and add private acquisition/release helpers.

### Split Judgment

Keep one plan. Context-aware batch admission and its cancellation regression are one compact concurrency invariant and both production and test changes must PASS together. Dependencies 03, 04, and 07 are satisfied by the three archived `complete.log` files cited above.

### Scope Rationale

- Do not modify proto-socket, projection payloads, generation/revision semantics, per-client send behavior, public protobuf schemas, TLS/lease contracts, credential persistence, contracts, specs, or tracked documentation.
- Keep whole projection batches serialized and preserve stable Edge ordering plus concurrent per-client error aggregation. Change only how callers wait to enter a batch.

### Final Routing

- Evaluation mode: `isolated-reassessment`.
- Finalizer: `finalize-task-policy.sh`, mode `pair`; build and review closures are true for scope, context, verification, evidence, ownership, and decision. Capability gap: none.
- Build scores: scope coupling 1, state/concurrency 2, blast/irreversibility 1, evidence/diagnosis 1, verification complexity 1; grade G06, base route `local-fit`, final route `recovery-boundary`, lane `cloud`, filename `PLAN-cloud-G06.md`.
- Review scores: 1/2/1/1/1; grade G06, route `official-review`, lane `cloud`, filename `CODE_REVIEW-cloud-G06.md`.
- `large_indivisible_context=false`; positive loop-risk signatures are `temporal_state` and `concurrent_consistency` (`loop_risk_count=2`).
- Recovery signals: `review_rework_count=5`, `evidence_integrity_failure=true`; recovery boundary is matched.

## Implementation Checklist

- [ ] Make projection batch admission context-aware so caller cancellation and refresh shutdown do not wait behind another serialized batch, while preserving whole-batch serialization and current concurrent per-client delivery; pass deterministic queued-batch cancellation and stop regressions.
- [ ] Run the focused, race, full secure-delivery, vet, diff, and secret-structure verification commands with fresh output.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1] Make serialized batch admission cancellable

**Problem:** `apps/control-plane/internal/wire/edge_server.go:331-332` acquires `broadcastMu` with `sync.Mutex.Lock`. When a mutation-triggered batch owns that mutex, the periodic refresh can block before reaching any per-client cancellation select. `stopProjectionRefresh` cancels the refresh context and waits at `apps/control-plane/internal/wire/edge_server.go:303-304`, but the mutex waiter cannot observe that cancellation.

**Before (`apps/control-plane/internal/wire/edge_server.go:331-332`):**

```go
s.broadcastMu.Lock()
defer s.broadcastMu.Unlock()
```

**Solution:** Replace the private mutex-only admission with a private context-aware single-owner gate initialized by `NewEdgeServerTLS`. Acquire the gate by selecting between ownership and `ctx.Done()`, release it with `defer`, and recheck `ctx.Err()` immediately after acquisition so a cancellation racing with an available gate cannot start snapshot creation. Preserve serialization for the entire snapshot/fan-out batch and retain the current per-client goroutines and ordered `errors.Join` results.

**After (`apps/control-plane/internal/wire/edge_server.go`):**

```go
if err := s.acquireProjectionBatch(ctx); err != nil {
	return err
}
defer s.releaseProjectionBatch()
if err := ctx.Err(); err != nil {
	return err
}
```

**Modified Files and Checklist:**

- [ ] `apps/control-plane/internal/wire/edge_server.go` — add a context-aware single-owner batch gate, initialize it, and use it around the existing complete batch.
- [ ] `apps/control-plane/internal/wire/edge_server_test.go` — add deterministic cancellation and stop coverage for a refresh/broadcast waiting behind an occupied batch gate.

**Test Strategy:** Add `TestEdgeServerBroadcastProjectionCancellationDoesNotWaitForPriorBatch` to occupy the private gate, start a second broadcast, cancel its context, and require `errors.Is(err, context.Canceled)` within a short bound without releasing the first batch. Add `TestEdgeServerStopCancelsProjectionRefreshWaitingForPriorBatch` by installing a refresh cancellation/done lifecycle around a broadcast queued behind the occupied gate, calling `stopProjectionRefresh`, and requiring prompt completion before gate release. Retain the existing stalled-client, all-client, mutation, and shutdown tests and run the wire package under `-race`.

**Verification:**

```bash
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery go test -count=1 ./apps/control-plane/internal/wire -run 'TestEdgeServer(BroadcastProjectionCancellationDoesNotWaitForPriorBatch|StopCancelsProjectionRefreshWaitingForPriorBatch|BroadcastProjectionDoesNotLetStalledEdgeBlockHealthyEdge|StopCancelsStalledProjectionRefresh|PeriodicallyRefreshesEveryActiveEdge|BroadcastProjectionAttemptsAllActiveEdges)'
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery go test -count=1 -race ./apps/control-plane/internal/wire
```

Expected: both commands exit 0; a canceled waiter and refresh stop return before the occupied batch is released, while whole batches remain serialized and current per-client fan-out behavior is unchanged.

## Modified Files Summary

| File | Item |
|------|------|
| `apps/control-plane/internal/wire/edge_server.go` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1 |
| `apps/control-plane/internal/wire/edge_server_test.go` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1 |
| `agent-task/m-principal-provider-credential-slot-routing/08+03,04,07_secure_delivery/CODE_REVIEW-cloud-G06.md` | REVIEW_REVIEW_REVIEW_REVIEW_REVIEW_API-1 |

## Final Verification

Fresh execution is required; cached `go test` output is not acceptable.

```bash
command -v go && go version && go env GOROOT
test -f agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/03+01,02_projection_auth/complete.log
test -f agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/04+03_principal_routes/complete.log
test -f agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/07+01,02,05_secret_material/complete.log
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery go test -count=1 ./packages/go/auth ./packages/go/config ./packages/go/credentiallease
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery go test -count=1 ./apps/control-plane/... ./apps/edge/... ./apps/node/...
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery go test -count=1 -race ./packages/go/auth ./packages/go/credentiallease ./apps/control-plane/internal/credentiallease ./apps/control-plane/internal/wire ./apps/edge/internal/authprojection ./apps/edge/internal/controlplane ./apps/edge/internal/service ./apps/edge/internal/transport ./apps/node/internal/node
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery make test-control-plane-edge-wire
env GOCACHE=/config/tmp/gocache-secure-delivery GOTMPDIR=/config/workspace/.gotmp-iop-secure-delivery TMPDIR=/config/workspace/.gotmp-iop-secure-delivery go vet ./apps/control-plane/... ./apps/edge/... ./apps/node/... ./packages/go/...
git diff --check
if rg --sort path -n 'bytes[[:space:]]+(secret|provider_secret)|map<string, string>[[:space:]]+(credential|provider_auth)' proto/iop/runtime.proto; then exit 1; fi
```

Expected: every command exits 0; focused tests prove context-aware serialized admission and stop cancellation, race detection reports no issue, and the existing three-process fixture still proves secure delivery without secret-bearing schema drift.

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