bbe8d830d5
Fix the spec-required data structure for `agents plan apply --format json`:
- artifacts: [] -> 0 (integer count per spec)
- changes: [] -> {"insertions": 0, "deletions": 0} (dict per spec)
- validation: rename "test" -> "tests" with nested dict structure, restructure
"lint" and "type_check" as nested dicts, rename "duration" -> "duration_s" (float)
- lifecycle.child_plans: [] -> 0 (integer count per spec)
- timing.applied_at key renamed to timing.started per spec
Update BDD tests to match corrected implementation:
- plan_apply_json_envelope.feature: check "tests" not "test" in validation
- plan_cli_coverage_boost.feature: remove non-spec "namespaced_name" assertion
- plan_cli_coverage_boost_steps.py: check flat string messages per spec,
not {"level", "text"} objects
ISSUES CLOSED: #9449
209 lines
9.7 KiB
Gherkin
209 lines
9.7 KiB
Gherkin
Feature: Plan CLI coverage boost
|
|
As a developer
|
|
I want to exercise uncovered branches in plan.py
|
|
So that code coverage is improved for the plan CLI module
|
|
|
|
# ---- _plan_spec_dict helper ----
|
|
|
|
Scenario: _plan_spec_dict returns error_message when truthy
|
|
Given a v3 Plan with error_message set to "Strategy failed"
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should contain key "error_message" with value "Strategy failed"
|
|
|
|
Scenario: _plan_spec_dict falls back to legacy format for non-Plan objects
|
|
Given a non-Plan object with string value "legacy plan data"
|
|
When I call _plan_spec_dict on the object
|
|
Then the spec dict should equal {"plan": "legacy plan data"}
|
|
|
|
Scenario: _plan_spec_dict omits error_message when it is None
|
|
Given a v3 Plan with error_message set to None
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should not contain key "error_message"
|
|
|
|
Scenario: _plan_spec_dict includes estimation_result when set
|
|
Given a v3 Plan with estimation_result set
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should contain key "estimation"
|
|
|
|
Scenario: _plan_spec_dict includes invariants when populated
|
|
Given a v3 Plan with invariants populated
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should contain key "invariants"
|
|
|
|
Scenario: _plan_spec_dict includes execution_environment when set
|
|
Given a v3 Plan with execution_environment set
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should contain key "execution_environment"
|
|
And the spec dict should contain key "execution_env_priority"
|
|
|
|
Scenario: _plan_spec_dict includes dod_evaluation when validation_summary set
|
|
Given a v3 Plan with validation_summary populated
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should contain key "dod_evaluation"
|
|
|
|
Scenario: _plan_spec_dict includes last_completed_step and last_checkpoint_id
|
|
Given a v3 Plan with last_completed_step and last_checkpoint_id
|
|
When I call _plan_spec_dict on the plan
|
|
Then the spec dict should contain key "last_completed_step"
|
|
And the spec dict should contain key "last_checkpoint_id"
|
|
|
|
# ---- _print_lifecycle_plan helper ----
|
|
|
|
Scenario: _print_lifecycle_plan prints all optional timestamps
|
|
Given a v3 Plan with all timestamps populated
|
|
When I call _print_lifecycle_plan on the plan
|
|
Then the printed output should contain "Strategize Started"
|
|
And the printed output should contain "Strategize Completed"
|
|
And the printed output should contain "Execute Started"
|
|
And the printed output should contain "Execute Completed"
|
|
And the printed output should contain "Applied At"
|
|
|
|
Scenario: _print_lifecycle_plan prints estimation_actor when set
|
|
Given a v3 Plan with estimation_actor set to "local/cost-estimator"
|
|
When I call _print_lifecycle_plan on the plan
|
|
Then the printed output should contain "Estimation Actor"
|
|
And the printed output should contain "local/cost-estimator"
|
|
|
|
Scenario: _print_lifecycle_plan prints invariant_actor when set
|
|
Given a v3 Plan with invariant_actor set to "local/invariant-checker"
|
|
When I call _print_lifecycle_plan on the plan
|
|
Then the printed output should contain "Invariant Actor"
|
|
And the printed output should contain "local/invariant-checker"
|
|
|
|
Scenario: _print_lifecycle_plan falls back for non-Plan objects
|
|
Given a non-Plan object with string value "legacy-plan-object"
|
|
When I call _print_lifecycle_plan on the object
|
|
Then the printed output should contain "legacy-plan-object"
|
|
|
|
# ---- execute_plan non-rich format ----
|
|
|
|
Scenario: execute_plan outputs JSON when format is json
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has a complete strategize plan for execute
|
|
When I invoke execute with "--format" "json" and plan id
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "plan_id"
|
|
And the plan coverage output should contain "sandbox"
|
|
And the plan coverage output should contain "worker"
|
|
And the plan coverage output should contain "progress"
|
|
And the plan coverage output should contain "strategy_summary"
|
|
And the plan coverage output should contain "command"
|
|
And the plan coverage output should contain "exit_code"
|
|
|
|
@tdd_issue @tdd_issue_4251 @tdd_expected_fail
|
|
Scenario: execute_plan JSON output has spec-required envelope structure
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has a complete strategize plan for execute
|
|
When I invoke execute with "--format" "json" and plan id
|
|
Then the plan coverage command should succeed
|
|
And the execute JSON output has the spec-required envelope fields
|
|
And the execute JSON output data has sandbox with strategy field
|
|
And the execute JSON output data has progress list with label and status
|
|
|
|
# ---- apply_plan non-rich format ----
|
|
|
|
Scenario: apply_plan outputs JSON when format is json
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has a complete execute plan for apply
|
|
When I invoke apply with "--format" "json" and plan id
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "plan_id"
|
|
|
|
@tdd_issue @tdd_issue_9817
|
|
Scenario: apply_plan JSON output has spec-required envelope structure
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has a complete execute plan for apply
|
|
When I invoke apply with "--format" "json" and plan id
|
|
Then the plan coverage command should succeed
|
|
And the apply JSON output has the spec-required envelope fields
|
|
And the apply JSON output data has plan_id field
|
|
|
|
# ---- list_plans regex and state/processing_state filtering ----
|
|
|
|
Scenario: list_plans filters by regex pattern
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has multiple plans for lifecycle list
|
|
When I invoke list with regex "alpha"
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "alpha"
|
|
And the plan coverage output should not contain "beta"
|
|
|
|
Scenario: list_plans filters by state
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has plans in different processing states
|
|
When I invoke list with "--state" "processing"
|
|
Then the plan coverage command should succeed
|
|
|
|
Scenario: list_plans filters by processing_state alias
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has plans in different processing states
|
|
When I invoke list with "--processing-state" "complete"
|
|
Then the plan coverage command should succeed
|
|
|
|
Scenario: list_plans rejects invalid regex
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has multiple plans for lifecycle list
|
|
When I invoke list with regex "[invalid"
|
|
Then the plan coverage command should abort
|
|
And the plan coverage output should contain "Invalid regex"
|
|
|
|
Scenario: list_plans filters by action name
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has multiple plans for lifecycle list
|
|
When I invoke list with "--action" "local/test-action"
|
|
Then the plan coverage command should succeed
|
|
|
|
Scenario: list_plans outputs JSON when format is json
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service has multiple plans for lifecycle list
|
|
When I invoke list with "--format" "json"
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "plan_id"
|
|
|
|
# ---- cancel_plan ----
|
|
|
|
Scenario: cancel_plan in non-rich format without reason
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service can cancel a plan
|
|
When I invoke cancel with "--format" "json" and no reason
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "plan_id"
|
|
And the plan coverage output should not contain "cancel_reason"
|
|
|
|
Scenario: cancel_plan in non-rich format with reason
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service can cancel a plan
|
|
When I invoke cancel with "--format" "json" and reason "not needed"
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "cancel_reason"
|
|
And the plan coverage output should contain "not needed"
|
|
|
|
Scenario: cancel_plan in rich format with reason
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service can cancel a plan
|
|
When I invoke cancel in rich format with reason "obsolete"
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "Plan cancelled"
|
|
And the plan coverage output should contain "Reason: obsolete"
|
|
|
|
Scenario: cancel_plan in rich format without reason
|
|
Given a plan lifecycle CLI runner for coverage
|
|
And a mocked lifecycle service for plan coverage commands
|
|
And the service can cancel a plan
|
|
When I invoke cancel in rich format without reason
|
|
Then the plan coverage command should succeed
|
|
And the plan coverage output should contain "Plan cancelled"
|