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

# Credential secure delivery와 runtime injection 계획

## For the Implementing Agent

`CODE_REVIEW-*-G??.md`의 구현 담당 섹션을 반드시 채운다. 모든 검증을 실제 실행하고 stdout/stderr를 포함한 evidence를 남긴 뒤 active 파일을 유지하고 review 준비 완료를 보고한다. 구현자는 사용자 질문, next-state 분류, archive, `complete.log`를 수행하지 않는다.

## Background

현재 Control Plane-Edge와 Edge-Node는 평문이고, Client wire는 hello만 제공하며, caller provider auth가 generic header로 Node까지 전달된다. 이 작업은 credential-plane을 명시적으로 켰을 때만 post-bootstrap HTTPS credential operation, projection/lease, Node dispatch를 인증·기밀 경로에 조립한다. Lease secret은 Edge에서 평문으로 풀지 않고 Node recipient key에 sealed하며, Control Plane issuer signature와 scope/expiry/revision으로 변조와 재사용을 차단한다.

## Replan Evidence

- `plan_cloud_G10_0.log`와 `code_review_cloud_G10_0.log`는 최초 계획/미구현 review stub이다.
- 최초 계획은 secure path를 default-off/dormant로 끝내면서 4개 Roadmap task를 check-on-pass 하려 했고, unsigned raw-secret protobuf가 tampered lease 및 proto debug 비노출을 충분히 증명하지 못했다.
- Client-Control Plane에는 실제 credential-bearing operation이 없는데 TLS listener만으로 S10을 충족한다고 간주한 점도 수정한다. Client protobuf에 raw secret을 추가하지 않고 전용 HTTPS handler를 사용한다.
- 구현 evidence/verdict가 없어 isolated reassessment했고 route는 결과적으로 동일하다.

## Archive Evidence Snapshot

- `agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/03+01,02_projection_auth/complete.log`: secret-free projection/cache와 managed ingress auth PASS.
- `agent-task/archive/2026/08/m-principal-provider-credential-slot-routing/04+03_principal_routes/complete.log`: principal route/discovery/no-fallback PASS.
- `agent-task/m-principal-provider-credential-slot-routing/07+01,02,05_secret_material/complete.log`: 현재 missing; 구현 전 exact path가 필요하다.
- prior unimplemented pair: `plan_cloud_G10_0.log`, `code_review_cloud_G10_0.log`.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/operational-observability-provider-management/milestones/principal-provider-credential-slot-routing.md)
- Task ids:
  - `secure-transport`: Client-Control Plane, Control Plane-Edge, Edge-Node credential path 인증·기밀성
  - `credential-lease`: bounded, scoped, tamper-evident dedicated lease delivery
  - `adapter-injection`: Node adapter 직전 profile auth injection과 cleanup
  - `revocation`: rotation/revoke generation/revision fence
- Completion mode: check-on-pass

## Analysis

### Files Read

- `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`
- `proto/iop/control.proto`
- `proto/iop/runtime.proto`
- `apps/control-plane/internal/wire/client.go`
- `apps/control-plane/internal/wire/client_test.go`
- `apps/control-plane/internal/wire/edge_server.go`
- `apps/control-plane/internal/credentialops/service.go`
- `apps/control-plane/cmd/control-plane/main.go`
- `apps/control-plane/cmd/control-plane/server.go`
- `apps/control-plane/cmd/control-plane/credential_commands.go`
- `apps/control-plane/cmd/control-plane/credential_commands_test.go`
- `apps/edge/internal/controlplane/connector.go`
- `apps/edge/internal/bootstrap/runtime.go`
- `apps/edge/internal/input/manager.go`
- `apps/edge/internal/transport/server.go`
- `apps/edge/internal/service/provider_tunnel.go`
- `apps/edge/internal/service/run_types.go`
- `apps/edge/internal/openai/dispatch_context.go`
- `apps/edge/internal/openai/provider_tunnel.go`
- `apps/edge/internal/openai/chat_handler.go`
- `apps/edge/internal/openai/responses_handler.go`
- `apps/edge/internal/openai/anthropic_handler.go`
- `apps/node/internal/transport/client.go`
- `apps/node/internal/node/tunnel_handler.go`
- `apps/node/internal/adapters/openai_compat/provider_tunnel.go`
- `packages/go/config/edge_types.go`
- `packages/go/config/node_types.go`
- `packages/go/config/load.go`
- `packages/go/config/validate.go`
- `packages/go/auth/auth.go`
- `packages/go/agentruntime/types.go`
- `configs/control-plane.yaml`
- `configs/edge.yaml`
- `configs/node.yaml`
- `Makefile`
- `agent-contract/inner/client-control-plane-wire.md`
- `agent-test/local/rules.md`
- `agent-test/local/control-plane-smoke.md`
- `agent-test/local/edge-smoke.md`
- `agent-test/local/node-smoke.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-test/local/client-smoke.md`

