<!-- task=m-iop-agent-cli-runtime/26+19,21,22,23,25_parity_cutover plan=0 tag=REFACTOR -->

# Go Task-Loop Parity and Production Cutover

## For the Implementing Agent

Fill every implementation-owned section in `CODE_REVIEW-cloud-G10.md` with actual evidence and leave active files in place. Only the official reviewer owns verdict, archives, `complete.log`, and next-state classification. If a parity row or verification remains unresolved, record it as a blocker; do not waive it, ask the user, or fabricate zero-match evidence.

## Background

The Python dispatcher is the stabilized behavioral reference, while the accepted architecture makes the Go standalone runtime the production owner. This final packet composes the previously completed common packages and host features, proves a disposition-complete parity matrix, and redirects the project skill to the `iop-agent` entry point with no Python runtime dependency.

## 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:
  - `parity-cutover`: classify Python/Node behavior and cut production task-loop ownership to Go with zero unclassified/runtime dependency/duplicate
- Completion mode: check-on-pass

## Analysis

### Files Read

- `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`
- `agent-spec/runtime/edge-node-execution.md`
- `agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md`
- `agent-ops/skills/project/orchestrate-agent-task-loop/agents/openai.yaml`
- `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/execution_target_policy.py`
- `agent-ops/skills/project/orchestrate-agent-task-loop/scripts/dispatcher_observation.py`
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `packages/go/agentconfig/runtime_config.go`
- `packages/go/agentconfig/runtime_config_test.go`
- `packages/go/agenttask/ports.go`
- `packages/go/agenttask/types.go`
- `packages/go/agentstate/store.go`
- `configs/iop-agent.providers.yaml`
- `Makefile`

### SDD Criteria

Approved scenario S13 maps to `parity-cutover`. Its Evidence Map requires a complete `absorb|replace|not-applicable` matrix, stale dependency/duplicate/Python fallback searches, zero unclassified rows, and Python disposal evidence at Milestone completion transition. The packet therefore makes Go the only production route and marks each reference file disposal-ready; reference Python sources may remain only until the explicit Milestone completion transition stated by the Milestone/SDD, and must have zero production callers before this task can PASS.

### Verification Context

No handoff was supplied. Local sources are `agent-test/local/rules.md` and platform-common/testing smoke profiles. Current runner is Linux arm64, Go 1.26.2, repo `/config/workspace/iop-s0`, branch `feature/iop-agent-cli-runtime`, analyzed HEAD `bf64b7d86511a527ff48ddf196e33531551e79a5`. The external S14 packet is a predecessor, so this packet consumes its redacted manifest rather than rerunning provider login smoke. Use fresh focused/full Go tests, race, vet, deterministic `rg --sort path` searches, Go command dry-run fixtures, and `git diff --check`. Cached results are not accepted.

### Test Coverage Gaps

- Common manager/provider/workspace packages exist, but no standalone task-loop adapter composes every required port.
- Python behavior is distributed across a large dispatcher/test suite and has no machine-validated disposition file.
- The project skill and testing rule still name `dispatch.py`.
- No zero-match guard prevents static route/model/capability tables or a Node-local duplicate from returning after cutover.
- Python physical deletion is intentionally reserved for Milestone completion transition; this packet must produce an exact disposal manifest and zero runtime callers first.

### Symbol References

- Production command references to `dispatch.py` occur in `agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md` and `agent-ops/rules/project/domain/testing/rules.md`; both are replaced.
- `agent-ops/rules/project/rules.md` maps the legacy dispatcher script/test paths and must be reclassified as reference-fixture-only until completion disposal.
- No shared Go symbol is renamed. The new task-loop adapters implement existing `agenttask` ports.

### Split Judgment

The cutover is indivisible: switching the skill before port composition/parity proof breaks the operator path, while proving parity without switching leaves Python in production. Required predecessors are the CLI closure at 19, project-log closure at 21, local control at 22, client process manager at 23, and logged-smoke closure at 25; none has a `complete.log` yet. The task is last so it can consume the actual CLI, project-log, control, client-process, and field-smoke contracts.

