UAT: agents plan rollback changes_reverted field is a flat list of path strings instead of spec-required {file, action} objects #2454

Open
opened 2026-04-03 18:26:50 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/plan-rollback-changes-reverted-schema
  • Commit Message: fix(cli): serialize changes_reverted as {file, action} objects in plan rollback JSON output
  • Milestone: v3.7.0
  • Parent Epic: #368

Bug Report

Feature Area: Sandbox & Checkpointing — Plan Rollback CLI Output

What was tested

The agents plan rollback CLI command JSON output format, specifically the changes_reverted field.

Expected behavior (from spec)

Per docs/specification.md lines 16041–16078, the changes_reverted field in the JSON output of agents plan rollback must be a list of objects, each with a file key (path string) and an action key ("restored" or "removed"):

"changes_reverted": [
  { "file": "src/auth/session.py", "action": "restored" },
  { "file": "src/auth/tokens.py", "action": "restored" },
  { "file": "tests/test_session.py", "action": "removed" },
  { "file": "tests/test_tokens.py", "action": "removed" }
]

Each entry must distinguish between files that were restored (reverted to their prior state) and files that were removed (deleted as part of the rollback, because they did not exist at the checkpoint).

Actual behavior (from code analysis)

The implementation in src/cleveragents/cli/commands/plan.py (line 3372) outputs:

"changes_reverted": result.changed_paths,

This serialises changed_paths — a flat list[str] of path strings — directly into the JSON output, e.g.:

"changes_reverted": ["src/auth/session.py", "tests/test_session.py"]

There is no action field to distinguish restored files from removed files, violating the spec schema.

Root cause

The RollbackResult domain model (src/cleveragents/domain/models/core/checkpoint.py lines 161–186) only tracks changed_paths: list[str]. It does not distinguish between files that were restored and files that were removed during the rollback. The service layer (src/cleveragents/application/services/checkpoint_service.py lines 259–368, specifically rollback_to_checkpoint which calls _git_changed_paths) returns a flat list with no action metadata.

Steps to reproduce

  1. Run agents plan rollback --yes <PLAN_ID> <CHECKPOINT_ID> --format json
  2. Observe changes_reverted in the output — it is a flat list of path strings, not {file, action} objects

Code locations

  • src/cleveragents/cli/commands/plan.py line 3372 — output construction (uses result.changed_paths directly)
  • src/cleveragents/domain/models/core/checkpoint.py lines 161–186 — RollbackResult model (only has changed_paths: list[str])
  • src/cleveragents/application/services/checkpoint_service.py lines 259–368 — rollback_to_checkpoint / _git_changed_paths (returns flat list, no action distinction)

Spec reference

docs/specification.md lines 16041–16078 — JSON output format for agents plan rollback

Subtasks

  • Add a RevertedFile value object (or similar) to src/cleveragents/domain/models/core/checkpoint.py with file: str and action: Literal["restored", "removed"] fields
  • Update RollbackResult to use reverted_files: list[RevertedFile] instead of changed_paths: list[str]
  • Update rollback_to_checkpoint in checkpoint_service.py to populate reverted_files with correct action values by comparing pre- and post-rollback git state
  • Update _git_changed_paths (or replace it) to return typed (path, action) pairs
  • Update src/cleveragents/cli/commands/plan.py line 3372 to serialise reverted_files as [{"file": f.file, "action": f.action} for f in result.reverted_files]
  • Tests (Behave): Add/update scenario for agents plan rollback --format json verifying changes_reverted schema matches spec
  • Tests (Robot): Add integration test asserting changes_reverted entries contain both file and action keys
  • Verify coverage >=97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
  • All nox stages pass.
  • Coverage >= 97%.

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-uat-tester

