Renames `plan lifecycle-list` to `plan list` and `plan lifecycle-apply` to `plan apply` to align with the specification's canonical command names. Removes legacy V2 plan commands that occupied those names.
- Renamed CLI command registrations from lifecycle-list/lifecycle-apply to list/apply
- Removed legacy V2 apply and list commands (~200 lines)
- Updated apply shortcut in main.py to delegate to v3 lifecycle
- Added defensive null check for plan existence in apply command
- Updated 63+ test, doc, and benchmark files for consistency
Closes#881
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
Implement the full correction-checkpoint rollback pipeline:
- Workspace snapshots: CheckpointService.create_workspace_snapshot()
creates diff-based checkpoints before decision execution, storing
only changed file paths in metadata.extra["diff_paths"]
- CorrectionService.revert_decisions(): new high-level entry point
that creates a correction, computes impact, invokes checkpoint
rollback, and archives artifacts in a single call
- Physical artifact archival: CheckpointService.archive_artifacts()
moves files to .cleveragents/archived_artifacts/ instead of just
flagging metadata. CorrectionService._archive_decision_artifacts()
delegates to this during revert execution
- Selective rollback: CheckpointService.selective_rollback() wraps
rollback_to_checkpoint with atomic semantics — captures HEAD before
rollback and recovers on failure
- Diff-based storage: _compute_diff_snapshot() computes changed paths
between checkpoints via git diff; snapshots store diff manifest and
SHA-256 hash in metadata
- CLI: plan rollback now accepts --to-checkpoint <id> in addition to
the positional checkpoint_id argument; uses selective_rollback for
atomic execution
- DI wiring: Container now injects checkpoint_service into
CorrectionService; CLI correct command uses container-provided
service instead of ad-hoc instance (fixes bug #986)
- Checkpoint model: pre_decision added to allowed checkpoint_type
values
- TDD: Removed @tdd_expected_fail from wiring test feature since the
DI bug is now fixed
ISSUES CLOSED: #943
Replace CliRunner + unittest.mock.patch with subprocess.run for all
21 CLI-facing test functions across the M1-M6 E2E verification helpers.
Application code fixes:
- action.py: _get_lifecycle_service() uses container.plan_lifecycle_service()
- plan.py: _get_lifecycle_service() uses container.plan_lifecycle_service()
- plan.py: three container.resolve(DecisionService) → container.decision_service()
Test infrastructure:
- New robot/helper_e2e_common.py with shared subprocess utilities
(run_cli, setup_workspace with DB migrations, cleanup_workspace)
- M1-M4, M6 helpers refactored to use run_cli() with real SQLite DB
- M5 unchanged (0 CLI tests, all domain-level)
- TDD detection updated to recognise run_cli() as subprocess invocation
- Remove @tdd_expected_fail from TDD feature + robot tags
- Update 8 Behave step files that mocked container.resolve() to use
container.decision_service() / container.plan_lifecycle_service()
## Summary
Fixes the `plan correct` CLI handler which never passes the decision tree or influence edges to `CorrectionService`, producing single-node impact analysis regardless of the plan's actual decision structure.
Closes#606
## Root Cause
The `correct_decision()` handler in `plan.py` created a bare `CorrectionService()` and called `analyze_impact()` and `execute_correction()` without passing `decision_tree` or `influence_edges`. Both parameters default to `None` -> empty dicts, causing `_compute_affected_subtree()` BFS to return only the single target decision, ignoring all descendants and influence-DAG dependents.
## Changes
### Production Fix (`src/cleveragents/cli/commands/plan.py`)
- Resolve `DecisionService` via `get_container()` (following the pattern used by `plan explain` and `plan tree`)
- Build structural tree adjacency list from `decision_svc.list_decisions(plan_id)` using `parent_decision_id` relationships
- Fetch influence edges from `decision_svc.get_influence_edges(plan_id)`
- Pass both `decision_tree` and `influence_edges` to `svc.analyze_impact()` and `svc.execute_correction()`
### Existing Test Fixups
- Updated 4 step definition files that mock `CorrectionService` to also mock the new `DecisionService` resolution path
### New Tests
- **Behave BDD**: 3 scenarios verifying tree/edge forwarding (dry-run subtree, execution subtree, leaf node)
- **Robot Framework**: 3 integration smoke tests
- **ASV Benchmark**: Tree building and analyze_impact overhead benchmarks
## Quality Gates
- `nox -s lint` — PASSED
- `nox -s typecheck` — 0 errors
- `nox -s unit_tests` — 9,109 scenarios, 0 failures
- `nox -s coverage_report` — 97%
ISSUES CLOSED: #606
Reviewed-on: cleveragents/cleveragents-core#639
Co-authored-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com>
Co-committed-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com>
Added targeted Behave BDD feature files and step definitions to improve
unit test coverage for:
- decision_service.py: Full coverage of all 7 service methods (18 scenarios)
- plan_apply_service.py: Branch coverage for handle_merge_failure (2 scenarios)
- plan_executor.py: Edge cases for rollback, checkpoint, and parse_steps (15 scenarios)
- cli/commands/plan.py: Uncovered region lines 1950-2273 (23 scenarios)
- repositories.py: Remaining missed branches and lines (14 scenarios)
- sandbox/checkpoint.py: Full coverage of CheckpointManager (26 scenarios)
- langgraph/bridge.py: Remaining uncovered lines and branches (10 scenarios)
- cli/commands/config.py: Safety net to maintain 100% coverage (42 scenarios)
Total: 150 new scenarios, 596 steps, all passing.
Also fixed a step definition collision in plan_lifecycle_coverage by renaming
"the delete result should be false" to "the plan delete result should be false".
ISSUES CLOSED: #475