### Scope Rationale

Do not change Node wire behavior, copy shared manager/provider algorithms into `apps/agent`, keep a Python fallback flag, hard-code lane/model/capacity tables, or delete Python reference fixtures before the zero-caller/disposition checks pass. Physical Python implementation deletion is performed only in the later Milestone completion transition required by S13, using the exact generated disposal manifest; this task does not silently treat retained reference files as production.

### Final Routing

- evaluation_mode: `first-pass`
- finalizer: `finalize-task-policy.sh pair`
- build: `cloud-G10`, basis `grade-boundary`, filename `PLAN-cloud-G10.md`
- review: `cloud-G10`, basis `official-review`, filename `CODE_REVIEW-cloud-G10.md`
- large_indivisible_context: `true`
- positive loop risks: `large behavior inventory`, `atomic operator cutover`, `cross-package port composition`, `zero-match/disposal evidence` (count `4`)
- recovery signals: rework `0`, evidence-integrity failure `false`
- capability-gap evidence: none

## Implementation Checklist

- [ ] Create a machine-validated disposition matrix covering every Python dispatcher/selector/observation and Node reference behavior as absorb, replace, or not-applicable.
- [ ] Implement standalone workflow, selection, provider, recovery, evidence, review, integration, and event adapters strictly over existing common Go contracts.
- [ ] Compose and test the production Go task-loop command, including dry-run, task-group filtering, retry-blocked, dependency-ready concurrency, lifecycle recovery, and terminal exit states.
- [ ] Redirect the project orchestration skill and testing rules to `iop-agent task-loop` and remove static model/route/capacity ownership from those surfaces.
- [ ] Add deterministic guards for zero unclassified rows, zero Python production callers/fallbacks, zero stale route/cap text, and zero Node duplicate implementation.
- [ ] Record exact Python reference-fixture disposal paths/checksums and the Milestone-completion deletion/verification procedure without deleting them before parity evidence closes.
- [ ] Update the standalone contract with actual S13 sources and run fresh package/full/race/vet/dry-run/cutover verification.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REFACTOR-1] Establish the Disposition Matrix

#### Problem

`agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md:155,180` requires every stabilized behavior to be classified, but no current artifact fails on an omitted or ambiguous row.

#### Solution

Add a YAML manifest keyed by stable behavior ID. Each row names reference sources/tests, one disposition, Go owner/source/test, invariants, and disposal status. Include routing/pinning, quota/promotion, prompt/session lifecycle, Pi selfcheck, official review, failure budgets, recovery, work claims, WORK_LOG, dependency frontier, process evidence, archive completion, and Node common-provider consumption. Validate unique IDs, existing paths, allowed dispositions, required Go evidence, no wildcard sources, and full reference symbol inventory.

#### Modified Files and Checklist

- [ ] `apps/agent/internal/taskloop/testdata/parity.yaml` — add the complete disposition matrix.
- [ ] `apps/agent/internal/taskloop/parity_test.go` — validate schema, coverage, paths, owners, and zero unclassified rows.

#### Test Strategy

Write `TestParityManifestIsDispositionComplete` plus negative fixtures generated in memory for missing/duplicate/unclassified/stale paths.

#### Verification

```bash
go test -count=1 ./apps/agent/internal/taskloop -run TestParityManifestIsDispositionComplete
```

Expected: zero missing, duplicate, or unclassified rows.

### [REFACTOR-2] Implement Standalone Task-Loop Adapters

#### Problem

`packages/go/agenttask/ports.go:40-349` defines workflow, selector, isolation, invoker, recovery, evidence, reviewer, integrator, and event ports; the standalone host has no production adapters for project task artifacts and CLI review flow.

#### Solution

Implement application adapters that translate project-owned PLAN/review artifacts into normalized `agenttask` snapshots, delegate route evaluation to immutable `agentpolicy`, construct catalog/common-runtime provider launches under `agentworkspace` confinement, inspect exact locators for recovery, observe/repair workflow evidence under shared contracts, invoke official review through the selected common provider, and delegate serial integration to `agentworkspace.SerialIntegrator`. Parsing remains application-owned; transitions/admission/integration decisions remain common-owned.

