forked from HAL9000/cleveragents-core
docs/api-lsp-acms-reference
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a0df5a4cd0 |
fix(cli): wrap format_output() in spec-required JSON/YAML envelope across all CLI commands
Implements the spec-required JSON/YAML output envelope for all CLI commands
that use format_output(). The envelope structure is:
{
"command": "<command that was run>",
"status": "ok" | "warn" | "error",
"exit_code": 0,
"data": { ... command-specific payload ... },
"timing": { "duration_ms": 123 },
"messages": [{ "level": "ok", "text": "..." }]
}
Changes:
- Add _build_envelope() helper to construct the spec-required envelope
- Add optional command, status, exit_code, messages parameters to format_output()
- Wrap json/yaml output in the envelope; plain/table/rich/color unchanged
- Add timing measurement (duration_ms) to all json/yaml outputs
- Add new BDD feature file (cli_json_envelope.feature) with 14 scenarios
testing envelope field presence, values, and data payload
- Update 14 existing step files to unwrap the envelope when checking
specific data keys (backward-compatible via _unwrap_envelope() helper)
Closes #3431
|
||
|
|
48cff5cfe0 |
refactor(cli): rename plan lifecycle-list and lifecycle-apply to match specification
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> |
||
|
|
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 |
||
|
|
414abb1396 |
fix(cli): add missing --yes flag to plan apply command (#1127)
## Summary Adds the `--yes`/`-y` flag to the `lifecycle-apply` CLI command as required by the specification (`agents plan apply [--yes|-y] <PLAN_ID>`). Without `--yes`, a confirmation prompt now displays before proceeding with the destructive Apply phase. With `--yes`, the apply proceeds immediately without prompting. Closes #932 ## Changes ### Source Code - **`src/cleveragents/cli/commands/plan.py`**: Added `yes: Annotated[bool, typer.Option("--yes", "-y", help="Skip confirmation prompt")] = False` parameter to `lifecycle_apply_plan`. Added `typer.confirm()` prompt before the apply operation, consistent with the pattern used by `rollback_plan`, `correct_plan`, and other destructive commands. - Confirmation prompt text matches spec exactly: `"Apply changes for plan {plan_id}?"` producing `Apply changes for plan <ID>? [y/N]:`. - Fixed redundant plan ID display when `pre_plan` is `None` — now shows `"Apply changes for plan X?"` instead of `"Apply plan X (X)?"`. - Added `except ValueError` handler consistent with sibling commands `lifecycle_execute_plan` and `_lifecycle_apply_with_id`. - Added `except Exception` catch-all handler with `isinstance(e, (typer.Abort, typer.Exit))` re-raise guard, consistent with `lifecycle_execute_plan`. - Moved `PlanPhase` and `ProcessingState` imports to module level per CONTRIBUTING.md §Import Guidelines. ### TDD Tag Removal (Bug Fix Workflow) - **`features/tdd_plan_apply_yes_flag.feature`**: Removed `@tdd_expected_fail` tag (leaving `@tdd_bug` and `@tdd_bug_932` as permanent regression guards). - **`robot/tdd_plan_apply_yes_flag.robot`**: Removed `tdd_expected_fail` tag (leaving `tdd_bug` and `tdd_bug_932`). ### Test Updates Updated all existing `lifecycle-apply` invocations across 17 test/benchmark files to pass `--yes`, since the new confirmation prompt would otherwise abort in non-interactive test environments: - 9 Behave step definition files - 3 Robot Framework helper scripts - 2 Robot Framework e2e acceptance tests - 3 ASV benchmark files (4 invocations: `cli_robot_flow_bench.py` ×2, `m1_sourcecode_smoke_bench.py` ×1, `plan_cli_smoke_bench.py` ×1) ### Confirmation Prompt Tests (New + Strengthened) - **`features/tdd_plan_apply_yes_flag.feature`**: 5 scenarios total: - `lifecycle-apply recognises the --yes long flag` — verifies flag acceptance, prompt suppression, exit code 0, and `apply_plan` was called - `lifecycle-apply recognises the -y short flag` — same as above for short flag - `lifecycle-apply without --yes prompts for confirmation and user declines` — verifies `"Apply cancelled."` message, `exit_code == 0`, and `apply_plan` was NOT called - `lifecycle-apply without --yes prompts for confirmation and user accepts` — verifies prompt appears, `exit_code == 0`, and `apply_plan` was called - `lifecycle-apply catches unexpected exceptions cleanly` — verifies `"Unexpected error"` output, no traceback leak, non-zero exit code (exercises the `except Exception` catch-all) - **`features/steps/tdd_plan_apply_yes_flag_steps.py`**: Refactored step definitions: - `_make_mock_plan` uses `PlanPhase` and `ProcessingState` enum types instead of raw strings - `_make_mock_plan` uses `datetime.now(tz=UTC)` instead of timezone-naive `datetime.now()` - Unified prompt suppression step handles both `--yes` and `-y` via parameterised step pattern - Added `When` step for unexpected error scenario with `RuntimeError` side_effect - Added `Then` step for non-zero exit code assertion - **Feature/Robot documentation**: Updated stale descriptions that said "implementation does not accept --yes" to reflect the flag is now implemented. ### Documentation - **`docs/reference/plan_cli.md`**: Updated `lifecycle-apply` section with: - `### Synopsis` heading with code block - `### Options` table listing `--yes/-y` and `--format/-f` flags - `### Arguments` table listing `PLAN_ID` - Matches the style used by other command sections in the same file ## Review Fixes (Cycle 3 — Luis's review) | ID | Severity | Issue | Resolution | |----|----------|-------|------------| | M1 | Medium | `typer.Abort()` on user decline produces exit code 1 and redundant "Aborted." | Changed to `raise typer.Exit(0)` — consistent with `correct_decision` and legacy `apply` | | M2 | Medium | Missing exit code assertion on decline scenario | Added `And the lifecycle-apply exit code should be 0` to the decline scenario | | M3 | Medium | Spec compliance: "summary of pending changes" not implemented | Deferred — spec example shows summary *after* confirmation, not before; implementation matches spec. Ticket-vs-spec ambiguity noted. | | L1 | Low | Missing `except Exception` catch-all handler | Added catch-all matching `lifecycle_execute_plan` pattern; re-raises `typer.Abort`/`typer.Exit` | | L2 | Low | Documentation description not updated | Expanded description in `plan_cli.md` to explain confirmation prompt and `--yes` | | L3 | Low | Dead code `is not None` guards | Removed both guards — `get_plan()` raises `NotFoundError`, never returns `None` | | I1 | Info | Duplicate `PlanPhase` import | Hoisted import to top of `try` block, eliminating duplicate at old line 2087 | | I2 | Info | `typer.confirm` without explicit `default=False` | Added `default=False` for consistency with sibling commands | | L4 | Low | No test for `--yes` after positional arg | Not addressed — Typer/Click handles both orderings; low risk | | L5 | Low | No test for auto-select + interactive prompt | Not addressed — separate concern outside ticket scope | | I3 | Info | Robot helper only tests flag recognition | By design — noted as informational | ## Review Fixes (Cycle 4 — Self-QA) | ID | Severity | Issue | Resolution | |----|----------|-------|------------| | Major-1 | Major | No test for `except Exception` catch-all handler | Added new scenario `"lifecycle-apply catches unexpected exceptions cleanly"` with `RuntimeError` side_effect; asserts `"Unexpected error"` output, no traceback, non-zero exit | | Minor-2 | Minor | Missing `ValueError` handler inconsistent with siblings | Added `except ValueError as e:` with `"[red]Execution Error:[/red]"` before catch-all, matching `lifecycle_execute_plan` and `_lifecycle_apply_with_id` | | Minor-3 | Minor | Flag scenarios don't verify `apply_plan` called | Added `And the lifecycle-apply should have called apply` to both `--yes` and `-y` scenarios | | Minor-4 | Minor | Stale docstring in Robot helper references `tdd_expected_fail` inversion | Updated to reflect bug is fixed and tests serve as regression guards | | Minor-5 | Minor | `plan_cli.md` lacks Options table for `lifecycle-apply` | Added Synopsis, Options, and Arguments sections matching sibling command style | | Nit-6 | Nit | Duplicated step defs for `--yes` vs `-y` prompt suppression | Unified into single parameterised step `"the lifecycle-apply {flag} output should not contain the confirmation prompt"` | | Nit-7 | Nit | `datetime.now()` timezone-naive | Changed to `datetime.now(tz=UTC)` | | Nit-8 | Nit | `_make_mock_plan` params use `str` instead of enum types | Changed to `PlanPhase` and `ProcessingState` enum types | ## Review Fixes (Cycle 5 — Jeff's approval note) | ID | Severity | Issue | Resolution | |----|----------|-------|------------| | Import-1 | Minor | `PlanPhase`/`ProcessingState` imports inside function body instead of module level | Moved to module-level import per CONTRIBUTING.md §Import Guidelines | ## Known Limitations / Deferred Items - **M3: Ticket AC mentions "summary of pending changes"** but the spec example only shows `"Apply changes for plan <ID>? [y/N]: y"` without a change summary. The implementation shows plan ID only (matching the spec), not a change summary. This is a ticket-vs-spec ambiguity; recommend discussing with ticket author. - **Legacy `apply` command** accepts `--yes` but does not pass it to `_lifecycle_apply_with_id()`. This is a pre-existing issue outside the scope of this ticket. - **`pre_plan is None` branch** has no explicit test. Pre-existing architectural issue; no action taken. ## Quality Gates | Gate | Result | |------|--------| | `nox -s lint` | ✅ passed | | `nox -s typecheck` | ✅ passed (0 errors) | | `nox -s unit_tests` | ✅ passed (471 features, 12,424 scenarios, 0 failures) | | `nox -s integration_tests` | ✅ passed (1,727 tests, 0 failures) | | `nox -s e2e_tests` | ✅ passed (41 tests, 0 failures) | | `nox -s coverage_report` | ✅ passed (≥97% coverage) | Reviewed-on: cleveragents/cleveragents-core#1127 Reviewed-by: Jeffrey Phillips Freeman <jeffrey.freeman@cleverthis.com> Co-authored-by: Rui Hu <rui.hu@cleverthis.com> Co-committed-by: Rui Hu <rui.hu@cleverthis.com> |
||
|
|
60af2cae0c |
fix(cli): make plan explain accept plan_id for plan-level explanation (#1057)
## Summary Fixes `plan explain` to accept both decision IDs and plan IDs as the positional argument, matching the M3 acceptance test usage pattern `plan explain <plan_id>`. ### Problem `explain_decision_cmd` only accepted a decision ULID. When the M3 acceptance test passed a plan ID, `svc.get_decision(plan_id)` returned `None`, causing "Decision not found" error with exit code 1. ### Fix 1. Renamed parameter `decision_id` → `identifier` 2. Tries `svc.get_decision(identifier)` first (backward compat) 3. Falls back to `svc.list_decisions(identifier)` treating it as a plan_id, explaining the root decision 4. Clear error if neither resolves ### Quality Gates | Session | Result | |---------|--------| | `nox -s lint` | PASS | | `nox -s typecheck` | PASS (0 errors) | | `nox -s unit_tests` (explain features) | 46/46 PASS | Closes #968 Reviewed-on: cleveragents/cleveragents-core#1057 Co-authored-by: Brent Edwards <brent.edwards@cleverthis.com> Co-committed-by: Brent Edwards <brent.edwards@cleverthis.com> |
||
|
|
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() |
||
|
|
61fc70d84b |
fix(cli): pass decision tree and influence edges to CorrectionService in plan correct handler (#639)
## 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> |
||
|
|
0e36755db9 |
fix(service): address review findings for decision service
- Rehydrate sequence counter from DB on restart (BUG-1) - Add uniqueness guard raising SequenceConflictError (BUG-2) - Fix delete_decision consistency between persisted/in-memory (BUG-3) - Validate new_decision_id exists in mark_superseded (BUG-4) - Include orphaned subtrees in get_tree output (BUG-5) - Remove dead _decision_seq/_next_seq from plan_lifecycle (BUG-7) - Export SequenceConflictError from services __init__ (SPEC-2) - Replace list[Any] with list[ArtifactRef] typing (SPEC-4) - Add actor_reasoning max_length validation (SEC-1) - Use SELECT COUNT(*) in count_decisions (PERF-1) - Replace MagicMock with create_autospec(Settings) (TEST-3) - Eliminate UnitOfWork.__new__() anti-pattern (TEST-4) - Use exact assertion counts in DI tests (TEST-5) - Add restart rehydration, BFS order, invalid type, and confidence boundary test scenarios (TEST-1/2/6/7) - Fix decision_service_coverage.feature to match actual API ISSUES CLOSED: #172 |
||
|
|
f66cb8d68e |
fix(cli): address review findings for plan explain and tree commands
- Remove global _PLAN_ID; generate per-step plan IDs on context (#8) - Fix sham orphan test; build children_map from all decisions (#1) - Delete dead constants; use _PATCH_RESUME_SVC_MOD in resume steps (#2) - Remove dead _resolve_active_plan_id mock from _invoke_correct (#5) - Make --mode/--guidance required Typer options (#3) - Show alternatives by default; remove --show-alternatives flag (#4) - Strengthen weak assertions on depth-limit and show-superseded (#6) - Add negative assertions for error type conflation (#7) ISSUES CLOSED: #174 |
||
|
|
1524f8d25f |
test(cli): add 32 behave scenarios to close plan.py diff-coverage gap
Cover CLI-level code paths for plan explain, tree, correct, resume, revert, and read-only guards that were unreached by existing unit tests. Raises plan.py diff-coverage from 69% to 99.7% (1 line remaining). |