### SDD Criteria

- SDD path: `agent-roadmap/sdd/operational-observability-provider-management/principal-provider-credential-slot-routing/SDD.md`; status: 승인.
- S10: Client/Edge/Node에서 올바른 TLS identity와 credential auth만 성공하고 plaintext/wrong peer는 secret 송신 전에 실패한다.
- S11: principal/slot/route/profile/target/node/revision/expiry가 결합되고 expired/revoked/tampered lease가 adapter 전에 거부된다.
- S12: upstream에는 profile의 정확한 auth header만 도달하며 proto debug/log/status/error/metric/response에는 raw secret이 없다.
- S13: in-flight는 시작한 attempt만 terminal까지, revoke/rotate 뒤 새 lease/send/retry는 새 revision 없이는 실패한다.
- Evidence Map S09-S13 row가 peer matrix, lease scope/tamper, upstream sentinel/redaction, revocation race를 checklist와 final verification에 고정한다.

### Verification Context

- 별도 handoff는 없었다. repository-native fallback evidence는 위 source/tests와 local control-plane/edge/node/platform profiles다.
- Go/protoc/flutter/protoc-gen-dart가 현재 host에 있다. proto는 source에서 생성하고 두 번 생성한 hash가 동일해야 한다.
- test CA, peer cert, Ed25519 issuer key와 X25519 recipient key는 temp directory에서 생성한다. 외부 provider/credential 없이 fake upstream으로 full-cycle을 검증한다.
- race/state changes는 `-race`; all Go tests use `-count=1`. confidence: medium-high because three process boundaries and generated contracts change한다.

### Test Coverage Gaps

- Client wire는 hello-only이고 bootstrap guard가 credential management proto를 금지한다. Bootstrap과 Client proto hello-only는 유지하되 authenticated HTTPS slot create/rotate operation은 별도로 필요하다.
- CP-Edge/Edge-Node는 TLS peer matrix가 없고 Node register token도 plaintext transport에 있다.
- projection messages는 dormant, lease issuer/cache/recipient encryption/signature가 없다.
- caller provider token이 generic header로 Node adapter에 전달되고 revocation ordering fence가 없다.

### Symbol References

- lease proto additions use new field numbers; existing names/field numbers are not reused.
- bootstrap guard는 remote bootstrap/management proto를 계속 금지하고 새 lease contract 이름만 명시적으로 허용한다. Post-bootstrap slot management는 protobuf가 아닌 HTTPS handler다.
- `ProviderTunnelRequest` receives a dedicated sealed credential message, never a raw `bytes secret` or generic header value.
- TLS config structs are explicit tagged server/client types rather than an untagged compressed example.

### Split Judgment

- secure transport, issuer/recipient lease envelope, candidate binding, injection and revocation are one security invariant: any partial production activation would expose or misroute credentials.
- 03/04 are satisfied; 07 is missing and blocks implementation. 09/10 wait on this packet.
- Although large, splitting the cross-boundary cryptographic envelope from its producer/consumer would not yield an independently deployable PASS state.

