5 Commits

Author SHA1 Message Date
freemo 631e847497 fix(cli): add checkpoint label, creation time, and side effects to rollback confirmation prompt
Resolves issue #3443: the `agents plan rollback` confirmation prompt was
missing the checkpoint's descriptive label, relative creation time, and
side-effects count (decisions invalidated / child plans cancelled).

Changes:
- Added `_format_relative_time(dt)` helper to produce human-readable
  relative timestamps (e.g. "42 minutes ago", "2 hours ago").
- In `rollback_plan`, moved `get_container()` / `checkpoint_service()`
  before the confirmation block so checkpoint metadata is available.
- When `--yes` is not passed, `svc.get_checkpoint()` is called to fetch
  the checkpoint label (`metadata.reason`) and creation time.
- Decisions created after the checkpoint are counted via
  `decision_service.list_decisions()`; `subplan_spawn` /
  `subplan_parallel_spawn` decisions are counted as child plans.
- Side-effects line is printed before the prompt when counts > 0.
- Falls back to the original simple prompt if checkpoint metadata
  cannot be fetched (e.g. checkpoint not found).
- Updated existing rollback mock helpers to wire `get_checkpoint` and
  `decision_service` properly.
- Added 3 new Behave scenarios covering label display, side-effects
  display, and fallback behaviour.

Closes #3443
2026-04-05 19:46:23 +00:00
freemo 38e05ac45a feat(correction): wire checkpoint rollback into correction service revert flow
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
2026-03-30 17:06:49 -04:00
freemo 5f07316641 fix: wire DI persistence and plan execute/apply for M1 lifecycle
Fixed 5 bugs preventing the M1 E2E acceptance test from passing:

1. _get_lifecycle_service() in action.py and plan.py bypassed the DI
   container, creating PlanLifecycleService without UnitOfWork. All
   plan/action data was in-memory only and lost between subprocess
   calls. Now uses container.plan_lifecycle_service() for DB persistence.

2. `plan execute` CLI only called service.execute_plan() (a pure state
   transition) without running PlanExecutor phase processing. Rewrote
   to detect the plan's current phase/state and dispatch synchronously:
   Strategize/queued → run_strategize(), Strategize/complete → transition
   + run_execute(), Execute/queued → run_execute().

3. `plan apply` CLI had no plan_id argument. Added optional positional
   plan_id with _lifecycle_apply_with_id() that drives the plan through
   Apply/queued → Apply/processing → Apply/applied.

4. Preflight guardrail in start_strategize() built action_registry from
   the in-memory _actions dict only. Added get_action(plan.action_name)
   call to load the action from DB into cache before the guardrail check.

5. Robot Framework Create File syntax used continuation lines producing
   9 arguments instead of 1. Fixed to use Catenate SEPARATOR=\n then
   pass single variable to Create File. Also fixed --branch main to
   --branch master (git init default).

update mocks for execute_plan CLI changes across unit and integration tests

The new execute_plan() command calls _get_plan_executor() and
service.get_plan(plan_id) for phase/state detection. Existing tests
only mocked _get_lifecycle_service, so MagicMock defaults caused
phase/state comparisons to fail.

Changes across 14 files:
- Patch _get_plan_executor in all test setups that invoke the CLI
  execute command (Behave step files + Robot helper scripts)
- Set service.get_plan.return_value to real Plan objects with correct
  phase/state so the execute_plan dispatch logic works
- Fix error-path tests to use STRATEGIZE/COMPLETE plans so the error
  side_effects are actually reached
- Fix "Multiple plans eligible" → "Multiple plans ready" message text
  to match existing test expectations

increase Robot Framework subprocess timeouts for CI resource contention

Three integration tests were timing out in CI due to resource contention
when pabot runs multiple test suites in parallel. All three pass locally
and the timeouts were simply too tight for constrained CI environments.

- tdd_session_create_di.robot: 30s → 90s (DI container init + DB setup)
- database_integration.robot: 60s → 120s (Run Python Script keyword)
- m3_e2e_verification.robot: 60s → 120s (correction-live-revert spawns
  3 sequential CLI subprocesses with full container initialization)

ISSUES CLOSED: #789
2026-03-15 20:50:02 +00:00
Brent E. Edwards 5e625b22e1 fix(test): convert M1-M6 E2E suites to real subprocess CLI invocations (closes #658)
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()
2026-03-12 20:42:14 +00:00
freemo a808c395f9 test(coverage): add Behave BDD tests to improve unit test coverage across 53 source modules
Add 53 new .feature files and corresponding step definition files targeting
uncovered lines identified in build/coverage.xml. Fix AmbiguousStep conflicts
in 7 pre-existing step files by disambiguating step text.

New tests cover: ACP clients/facade, actor CLI/config, application container,
ACMS service/strategies, async worker, automation profile CLI, autonomy
guardrail, bridge, change model, config CLI/service, context service,
cross-plan correction, database models, decision service, decomposition
clustering/service, discovery handler, langchain chat provider, langgraph
nodes, materializers, multi-project service, plan apply/CLI/lifecycle/model/
preflight/resume/service, PostgreSQL analyzer, project CLI/context CLI,
provider registry, reactive application/route, repositories, resolver handler,
resource registry service, resume model, retry patterns, sandbox protocol,
server CLI, skill CLI/service, skills registry, subplan execution/service,
system CLI, UKO loader, UoW, and YAML template engine.

Closes #645
2026-03-09 13:01:58 -04:00