<!-- task=m-iop-agent-cli-runtime/12+10,11_change_set_integration plan=1 tag=REVIEW_API -->

# Restore Atomic Change-set Integration Semantics

## For the Implementing Agent

Implement only this follow-up scope. Run every verification command, fill the implementation-owned sections in `CODE_REVIEW-*-G??.md` with actual notes and output, keep both 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 only in implementation-owned evidence fields; do not ask the user, call user-input tools, create stop files, classify the next state, archive logs, or write `complete.log`.

## Background

The first review found three S19 violations despite the existing suite passing. Parent directory deletion can remove a managed predecessor's unseen descendant, validation can mutate canonical paths outside the rollback manifest, and lower blocked/stopped ordinals can be bypassed before they are terminal. The fixes must preserve one atomic serial-integration invariant across the workspace backend and manager queue.

## Archive Evidence Snapshot

- Prior plan: `agent-task/m-iop-agent-cli-runtime/12+10,11_change_set_integration/plan_cloud_G10_0.log`
- Prior review: `agent-task/m-iop-agent-cli-runtime/12+10,11_change_set_integration/code_review_cloud_G10_0.log`
- Verdict: FAIL; Required=3, Suggested=0, Nit=0.
- Affected files: `packages/go/agentworkspace/integrator.go`, `packages/go/agentworkspace/integrator_test.go`, `packages/go/agenttask/integration_queue.go`, `packages/go/agenttask/integration_queue_test.go`.
- Evidence: the fresh race suite, package-wide suite, vet, formatting, and diff checks passed; a focused reviewer reproducer failed because an ordinal-2 directory deletion removed `tree/new.txt` added by ordinal 1.
- Roadmap carryover: `change-set-integration` remains incomplete until S19 clean merge, exact rollback, deterministic ordinal, revised retry, restart, and retention evidence pass.

## 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:
  - `change-set-integration`: immutable change set and serial integration
- Completion mode: check-on-pass

## Analysis

### Files Read

- `packages/go/agentworkspace/change_set.go`
- `packages/go/agentworkspace/integrator.go`
- `packages/go/agentworkspace/integrator_test.go`
- `packages/go/agentworkspace/snapshot.go`
- `packages/go/agentworkspace/overlay.go`
- `packages/go/agentstate/store.go`
- `packages/go/agentstate/store_test.go`
- `packages/go/agenttask/integration.go`
- `packages/go/agenttask/integration_queue.go`
- `packages/go/agenttask/integration_queue_test.go`
- `packages/go/agenttask/state_machine.go`
- `packages/go/agenttask/workflow.go`
- `packages/go/agenttask/ports.go`
- `packages/go/agenttask/types.go`
- `agent-contract/inner/agent-runtime.md`
- `agent-contract/inner/iop-agent-cli-runtime.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`

