<!-- task=m-iop-agent-cli-runtime/06+05_config_registry plan=1 tag=REVIEW_API -->

# Reject Partial Runtime Target References

## For the Implementing Agent

Implement only this follow-up, run every verification command, and fill all implementation-owned sections in `CODE_REVIEW-*-G??.md` with actual notes and output. Keep the active files in place and report ready for review; finalization belongs to the code-review skill. If blocked, record 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`.

## Background

The initial config-registry implementation passed its package, race, vet, and broader Go regression checks. Official review found that a partial selection default can bypass catalog validation when `profile` is empty. This follow-up closes that strict-validation gap without changing watcher, revision, merge, or schema ownership behavior.

## Archive Evidence Snapshot

- Prior task path: `agent-task/m-iop-agent-cli-runtime/06+05_config_registry`.
- Archived pair: `agent-task/m-iop-agent-cli-runtime/06+05_config_registry/plan_cloud_G09_0.log` and `agent-task/m-iop-agent-cli-runtime/06+05_config_registry/code_review_cloud_G09_0.log`.
- Verdict: FAIL; Required=1, Suggested=0, Nit=0.
- Required finding: `packages/go/agentconfig/runtime_config.go:569` accepts provider-only or model-only `TargetRef` values because catalog binding returns early when `profile` is empty.
- Affected files: `packages/go/agentconfig/runtime_config.go`, `packages/go/agentconfig/runtime_config_test.go`.
- Reviewer verification: fresh package, repeated, race, vet, importer, and `packages/go/...` tests passed; a focused configured-catalog reproducer with `selection.default.provider: missing-provider` failed because the load unexpectedly succeeded.
- Roadmap carryover: SDD scenario S05 and Milestone Task `config-registry` remain incomplete until strict invalid-catalog-reference rejection has PASS evidence.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- Milestone link: [Milestone document](agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md)
- Task ids:
  - `config-registry`: repo-global/local registry and immutable revision
- Completion mode: check-on-pass

## Analysis

### Files Read

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-test/local/rules.md`
- `agent-test/local/platform-common-smoke.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`
- `agent-contract/index.md`
- `agent-contract/inner/agent-runtime.md`
- `agent-contract/inner/iop-agent-cli-runtime.md`
- `packages/go/agentconfig/catalog.go`
- `packages/go/agentconfig/load.go`
- `packages/go/agentconfig/validate.go`
- `packages/go/agentconfig/runtime_config.go`
- `packages/go/agentconfig/watcher.go`
- `packages/go/agentconfig/catalog_test.go`
- `packages/go/agentconfig/default_catalog_test.go`
- `packages/go/agentconfig/runtime_config_test.go`
- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/05_contract_boundary/complete.log`
- `agent-task/m-iop-agent-cli-runtime/06+05_config_registry/plan_cloud_G09_0.log`
- `agent-task/m-iop-agent-cli-runtime/06+05_config_registry/code_review_cloud_G09_0.log`

### SDD Criteria

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`; approved, with its lock released.
- Targeted scenario: S05 for Milestone Task `config-registry`.
- Evidence Map S05 requires repo-global/local merge, read-only repo input, invalid configuration, watcher behavior, and revision A/B integration evidence.
- The follow-up checklist narrows the invalid-configuration evidence to the missing catalog-reference variants while retaining the complete S05 regression commands.

### Test Environment Rules

- Environment: `local`.
- `agent-test/local/rules.md` was present and read. It requires the host `go` binary/GOROOT identity to be recorded and fresh target-package verification to run in the current checkout.
- `agent-test/local/platform-common-smoke.md` was present and read. Its protobuf generation and Edge-Node transport commands are not applicable because this follow-up changes neither proto nor Edge-Node wire; direct `agentconfig`, importer, and shared package regression commands are used from the original plan and contract change checklist.
- Required commands use `-count=1`; cached output is not acceptable for closure. The repeated package test and race test provide stability evidence.
- No external runner, service, credential, port, or non-local preflight is required.

### Test Coverage Gaps

- Existing tests cover unknown profiles and profile/provider/model mismatches only after a profile is present.
- No test rejects provider-only or model-only `selection.default` values, so both variants bypass the configured catalog.
- Existing merge, immutable snapshot, read-only repo, invalid YAML/value, and watcher A/B tests remain applicable and need no behavioral rewrite.

### Symbol References

- None. No symbol is renamed or removed.

### Split Judgment

- Keep one compact plan: structural `TargetRef` validation and its regression table form one indivisible strict-load invariant.
- Subtask predecessor `05_contract_boundary` is satisfied by `agent-task/archive/2026/07/m-iop-agent-cli-runtime/05_contract_boundary/complete.log`.