## Metadata - **Branch**: `fix/plan-rollback-changes-reverted-schema` - **Commit Message**: `fix(cli): serialize changes_reverted as {file, action} objects in plan rollback JSON output` - **Milestone**: v3.7.0 - **Parent Epic**: #368 ## Bug Report **Feature Area**: Sandbox & Checkpointing — Plan Rollback CLI Output ### What was tested The `agents plan rollback` CLI command JSON output format, specifically the `changes_reverted` field. ### Expected behavior (from spec) Per `docs/specification.md` lines 16041–16078, the `changes_reverted` field in the JSON output of `agents plan rollback` must be a list of objects, each with a `file` key (path string) and an `action` key (`"restored"` or `"removed"`): ```json "changes_reverted": [ { "file": "src/auth/session.py", "action": "restored" }, { "file": "src/auth/tokens.py", "action": "restored" }, { "file": "tests/test_session.py", "action": "removed" }, { "file": "tests/test_tokens.py", "action": "removed" } ] ``` Each entry must distinguish between files that were **restored** (reverted to their prior state) and files that were **removed** (deleted as part of the rollback, because they did not exist at the checkpoint). ### Actual behavior (from code analysis) The implementation in `src/cleveragents/cli/commands/plan.py` (line 3372) outputs: ```python "changes_reverted": result.changed_paths, ``` This serialises `changed_paths` — a flat `list[str]` of path strings — directly into the JSON output, e.g.: ```json "changes_reverted": ["src/auth/session.py", "tests/test_session.py"] ``` There is no `action` field to distinguish restored files from removed files, violating the spec schema. ### Root cause The `RollbackResult` domain model (`src/cleveragents/domain/models/core/checkpoint.py` lines 161–186) only tracks `changed_paths: list[str]`. It does not distinguish between files that were restored and files that were removed during the rollback. The service layer (`src/cleveragents/application/services/checkpoint_service.py` lines 259–368, specifically `rollback_to_checkpoint` which calls `_git_changed_paths`) returns a flat list with no action metadata. ### Steps to reproduce 1. Run `agents plan rollback --yes <PLAN_ID> <CHECKPOINT_ID> --format json` 2. Observe `changes_reverted` in the output — it is a flat list of path strings, not `{file, action}` objects ### Code locations - `src/cleveragents/cli/commands/plan.py` line 3372 — output construction (uses `result.changed_paths` directly) - `src/cleveragents/domain/models/core/checkpoint.py` lines 161–186 — `RollbackResult` model (only has `changed_paths: list[str]`) - `src/cleveragents/application/services/checkpoint_service.py` lines 259–368 — `rollback_to_checkpoint` / `_git_changed_paths` (returns flat list, no action distinction) ### Spec reference `docs/specification.md` lines 16041–16078 — JSON output format for `agents plan rollback` ## Subtasks - [ ] Add a `RevertedFile` value object (or similar) to `src/cleveragents/domain/models/core/checkpoint.py` with `file: str` and `action: Literal["restored", "removed"]` fields - [ ] Update `RollbackResult` to use `reverted_files: list[RevertedFile]` instead of `changed_paths: list[str]` - [ ] Update `rollback_to_checkpoint` in `checkpoint_service.py` to populate `reverted_files` with correct `action` values by comparing pre- and post-rollback git state - [ ] Update `_git_changed_paths` (or replace it) to return typed `(path, action)` pairs - [ ] Update `src/cleveragents/cli/commands/plan.py` line 3372 to serialise `reverted_files` as `[{"file": f.file, "action": f.action} for f in result.reverted_files]` - [ ] Tests (Behave): Add/update scenario for `agents plan rollback --format json` verifying `changes_reverted` schema matches spec - [ ] Tests (Robot): Add integration test asserting `changes_reverted` entries contain both `file` and `action` keys - [ ] Verify coverage >=97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly, followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly. - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. - All nox stages pass. - Coverage >= 97%. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
freemo added this to the v3.7.0 milestone 2026-04-03 18:27:02 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: Should Have — Important spec requirement or quality improvement. Should be included in the milestone if possible.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: Should Have — Important spec requirement or quality improvement. Should be included in the milestone if possible. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#368 Epic: Subplans & Parallelism
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2454
No description provided.