#### Modified Files and Checklist

- [ ] `apps/agent/internal/taskloop/workflow.go` — parse registered project task artifacts and explicit predecessors.
- [ ] `apps/agent/internal/taskloop/workflow_test.go` — cover active/complete/malformed/dependency fixtures.
- [ ] `apps/agent/internal/taskloop/selector.go` — adapt immutable policy decisions.
- [ ] `apps/agent/internal/taskloop/selector_test.go` — cover route pin/tamper/failover.
- [ ] `apps/agent/internal/taskloop/provider.go` — adapt catalog/common provider launches.
- [ ] `apps/agent/internal/taskloop/provider_test.go` — prove confinement and locator ownership.
- [ ] `apps/agent/internal/taskloop/recovery.go` — inspect exact process/session/artifact locators.
- [ ] `apps/agent/internal/taskloop/recovery_test.go` — cover live/submitted/exited/ambiguous.
- [ ] `apps/agent/internal/taskloop/evidence.go` — observe/repair plan-review evidence.
- [ ] `apps/agent/internal/taskloop/evidence_test.go` — cover provider-neutral and Pi-only repair.
- [ ] `apps/agent/internal/taskloop/review.go` — invoke official review through common runtime.
- [ ] `apps/agent/internal/taskloop/review_test.go` — cover verdict and no premature review.
- [ ] `apps/agent/internal/taskloop/integration.go` — bind immutable change sets/integrator.
- [ ] `apps/agent/internal/taskloop/integration_test.go` — cover retained results/terminal-deferred continuation.

#### Test Strategy

Every adapter gets normal, boundary, malformed identity, cancellation, and restart tests with fake provider processes. No unit/integration test may launch real provider CLIs.

#### Verification

```bash
go test -count=1 ./apps/agent/internal/taskloop
go test -count=1 -race ./apps/agent/internal/taskloop
```

Expected: all adapter and ordering matrices pass without real provider calls.

### [REFACTOR-3] Compose the Go Task-Loop Command

#### Problem

`agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md:172-193` still calls Python, and no standalone CLI command owns scanning, lifecycle, or terminal exit codes.

#### Solution

Compose the adapters with `agentstate.Store`, `agenttask.Manager`, `agentworkspace`, project logs, and host lifecycle. Add `iop-agent task-loop [--dry-run] [--task-group NAME] [--retry-blocked]`. Preserve deterministic attention/lifecycle output while deriving provider/model/capacity from the immutable runtime catalog/policy. Exit 0 only when all in-scope work is terminal-complete, 2 for drained blockers, and 3 for non-terminal tracking state.

#### Modified Files and Checklist

- [ ] `apps/agent/internal/taskloop/module.go` — compose stores/adapters/manager and terminal states.
- [ ] `apps/agent/internal/taskloop/module_test.go` — cover lifecycle, restart, frontier, blocker, and exit codes.
- [ ] `apps/agent/internal/command/task_loop.go` — add the Cobra subcommand.
- [ ] `apps/agent/internal/command/task_loop_test.go` — cover flags/output/exit behavior.
- [ ] `apps/agent/cmd/agent/main.go` — register production task-loop composition.
- [ ] `apps/agent/cmd/agent/main_test.go` — cover process exit mapping.

#### Test Strategy

Use two registered project fixtures with explicit dependencies, disjoint/overlapping work, one blocked provider, restart state, and completion. Assert only explicit predecessors gate execution and unrelated project work drains.

#### Verification

```bash
go test -count=1 -race ./apps/agent/internal/taskloop ./apps/agent/internal/command ./apps/agent/cmd/agent
make build-agent
build/bin/iop-agent task-loop --help
```

Expected: tests pass and help exposes all compatibility flags.

### [REFACTOR-4] Cut the Project Skill to Go

#### Problem

`agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md:172-193` invokes `dispatch.py`, and the skill owns static route/model/capacity tables that can drift from runtime config.

#### Solution