### Scope Rationale

- This packet includes the minimum safe activation gate: enabled mode requires all secure dependencies, uses CP projection/lease only, and rejects caller provider auth. Without it, the four targeted tasks cannot be honestly completed.
- 09 owns the exhaustive migration/rollback/reload matrix and slot attribution completion, but does not activate a previously dormant unsafe path.
- Remote bootstrap remains prohibited. The Client operation is a thin principal-authenticated HTTPS adapter over the existing slot/route lifecycle service, including secret-bearing create/rotate and safe route/lifecycle operations needed for real dispatch. Secret create/rotate uses a bounded `application/octet-stream` body plus safe metadata fields so the handler can zero mutable bytes; non-secret operations use JSON. Flutter UI UX and protobuf management wire remain out of scope.
- Provider failover, persistent leases, auto-rotation and A2A/native normalized adapter paths remain out of scope.

### Final Routing

- evaluation_mode `isolated-reassessment`; finalizer `finalize-task-policy.sh pair` exactly once.
- build closures 모두 true; scores `2,2,2,2,2` = G10; route `grade-boundary`; `large_indivisible_context=true`; positive risks `temporal_state`, `concurrent_consistency`, `boundary_contract`, `structured_interpretation`, `variant_product` (5); `PLAN-cloud-G10.md`.
- review scores `2,2,2,2,2` = G10; `official-review`, `CODE_REVIEW-cloud-G10.md`, Codex `gpt-5.6-sol` xhigh.
- `review_rework_count=0`, `evidence_integrity_failure=false`; recovery boundary와 capability gap은 없다.

## Implementation Checklist

- [ ] Enforce TLS/auth on every credential-bearing Client-CP, CP-Edge, and Edge-Node operation without plaintext fallback.
- [ ] Add a signed, scope-bound lease whose credential is sealed to the selected Node and never plaintext at Edge/protobuf debug boundaries.
- [ ] Bind lease acquisition/delivery to exact projection generation, candidate node, route/profile/target and revisions.
- [ ] Decrypt and inject only inside the Node adapter immediately before upstream send, then zero request-local plaintext.
- [ ] Activate managed mode only when the complete secure composition is valid and fence revoke/rotate/queue/retry ordering.
- [ ] Regenerate Go/Dart protobufs and add fresh peer, tamper, full-cycle, race, redaction and generation-determinism tests.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [API-1] Credential-bearing HTTPS operation and boundary-specific TLS auth

**Problem:** Client-facing HTTP, CP-Edge and Edge-Node transports are plaintext. Client has no credential-bearing operation, so listener TLS alone cannot satisfy S10.

**Solution:**

- Client-CP: run the existing public HTTP server with TLS 1.3/server identity validation and add a thin post-bootstrap adapter for the existing principal-scoped slot/route lifecycle service. Secret-bearing slot create/rotate accepts a maximum 64 KiB mutable `application/octet-stream` body with safe vendor/kind/alias/revision fields, rejects redirects/content-type/oversize, and zeros the buffer after the service call; safe list/update/disable/revoke/route operations use strict JSON. All operations authenticate with the IOP principal bearer token; body/header logging is forbidden and responses contain safe metadata only. Browser-compatible Client authentication is application-layer principal auth inside server-authenticated HTTPS, not mandatory client certificates. The protobuf Client wire stays hello-only and carries no secret.
- CP-Edge and Edge-Node: require mutual TLS 1.3 with CA, cert, key, expected server name and peer-role verification when credential-plane is enabled. No retry path downgrades to plaintext.
- Bootstrap/first-principal creation stays host-local CLI-only; update its structural guard only to allow new lease proto names, not management messages.

Before (`apps/control-plane/cmd/control-plane/server.go:111-116`):

```go
server := &http.Server{Addr: cfg.Server.Listen, Handler: mux}
go func() {
	if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		logger.Warn("control-plane server exited", zap.Error(err))
	}
}()
```

