<!-- task=m-iop-hot-path-one-shot-execution/10+07,09_light_flow plan=3 tag=REVIEW_API milestone-task=light-flow -->

# Preserve Opaque Correlations and Decode Protocol Payload Evidence

## For the Implementing Agent

Implement this follow-up, run every verification command, and fill the implementation-owned sections of `CODE_REVIEW-cloud-G05.md` with actual notes and stdout/stderr. Keep both active files in place and report ready for official review. If blocked, record only the exact blocker, attempted commands/output, and resume condition in implementation-owned evidence fields. Do not ask the user, call user-input tools, create control-plane stop files, classify the next state, archive logs, or write `complete.log`; finalization belongs to code review.

## Background

The third light-flow review confirmed that fresh focused/common race tests pass and that the selected Anthropic candidate now reaches the Messages builder. It also found that the new safe-token fence rejects valid configured provider identifiers such as `provider.actual`, while the tunnel regression still skips a missing preparation hook and inspects undifferentiated body substrings instead of decoded protocol messages. This follow-up preserves opaque correlation compatibility with a bounded line-safe representation and closes the exact Chat/Messages evidence gap.

## Archive Evidence Snapshot

- Current pair after review finalization: `plan_cloud_G05_2.log` and `code_review_cloud_G05_2.log`; verdict `FAIL`, `review_rework_count=3`, `evidence_integrity_failure=true`.
- Required finding 1: `validateStageCorrelation` applies the logical-request token alphabet to `ProviderID`, although `NodeProviderConf.Validate` accepts every non-empty provider ID; a valid dotted provider route can therefore fail before local/review prompt construction.
- Required finding 2: the tunnel assertions remain optional when `PrepareProtocolTunnel` is nil and inspect raw JSON substrings instead of decoding the selected protocol's exact `messages` content.
- Affected files: `apps/edge/internal/openai/hot_path_stage_input.go` and `apps/edge/internal/openai/hot_path_light_test.go`.
- Fresh reviewer evidence: both item race tests, focused light/review race tests, common race tests, focused vet, formatting, and `git diff --check` exit 0; source/contract inspection contradicts the two checked completion claims above.
- Earlier loop evidence remains in `plan_cloud_G10_0.log`, `code_review_cloud_G10_0.log`, `plan_local_G05_1.log`, and `code_review_cloud_G05_1.log`; predecessors 07 and 09 remain satisfied by their exact archived `complete.log` files.

## Dependencies and Execution Order

- Index 07 is satisfied by `agent-task/archive/2026/08/m-iop-hot-path-one-shot-execution/07+02,04,06_route_selector_direct/complete.log`.
- Index 09 is satisfied by `agent-task/archive/2026/08/m-iop-hot-path-one-shot-execution/09+06,08_artifact_pair/complete.log`.
- Preserve the existing `10+07,09_light_flow` task path. Complete correlation serialization and decoded tunnel assertions together because both define the provider-visible S08 stage-input boundary.

## Analysis

### Files Read