Rewrite procedure examples to call `iop-agent task-loop`; keep skill-level user interaction/final gates but delegate task scan, selection, capacity, recovery, logs, and lifecycle to the daemon command. Remove hard-coded provider/model/time/capacity tables and refer to runtime-config revisions/evidence. Update testing domain ownership from Python scripts/tests to the Go command and parity fixture. Retain Python paths only in the disposal manifest as non-production reference fixtures.

#### Modified Files and Checklist

- [ ] `agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md` — use Go runtime and remove static route/cap ownership.
- [ ] `agent-ops/rules/project/domain/testing/rules.md` — update dispatcher verification ownership.
- [ ] `agent-ops/rules/project/rules.md` — replace legacy path mappings with current task-loop/parity verification paths.

#### Test Strategy

Static tests in API-5 prove no runtime Python command or model table remains. Dry-run through the built binary proves the documented flags.

#### Verification

```bash
rg -n --sort path 'dispatch\\.py|python3 .*orchestrate-agent-task-loop|gpt-5\\.6|claude-opus|Gemini|ornith|laguna' \
  agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md \
  agent-ops/rules/project/domain/testing/rules.md \
  agent-ops/rules/project/rules.md
```

Expected: zero matches.

### [REFACTOR-5] Add Cutover and Duplicate Guards

#### Problem

`agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md:155,180` requires zero Python fallback, stale static policy, and Node duplicate, but no executable guard enforces those zero-match conditions.

#### Solution

Add Go tests that run deterministic repository searches and inspect the parity manifest. Production surfaces must not invoke/reference Python dispatcher files; task-loop sources must not contain hard-coded model/capacity tables; Node must consume common `agentruntime`/`agentprovider` rather than define task manager/provider lifecycle duplicates. Permit Python filenames only inside the parity disposal manifest and their own reference directory.

#### Modified Files and Checklist

- [ ] `apps/agent/internal/taskloop/cutover_test.go` — add zero-match and ownership guards.
- [ ] `Makefile` — add `test-iop-agent-parity`.

#### Test Strategy

`TestNoPythonProductionDependency`, `TestNoStaticRouteCapabilityOwnership`, and `TestNoNodeDuplicateAgentRuntime` must report exact paths/lines on failure.

#### Verification

```bash
make test-iop-agent-parity
```

Expected: disposition count is complete and all three zero-match guards pass.

### [REFACTOR-6] Prepare Python Disposal Evidence

#### Problem

`agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md:155,180` requires physical Python disposal at Milestone completion, but deletion before verified Go cutover would remove the behavioral oracle prematurely.

#### Solution

Record every Python reference source/test path, SHA-256, corresponding parity row, and `production_callers=0` in the manifest. Add a read-only `iop-agent task-loop parity --disposal-manifest` command that prints the exact paths and a completion-transition verification command. Do not add a Python fallback or an automatic delete flag. The later Milestone completion transition deletes only these manifest-resolved paths after all Roadmap tasks and completion review gates pass.

#### Modified Files and Checklist

- [ ] `apps/agent/internal/taskloop/testdata/parity.yaml` — add exact disposal inventory and hashes.
- [ ] `apps/agent/internal/taskloop/parity.go` — load/validate/report disposal readiness.
- [ ] `apps/agent/internal/command/task_loop.go` — expose read-only parity report.
- [ ] `apps/agent/internal/taskloop/parity_test.go` — verify hashes and zero production callers.

#### Test Strategy

Mutated hash/path/caller fixtures must fail. The report must be stable-sorted and contain no archive scan.

#### Verification

```bash
build/bin/iop-agent task-loop parity --disposal-manifest
go test -count=1 ./apps/agent/internal/taskloop -run 'TestParity|TestNoPython'
```

Expected: every retained Python reference is checksum-bound and has zero production callers.

### [REFACTOR-7] Record S13 Sources and Full Regression

#### Problem

`agent-contract/inner/iop-agent-cli-runtime.md:9-14,139-147` lacks actual S13 parity/cutover sources, and package tests alone cannot detect repository-wide regression.

#### Solution