### SDD Criteria

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`; status `[승인됨]`, lock released.
- Target: S19 / `change-set-integration`.
- Acceptance requires clean managed-predecessor three-way integration, no partial canonical mutation after conflict/drift/validation failure, deterministic dispatch-ordinal admission, later independent progress only after terminal disposition, revised immutable retry, and restart idempotency.
- Evidence Map S19 requires ordinal, clean/conflict, managed/unmanaged drift, validation rollback, terminal-deferred advance, retry revision, restart, retention, and atomic/no-duplicate `IntegrationRecord` evidence. These rows define both implementation items and every focused regression below.

### Verification Context

- No separate `verification_context` handoff was supplied.
- Repository-native sources: `agent-test/local/rules.md`, `agent-test/local/platform-common-smoke.md`, the active plan/review logs, S19, both runtime contracts, and the package tests listed above.
- Preconditions: local checkout, `/config/workspace/iop-s0`, Go from `PATH`, Git available, no external service or credential.
- Fresh review evidence: Go 1.26.2 at `/config/opt/go`, Git at `/bin/git`; race, package-wide tests, vet, formatting, and `git diff --check` passed. The focused managed-descendant reproducer failed deterministically.
- Constraints: use temporary Git fixtures; do not add repository-local verification tools. Fresh `-count=1` output is required.
- External verification: not applicable. This remains host-neutral package behavior and does not change a binary, transport, provider invocation, config, or protobuf surface.
- Confidence: high; each Required finding has a direct source path and deterministic oracle.

### Test Coverage Gaps

- Parent directory delete/type replacement versus a managed predecessor descendant: uncovered and reviewer-reproduced.
- Validator writes outside `ChangeSet.WriteSet` before returning failure: uncovered.
- Lower ordinal in `blocked` or `stopped` without a change set, followed by resume: uncovered.
- Revised immutable change set after retained conflict and later independent integration: only the fake manager port is covered; the real durable backend path is uncovered.

### Symbol References

None. No symbol rename or removal is planned.

### Split Judgment

Keep one plan. Candidate construction, validation isolation, canonical apply/rollback, durable attempt state, and manager ordinal admission form one S19 transaction invariant and cannot independently PASS. Predecessors are satisfied by `agent-task/archive/2026/07/m-iop-agent-cli-runtime/10+06_state_recovery/complete.log` and `agent-task/archive/2026/07/m-iop-agent-cli-runtime/11+06_workspace_overlay/complete.log`.

### Scope Rationale

Limit changes to the four files in `Modified Files Summary`. Do not change change-set identity, state-store envelope, overlay confinement, contract documents, roadmap state, provider execution, configuration, protobuf, or binary entrypoints; current contracts already state the required semantics. Extending `ValidationRequest` with a candidate-root field inside `integrator.go` is in scope.

### Final Routing

- `evaluation_mode=isolated-reassessment`; `finalizer=finalize-task-policy.sh`; `finalizer_mode=pair`.
- Build closures: scope/context/verification/evidence/ownership/decision all true. Scores=`2/2/2/1/1`, grade=G08, base=`local-fit`, route=`risk-boundary`, lane=`cloud`, filename=`PLAN-cloud-G08.md`.
- Review closures: scope/context/verification/evidence/ownership/decision all true. Scores=`2/2/2/2/2`, grade=G10, route=`official-review`, lane=`cloud`, filename=`CODE_REVIEW-cloud-G10.md`.
- `large_indivisible_context=false`.
- Positive loop risks: `temporal_state`, `concurrent_consistency`, `boundary_contract`, `structured_interpretation`; count=4.
- Recovery signals: `review_rework_count=1`, `evidence_integrity_failure=false`; recovery boundary=false.
- Capability gap: none.

## Implementation Checklist

- [ ] Preserve or explicitly conflict on managed predecessor descendants during directory deletion/type replacement, and validate the candidate outside the canonical workspace before mutation.
- [ ] Require every lower dispatch ordinal to be completed or terminal-deferred before integration, and add real backend revised-retry plus focused ordering/rollback regressions.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Make candidate validation and hierarchical merge atomic

**Problem:** `packages/go/agentworkspace/integrator.go:611` compares only the parent entry, so line 877 recursively deletes descendants introduced by a managed predecessor. At line 334 the validator receives the writable canonical root, while rollback capture at line 811 stores only the change-set write set; validator side effects can therefore survive a failed integration.

**Solution:** Build a runtime-owned candidate view from the exact observed workspace, apply the prepared three-way result there, and add `ValidationRoot` to `ValidationRequest` so the validator uses that candidate while `CanonicalRoot` remains the immutable workspace identity. Reconfirm the canonical fingerprint after validation, then persist the applying record and apply only the frozen prepared changes. For directory delete/type replacement, compare base/current descendant sets: preserve independent additions when a directory remains a container, return retained conflict when the target type cannot coexist, and never use recursive deletion for an unproven-empty managed parent.

Before (`packages/go/agentworkspace/integrator.go:334`):

```go
if err := integrator.validator(ctx, ValidationRequest{
	CanonicalRoot: changeSet.CanonicalRoot,
```

Before (`packages/go/agentworkspace/integrator.go:876`):

```go
if change.Result == nil {
	if err := os.RemoveAll(target); err != nil {
```

After:

```go
validationRoot, cleanup, err := integrator.prepareValidationCandidate(ctx, observed, prepared)
request := ValidationRequest{
	CanonicalRoot: changeSet.CanonicalRoot,
	ValidationRoot: validationRoot,
}
// Validate the candidate, recheck canonical drift, then durably enter applying.
```

Directory removal must use a non-recursive, hierarchy-aware operation after descendant reconciliation.

**Modified Files and Checklist:**

- [ ] `packages/go/agentworkspace/integrator.go` — stage and validate the exact candidate outside canonical, recheck drift, and reconcile parent/descendant operations without blind `RemoveAll`.
- [ ] `packages/go/agentworkspace/integrator_test.go` — add managed-descendant preservation/conflict, validator-side-effect isolation, apply rollback, restart, and revised-change-set-after-advance coverage.

**Test Strategy:** Add `TestSerialIntegratorPreservesManagedDescendantAcrossDirectoryDeletion`, `TestSerialIntegratorValidationMutationDoesNotEscapeCandidateView`, and `TestSerialIntegratorRevisedChangeSetAfterConflictAndLaterAdvance`. Use the existing temporary Git fixture, assert exact canonical digests/content, retained first attempt, new immutable identity/attempt, and no validator-created canonical path.

**Verification:**

```bash
go test -count=1 -run '^TestSerialIntegrator' -v ./packages/go/agentworkspace
```

Expected: all focused integration and regression cases pass with no canonical mutation on rejected attempts.

### [REVIEW_API-2] Enforce terminal lower-ordinal admission

**Problem:** `packages/go/agenttask/integration_queue.go:218` releases a higher ordinal when a lower work is `blocked` or `stopped` and has no current change set. Both states can later return to `ready` without changing `DispatchOrdinal`, allowing the lower change set to integrate after the higher one.

**Solution:** Treat only `completed` and `terminal_deferred` lower ordinals as released. Keep blocked/stopped/reviewing/pending work as barriers, regardless of whether a change set is currently present.

Before (`packages/go/agenttask/integration_queue.go:218`):

```go
switch work.State {
case WorkStateCompleted, WorkStateTerminalDeferred:
	continue
case WorkStateBlocked, WorkStateStopped:
	if work.ChangeSet == nil {
		continue
	}
}
```

After:

```go
if work.State == WorkStateCompleted || work.State == WorkStateTerminalDeferred {
	continue
}
return false
```

**Modified Files and Checklist:**

- [ ] `packages/go/agenttask/integration_queue.go` — remove non-terminal blocked/stopped bypass.
- [ ] `packages/go/agenttask/integration_queue_test.go` — cover blocked/stopped lower ordinals, resume, terminal release, and stable integration order.

**Test Strategy:** Add or extend `TestIntegrationCandidateRequiresTerminalLowerOrdinal` as a table over reviewing, blocked, stopped, completed, and terminal-deferred states. Add `TestIntegrationStopResumePreservesOrdinal` as a manager-level case proving the original lower ordinal integrates first.

**Verification:**

```bash
go test -count=1 -run '^(TestIntegrationCandidateRequiresTerminalLowerOrdinal|TestIntegrationStopResumePreservesOrdinal|TestIntegrationOutOfOrderWorkerCompletionUsesDispatchOrdinal|TestIntegrationTerminalDeferredAdvancesIndependentQueue|TestRevisedChangeSetUsesNextIntegrationAttempt|TestRestartReplayUsesStableIdempotencyKeysWithoutDuplicateCalls)$' -v ./packages/go/agenttask
```

Expected: non-terminal lower ordinals remain barriers; completed/terminal-deferred states release the queue; replay and revised attempts remain stable.

## Dependencies and Execution Order

Implement `REVIEW_API-1` before the cross-package final suite, then `REVIEW_API-2`. Both must pass together because the backend and manager jointly enforce S19.

## Modified Files Summary

| File | Item |
|---|---|
| `packages/go/agentworkspace/integrator.go` | REVIEW_API-1 |
| `packages/go/agentworkspace/integrator_test.go` | REVIEW_API-1 |
| `packages/go/agenttask/integration_queue.go` | REVIEW_API-2 |
| `packages/go/agenttask/integration_queue_test.go` | REVIEW_API-2 |

## Final Verification

```bash
command -v go && readlink -f "$(command -v go)" && go version && go env GOROOT
command -v git
go test -count=1 -run '^TestSerialIntegrator' -v ./packages/go/agentworkspace
go test -count=1 -run '^(TestIntegrationCandidateRequiresTerminalLowerOrdinal|TestIntegrationStopResumePreservesOrdinal|TestIntegrationOutOfOrderWorkerCompletionUsesDispatchOrdinal|TestIntegrationTerminalDeferredAdvancesIndependentQueue|TestRevisedChangeSetUsesNextIntegrationAttempt|TestRestartReplayUsesStableIdempotencyKeysWithoutDuplicateCalls)$' -v ./packages/go/agenttask
go test -count=1 -race ./packages/go/agentworkspace ./packages/go/agentstate ./packages/go/agenttask
go test -count=1 ./packages/go/...
go vet ./packages/go/...
gofmt -d packages/go/agentworkspace/integrator.go packages/go/agentworkspace/integrator_test.go packages/go/agenttask/integration_queue.go packages/go/agenttask/integration_queue_test.go
git diff --check
```

Expected: every command exits zero; fresh tests prove hierarchy-safe merge, validation isolation, exact rollback, terminal ordinal admission, revised retry, restart replay, and package-wide compatibility. Cached test output is not acceptable for the focused, race, or package-wide commands. Repository E2E smoke and full-cycle execution remain not applicable because no user execution pipeline changes.

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