Files
cleveragents-core/docs/reference/plan_apply.md
freemo 9f2e7e88b0 feat(plan): add diff review and apply integration
Add PlanApplyService with diff(), artifacts(), persist_apply_summary(),
handle_merge_failure(), and guard_empty_changeset() methods.

- plan diff: renders changeset in rich/plain/json/yaml formats
- plan artifacts: shows plan metadata, changeset summary, sandbox refs
- persist_apply_summary: stores files_changed/validations_run in plan metadata
- handle_merge_failure: transitions plan to error state with conflict details
- guard_empty_changeset: blocks apply on empty changeset (--allow-empty override)

CLI: plan diff and plan artifacts commands with --format flag.
Tests: 20 Behave scenarios, 8 Robot integration tests, 4 ASV benchmarks.
Docs: docs/reference/plan_apply.md with CLI reference.

Implements D0b.apply from the implementation plan.
2026-02-21 10:22:18 -05:00

4.2 KiB

Plan Diff & Apply Reference

This document describes the diff review and apply integration features added in D0b.apply.

CLI Commands

agents plan diff <plan_id>

Show the ChangeSet produced during Execute as a unified diff, grouped by resource path.

Options:

Flag Description
--format, -f Output format: rich (default), plain, json, yaml

Examples:

# Rich output with coloured operation labels
agents plan diff 01HXYZ...

# Plain unified-diff output
agents plan diff 01HXYZ... --format plain

# Machine-readable JSON
agents plan diff 01HXYZ... --format json

Output fields (JSON/YAML):

Field Type Description
changeset_id string ULID of the ChangeSet
plan_id string ULID of the plan
total_changes int Number of change entries
summary object {creates, modifies, deletes, renames, paths_changed, resources_involved}
entries list Per-file entries with path, operation, hashes, timestamps

agents plan artifacts <plan_id>

Show plan artifacts: ChangeSet metadata, sandbox references, file change list, and validation results.

Options:

Flag Description
--format, -f Output format: rich (default), plain, json, yaml

Output fields (JSON/YAML):

Field Type Description
plan_id string Plan ULID
phase string Current lifecycle phase
processing_state string Current processing state
changeset_id string ChangeSet ULID (null if Execute not complete)
sandbox_refs list Active sandbox reference IDs
changeset_summary object Summary counts from SpecChangeSet
files_changed list {path, operation} per changed file
validation_summary object Validation results (if available)
apply_summary object Files changed count, validations run (after apply)

Apply Integration

Empty ChangeSet Guard

The apply pipeline checks whether the ChangeSet has any entries before proceeding. If the ChangeSet is empty, apply is blocked with a clear message:

Plan <id> has an empty ChangeSet. No changes to apply. Use --allow-empty to override.

Set --allow-empty to bypass this check for plans that intentionally produce no file changes (e.g. validation-only plans).

Apply Summary Persistence

When apply completes, the following metadata is stored in the plan:

  • apply_files_changed: Number of files written/modified/deleted
  • apply_validations_run: Number of validation checks executed
  • apply_completed_at: ISO-8601 timestamp of apply completion

This metadata is visible via agents plan status and agents plan artifacts.

Merge Failure Handling

When a sandbox merge fails during apply:

  1. The plan transitions to ERRORED processing state
  2. error_message is set to "Merge failed: <details>"
  3. error_details includes:
    • merge_conflict: Description of the conflict
    • sandbox_rollback: Set to "pending" for cleanup

Recovery steps:

  1. Review conflict details via agents plan status <id>
  2. Re-run execute phase after resolving conflicts: agents plan execute <id>
  3. Or fix validation issues and retry apply

Processing State Flow

Execute/COMPLETE
    |
    v
Apply/QUEUED  -->  Apply/PROCESSING  -->  Apply/APPLIED (terminal success)
                        |
                        +-->  Apply/ERRORED (merge failure)
                        +-->  Apply/CONSTRAINED (invariant violation)

Service API

PlanApplyService

from cleveragents.application.services.plan_apply_service import PlanApplyService

service = PlanApplyService(
    lifecycle_service=lifecycle,
    changeset_store=store,  # optional InMemoryChangeSetStore
)

# Generate diff
diff_text = service.diff(plan_id, fmt="json")

# Get artifacts
artifacts = service.artifacts(plan_id, fmt="json")

# Guard empty changeset
service.guard_empty_changeset(plan_id, allow_empty=False)

# Persist apply summary
service.persist_apply_summary(plan_id, files_changed=5, validations_run=3)

# Handle merge failure
service.handle_merge_failure(plan_id, conflict_details="...")