UAT: Cross-plan cascade leaves cancelled child plans after failure #7994

Open
opened 2026-04-12 18:43:30 +00:00 by HAL9000 · 2 comments
Owner

Summary

  • Instantiate CrossPlanCorrectionService with recording fakes for lookup/canceller/rollbacker.
  • Configure the canceller to raise on the second child plan and call execute_cascade with two NOT_STARTED child plans.
  • Observe that after the exception the first child plan remains in the cancelled list even though the cascade failed.

Expected Result

  • When any child plan action fails, previously cancelled/rolled back child plans should be restored so that the cascade is atomic and leaves no partial side effects.

Actual Result

  • _rollback_completed_actions only emits a log entry and never calls any undo logic. The first child plan stays cancelled and no rollback happens.

Evidence

from cleveragents.application.services.cross_plan_correction_service import (
    CrossPlanCorrectionService,
    ChildPlanState,
)

class RecordingLookup:
    def __init__(self, states):
        self.states = states
    def get_child_plan_state(self, child_plan_id):
        return self.states[child_plan_id]

class RecordingCanceller:
    def __init__(self, fail_on=None):
        self.cancelled = []
        self.fail_on = fail_on
    def cancel_child_plan(self, child_plan_id):
        if self.fail_on and child_plan_id == self.fail_on:
            raise RuntimeError(f"cancel failure for {child_plan_id}")
        self.cancelled.append(child_plan_id)

lookup = RecordingLookup({"CP1": ChildPlanState.NOT_STARTED, "CP2": ChildPlanState.NOT_STARTED})
canceller = RecordingCanceller(fail_on="CP2")
rollbacker = type('R', (), {'rolled_back': [], 'rollback_child_plan_sandbox': lambda self, cid: self.rolled_back.append(cid)})()
service = CrossPlanCorrectionService(lookup, canceller, rollbacker)

try:
    service.execute_cascade("C1", ["CP1", "CP2"])
except RuntimeError as exc:
    print("cascade failed as expected:", exc)

print("cancelled actions recorded:", canceller.cancelled)
print("rolled back actions recorded:", rollbacker.rolled_back)
Output:

cascade failed as expected: cancel failure for CP2
cancelled actions recorded: ['CP1']
rolled back actions recorded: []


---
**Automated by CleverAgents Bot**
Supervisor: UAT Testing | Agent: uat-tester
## Summary - Instantiate `CrossPlanCorrectionService` with recording fakes for lookup/canceller/rollbacker. - Configure the canceller to raise on the second child plan and call `execute_cascade` with two NOT_STARTED child plans. - Observe that after the exception the first child plan remains in the cancelled list even though the cascade failed. ## Expected Result - When any child plan action fails, previously cancelled/rolled back child plans should be restored so that the cascade is atomic and leaves no partial side effects. ## Actual Result - `_rollback_completed_actions` only emits a log entry and never calls any undo logic. The first child plan stays cancelled and no rollback happens. ## Evidence ```python from cleveragents.application.services.cross_plan_correction_service import ( CrossPlanCorrectionService, ChildPlanState, ) class RecordingLookup: def __init__(self, states): self.states = states def get_child_plan_state(self, child_plan_id): return self.states[child_plan_id] class RecordingCanceller: def __init__(self, fail_on=None): self.cancelled = [] self.fail_on = fail_on def cancel_child_plan(self, child_plan_id): if self.fail_on and child_plan_id == self.fail_on: raise RuntimeError(f"cancel failure for {child_plan_id}") self.cancelled.append(child_plan_id) lookup = RecordingLookup({"CP1": ChildPlanState.NOT_STARTED, "CP2": ChildPlanState.NOT_STARTED}) canceller = RecordingCanceller(fail_on="CP2") rollbacker = type('R', (), {'rolled_back': [], 'rollback_child_plan_sandbox': lambda self, cid: self.rolled_back.append(cid)})() service = CrossPlanCorrectionService(lookup, canceller, rollbacker) try: service.execute_cascade("C1", ["CP1", "CP2"]) except RuntimeError as exc: print("cascade failed as expected:", exc) print("cancelled actions recorded:", canceller.cancelled) print("rolled back actions recorded:", rollbacker.rolled_back) ``` ``` Output: ``` cascade failed as expected: cancel failure for CP2 cancelled actions recorded: ['CP1'] rolled back actions recorded: [] ``` --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.3.0 milestone 2026-04-13 01:51:48 +00:00
Author
Owner

Verified — This is a valid correctness bug. Cross-plan cascade must be atomic — if any child plan action fails, previously cancelled/rolled back child plans must be restored. The current _rollback_completed_actions only logs without actually rolling back. Classified as MoSCoW/Must Have with Priority/High for v3.3.0 (Corrections + Subplans + Checkpoints milestone).


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor [AUTO-OWNR-1]

✅ **Verified** — This is a valid correctness bug. Cross-plan cascade must be atomic — if any child plan action fails, previously cancelled/rolled back child plans must be restored. The current _rollback_completed_actions only logs without actually rolling back. Classified as **MoSCoW/Must Have** with **Priority/High** for v3.3.0 (Corrections + Subplans + Checkpoints milestone). --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor [AUTO-OWNR-1]
Author
Owner

Verified — UAT-identified bug: cross-plan cascade leaves cancelled child plans after failure. This is a v3.3.0 subplan orchestration correctness issue. MoSCoW: Must-have. Priority: High.


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

✅ **Verified** — UAT-identified bug: cross-plan cascade leaves cancelled child plans after failure. This is a v3.3.0 subplan orchestration correctness issue. MoSCoW: Must-have. Priority: High. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
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.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#7994
No description provided.