UAT: _cleveragents/plan/apply A2A handler leaves plan in apply/queued state — never drives plan to terminal applied state #2578

Open
opened 2026-04-03 18:59:00 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/a2a-plan-apply-terminal-state
  • Commit Message: fix(a2a): drive plan to terminal applied state in _handle_plan_apply
  • Milestone: v3.8.0
  • Parent Epic: #399

Background

The _cleveragents/plan/apply A2A extension method is the remote equivalent of the CLI agents plan apply command. Per spec §43263, this method must map to PlanLifecycle.apply() and drive the plan all the way to its terminal apply/applied state.

The current implementation in src/cleveragents/a2a/facade.py (A2AFacade._handle_plan_apply) calls svc.apply_plan(plan_id) which only transitions the plan from execute/completeapply/queued. It never calls start_apply() or complete_apply() (or the equivalent _complete_apply_if_queued() helper) to advance the plan through apply/queued → apply/processing → apply/applied.

The CLI command (agents plan apply) correctly calls service.apply_plan(plan_id) followed by service._complete_apply_if_queued(plan_id) to reach the terminal state. The A2A handler must match this behaviour.

Current Behavior

After a client calls _cleveragents/plan/apply via the A2A interface, the plan is left in apply/queued state. Any subsequent operation that checks for a terminal state (e.g., apply/applied) will incorrectly find the plan still active. The response also returns plan.phase.value (e.g., "apply") rather than the processing state (e.g., "applied"), giving the caller a misleading status.

Affected code — src/cleveragents/a2a/facade.py, method A2AFacade._handle_plan_apply:

def _handle_plan_apply(self, params: dict[str, Any]) -> dict[str, Any]:
    svc = self._plan_lifecycle_service
    plan_id = params.get("plan_id", "")
    if svc is None:
        return {"plan_id": plan_id, "status": "applied"}
    if not plan_id:
        raise ValueError("plan_id is required")
    plan = svc.apply_plan(plan_id)  # Only transitions to apply/queued
    return {"plan_id": plan.identity.plan_id, "status": plan.phase.value}
    # Missing: svc._complete_apply_if_queued(plan_id) to reach terminal state

Expected Behavior

Per spec §43263, _cleveragents/plan/apply must drive the plan to its terminal apply/applied state, matching the CLI agents plan apply command:

  1. Call svc.apply_plan(plan_id) → transitions plan to apply/queued.
  2. Call svc._complete_apply_if_queued(plan_id) (or equivalent) → drives plan through apply/queued → apply/processing → apply/applied.
  3. Return {"plan_id": ..., "status": plan.processing_state.value} (e.g., "applied"), not plan.phase.value.

