@plan @executor @coverage Feature: PlanExecutor coverage gaps As a developer I want comprehensive tests for PlanExecutor, StrategizeStubActor, and ExecuteStubActor So that uncovered branches and lines are fully exercised # -- PlanExecutor __init__ validation -- @init @error Scenario: PlanExecutor raises ValidationError when lifecycle_service is None When I construct a PlanExecutor with None lifecycle_service Then a PE ValidationError should be raised containing "lifecycle_service" @init Scenario: PlanExecutor initialises successfully with valid lifecycle_service Given a mock plan lifecycle service for plan executor When I construct a PlanExecutor with the mock lifecycle service Then the PlanExecutor should be created without error # -- has_runtime property -- @property Scenario: has_runtime is True when execution_context is provided Given a mock plan lifecycle service for plan executor And a mock execution context When I construct a PlanExecutor with the mock lifecycle service and execution context Then the executor has_runtime property should be True @property Scenario: has_runtime is False when no execution_context is provided Given a mock plan lifecycle service for plan executor When I construct a PlanExecutor with the mock lifecycle service Then the executor has_runtime property should be False # -- changeset_store property -- @property Scenario: changeset_store returns store from execution_context Given a mock plan lifecycle service for plan executor And a mock execution context with a changeset store When I construct a PlanExecutor with the mock lifecycle service and execution context Then the executor changeset_store should be the mock store @property Scenario: changeset_store returns None when no execution_context Given a mock plan lifecycle service for plan executor When I construct a PlanExecutor with the mock lifecycle service Then the executor changeset_store should be None # -- run_strategize guard: wrong phase -- @strategize @error Scenario: run_strategize raises PlanError when plan is not in STRATEGIZE phase Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in EXECUTE phase When I attempt to run strategize on the executor Then a PE PlanError should be raised containing "not in Strategize phase" # -- run_strategize guard: empty plan_id -- @strategize @error Scenario: run_strategize raises ValidationError for empty plan_id Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service When I attempt to run strategize with an empty plan_id Then a PE ValidationError should be raised containing "plan_id" # -- run_strategize exception handling (except branch) -- @strategize @error Scenario: run_strategize calls fail_strategize when an exception occurs during execution Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in STRATEGIZE phase And the lifecycle start_strategize will raise a RuntimeError When I attempt to run strategize and expect an exception Then fail_strategize should have been called with the plan_id And the raised exception should be a RuntimeError @strategize @error Scenario: run_strategize records error_details on plan when exception occurs Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in STRATEGIZE phase that fails during actor execute When I attempt to run strategize and expect an exception Then the plan error_details should contain the exception_type And fail_strategize should have been called with the plan_id # -- _guard_execute: wrong phase -- @execute @error Scenario: run_execute raises PlanError when plan is not in EXECUTE phase Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in STRATEGIZE phase for execute guard When I attempt to run execute on the executor Then a PE PlanError should be raised containing "not in Execute phase" # -- _guard_execute: wrong state -- @execute @error Scenario: run_execute raises PlanError when plan state is not QUEUED Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in EXECUTE phase with PROCESSING state When I attempt to run execute on the executor Then a PE PlanError should be raised containing "not queued for execution" # -- _guard_execute: None decision_root_id -- @execute @error Scenario: run_execute raises PlanError when decision_root_id is None Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in EXECUTE phase with QUEUED state but no decision root When I attempt to run execute on the executor Then a PE PlanError should be raised containing "no decision tree" # -- run_execute routing to stub -- @execute @stub Scenario: run_execute routes to stub actor when no execution_context Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service and no execution context And the lifecycle returns a fully valid plan for stub execution When I run execute on the executor Then the plan executor result should be an ExecuteResult And complete_execute should have been called # -- run_execute routing to runtime -- @execute @runtime Scenario: run_execute routes to runtime actor when execution_context is set Given a mock plan lifecycle service for plan executor And a mock execution context And a PlanExecutor with the mock lifecycle service and execution context and tool runner And the lifecycle returns a fully valid plan for runtime execution When I run execute on the executor Then the plan executor result should be a RuntimeExecuteResult And complete_execute should have been called # -- StrategizeStubActor with stream_callback -- @actor @strategize Scenario: StrategizeStubActor emits stream events when callback is provided Given a stream event collector When I execute the StrategizeStubActor with a plan_id and stream callback Then the collector should contain a "strategize_started" event And the collector should contain a "strategize_decisions" event And the collector should contain a "strategize_complete" event @actor @strategize Scenario: StrategizeStubActor works without stream_callback When I execute the StrategizeStubActor with a plan_id and no callback Then the strategize result should have a valid decision_root_id And the strategize result should have at least one decision # -- ExecuteStubActor with stream_callback -- @actor @execute Scenario: ExecuteStubActor emits stream events when callback is provided Given a stream event collector And a list of two strategy decisions When I execute the ExecuteStubActor with the decisions and stream callback Then the collector should contain an "execute_started" event And the collector should contain an "execute_step" event And the collector should contain an "execute_complete" event @actor @execute Scenario: ExecuteStubActor works without stream_callback Given a list of two strategy decisions When I execute the ExecuteStubActor with the decisions and no callback Then the execute result should have a valid changeset_id And the execute result tool_calls_count should be zero # -- run_strategize happy path with stream_callback (lines 138-143) -- @strategize Scenario: run_strategize succeeds with stream_callback on a valid plan Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service And the lifecycle returns a plan in STRATEGIZE phase And a stream event collector When I run strategize with the stream callback Then the strategize result should have decisions And complete_strategize should have been called # -- run_strategize happy path sets execution_context.decision_root_id -- @strategize Scenario: run_strategize sets decision_root_id on execution_context when present Given a mock plan lifecycle service for plan executor And a mock execution context And a PlanExecutor with the mock lifecycle and execution context And the lifecycle returns a plan in STRATEGIZE phase When I run strategize successfully Then the execution context decision_root_id should be set # -- run_execute with stub and exception -- @execute @error Scenario: run_execute calls fail_execute when stub execution raises an error Given a mock plan lifecycle service for plan executor And a PlanExecutor with the mock lifecycle service and no execution context And the lifecycle returns a fully valid plan for stub execution And the stub execute actor is patched to raise an error When I attempt to run execute and expect an exception Then fail_execute should have been called with the plan_id