After:

```go
import (
	"crypto/tls"
	"iop/apps/control-plane/internal/credentialops"
)

tlsConfig := mustCredentialTLS(cfg.Server.TLS)
registerCredentialSlotHandlers(mux, credentialService)
server := &http.Server{Addr: cfg.Server.Listen, Handler: mux, TLSConfig: tlsConfig}
go func() { _ = server.ListenAndServeTLS(cfg.Server.TLS.CertFile, cfg.Server.TLS.KeyFile) }()
```

**Modified Files and Checklist:**

- [ ] Add tagged TLS helpers/config in `packages/go/auth/auth.go`, `packages/go/config/tls_types.go`, `packages/go/config/tls_types_test.go`, `packages/go/config/edge_types.go`, `packages/go/config/node_types.go`, `packages/go/config/load.go`, and `packages/go/config/validate.go`.
- [ ] Keep Client proto hello-only; extend `proto/iop/control.proto` only for projection/lease and regenerate `proto/gen/iop/control.pb.go` plus the four exact `apps/client/lib/gen/proto/iop/control.*.dart` outputs listed in the summary.
- [ ] Add `apps/control-plane/cmd/control-plane/credential_http_handlers.go` and `apps/control-plane/cmd/control-plane/credential_http_handlers_test.go`; update `apps/control-plane/cmd/control-plane/main.go` and `apps/control-plane/cmd/control-plane/server.go` to mount them only on HTTPS.
- [ ] Update `apps/control-plane/internal/wire/edge_server.go`, `apps/edge/internal/controlplane/connector.go`, `apps/edge/internal/transport/server.go`, and `apps/node/internal/transport/client.go` for mTLS without downgrade.
- [ ] Update `configs/control-plane.yaml`, `configs/edge.yaml`, and `configs/node.yaml` with secret-free cert path placeholders.
- [ ] Add peer/auth matrices in `apps/control-plane/internal/wire/credential_tls_test.go`, `apps/edge/internal/transport/credential_tls_test.go`, and `apps/node/internal/transport/credential_tls_test.go`; update `apps/control-plane/cmd/control-plane/credential_commands_test.go` for the bootstrap/lease proto guard.

**Test Strategy:** generated temp CA and distinct client/edge/node identities. Assert failure before management handler, lease issuer, register handler or secret read. Confirm remote bootstrap/management proto remains absent while authenticated slot/route lifecycle works only over HTTPS, never plain HTTP. Cover content type, 64 KiB boundary, oversize, short read/cancel, cross-principal and stale revision; logs/errors/responses never echo bearer/body and owned body bytes are zeroed.

**Verification:** focused auth/config/wire/transport tests plus `make test-control-plane-edge-wire`.

### [API-2] Issuer-signed, Node-sealed bounded lease

**Problem:** a raw `bytes secret` lease would be exposed by generic protobuf formatting and plain field mutation would not give Node independent proof of CP issuance.

**Solution:** Add shared `packages/go/credentiallease` primitives:

- Control Plane creates canonical scope over principal, slot, route, profile, upstream target, node ID, slot/route revisions, projection generation, issued/expiry timestamps and lease ID.
- Node advertises an X25519 recipient public key/key id during authenticated registration; Edge binds it to the selected live node and includes it in the lease request.
- CP decrypts the at-rest envelope only after one store snapshot validates active rows, derives an ephemeral X25519/HKDF/AES-GCM key, seals the secret with canonical scope as AAD, signs scope + sealed envelope with a dedicated external Ed25519 issuer key, then zeros plaintext.
- Edge verifies issuer signature and caches only the signed sealed envelope under the complete immutable key. Node pins the issuer public key, verifies signature/scope/recipient/expiry and a bounded consumed-lease set, and only then decrypts. Duplicate lease IDs are rejected until expiry.

