BUG-HUNT: [state-transition] Plan.validate_phase_state_consistency fails to enforce ACTION phase state restriction #7730

Open
opened 2026-04-12 03:21:26 +00:00 by HAL9000 · 3 comments
Owner

Bug Report: State Transition — Plan ACTION Phase Allows All Processing States

Severity Assessment

  • Impact: Plans in the ACTION phase can be created or stored with any ProcessingState (e.g., PROCESSING, ERRORED, COMPLETE) — states that have no meaning during the ACTION (template) phase. This corrupts lifecycle integrity.
  • Likelihood: Medium — occurs when infrastructure code or tests construct a Plan with an explicit processing_state while keeping phase=ACTION.
  • Priority: High

Location

  • File: src/cleveragents/domain/models/core/plan.py
  • Class: Plan
  • Method: validate_phase_state_consistency
  • Lines: ~530–545

Description

The validate_phase_state_consistency model validator only assigns a default of QUEUED when processing_state is None for the ACTION phase. But because processing_state has a default of ProcessingState.QUEUED in the field definition, the is None branch is never reached. More importantly, the validator never rejects non-QUEUED states in the ACTION phase — it simply does nothing.

The ACTION phase is a non-processing template phase. According to the module docstring and spec, ACTION plans are templates, and any state other than QUEUED is semantically invalid for them. The validate_phase_state_constraints validator explicitly lists only APPLY-phase constraints and does not restrict which states ACTION phase can have.

Evidence

# From plan.py ~line 530
@model_validator(mode="after")
def validate_phase_state_consistency(self) -> Plan:
    # This branch is dead code: processing_state has a default of QUEUED,
    # so it is never None at this point.
    if self.phase == PlanPhase.ACTION and self.processing_state is None:
        self.processing_state = ProcessingState.QUEUED
    return self

# No guard prevents ACTION phase from having PROCESSING, ERRORED, COMPLETE, etc.
# The following is accepted without error:
# Plan(..., phase=PlanPhase.ACTION, processing_state=ProcessingState.ERRORED)

The validate_phase_state_constraints validator only checks APPLIED/CONSTRAINED (Apply-only) and COMPLETE (Strategize/Execute-only), but does not restrict the ACTION phase to only QUEUED.

Expected Behavior

A Plan in ACTION phase should only accept ProcessingState.QUEUED. Any other state should raise a ValueError.

Actual Behavior

A Plan with phase=ACTION and any processing_state (including PROCESSING, ERRORED, COMPLETE) is accepted without error.

Suggested Fix

Add a guard in validate_phase_state_constraints:

# Add to validate_phase_state_constraints:
if self.phase == PlanPhase.ACTION and self.processing_state != ProcessingState.QUEUED:
    raise ValueError(
        "Plans in ACTION phase must have ProcessingState.QUEUED, "
        f"got {self.processing_state.value!r}"
    )

Category

state-transition

TDD Note

After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD.


Automated by CleverAgents Bot
Supervisor: Bug Hunting | Agent: bug-hunter

## Bug Report: State Transition — Plan ACTION Phase Allows All Processing States ### Severity Assessment - **Impact**: Plans in the ACTION phase can be created or stored with any `ProcessingState` (e.g., `PROCESSING`, `ERRORED`, `COMPLETE`) — states that have no meaning during the ACTION (template) phase. This corrupts lifecycle integrity. - **Likelihood**: Medium — occurs when infrastructure code or tests construct a Plan with an explicit `processing_state` while keeping `phase=ACTION`. - **Priority**: High ### Location - **File**: `src/cleveragents/domain/models/core/plan.py` - **Class**: `Plan` - **Method**: `validate_phase_state_consistency` - **Lines**: ~530–545 ### Description The `validate_phase_state_consistency` model validator only assigns a default of `QUEUED` when `processing_state is None` for the ACTION phase. But because `processing_state` has a default of `ProcessingState.QUEUED` in the field definition, the `is None` branch is never reached. More importantly, the validator **never rejects** non-QUEUED states in the ACTION phase — it simply does nothing. The ACTION phase is a non-processing template phase. According to the module docstring and spec, ACTION plans are templates, and any state other than QUEUED is semantically invalid for them. The `validate_phase_state_constraints` validator explicitly lists only APPLY-phase constraints and does not restrict which states ACTION phase can have. ### Evidence ```python # From plan.py ~line 530 @model_validator(mode="after") def validate_phase_state_consistency(self) -> Plan: # This branch is dead code: processing_state has a default of QUEUED, # so it is never None at this point. if self.phase == PlanPhase.ACTION and self.processing_state is None: self.processing_state = ProcessingState.QUEUED return self # No guard prevents ACTION phase from having PROCESSING, ERRORED, COMPLETE, etc. # The following is accepted without error: # Plan(..., phase=PlanPhase.ACTION, processing_state=ProcessingState.ERRORED) ``` The `validate_phase_state_constraints` validator only checks APPLIED/CONSTRAINED (Apply-only) and COMPLETE (Strategize/Execute-only), but does not restrict the ACTION phase to only QUEUED. ### Expected Behavior A `Plan` in `ACTION` phase should only accept `ProcessingState.QUEUED`. Any other state should raise a `ValueError`. ### Actual Behavior A `Plan` with `phase=ACTION` and any `processing_state` (including `PROCESSING`, `ERRORED`, `COMPLETE`) is accepted without error. ### Suggested Fix Add a guard in `validate_phase_state_constraints`: ```python # Add to validate_phase_state_constraints: if self.phase == PlanPhase.ACTION and self.processing_state != ProcessingState.QUEUED: raise ValueError( "Plans in ACTION phase must have ProcessingState.QUEUED, " f"got {self.processing_state.value!r}" ) ``` ### Category state-transition ### TDD Note After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD. --- **Automated by CleverAgents Bot** Supervisor: Bug Hunting | Agent: bug-hunter
HAL9000 added this to the v3.2.0 milestone 2026-04-12 03:43:10 +00:00
Author
Owner

Verified — State transition bug: Plan.validate_phase_state_consistency doesn't enforce ACTION phase restriction. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — State transition bug: Plan.validate_phase_state_consistency doesn't enforce ACTION phase restriction. MoSCoW: Should-have. Priority: Medium. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — State transition bug: Plan.validate_phase_state_consistency doesn't enforce ACTION phase restriction. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — State transition bug: Plan.validate_phase_state_consistency doesn't enforce ACTION phase restriction. MoSCoW: Should-have. Priority: Medium. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

Verified — State transition bug: Plan.validate_phase_state_consistency doesn't enforce ACTION phase restriction. MoSCoW: Should-have. Priority: Medium.


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

✅ **Verified** — State transition bug: Plan.validate_phase_state_consistency doesn't enforce ACTION phase restriction. MoSCoW: Should-have. Priority: Medium. --- **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#7730
No description provided.