<!-- task=m-iop-hot-path-one-shot-execution/01_preset_schema plan=2 tag=REVIEW_API milestone-task=preset-schema,hot-preset -->

# Correct Execution Preset Schema and Fail-Closed Validation

## For the Implementing Agent

Implement this follow-up, run every verification command, and fill every implementation-owned section of `CODE_REVIEW-cloud-G06.md` with actual notes and stdout/stderr. Keep the active files in place and report ready for 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 the code-review skill.

## Background

The first implementation added a data-only preset catalog, but its YAML shape diverges from the approved SDD and its validator accepts invalid multi-mode routes and required-stage option overflow. This follow-up replaces the unconsumed schema before downstream child 02 publishes immutable generations.

## Archive Evidence Snapshot

- Current pair will be archived as `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/plan_local_G03_1.log` and `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/code_review_cloud_G03_1.log`.
- Verdict: FAIL. Required 2, Suggested 0, Nit 0.
- Required: restore the approved top-level `execution_presets[]` selector/per-mode-route/workspace-tool shape; validate every allowed mode and all stage option bounds deterministically.
- Reviewer evidence: focused, race, vet, and `git diff --check` passed. A focused reproducer accepted `allowed_modes: [light,direct]` with light stages and a five-option required light stage, while the approved top-level list shape failed decode with `execution_presets expected a map, got slice`.
- Roadmap carryover: `milestone-task=preset-schema,hot-preset`; SDD S02/S04 remain the acceptance boundary. Runtime generation, model-to-preset one-of, authorization, and request-local binding compilation remain in later children.

## Analysis

### Files Read

- `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-contract/inner/edge-config-runtime-refresh.md`
- `agent-spec/runtime/provider-pool-config-refresh.md`
- `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/PLAN-local-G03.md`
- `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/CODE_REVIEW-cloud-G03.md`
- `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/plan_local_G07_0.log`
- `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/code_review_cloud_G07_0.log`
- `agent-task/m-iop-hot-path-one-shot-execution/02+01_preset_generation/PLAN-local-G07.md`
- `agent-task/m-iop-hot-path-one-shot-execution/08+02,04,06_workspace_binding/PLAN-local-G06.md`
- `packages/go/config/config.go`
- `packages/go/config/edge_types.go`
- `packages/go/config/execution_preset_types.go`
- `packages/go/config/load.go`
- `packages/go/config/provider_types.go`
- `packages/go/config/execution_preset_config_test.go`
- `configs/edge.yaml`
- `go.mod`

### SDD Criteria

The selected SDD is approved and unlocked. First-line scope remains `milestone-task=preset-schema,hot-preset`. S02 requires preset decode/normalization suitable for later generation isolation; S04 requires registered `direct`/`light` shapes and startup rejection of `heavy`/custom handlers. Evidence Map rows S02/S04 require the config fixture and handler-registry evidence implemented here, so the checklist uses the exact Interface Contract fields at SDD lines 90-94 and tests multi-mode route behavior rather than separate single-mode presets only.

### Verification Context

No external handoff was supplied. Repository-native evidence came from the platform-common/testing domain rules, `agent-test/local/platform-common-smoke.md`, the approved SDD, current source/tests, and fresh reviewer commands. Go resolves to `/config/.local/bin/go` (`go1.26.2 linux/arm64`, GOROOT `/config/opt/go`). `go test -count=1 ./packages/go/config`, `go test -race -count=1 ./packages/go/config`, `go vet ./packages/go/config`, and `git diff --check` all exited 0. The broader `go test -count=1 ./packages/go/...` was not a closure oracle because unrelated fake-CLI and confinement suites fail on this host's executable-temp/xattr restrictions; the affected config package passed in both attempts. No external provider, credential, port, or runner is required. Confidence: high.

### Test Coverage Gaps

- Approved SDD list/selector/routes/workspace-tools decode: missing; current fixtures use the divergent nested catalog.
- One preset with both `direct` and `light`: missing; current tests use separate single-mode presets.
- Required-stage option overflow: missing and currently fail-open.
- Selector/stage canonical model references, route/allowed-mode exact correspondence, duplicate alternatives, missing workspace operations, and deterministic unsupported-mode diagnostics: missing.
- Provider-only compatibility: covered and must remain covered.

### Symbol References

No committed symbol is renamed. The uncommitted preset types are referenced only by `EdgeConfig`, their config tests, and downstream active child plans; child 02 is blocked on this directory's `complete.log` and will consume the corrected types.

### Split Judgment

Keep one compact follow-up. The YAML types, in-place normalization, closed validation, and regression fixtures form one contract and cannot independently PASS. Do not move immutable generation publication into child 01; child 02 remains the dependent runtime boundary.

### Scope Rationale

Modify only the config schema/load/test boundary. Exclude runtime cloning/refresh (child 02), `models[].execution_preset` one-of (child 03), principal authorization, selector execution, request state, workspace binding compilation (child 08), protocol streaming, and active preset examples in `configs/edge.yaml`. The checked-in example remains provider-only until runtime activation is implemented.

### Final Routing

`evaluation_mode=isolated-reassessment`; `finalizer=finalize-task-policy.sh` (`pair`). Build and review closures are all true. Scores `(scope=2,state=0,blast=2,evidence=2,verification=0)` yield G06. Build base is `local-fit`, `large_indivisible_context=false`, positive risks are `boundary_contract,structured_interpretation,variant_product` (3), `review_rework_count=1`, and `evidence_integrity_failure=true`; recovery boundary routes build to cloud as `PLAN-cloud-G06.md`. Official review is cloud G06 in `CODE_REVIEW-cloud-G06.md`; no capability gap or user decision remains.