### Scope Rationale

- Change only partial `TargetRef` validation and focused tests.
- Do not alter watcher polling/coalescing, revision hashing, merge precedence, array replacement, catalog normalization, contracts, roadmap files, other runtime packages, or protobuf.

### Final Routing

- `evaluation_mode=isolated-reassessment`; finalizer=`finalize-task-policy.sh`, mode=`pair`.
- Build closures: scope/context/verification/evidence/ownership/decision are all closed from the source branch, contract requirement, focused failing reproducer, and deterministic tests. Capability gap: none.
- Build scores: scope=1, state=0, blast=1, evidence=0, verification=1; grade G03; base/route basis=`local-fit`; lane=`local`; filename=`PLAN-local-G03.md`.
- Review closures: all closed. Review scores: scope=1, state=0, blast=1, evidence=1, verification=1; route basis=`official-review`; lane=`cloud`; grade G04; filename=`CODE_REVIEW-cloud-G04.md`.
- `large_indivisible_context=false`; matched loop risks=`structured_interpretation`; count=1.
- Recovery signals: `review_rework_count=1`, `evidence_integrity_failure=false`; risk boundary=false; recovery boundary=false.

## Implementation Checklist

- [ ] Reject non-empty provider/model selection targets that omit the runtime profile, while preserving a fully empty optional default and existing profile-based catalog validation.
- [ ] Add table-driven provider-only and model-only regression cases and run fresh package, repeated, race, importer, shared-package, vet, formatting, and diff verification.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Enforce Complete Selection Target Identity

**Problem:** At `packages/go/agentconfig/runtime_config.go:569`, catalog binding returns success whenever `target.Profile` is empty. A configured catalog therefore accepts unknown provider-only and model-only selection defaults, violating the contract requirement that invalid catalog references fail the load.

**Solution:** Treat a fully empty optional selection default as valid, but reject any `TargetRef` that supplies `provider` or `model` without the runtime `profile`. Enforce this structural rule in `validateTargetRef` so it also applies before catalog-specific resolution.

Before (`packages/go/agentconfig/runtime_config.go:650`):

```go
func validateTargetRef(label string, target TargetRef) error {
	for field, value := range map[string]string{
		"provider": target.Provider,
		"model":    target.Model,
		"profile":  target.Profile,
	} {
```

After:

```go
func validateTargetRef(label string, target TargetRef) error {
	if target.Profile == "" && (target.Provider != "" || target.Model != "") {
		return fmt.Errorf("agentconfig: %s profile is required when provider or model is set", label)
	}
	for field, value := range map[string]string{
		"provider": target.Provider,
		"model":    target.Model,
		"profile":  target.Profile,
	} {
```

**Modified Files and Checklist:**

- [ ] `packages/go/agentconfig/runtime_config.go`: reject partial target identities before catalog lookup while retaining the all-empty optional default.
- [ ] `packages/go/agentconfig/runtime_config_test.go`: add a table-driven regression for provider-only and model-only selection defaults and confirm a fully empty default remains valid.

**Test Strategy:** Add `TestLoadRuntimeConfigRejectsPartialSelectionDefaultTargets` in `packages/go/agentconfig/runtime_config_test.go`. Use the configured catalog fixture, a valid local profile, and provider-only/model-only replacements; assert each load fails with a profile-required diagnostic. Include an all-empty default control that loads successfully.

**Verification:** `go test -count=1 ./packages/go/agentconfig` must pass.

## Modified Files Summary

| File | Item |
|---|---|
| `packages/go/agentconfig/runtime_config.go` | REVIEW_API-1 |
| `packages/go/agentconfig/runtime_config_test.go` | REVIEW_API-1 |

## Dependencies and Execution Order

`agent-task/archive/2026/07/m-iop-agent-cli-runtime/05_contract_boundary/complete.log` satisfies predecessor index `05`. Apply the validation change and its regression table together before final verification.

## Final Verification

```bash
command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT
go test -count=1 ./packages/go/agentconfig
go test -count=20 ./packages/go/agentconfig
go test -count=1 -race ./packages/go/agentconfig
go test -count=1 ./packages/go/agentprovider/catalog ./packages/go/agenttask
go test -count=1 ./packages/go/...
go vet ./packages/go/agentconfig
gofmt -d packages/go/agentconfig/runtime_config.go packages/go/agentconfig/runtime_config_test.go packages/go/agentconfig/watcher.go
git diff --check
```

All commands must pass with fresh test execution and `gofmt -d`/`git diff --check` must produce no diagnostics.

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