- `apps/edge/internal/openai/hot_path_stage_input.go`
- `apps/edge/internal/openai/hot_path_dispatch.go`
- `apps/edge/internal/openai/hot_path_light.go`
- `apps/edge/internal/openai/hot_path_light_test.go`
- `apps/edge/internal/openai/request_coordinator.go`
- `apps/edge/internal/openai/provider_test_support_test.go`
- `apps/edge/internal/openai/anthropic_surface_test.go`
- `apps/edge/internal/service/provider_pool.go`
- `packages/go/config/provider_types.go`
- `packages/go/config/load.go`
- `agent-contract/index.md`
- `agent-contract/inner/edge-config-runtime-refresh.md`
- `agent-contract/outer/openai-compatible-api.md`
- `agent-contract/outer/anthropic-compatible-api.md`
- `agent-task/m-iop-hot-path-one-shot-execution/10+07,09_light_flow/PLAN-cloud-G05.md`
- `agent-task/m-iop-hot-path-one-shot-execution/10+07,09_light_flow/CODE_REVIEW-cloud-G05.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md`
- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/iop-hot-path-one-shot-execution.md`
- `agent-roadmap/sdd/knowledge-tool-optimization-extension/iop-hot-path-one-shot-execution/SDD.md`
- `agent-test/local/rules.md`
- `agent-test/local/edge-smoke.md`

### SDD Criteria

The selected SDD is approved and unlocked. The preserved `milestone-task=light-flow` maps to Acceptance Scenario S08 and Evidence Map row S08. S08 requires immutable stage-input isolation and deterministic pass/defect review-state evidence, so provider/config-owned correlation strings must remain compatible without creating prompt structure, and selected Chat/Messages request bodies must prove the exact predecessor prompt appears in the protocol message content.

### Verification Context

No separate verification handoff was supplied. Repository-native context comes from `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md`, the active pair, source, contracts, SDD, and fresh reviewer commands. The current checkout is `/config/workspace/iop-s0` on `feature/iop-hot-path-one-shot-execution` at `a172f23e`, with `/config/.local/bin/go`, Go `1.26.2 linux/arm64`, and a shared dirty worktree. Deterministic package verification requires no credential, provider, device, external runner, or interactive session. Fresh item/focused/common race commands, focused vet, formatting, and diff checks are the required oracle; SDD S16 owns live provider/agent smoke. Confidence is high because the tests capture the production `ProviderPoolDispatchRequest`, invoke its selected-candidate preparation callback, and can decode `BuildBody` directly.

### Test Coverage Gaps

- `TestHotPathStageInputIsolation` proves unsafe controls and overlength strings fail, but currently classifies valid provider punctuation as an invalid logical request ID and has no accepted dotted-provider regression.
- `TestHotPathLightLocalTransition` carries the actual selected candidate, but a nil preparation callback silently skips tunnel checks and raw substring assertions do not prove the prompt occupies the first user message in the Chat or Messages body.
- Existing pass/repair state-machine tests cover fixed local/review binding and cleanup transitions; no state-machine change is required.

### Symbol References

None. No symbol rename or removal is planned; `validLogicalRequestID` remains the validator for IOP-owned logical, stage, run, and tool-call identities.

### Split Judgment

Keep one compact plan. The line-safe correlation representation and decoded protocol assertions jointly close one provider-visible input invariant and cannot independently establish S08 evidence. Archived predecessor 07 and 09 completion logs satisfy the directory-declared dependencies.

### Scope Rationale

Limit production changes to correlation validation/serialization and test changes to the existing light-flow fixture/helpers. Do not change stage transitions, route/credential revalidation, provider/config validation, artifact mapping, public response identity, workspace tool semantics, cleanup, heavy mode, contracts, specs, or live smoke.

### Final Routing

`evaluation_mode=isolated-reassessment`; `finalizer=finalize-task-policy.sh` pair. Build and review closures are all true. Build scores `(1,0,1,2,1)` produce G05 with base `local-fit`; review scores `(1,0,1,2,1)` produce G05. `large_indivisible_context=false`; positive risks are `boundary_contract`, `structured_interpretation`, and `variant_product` (`loop_risk_count=3`). `review_rework_count=3` and `evidence_integrity_failure=true` trigger `recovery-boundary`, so the build route is cloud G05 with `PLAN-cloud-G05.md`. Official review is cloud G05 with `CODE_REVIEW-cloud-G05.md`, Codex `gpt-5.6-sol` xhigh. No capability gap or user decision exists.

## Implementation Checklist

- [ ] Preserve bounded opaque provider correlations with a deterministic line-safe prompt representation while keeping IOP-owned IDs strict.
- [ ] Require decoded normalized, OpenAI Chat, and Anthropic Messages correlation/isolation evidence with no optional tunnel path.
- [ ] Run focused, common race, vet, format, and diff verification with fresh test execution.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Preserve contract-compatible opaque correlation values

#### Problem

`apps/edge/internal/openai/hot_path_stage_input.go:76` validates `StageID`, `ResponseID`, `RunID`, `ProviderID`, and `Terminal` with `validLogicalRequestID`. That alphabet is correct for IOP-owned IDs but rejects punctuation in provider/config-owned values; `packages/go/config/provider_types.go:108` accepts `provider.actual`, while `hot_path_stage_input.go:86` rejects it before local/review dispatch.

#### Solution

Keep `StageID` and `RunID` on `validLogicalRequestID`. Validate `ResponseID`, `ProviderID`, and `Terminal` as non-empty, bounded opaque correlations with control characters rejected, then serialize the whole correlation as deterministic single-line JSON so quotes and delimiters cannot create prompt structure. Add the required imports explicitly:

```go
import (
	"encoding/json"
	"fmt"
	"strings"
	"unicode"
)
```

Before (`apps/edge/internal/openai/hot_path_stage_input.go:80`):

```go
if !validLogicalRequestID(correlation.ResponseID) {
	return fmt.Errorf("%s commit correlation ResponseID %q is invalid", role, correlation.ResponseID)
}
```

After:

```go
if !validOpaqueStageCorrelation(correlation.ResponseID) {
	return fmt.Errorf("%s commit correlation ResponseID is invalid", role)
}
encoded, err := json.Marshal(correlationPromptValue{ /* exact fields */ })
```

#### Modified Files and Checklist

- [ ] `apps/edge/internal/openai/hot_path_stage_input.go` — separate IOP-owned ID validation from bounded opaque correlation validation and emit one deterministic JSON data line per committed stage.
- [ ] `apps/edge/internal/openai/hot_path_light_test.go` — accept dotted/delimited provider-owned values exactly, reject empty/control/overlength values, and assert serialized correlations remain one data line.

#### Test Strategy

Update `TestHotPathStageInputIsolation`. Add accepted values such as `provider.actual`, `response:opaque/value`, and a quoted/comma-bearing token; assert prompt construction succeeds, JSON decoding preserves the exact strings, and no value adds a prompt line. Retain fail-closed cases for empty, newline/control, and over-256-byte opaque correlations plus strict invalid `StageID`/`RunID` coverage.

#### Verification

```bash
go test -race -count=1 ./apps/edge/internal/openai -run '^TestHotPathStageInputIsolation$'
```

Expected: PASS with fresh execution; valid configured/provider punctuation round-trips exactly, control/overlength input fails closed, and every committed block remains deterministic and line-safe.

### [REVIEW_API-2] Decode and require selected-protocol message payloads

#### Problem

`apps/edge/internal/openai/hot_path_light_test.go:437` and line 506 guard tunnel inspection with `if req.PrepareProtocolTunnel != nil`, so removing the production callback would not fail the regression. Lines 451-459 and 520-532 search undifferentiated JSON bytes, contrary to the active plan's requirement to decode the body and prove the prompt sits in the selected protocol's message content.

#### Solution

Call the preparation helper unconditionally and fail when the hook or `BuildBody` is missing. Decode the body into a minimal messages envelope, require the first message to be the protocol's user message with string content equal to `Run.Prompt`, then perform exact selector/local correlation and forbidden-value assertions on that decoded prompt. Keep explicit `/v1/chat/completions` + `chat_completions` and `/v1/messages` + `messages` checks from the actual selected candidate.

Before (`apps/edge/internal/openai/hot_path_light_test.go:437`):

```go
if req.PrepareProtocolTunnel != nil {
	prepared, body, bodyErr := buildTunnelBodyFromRequest(req, selected)
	// raw substring assertions
}
```

After:

```go
prepared, tunnelPrompt, err := decodeSelectedTunnelPrompt(req, selected)
if err != nil {
	t.Fatal(err)
}
if tunnelPrompt != req.Run.Prompt {
	t.Fatalf("decoded tunnel prompt mismatch")
}
```

#### Modified Files and Checklist

- [ ] `apps/edge/internal/openai/hot_path_light_test.go` — make preparation mandatory, decode the selected protocol body, assert exact first-user-message content/path/operation, and check exact correlations plus forbidden values in the decoded prompt.

#### Test Strategy

Extend `TestHotPathLightLocalTransition` through `assertCleanupPending` for both endpoint variants. Decode each captured local/review request body, prove OpenAI uses `/v1/chat/completions` and Anthropic uses `/v1/messages`, require the first user message content to equal the normalized prompt, assert local contains only selector stage/response and review contains selector plus local stage/response, and fail on a missing preparation callback.

#### Verification

```bash
go test -race -count=1 ./apps/edge/internal/openai -run 'TestHotPath(LightLocal|StageInput)'
```

Expected: PASS for OpenAI and Anthropic variants with mandatory decoded normalized/Chat/Messages correlation evidence.

## Modified Files Summary

| File | Items |
|---|---|
| `apps/edge/internal/openai/hot_path_stage_input.go` | REVIEW_API-1 |
| `apps/edge/internal/openai/hot_path_light_test.go` | REVIEW_API-1, REVIEW_API-2 |
| `agent-task/m-iop-hot-path-one-shot-execution/10+07,09_light_flow/CODE_REVIEW-cloud-G05.md` | REVIEW_API-1, REVIEW_API-2 |

## Final Verification

```bash
go test -race -count=1 ./apps/edge/internal/openai -run 'TestHotPath(Light|Review|StageInput)'
go test -race -count=1 ./packages/go/streamgate ./packages/go/config ./apps/edge/internal/openai ./apps/edge/internal/service
go vet ./apps/edge/internal/openai
gofmt -d apps/edge/internal/openai/hot_path_stage_input.go apps/edge/internal/openai/hot_path_light_test.go
git diff --check
```

Expected: every command exits 0; both Go test commands use fresh `-count=1`; contract-compatible opaque correlations and mandatory decoded OpenAI/Anthropic selected-protocol payload assertions pass; formatting and diff checks produce no output. Repository Edge-Node diagnostics, supplemental E2E smoke, full-cycle live execution, and credentialed provider smoke are not run because this follow-up is deterministic S08 input/test hardening and S16 owns live Hot Path smoke.

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