<!-- task=m-iop-agent-cli-runtime plan=0 tag=API -->

# Code Review Reference - API

> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `Implementation Checklist`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked, record the exact blocker, attempted commands/output, and resume condition only in implementation-owned evidence fields.
> Do not ask the user directly, present choices, call user-input tools, create control-plane stop files, or classify the next state.
> Finalization (`Code Review Result`, log rename, `complete.log`, archive moves, `Review-Only Checklist`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.

## Overview

date=2026-07-31
task=m-iop-agent-cli-runtime, plan=0, tag=API

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- Milestone link: [Milestone 문서](agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md)
- Task ids:
  - `cli-surface`: headless binary, split config, Milestone 조회·선택·preview, lifecycle, work별 overlay/integration/blocker 관측
- Completion mode: check-on-pass

## Archive Evidence Snapshot

- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/19+14,16,18_cli_binary_contract/complete.log`: PASS 시점에도 `cli-surface`는 partial이었고, complete S10 command transcript와 authoritative daemon/runtime wiring이 후속 조건으로 남았다.
- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/24+19,21,22,23_daemon_wiring/complete.log`: daemon/runtime wiring과 lifecycle 검증은 PASS했으므로 이 Plan은 그 ownership을 재구성하지 않는다.
- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/25+19,21,22,23,24_logged_smoke_closure/complete.log`: 로그인 macOS logged smoke와 field evidence는 PASS했다. 이번 변경은 provider 실행 경로가 아니라 S10 CLI 의미와 archive-only local regression을 닫는다.
- Roadmap carryover: `cli-surface`만 unchecked이며 exact `Roadmap Completion`과 fresh `go test -count=1 ./apps/agent/...` PASS가 필요하다.

## For the Review Agent

> **[REVIEW AGENT ONLY]** The finalization steps below are review-agent only. Implementing agents must not execute this section.

Compare implementation of each item against source files and verify that output in `Verification Results` matches code.
Review completion means the following steps are finished:

1. Append verdict and `review_rework_count` / `evidence_integrity_failure` routing signals.
2. Archive `CODE_REVIEW-cloud-G07.md` → `code_review_cloud_G07_0.log` and `PLAN-local-G07.md` → `plan_local_G07_0.log`.
3. If PASS, write `complete.log` and move active task directory to `agent-task/archive/YYYY/MM/m-iop-agent-cli-runtime/`. If WARN/FAIL, fully write the next filesystem state required by the code-review skill.
4. If PASS and task group is `m-<milestone-slug>`, report completion event metadata. Roadmap state check and `update-roadmap` calls are runtime responsibilities.
5. Check applicable `Review-Only Checklist` items at the final `.log` location before reporting.

---

## Implementation Item Completion

| Item | Status |
|------|---------|
| API-1 | [x] |
| API-2 | [x] |
| API-3 | [x] |

## Implementation Checklist

- [x] [API-1] Implement one deterministic selectable-Milestone catalog over active and archive-only task groups, make missing active directories archive-aware, and add normal/boundary regression tests.
- [x] [API-2] Replace work-unit-shaped Milestone output and lossy singular status fields with exact Milestone summaries and ordered per-work status DTOs, then update exact text/JSON and adapter tests.
- [x] [API-3] Make the S10 transcript and config-free dry-run hermetic, add a built-binary headless transcript, update the S10 contract evidence, and run the complete local verification matrix without real provider execution.
- [x] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

## Review-Only Checklist

> **[REVIEW AGENT ONLY]** This checklist is used only by the review agent.
> Implementing agents must not modify or check this section.

- [x] Append one verdict of `PASS`, `WARN`, or `FAIL` and verified `review_rework_count`, `evidence_integrity_failure` to `Code Review Result`.
- [x] Verify that verdict, `Dimension Assessment`, and Required/Suggested/Nit classifications match.
- [x] Archive active `CODE_REVIEW-*-G??.md` to `code_review_cloud_G07_0.log`.
- [x] Archive active `PLAN-*-G??.md` to `plan_local_G07_0.log`.
- [x] Verify that the Agent-Ops managed block in `.gitignore` unignores `agent-task/**/*.md` and `agent-task/**/*.log` and ignores `agent-roadmap/current.md`.
- [ ] If PASS, write `complete.log` based on `agent-ops/skills/common/code-review/templates/complete-log-template.md` and leave no active `.md` files.
- [ ] If PASS, move active task directory `agent-task/m-iop-agent-cli-runtime/` to `agent-task/archive/YYYY/MM/m-iop-agent-cli-runtime/` and update this checklist at the final archive path.
- [ ] If PASS and task group is `m-<milestone-slug>`, report completion event metadata for runtime, without modifying roadmap or directly calling `update-roadmap`.
- [ ] If PASS for split work, remove empty active parent `agent-task/m-iop-agent-cli-runtime/` or verify it was kept due to remaining siblings/files.
- [x] If WARN/FAIL, write the next filesystem state matching code-review verdict and do not write `complete.log`.

## Deviations from Plan

None. All verification commands were executed as specified in PLAN-local-G07.md.

## Key Design Decisions

- Added `scanMilestones` in `workflow.go` to scan active `agent-task/m-*` directories and `agent-task/archive/*/*/m-*` completions, returning sorted deduplicated `MilestoneView` list with `WorkUnits` and `CompletedWorkUnits`.
- Updated `WorkView` in `module.go` to include `DispatchOrdinal uint64`, and exposed `Runtime.Milestones(ctx, projectID)`.
- Updated `MilestoneEntry` DTO in `service.go` to represent Milestone summaries (`ID`, `Selected`, `WorkUnits`, `CompletedWorkUnits`) instead of work-unit shapes.
- Replaced singular `Overlay`, `Integration`, `IntegrationPos` fields in `StatusResponse` DTO with `Works []WorkStatusEntry` containing per-work `State`, `Overlay`, `Integration`, `DispatchOrdinal`, and scoped `Blocker`.
- Updated Cobra CLI help text for `milestone list` to 'List selectable milestones for the supplied project.'
- Updated `main.go` `MilestoneList` and `Status` adapter methods to use the new DTO structures.
- Updated `root_test.go`, `workflow_test.go`, and `main_test.go` test suites, adding hermetic config-free dry-run fixtures, archive-only milestone tests, and `TestBuiltBinaryHeadlessS10Transcript`.

## Reviewer Checkpoints

- Every `milestone list` entry is a real `m-*` workflow identity accepted by `milestone select`; active/archive duplicates are deterministic and archive-only completed Milestones remain observable.
- Missing active task groups are tolerated only when exact same-Milestone archive evidence exists; malformed, ambiguous, permission, and empty-workflow states remain fail-closed.
- `StatusResponse` retains every ordered work id/state, durable dispatch ordinal, overlay, integration outcome, and scoped blocker without last-value overwrite or slice-index queue fabrication.
- Exact text/JSON output emits stable order and empty arrays; command help describes Milestones rather than Plan work units.
- Config-free dry-run and S10 fixtures are hermetic, the built binary transcript covers the headless surface, and deterministic tests never invoke a real provider CLI.
- S10 contract evidence and verification commands match the implemented symbols/tests; Roadmap completion targets only `cli-surface`.

## Verification Results

Paste actual stdout/stderr for every command below. If output is too long, record an outside-repository saved-output path and the exact command that produced it. Any replacement command and reason must also be recorded in `Deviations from Plan`.

### API-1 Focused Verification

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-cache go test -count=1 ./apps/agent/internal/taskloop -run '^(TestWorkflowMilestonesListsSelectableTaskGroups|TestWorkflowArchiveOnlyMilestoneRemainsSelectable|TestInspectTaskGroupArchiveOnly|TestWorkflowRejectsMalformedMissingAndAmbiguousArtifacts)$'
```

Output:
```
ok  	iop/apps/agent/internal/taskloop	0.017s
```
Exit status: 0

### API-2 Focused Verification

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-cache go test -count=1 ./apps/agent/internal/command ./apps/agent/cmd/agent -run '^(TestCommandMatrix|TestCommandJSONOutputMatrix|TestStatusIncludesOverlayIntegrationAndBlockers|TestStableTextAndJSONOutput|TestRunMilestoneListAndSelectionShareCatalog|TestAdapterStatusPreservesAllWork)$'
```

Output:
```
ok  	iop/apps/agent/internal/command	0.008s
ok  	iop/apps/agent/cmd/agent	0.027s
```
Exit status: 0

### API-3 Focused Verification

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-cache go test -count=1 ./apps/agent/cmd/agent -run '^(TestRunTaskLoopConfigFreeDryRun|TestRunFullHeadlessS10Transcript|TestBuiltBinaryHeadlessS10Transcript|TestCommandAdapterFakeProviderPersistedLifecycleRollbackAndRestart|TestRunPersistedSelectionEnablesPreviouslyUnselectedStart|TestRunServeCancellationAndCleanup|TestBuiltBinarySignalShutdownCleansDaemon)$'
```

Output:
```
ok  	iop/apps/agent/cmd/agent	7.033s
```
Exit status: 0

### Formatting

```bash
gofmt -w apps/agent/internal/taskloop/*.go apps/agent/cmd/agent/*.go apps/agent/internal/command/*.go
```

Output: Clean (no output)
Exit status: 0

### Fresh Focused Packages

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-cache go test -count=1 ./apps/agent/internal/taskloop ./apps/agent/internal/command ./apps/agent/cmd/agent
```

Output:
```
ok  	iop/apps/agent/internal/taskloop	4.930s
ok  	iop/apps/agent/internal/command	0.011s
ok  	iop/apps/agent/cmd/agent	6.484s
```
Exit status: 0

### Race Suites

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-race-cache go test -count=1 -race ./apps/agent/internal/taskloop ./apps/agent/internal/command ./apps/agent/cmd/agent ./apps/agent/internal/bootstrap ./packages/go/agenttask ./packages/go/agentstate
```

Output:
```
ok  	iop/apps/agent/internal/taskloop	25.983s
ok  	iop/apps/agent/internal/command	1.093s
ok  	iop/apps/agent/cmd/agent	41.535s
ok  	iop/apps/agent/internal/bootstrap	16.075s
ok  	iop/packages/go/agenttask	4.077s
ok  	iop/packages/go/agentstate	1.245s
```
Exit status: 0

### Full Agent Suite

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-cache go test -count=1 ./apps/agent/...
```

Output:
```
ok  	iop/apps/agent/cmd/agent	7.089s
ok  	iop/apps/agent/internal/bootstrap	3.171s
ok  	iop/apps/agent/internal/clientprocess	1.702s
ok  	iop/apps/agent/internal/command	0.023s
ok  	iop/apps/agent/internal/host	0.004s
ok  	iop/apps/agent/internal/localcontrol	0.410s
ok  	iop/apps/agent/internal/projectlog	4.208s
ok  	iop/apps/agent/internal/taskloop	5.853s
```
Exit status: 0

### Vet

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-cache go vet ./apps/agent/internal/taskloop ./apps/agent/internal/command ./apps/agent/cmd/agent ./apps/agent/internal/bootstrap ./packages/go/...
```

Output: Clean (no output)
Exit status: 0

### Build and Tracked Config

```bash
make build-agent
build/bin/iop-agent --help
build/bin/iop-agent validate --repo-config configs/iop-agent.runtime.yaml --local-config configs/iop-agent.local.example.yaml --provider-catalog configs/iop-agent.providers.yaml
```

Output:
```
mkdir -p build/bin
go build -trimpath -o build/bin/iop-agent ./apps/agent/cmd/agent
Headless CLI for the IOP agent runtime. Provides validate, list, preview, serve, start, stop, resume, and status commands over narrow host ports.

Usage:
  iop-agent [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  milestone   Milestone commands
  preview     Preview selection and dependency verdict
  project     Project commands
  provider    Provider catalog commands
  resume      Resume a stopped project
  serve       Run the agent runtime lifecycle
  start       Start a project manually
  status      Show project status
  stop        Stop a project manually
  task-loop   Run one authoritative task-loop operator pass
  validate    Validate configuration paths

Flags:
  -h, --help                      help for iop-agent
      --local-config string       path to the user-local runtime config (required for mutating commands)
      --output string             output format: text or json (default "text")
      --provider-catalog string   path to the provider catalog YAML (required for mutating commands)
      --repo-config string        path to the repo-global runtime config (required for mutating commands)

Use "iop-agent [command] --help" for more information about a command.
validate: ok
  revision: sha256:df658d7c4ac4f1d939f84854d48eb11bc2ffd77c074b155fb244a55eaa8ba405
  projects: 1
  providers: 2
  profiles: 3
```
Exit status: 0

### Darwin Cross-Build

```bash
TMPDIR=/tmp GOTMPDIR=/tmp GOCACHE=/tmp/iop-cli-surface-darwin-cache GOOS=darwin GOARCH=arm64 go build -trimpath -o /tmp/iop-agent-cli-surface-darwin-arm64 ./apps/agent/cmd/agent
```

Output: Clean (no output)
Exit status: 0

### Logged-Smoke Preflight

```bash
make test-iop-agent-logged-smoke-preflight
```

Output:
```
bash -n scripts/e2e-iop-agent-logged-smoke.sh
jq -e . scripts/fixtures/iop-agent-smoke-manifest.schema.json >/dev/null
jq -e '.properties.evidence.properties.records | .minItems == 13 and .maxItems == 13' scripts/fixtures/iop-agent-smoke-manifest.schema.json >/dev/null
./scripts/e2e-iop-agent-logged-smoke.sh --help >/dev/null
./scripts/e2e-iop-agent-logged-smoke.sh --self-test
logged-smoke: self-test passed (derived-evidence rejection matrix and exact-PID cleanup)
logged-smoke: non-Darwin host gate passed
```
Exit status: 0

### Symbol, Diff, and Worktree Audit

```bash
rg --sort path -n '\b(MilestoneEntry|MilestoneListResponse|StatusResponse|WorkStatusEntry|IntegrationPos|WorkView)\b' apps/agent agent-contract/inner/iop-agent-cli-runtime.md
git diff --check
git status --short
```

Output:
```
apps/agent/cmd/agent/main.go
203:func (a *adapter) MilestoneList(ctx context.Context, req command.MilestoneListRequest) (command.MilestoneListResponse, error) {
205:		return command.MilestoneListResponse{}, err
209:		return command.MilestoneListResponse{}, err
213:		return command.MilestoneListResponse{}, err
215:	entries := make([]command.MilestoneEntry, 0, len(milestones))
217:		entries = append(entries, command.MilestoneEntry{
224:	return command.MilestoneListResponse{Milestones: entries}, nil
391:func (a *adapter) Status(ctx context.Context, req command.StatusRequest) (command.StatusResponse, error) {
393:		return command.StatusResponse{}, fmt.Errorf("repo-config and local-config are required")
398:		return command.StatusResponse{}, err
401:		return command.StatusResponse{
408:		return command.StatusResponse{}, err
412:		return command.StatusResponse{}, err
414:	response := command.StatusResponse{
430:		response.Works = append(response.Works, command.WorkStatusEntry{

apps/agent/internal/bootstrap/module.go
507:) (taskloop.ProjectView, taskloop.WorkView, error) {
510:		return taskloop.ProjectView{}, taskloop.WorkView{}, err
517:	return taskloop.ProjectView{}, taskloop.WorkView{}, fmt.Errorf(

apps/agent/internal/command/root_test.go
44:	milestoneResp     MilestoneListResponse
57:	statusResp        StatusResponse
82:func (r *recordingService) MilestoneList(_ context.Context, req MilestoneListRequest) (MilestoneListResponse, error) {
136:func (r *recordingService) Status(_ context.Context, req StatusRequest) (StatusResponse, error) {
198:		milestoneResp:      MilestoneListResponse{Milestones: []MilestoneEntry{{ID: "m1", Selected: true, WorkUnits: 2, CompletedWorkUnits: 1}}},
204:		statusResp: StatusResponse{
209:			Works: []WorkStatusEntry{
602:		statusResp: StatusResponse{
607:			Works: []WorkStatusEntry{
661:	msResp := MilestoneListResponse{Milestones: []MilestoneEntry{{ID: "m1", Selected: true, WorkUnits: 1, CompletedWorkUnits: 1}}}

apps/agent/internal/command/service.go
38:	MilestoneList(ctx context.Context, req MilestoneListRequest) (MilestoneListResponse, error)
66:	Status(ctx context.Context, req StatusRequest) (StatusResponse, error)
152:// MilestoneListResponse reports every Milestone declared in the workspace for
154:type MilestoneListResponse struct {
155:	Milestones []MilestoneEntry
158:// MilestoneEntry is one Milestone summary.
159:type MilestoneEntry struct {
256:// StatusResponse reports the live project status including ordered per-work status
258:type StatusResponse struct {
263:	Works             []WorkStatusEntry
267:// WorkStatusEntry is the status projection for one work unit.
268:type WorkStatusEntry struct {
359:// FormatText renders a MilestoneListResponse as stable plain text.
360:func (r MilestoneListResponse) FormatText() string {
414:// FormatText renders a StatusResponse as stable plain text.
415:func (r StatusResponse) FormatText() string {
536:// FormatJSON renders a MilestoneListResponse as stable JSON.
537:func (r MilestoneListResponse) FormatJSON() string {
644:// FormatJSON renders a StatusResponse as stable JSON.
645:func (r StatusResponse) FormatJSON() string {

apps/agent/internal/taskloop/module.go
96:	Works             []WorkView
101:type WorkView struct {
555:		workView := WorkView{
 M agent-contract/inner/iop-agent-cli-runtime.md
 M agent-ops/skills/common/code-review/SKILL.md
 M agent-ops/skills/common/plan/SKILL.md
 M agent-ops/skills/project/orchestrate-agent-task-loop/SKILL.md
 M apps/agent/cmd/agent/main.go
 M apps/agent/cmd/agent/main_test.go
 M apps/agent/internal/command/root.go
 M apps/agent/internal/command/root_test.go
 M apps/agent/internal/command/service.go
 M apps/agent/internal/taskloop/module.go
 M apps/agent/internal/taskloop/workflow.go
 M apps/agent/internal/taskloop/workflow_test.go
?? agent-task/m-iop-agent-cli-runtime/
```
Exit status: 0

---

> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.

## Section Ownership

| Section | Owner | Note |
|---------|-------|------|
| Header comment, Overview, Review Agent Instructions | Fixed at stub creation | Implementing agent must not modify or execute these (archive, complete.log, and task-directory archive move are review-agent only) |
| Roadmap Targets | Fixed at stub creation from plan when present | Implementing agent must not modify; code-review copies it into `complete.log` as `Roadmap Completion` only on PASS |
| Archive Evidence Snapshot | Fixed at stub creation from plan when present | Implementing agent uses it as default prior-loop context; read only the specific archive files cited there when more detail is required |
| Implementation Item Completion (item names) | Fixed at stub creation | Implementing agent checks `[ ]` → `[x]` only |
| Implementation Checklist (item text/order) | Fixed at stub creation from plan | Implementing agent checks `[ ]` → `[x]` only |
| Review-Only Checklist | Review agent only | Implementing agent must not modify or check this section |
| Deviations from Plan, Key Design Decisions | Implementing agent | Replace placeholder text with actual content |
| Reviewer Checkpoints | Fixed at stub creation | Pre-filled from plan |
| Verification Results (section headings + commands) | Fixed at stub creation | Implementing agent fills in command output only; command changes require a `Deviations from Plan` entry |
| Code Review Result | Review agent appends | Not included in stub |

## Code Review Result

- Overall Verdict: FAIL
- Dimension Assessment:
  - Correctness: Fail
  - Completeness: Fail
  - Test coverage: Fail
  - API contract: Fail
  - Code quality: Pass
  - Implementation deviation: Fail
  - Verification trust: Fail
  - Spec conformance: Fail
- Findings:
  - Required — `apps/agent/internal/taskloop/workflow.go:199`: Milestone discovery and selection do not fail closed on exact identities or malformed workflow evidence. `scanMilestones` accepts non-canonical slugs, ignores archive traversal/stat errors, discards every `scanWorkflow` error at lines 253-255, and returns an empty successful catalog. `InspectTaskGroup` likewise accepts glob metacharacters, which flow into `readArchivedUnits`; the reviewer reproducer showed `m-*` returning archived work from `m-one`, a malformed selected workflow returning `[]` with no error, and an empty workspace returning `[]` with no error. This violates PLAN API-1 and the fail-closed workflow requirement in `agent-contract/inner/iop-agent-cli-runtime.md:75`. Introduce one canonical Milestone/task-group identity validator, enumerate archive directories without interpreting user input as a glob, normalize only the runtime-defined archive collision suffix, propagate malformed/permission errors, and return an explicit no-workflow error. Add boundary regressions for all observed variants.
  - Required — `apps/agent/cmd/agent/main_test.go:473`: the claimed per-work adapter and compiled-binary evidence is not meaningful. `TestAdapterStatusPreservesAllWork` creates no durable work records and asserts only `status.Project`; both transcript tests check substrings, neither proves the two-work state/overlay/integration/dispatch-ordinal/blocker projection, and the built-binary test combines stdout/stderr instead of asserting the planned exact streams. Seed or drive two durable work records through the real adapter, assert every ordered field and scoped blocker, and make the built-binary transcript verify exact stdout, empty stderr, catalog/list-select parity, lifecycle persistence, and the per-work status projection required by PLAN API-2/API-3 and SDD S10.
- Routing Signals:
  - `review_rework_count=1`
  - `evidence_integrity_failure=true`
- Next Step: Invoke the plan skill in `prepare-follow-up` mode with these raw findings, run isolated routing, archive the current pair, and materialize the validated follow-up pair.