The at-rest AES key, lease issuer private key, and Node recipient private key are separate external mount files. Ed25519/X25519 private keys use strict PKCS#8 PEM; public verifier keys use PKIX PEM; key IDs are the lowercase SHA-256 digest of canonical public-key bytes. Resolve/validate mounts using the same target/permission rules as 07. Public verifier/recipient keys may be projected but are never accepted from caller metadata. Lease TTL defaults to 60 seconds and is configurable only within 5..300 seconds. Edge cache and Node consumed-ID set default to 1024 entries, accept only 1..4096, prune by signed expiry, and fail closed instead of evicting a still-valid replay fence to admit overflow.

Before (`proto/iop/control.proto:104-115`):

```proto
message PrincipalProjectionApplyRequest { PrincipalProjection projection = 1; }
message PrincipalProjectionApplyResponse {
  bool applied = 1;
  uint64 accepted_generation = 2;
  string reason = 3;
}
```

After:

```proto
message CredentialLeaseScope { /* immutable safe scope and expiry */ }
message SealedCredentialPayload {
  bytes ephemeral_public_key = 1;
  bytes nonce = 2;
  bytes ciphertext = 3;
}
message SignedCredentialLease {
  CredentialLeaseScope scope = 1;
  SealedCredentialPayload sealed = 2;
  string issuer_key_id = 3;
  bytes signature = 4;
}
```

Go producers/consumers import the new shared package explicitly:

```go
import "iop/packages/go/credentiallease"
```

**Modified Files and Checklist:**

- [ ] Add `packages/go/credentiallease/envelope.go` and `packages/go/credentiallease/envelope_test.go` for canonical encoding, signature, X25519 sealing, tamper and zero-copy behavior.
- [ ] Extend `proto/iop/control.proto` and `proto/iop/runtime.proto`; regenerate `proto/gen/iop/control.pb.go`, `proto/gen/iop/runtime.pb.go`, and all eight exact Dart control/runtime generated files in the summary.
- [ ] Add `apps/control-plane/internal/credentiallease/service.go`, `apps/control-plane/internal/credentiallease/service_test.go`, and the handler option in `apps/control-plane/internal/wire/edge_server.go`.
- [ ] Extend `apps/node/internal/transport/client.go`, `packages/go/config/node_types.go`, `apps/edge/internal/controlplane/connector.go`, and `apps/edge/internal/service/credential_lease.go` for recipient identity and exact-key cache.
- [ ] Validate issuer/recipient key configuration through `apps/control-plane/cmd/control-plane/main.go`, `apps/edge/internal/bootstrap/runtime.go`, `configs/control-plane.yaml`, `configs/edge.yaml`, and `configs/node.yaml` before ready state.

**Test Strategy:** deterministic clock plus generated keys for every wrong principal/slot/route/profile/target/node/revision/generation/recipient, TTL/cache bounds, overflow, expiry pruning, replay, revocation, signature/ciphertext/scope tamper and unavailable CP cache rules. Invalid input must not call keyring `Open` or upstream.

**Verification:** `go test -count=1 -race ./packages/go/credentiallease ./apps/control-plane/internal/credentiallease ./apps/edge/internal/controlplane ./apps/edge/internal/service ./apps/node/internal/node`.

### [API-3] Candidate-bound sealed delivery and last-moment injection

**Problem:** caller provider auth is copied through `SubmitProviderTunnelRequest.Headers` and Node forwards it directly.

**Solution:** Resolve route/profile/candidate node first, request the exact recipient-bound lease, and place only `SignedCredentialLease` in a dedicated runtime field. Generic headers/metadata must reject managed provider authorization. Node atomically checks/records lease consumption, validates/decrypts into request-local memory immediately before adapter send; adapter clones non-sensitive headers, rejects auth-header collision, injects profile scheme/header, calls upstream once, then zeros all owned secret bytes on success/error/cancel.

Before (`proto/iop/runtime.proto:65-83`):

```proto
message ProviderTunnelRequest {
  map<string, string> headers = 7;
  bytes body = 8;
  string operation = 13;
}
```