Record taskloop/parity/skill source paths and the explicit completion-transition disposal boundary. Run focused, race, all Go package, vet, dry-run, parity, and static searches after the cutover.

#### Modified Files and Checklist

- [ ] `agent-contract/inner/iop-agent-cli-runtime.md` — add S13 source/evidence/disposal links.

#### Test Strategy

No new test file beyond API-1 through API-6; run the complete suite fresh.

#### Verification

```bash
go test -count=1 ./packages/go/... ./apps/agent/...
go vet ./packages/go/... ./apps/agent/...
build/bin/iop-agent task-loop --dry-run --task-group m-iop-agent-cli-runtime
git diff --check
```

Expected: all pass with no real provider launch in tests.

## Dependencies and Execution Order

Required predecessors are `19+14,16,18_cli_binary_contract`, `21+13,17,20_project_log_sink`, `22+16_local_control`, `23+14,16,22_client_process_manager`, and `25+19,21,22,23,24_logged_smoke_closure`. Each must have exactly one same-group active or archived `complete.log`; all are currently missing. Complete REFACTOR-1/2 before command composition, REFACTOR-3 before skill cutover, then REFACTOR-4/5/6/7.

## Modified Files Summary

| File | Item |
|------|------|
| `apps/agent/internal/taskloop/testdata/parity.yaml` | REFACTOR-1, REFACTOR-6 |
| `apps/agent/internal/taskloop/parity.go` | REFACTOR-6 |
| `apps/agent/internal/taskloop/parity_test.go` | REFACTOR-1, REFACTOR-6 |
| `apps/agent/internal/taskloop/workflow.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/workflow_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/selector.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/selector_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/provider.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/provider_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/recovery.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/recovery_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/evidence.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/evidence_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/review.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/review_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/integration.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/integration_test.go` | REFACTOR-2 |
| `apps/agent/internal/taskloop/module.go` | REFACTOR-3 |
| `apps/agent/internal/taskloop/module_test.go` | REFACTOR-3 |
| `apps/agent/internal/taskloop/cutover_test.go` | REFACTOR-5 |
| `apps/agent/internal/command/task_loop.go` | REFACTOR-3, REFACTOR-6 |
| `apps/agent/internal/command/task_loop_test.go` | REFACTOR-3 |
| `apps/agent/cmd/agent/main.go` | REFACTOR-3 |
| `apps/agent/cmd/agent/main_test.go` | REFACTOR-3 |
| `agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md` | REFACTOR-4 |
| `agent-ops/rules/project/domain/testing/rules.md` | REFACTOR-4 |
| `agent-ops/rules/project/rules.md` | REFACTOR-4 |
| `Makefile` | REFACTOR-5 |
| `agent-contract/inner/iop-agent-cli-runtime.md` | REFACTOR-7 |

## Final Verification

```bash
gofmt -w apps/agent/internal/taskloop/*.go apps/agent/internal/command/task_loop*.go apps/agent/cmd/agent/*.go
go test -count=1 ./apps/agent/internal/taskloop ./apps/agent/internal/command ./apps/agent/cmd/agent
go test -count=1 -race ./apps/agent/internal/taskloop ./packages/go/agenttask ./packages/go/agentstate
go test -count=1 ./packages/go/... ./apps/agent/...
go vet ./packages/go/... ./apps/agent/...
make build-agent
make test-iop-agent-parity
build/bin/iop-agent task-loop --help
build/bin/iop-agent task-loop --dry-run --task-group m-iop-agent-cli-runtime
build/bin/iop-agent task-loop parity --disposal-manifest
rg -n --sort path 'dispatch\\.py|python3 .*orchestrate-agent-task-loop|gpt-5\\.6|claude-opus|Gemini|ornith|laguna' agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md agent-ops/rules/project/domain/testing/rules.md agent-ops/rules/project/rules.md
git diff --check
```

Expected: every test/build/vet/dry-run/parity command passes and the final `rg` returns exit 1 with no matches. Python reference fixtures remain checksum-bound and have zero callers until the separate Milestone completion transition deletes exactly the disposal manifest paths. After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.