Subtasks

  • Read spec §43263 and confirm the full expected state-machine path for PlanLifecycle.apply()
  • Fix A2AFacade._handle_plan_apply in src/cleveragents/a2a/facade.py to call svc._complete_apply_if_queued(plan_id) after svc.apply_plan(plan_id)
  • Update the return value to use plan.processing_state.value instead of plan.phase.value
  • Tests (Behave): Add/update BDD scenario for _cleveragents/plan/apply verifying plan reaches apply/applied terminal state
  • Tests (Robot): Add/update integration test confirming A2A plan/apply end-to-end terminal state
  • Verify the fix matches CLI agents plan apply behaviour (same state transitions, same terminal state)
  • Verify coverage ≥ 97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A2AFacade._handle_plan_apply calls both svc.apply_plan(plan_id) and svc._complete_apply_if_queued(plan_id) (or equivalent), driving the plan to the terminal apply/applied state.
  • The response returns plan.processing_state.value (e.g., "applied") rather than plan.phase.value.
  • BDD and integration tests confirm the plan reaches apply/applied after a _cleveragents/plan/apply call.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly (fix(a2a): drive plan to terminal applied state in _handle_plan_apply), followed by a blank line, then additional lines providing relevant implementation details.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly (fix/a2a-plan-apply-terminal-state).
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.
  • All nox stages pass.
  • Coverage ≥ 97%.

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/a2a-plan-apply-terminal-state` - **Commit Message**: `fix(a2a): drive plan to terminal applied state in _handle_plan_apply` - **Milestone**: v3.8.0 - **Parent Epic**: #399 ## Background The `_cleveragents/plan/apply` A2A extension method is the remote equivalent of the CLI `agents plan apply` command. Per spec §43263, this method must map to `PlanLifecycle.apply()` and drive the plan all the way to its terminal `apply/applied` state. The current implementation in `src/cleveragents/a2a/facade.py` (`A2AFacade._handle_plan_apply`) calls `svc.apply_plan(plan_id)` which only transitions the plan from `execute/complete` → `apply/queued`. It never calls `start_apply()` or `complete_apply()` (or the equivalent `_complete_apply_if_queued()` helper) to advance the plan through `apply/queued → apply/processing → apply/applied`. The CLI command (`agents plan apply`) correctly calls `service.apply_plan(plan_id)` followed by `service._complete_apply_if_queued(plan_id)` to reach the terminal state. The A2A handler must match this behaviour. ## Current Behavior After a client calls `_cleveragents/plan/apply` via the A2A interface, the plan is left in `apply/queued` state. Any subsequent operation that checks for a terminal state (e.g., `apply/applied`) will incorrectly find the plan still active. The response also returns `plan.phase.value` (e.g., `"apply"`) rather than the processing state (e.g., `"applied"`), giving the caller a misleading status. Affected code — `src/cleveragents/a2a/facade.py`, method `A2AFacade._handle_plan_apply`: ```python def _handle_plan_apply(self, params: dict[str, Any]) -> dict[str, Any]: svc = self._plan_lifecycle_service plan_id = params.get("plan_id", "") if svc is None: return {"plan_id": plan_id, "status": "applied"} if not plan_id: raise ValueError("plan_id is required") plan = svc.apply_plan(plan_id) # Only transitions to apply/queued return {"plan_id": plan.identity.plan_id, "status": plan.phase.value} # Missing: svc._complete_apply_if_queued(plan_id) to reach terminal state ``` ## Expected Behavior Per spec §43263, `_cleveragents/plan/apply` must drive the plan to its terminal `apply/applied` state, matching the CLI `agents plan apply` command: 1. Call `svc.apply_plan(plan_id)` → transitions plan to `apply/queued`. 2. Call `svc._complete_apply_if_queued(plan_id)` (or equivalent) → drives plan through `apply/queued → apply/processing → apply/applied`. 3. Return `{"plan_id": ..., "status": plan.processing_state.value}` (e.g., `"applied"`), not `plan.phase.value`. ## Subtasks - [ ] Read spec §43263 and confirm the full expected state-machine path for `PlanLifecycle.apply()` - [ ] Fix `A2AFacade._handle_plan_apply` in `src/cleveragents/a2a/facade.py` to call `svc._complete_apply_if_queued(plan_id)` after `svc.apply_plan(plan_id)` - [ ] Update the return value to use `plan.processing_state.value` instead of `plan.phase.value` - [ ] Tests (Behave): Add/update BDD scenario for `_cleveragents/plan/apply` verifying plan reaches `apply/applied` terminal state - [ ] Tests (Robot): Add/update integration test confirming A2A `plan/apply` end-to-end terminal state - [ ] Verify the fix matches CLI `agents plan apply` behaviour (same state transitions, same terminal state) - [ ] Verify coverage ≥ 97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - `A2AFacade._handle_plan_apply` calls both `svc.apply_plan(plan_id)` and `svc._complete_apply_if_queued(plan_id)` (or equivalent), driving the plan to the terminal `apply/applied` state. - The response returns `plan.processing_state.value` (e.g., `"applied"`) rather than `plan.phase.value`. - BDD and integration tests confirm the plan reaches `apply/applied` after a `_cleveragents/plan/apply` call. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly (`fix(a2a): drive plan to terminal applied state in _handle_plan_apply`), followed by a blank line, then additional lines providing relevant implementation details. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly (`fix/a2a-plan-apply-terminal-state`). - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. - All nox stages pass. - Coverage ≥ 97%. --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.8.0 milestone 2026-04-03 18:59:14 +00:00
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: Should Have — Spec compliance or quality improvement.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: Should Have — Spec compliance or quality improvement. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#399 Epic: Post-MVP Server & Clients
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#2578
No description provided.