After:

```proto
message ProviderTunnelRequest {
  map<string, string> headers = 7;
  bytes body = 8;
  string operation = 13;
  SignedCredentialLease credential_lease = 14;
}
```

**Modified Files and Checklist:**

- [ ] Update `apps/edge/internal/openai/dispatch_context.go`, `chat_handler.go`, `responses_handler.go`, `anthropic_handler.go`, and `provider_tunnel.go`.
- [ ] Update `apps/edge/internal/service/provider_tunnel.go`, `apps/edge/internal/service/run_types.go`, and `packages/go/agentruntime/types.go` for immutable scope and a dedicated sealed payload.
- [ ] Update `apps/node/internal/node/tunnel_handler.go` and `apps/node/internal/adapters/openai_compat/provider_tunnel.go` for validation/decrypt/injection.
- [ ] Add `apps/edge/internal/service/credential_delivery_test.go`, `apps/node/internal/node/credential_lease_test.go`, and `apps/node/internal/adapters/openai_compat/credential_injection_test.go` for bearer/x-api-key, collision, cleanup and no-generic-map cases.

**Test Strategy:** exactly one expected auth header reaches fake upstream. Sentinel secret is absent from proto `String`, logs, errors, status, metrics, response, generic maps and Edge heap-owned lease object. Invalid scope/decrypt/header collision makes zero upstream calls.

**Verification:** full affected Edge/Node tests after proto generation.

### [API-4] Secure activation and revoke/rotate ordering fence

**Problem:** completing secure tasks while their production path is dormant would be a false PASS, and queued/recovery sends can race a new projection.

**Solution:** Add one explicit credential-plane activation gate. Enabled startup requires HTTPS management, CP-Edge/Edge-Node mTLS, issuer/verifier/recipient keys, keyring, projection freshness and lease provider; it rejects legacy provider-auth/caller credentials and never falls back. Disabled mode keeps legacy behavior and never registers credential operations or lease flow. Capture projection generation/revisions in dispatch binding, evict stale leases on apply, validate immediately before each direct/queued/recovery send, and consume the lease atomically at Node adapter admission immediately before decrypt/injection. A consumed/started attempt may finish once; validation/header/upstream failures do not make the lease reusable, and no old-revision retry starts.

Before (`apps/edge/internal/openai/principal.go:192-219`):

```go
projection := s.PrincipalProjection()
if projection != nil {
	digest := sha256.Sum256([]byte(token))
	view, matched := projection.AuthenticatedView(digest)
	if view.State != authprojection.StateUnmanaged {
		if !headersOK || token == "" || !matched {
			return openAIPrincipal{}, view, false
		}
		return openAIPrincipal{
			PrincipalRef: view.Principal.PrincipalRef, PrincipalAlias: view.Principal.PrincipalAlias,
			TokenRef: view.Principal.TokenRef, Source: principalSourceProjection,
		}, view, true
	}
}
```

After:

```go
switch s.credentialMode {
case credentialModeManaged:
	return authenticateManagedOnly(s.PrincipalProjection(), token)
case credentialModeLegacy:
	return authenticateLegacyOnly(s.cfg, token)
default:
	return openAIPrincipal{}, authprojection.AuthenticatedView{}, false
}
```

**Modified Files and Checklist:**

- [ ] Complete activation prerequisites in `packages/go/config/edge_types.go`, `packages/go/config/load.go`, `packages/go/config/validate.go`, `apps/edge/internal/bootstrap/runtime.go`, and `apps/edge/internal/input/manager.go`.
- [ ] Fence eviction and direct/queued/recovery paths in `apps/edge/internal/service/credential_lease.go`, `apps/edge/internal/service/provider_tunnel.go`, and `apps/edge/internal/openai/provider_tunnel.go`.
- [ ] Add ordering cases in `apps/control-plane/internal/credentiallease/revocation_test.go`, `apps/edge/internal/service/credential_lease_test.go`, `apps/edge/internal/service/credential_delivery_test.go`, and `apps/node/internal/node/credential_lease_test.go`.