## Implementation Checklist

- [ ] Replace the preset YAML/types with the approved top-level selector, per-mode routes/stages, canonical model references, and ordered workspace-tool alternatives; normalize identifiers in place.
- [ ] Enforce strict preset-field decoding, exact allowed-mode/route correspondence, direct/light stage rules, option and binding bounds, unique identifiers, canonical model resolution, unsupported handler rejection, and deterministic diagnostics.
- [ ] Rewrite preset config tests for SDD-shaped valid fixtures and all reviewer fail-open regressions while preserving provider-only compatibility.
- [ ] Run focused, fresh, race, vet, and diff verification exactly as written.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Restore the preset contract and fail-closed validator

#### Problem

`packages/go/config/execution_preset_types.go:12-57` decodes a nested `execution_presets.presets[]` shape with `selector_stage`, shared `route_stages`, and workspace ids instead of the approved SDD fields. `validatePreset` at lines 155-160 checks only the first allowed mode, and `validatePresetRouteStages` at lines 200-210 skips option bounds for required stages. The current tests at `packages/go/config/execution_preset_config_test.go:119-166` cover multiple presets, not one multi-mode preset.

#### Solution

Replace the unconsumed types before downstream publication:

```go
// Before: edge_types.go:66 and execution_preset_types.go:22-38
ExecutionPresets ExecutionPresetCatalog
type ExecutionPreset struct {
    ID                string
    SelectorStage     string
    RouteStages       []ExecutionRouteStage
    AllowedModes      []string
    WorkspaceBindings []ExecutionWorkspaceBinding
}

// After
ExecutionPresets []ExecutionPreset
type ExecutionPreset struct {
    ID             string
    Selector       ExecutionModelBinding
    AllowedModes   []string
    Routes         map[string]ExecutionRoute
    WorkspaceTools []ExecutionWorkspaceToolAlternative
}
type ExecutionModelBinding struct {
    Model   string
    Options map[string]any
}
type ExecutionRouteStage struct {
    Role    string
    Model   string
    Options map[string]any
}
```

Use `mapstructure`/YAML tags for the exact SDD keys. Keep workspace alternatives ordered as a slice. Each alternative has a unique name and a closed `prepare|read|write|delete` operation map; each operation declares tool-name/schema matching, canonical-to-actual argument locations, success/error result matching, and whether write creates missing parents. These are data-only descriptors for child 08, not executable callbacks.

Decode the `execution_presets` subtree with unused-field reporting so unsupported handler/field spellings cannot disappear silently. The existing `github.com/mitchellh/mapstructure` module may be promoted from indirect to direct without changing its version. Normalize ids, modes, roles, model refs, alternative names, operation/tool fields in place. Build the canonical `models[].id` set and reject dangling selector/stage refs. Require unique allowed modes and route keys exactly equal to them; `direct` has zero stages, `light` has exactly `local,review`, and every stage option map is bounded before role matching. Require `read/write/delete` for light plus `prepare` when write cannot create parents. Sort descriptor/route names before diagnostics.

#### Modified Files and Checklist

- [ ] `go.mod` — promote the already-resolved mapstructure dependency only if required for strict subtree decoding.
- [ ] `packages/go/config/config.go` — update responsibility comments for the corrected types.
- [ ] `packages/go/config/edge_types.go` — expose top-level `execution_presets[]`.
- [ ] `packages/go/config/execution_preset_types.go` — replace data shapes and implement in-place normalization plus deterministic closed validation.
- [ ] `packages/go/config/load.go` — strict-decode the preset subtree and pass canonical model ids into validation.
- [ ] `packages/go/config/execution_preset_config_test.go` — replace divergent fixtures and add regression matrices.

#### Test Strategy

Rewrite `TestLoadEdgeExecutionPresetCatalog` with direct-only and one `direct,light` preset using `selector`, `routes.direct.stages`, `routes.light.stages` with canonical model ids/options, and ordered workspace-tool alternatives. Expand `TestLoadEdgeExecutionPresetRejectsInvalidShape` for the approved top-level list, unknown preset fields, duplicate ids/modes/routes/alternatives, dangling selector/stage models, missing/extra route keys, direct stages, light order/count, five options on a required stage, missing workspace roles/prepare capability, heavy/custom handlers, and stable sorted error text. Retain the provider-only fixture.

#### Verification

Run `go test -count=1 ./packages/go/config -run 'TestLoadEdgeExecutionPreset(Catalog|RejectsInvalidShape)$'`; expect PASS with both reviewer fail-open cases rejected.

## Modified Files Summary

| File | Items |
|------|-------|
| `go.mod` | REVIEW_API-1 |
| `packages/go/config/config.go` | REVIEW_API-1 |
| `packages/go/config/edge_types.go` | REVIEW_API-1 |
| `packages/go/config/execution_preset_types.go` | REVIEW_API-1 |
| `packages/go/config/load.go` | REVIEW_API-1 |
| `packages/go/config/execution_preset_config_test.go` | REVIEW_API-1 |
| `agent-task/m-iop-hot-path-one-shot-execution/01_preset_schema/CODE_REVIEW-cloud-G06.md` | REVIEW_API-1 |

## Final Verification

Cached test output is not acceptable.

```bash
go test -count=1 ./packages/go/config -run 'TestLoadEdgeExecutionPreset(Catalog|RejectsInvalidShape)$'
go test -count=1 ./packages/go/config
go test -race -count=1 ./packages/go/config
go vet ./packages/go/config
git diff --check
```

Expected: every command exits 0; the approved SDD preset shape loads, provider-only configs remain compatible, all allowed modes resolve to exact validated routes, every canonical model reference resolves, and unsupported or malformed shapes fail deterministically.

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