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
105 lines
6.1 KiB
Gherkin
105 lines
6.1 KiB
Gherkin
Feature: plan apply --format json returns spec-required JSON envelope
|
|
As a programmatic consumer of the CleverAgents CLI
|
|
I want ``agents plan apply --format json`` to return a spec-compliant JSON envelope
|
|
So that tooling and scripts can reliably parse the apply output
|
|
|
|
Background:
|
|
Given a plan CLI runner for the apply JSON envelope test
|
|
|
|
# ── Envelope field presence ──────────────────────────────────────────────
|
|
|
|
Scenario: apply JSON output includes all required top-level envelope fields
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON envelope should contain field "command"
|
|
And the apply JSON envelope should contain field "status"
|
|
And the apply JSON envelope should contain field "exit_code"
|
|
And the apply JSON envelope should contain field "data"
|
|
And the apply JSON envelope should contain field "timing"
|
|
And the apply JSON envelope should contain field "messages"
|
|
|
|
Scenario: apply JSON envelope command field is "plan apply"
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON envelope command should be "plan apply"
|
|
|
|
Scenario: apply JSON envelope status field is "ok"
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON envelope status should be "ok"
|
|
|
|
Scenario: apply JSON envelope exit_code field is 0
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON envelope exit_code should be 0
|
|
|
|
Scenario: apply JSON envelope messages is a non-empty list
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON envelope messages should be a non-empty list
|
|
|
|
# ── Data field structure ─────────────────────────────────────────────────
|
|
|
|
Scenario: apply JSON envelope data field contains required sub-fields
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON data should contain field "artifacts"
|
|
And the apply JSON data should contain field "changes"
|
|
And the apply JSON data should contain field "project"
|
|
And the apply JSON data should contain field "applied_at"
|
|
And the apply JSON data should contain field "validation"
|
|
And the apply JSON data should contain field "sandbox_cleanup"
|
|
And the apply JSON data should contain field "lifecycle"
|
|
|
|
Scenario: apply JSON data validation field contains test lint and type_check
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON data validation should contain field "tests"
|
|
And the apply JSON data validation should contain field "lint"
|
|
And the apply JSON data validation should contain field "type_check"
|
|
|
|
Scenario: apply JSON data lifecycle field contains required sub-fields
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON data lifecycle should contain field "phase"
|
|
And the apply JSON data lifecycle should contain field "state"
|
|
And the apply JSON data lifecycle should contain field "total_duration"
|
|
And the apply JSON data lifecycle should contain field "total_cost"
|
|
And the apply JSON data lifecycle should contain field "decisions_made"
|
|
And the apply JSON data lifecycle should contain field "child_plans"
|
|
|
|
Scenario: apply JSON data sandbox_cleanup field contains worktree branch checkpoint
|
|
When I invoke plan apply with --format json and a mocked service
|
|
Then the apply JSON data sandbox_cleanup should contain field "worktree"
|
|
And the apply JSON data sandbox_cleanup should contain field "branch"
|
|
And the apply JSON data sandbox_cleanup should contain field "checkpoint"
|
|
|
|
# ── sandbox_cleanup derives from actual plan state ───────────────────────
|
|
|
|
Scenario: sandbox_cleanup shows removed state for terminal apply plan
|
|
When I invoke plan apply with --format json and a terminal apply plan
|
|
Then the apply JSON data sandbox_cleanup worktree should be "removed"
|
|
And the apply JSON data sandbox_cleanup branch should be "merged to main"
|
|
And the apply JSON data sandbox_cleanup checkpoint should be "archived"
|
|
|
|
Scenario: sandbox_cleanup shows active state for non-terminal plan
|
|
When I invoke plan apply with --format json and a non-terminal plan
|
|
Then the apply JSON data sandbox_cleanup worktree should be "active"
|
|
And the apply JSON data sandbox_cleanup branch should be "open"
|
|
And the apply JSON data sandbox_cleanup checkpoint should be "pending"
|
|
|
|
# ── Command isolation ────────────────────────────────────────────────────
|
|
|
|
Scenario: plan status --format json does not emit plan apply command field
|
|
When I invoke plan status with --format json and a mocked service
|
|
Then the plan status JSON output should not have command "plan apply"
|
|
|
|
Scenario: plan cancel --format json does not emit plan apply command field
|
|
When I invoke plan cancel with --format json and a mocked service
|
|
Then the plan cancel JSON output should not have command "plan apply"
|
|
|
|
# ── Legacy plan fallback ─────────────────────────────────────────────────
|
|
|
|
Scenario: apply JSON envelope handles legacy plan object gracefully
|
|
When I invoke the apply output dict with a legacy plan object
|
|
Then the legacy apply JSON envelope command should be "plan apply"
|
|
And the legacy apply JSON envelope data should contain field "plan"
|
|
|
|
# ── total_cost from cost_metadata ────────────────────────────────────────
|
|
|
|
Scenario: apply JSON data lifecycle total_cost reflects plan cost_metadata
|
|
When I invoke plan apply with --format json and a plan with cost metadata
|
|
Then the apply JSON data lifecycle total_cost should start with "$"
|