**Test Strategy:** deterministic clocks/barriers under `-race`; assert at most one upstream call and no retry with stale scope. 09 will add the exhaustive migration/reload compatibility table.

**Verification:** affected CP/Edge/Node race tests and three-process fake-upstream cycle.

## Dependencies and Execution Order

1. 03 and 04 are satisfied. Do not implement until `agent-task/m-principal-provider-credential-slot-routing/07+01,02,05_secret_material/complete.log` exists.
2. Implement API-1 and API-2, then API-3, then API-4; no partial production enablement.
3. 09 and 10 wait for this directory's `complete.log`.

## Modified Files Summary

| File | Items |
|------|-------|
| `packages/go/auth/auth.go` | API-1 |
| `packages/go/config/tls_types.go` | API-1 |
| `packages/go/config/tls_types_test.go` | API-1 |
| `packages/go/config/edge_types.go` | API-1, API-4 |
| `packages/go/config/node_types.go` | API-1, API-2 |
| `packages/go/config/load.go` | API-1, API-4 |
| `packages/go/config/validate.go` | API-1, API-4 |
| `packages/go/credentiallease/envelope.go` | API-2 |
| `packages/go/credentiallease/envelope_test.go` | API-2 |
| `packages/go/agentruntime/types.go` | API-3 |
| `proto/iop/control.proto` | API-1, API-2 |
| `proto/iop/runtime.proto` | API-2, API-3 |
| `proto/gen/iop/control.pb.go` | API-1, API-2 |
| `proto/gen/iop/runtime.pb.go` | API-2, API-3 |
| `apps/client/lib/gen/proto/iop/control.pb.dart` | API-1, API-2 |
| `apps/client/lib/gen/proto/iop/control.pbenum.dart` | API-1, API-2 |
| `apps/client/lib/gen/proto/iop/control.pbjson.dart` | API-1, API-2 |
| `apps/client/lib/gen/proto/iop/control.pbserver.dart` | API-1, API-2 |
| `apps/client/lib/gen/proto/iop/runtime.pb.dart` | API-2, API-3 |
| `apps/client/lib/gen/proto/iop/runtime.pbenum.dart` | API-2, API-3 |
| `apps/client/lib/gen/proto/iop/runtime.pbjson.dart` | API-2, API-3 |
| `apps/client/lib/gen/proto/iop/runtime.pbserver.dart` | API-2, API-3 |
| `apps/control-plane/cmd/control-plane/main.go` | API-1, API-2, API-4 |
| `apps/control-plane/cmd/control-plane/server.go` | API-1, API-2, API-4 |
| `apps/control-plane/cmd/control-plane/credential_http_handlers.go` | API-1 |
| `apps/control-plane/cmd/control-plane/credential_http_handlers_test.go` | API-1 |
| `apps/control-plane/cmd/control-plane/credential_commands_test.go` | API-1 |
| `apps/control-plane/internal/wire/edge_server.go` | API-1, API-2 |
| `apps/control-plane/internal/wire/credential_tls_test.go` | API-1 |
| `apps/control-plane/internal/credentiallease/service.go` | API-2 |
| `apps/control-plane/internal/credentiallease/service_test.go` | API-2 |
| `apps/control-plane/internal/credentiallease/revocation_test.go` | API-4 |
| `apps/edge/internal/controlplane/connector.go` | API-1, API-2 |
| `apps/edge/internal/transport/server.go` | API-1 |
| `apps/edge/internal/transport/credential_tls_test.go` | API-1 |
| `apps/edge/internal/bootstrap/runtime.go` | API-1, API-2, API-4 |
| `apps/edge/internal/input/manager.go` | API-2, API-4 |
| `apps/edge/internal/openai/dispatch_context.go` | API-3 |
| `apps/edge/internal/openai/chat_handler.go` | API-3 |
| `apps/edge/internal/openai/responses_handler.go` | API-3 |
| `apps/edge/internal/openai/anthropic_handler.go` | API-3 |
| `apps/edge/internal/openai/provider_tunnel.go` | API-3, API-4 |
| `apps/edge/internal/service/credential_lease.go` | API-2, API-4 |
| `apps/edge/internal/service/credential_lease_test.go` | API-2, API-4 |
| `apps/edge/internal/service/credential_delivery_test.go` | API-3, API-4 |
| `apps/edge/internal/service/provider_tunnel.go` | API-3, API-4 |
| `apps/edge/internal/service/run_types.go` | API-3, API-4 |
| `apps/node/internal/transport/client.go` | API-1, API-2 |
| `apps/node/internal/transport/credential_tls_test.go` | API-1 |
| `apps/node/internal/node/tunnel_handler.go` | API-2, API-3 |
| `apps/node/internal/node/credential_lease_test.go` | API-2, API-3, API-4 |
| `apps/node/internal/adapters/openai_compat/provider_tunnel.go` | API-3 |
| `apps/node/internal/adapters/openai_compat/credential_injection_test.go` | API-3 |
| `configs/control-plane.yaml` | API-1, API-2 |
| `configs/edge.yaml` | API-1, API-4 |
| `configs/node.yaml` | API-1, API-2 |
| `agent-task/m-principal-provider-credential-slot-routing/08+03,04,07_secure_delivery/CODE_REVIEW-cloud-G10.md` | all |

## Final Verification

Run from `/config/workspace/iop-s0`; all outputs must be fresh.

```bash
command -v go && go version && go env GOROOT
command -v protoc && command -v protoc-gen-dart && command -v flutter
git status --short --branch
make proto
make proto-dart
sha256sum proto/gen/iop/control.pb.go proto/gen/iop/runtime.pb.go apps/client/lib/gen/proto/iop/control.pb.dart apps/client/lib/gen/proto/iop/control.pbenum.dart apps/client/lib/gen/proto/iop/control.pbjson.dart apps/client/lib/gen/proto/iop/control.pbserver.dart apps/client/lib/gen/proto/iop/runtime.pb.dart apps/client/lib/gen/proto/iop/runtime.pbenum.dart apps/client/lib/gen/proto/iop/runtime.pbjson.dart apps/client/lib/gen/proto/iop/runtime.pbserver.dart > /tmp/iop-credential-proto-first.sha256
make proto
make proto-dart
sha256sum proto/gen/iop/control.pb.go proto/gen/iop/runtime.pb.go apps/client/lib/gen/proto/iop/control.pb.dart apps/client/lib/gen/proto/iop/control.pbenum.dart apps/client/lib/gen/proto/iop/control.pbjson.dart apps/client/lib/gen/proto/iop/control.pbserver.dart apps/client/lib/gen/proto/iop/runtime.pb.dart apps/client/lib/gen/proto/iop/runtime.pbenum.dart apps/client/lib/gen/proto/iop/runtime.pbjson.dart apps/client/lib/gen/proto/iop/runtime.pbserver.dart > /tmp/iop-credential-proto-second.sha256
diff -u /tmp/iop-credential-proto-first.sha256 /tmp/iop-credential-proto-second.sha256
make client-test
(cd apps/client && flutter analyze)
go test -count=1 ./packages/go/auth ./packages/go/config ./packages/go/credentiallease
go test -count=1 ./apps/control-plane/... ./apps/edge/... ./apps/node/...
go test -count=1 -race ./packages/go/credentiallease ./apps/control-plane/internal/credentiallease ./apps/edge/internal/authprojection ./apps/edge/internal/service ./apps/node/internal/node
make test-control-plane-edge-wire
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: deterministic generation, tests/race/smoke/vet/diff pass; guarded runtime-proto scan has no raw-secret/generic credential field. Review must separately list the HTTPS sensitive-input boundary, every intentional sealed-payload/adapter injection reference, and prove the sentinel is absent from output.

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