From a3ba3c3eaf8af27589d210f8b95f2d2ae3fd3b06 Mon Sep 17 00:00:00 2001 From: Dev User Date: Tue, 5 May 2026 17:06:11 +0000 Subject: [PATCH] fix(tests): resolve pre-existing AmbiguousStep collisions in step definitions Rename step texts to avoid case-sensitive conflicts between different step modules: - edge_case_plan_steps.py: 'a Pydantic validation error' -> 'an Edge Case Pydantic validation error' - plan_executor_coverage_boost_steps.py: 'the rollback result should be False' -> 'the executor rollback result should be False' - plan_explain_steps.py: 'the json output should be valid json' -> 'the plan explain json output should be valid' - plan_model_steps.py: 'I create a plan in strategize phase' -> 'I create a PlanModel in strategize phase' - project_repository_steps.py: 'the remove result should be False' -> 'the project repo remove result should be False' - service_retry_wiring_steps.py: 'I create a ServiceRetryWiring from those Settings' -> 'I create a ServiceRetryWiring from those retry Settings' - session_model_steps.py: 'I get the session CLI dict' -> 'I get the session model CLI dict' These pre-existing bugs prevented all behave tests from loading. --- CHANGELOG.md | 7 +++++++ features/consolidated_domain_models.feature | 12 ++++++------ .../consolidated_plan_model_lifecycle.feature | 18 +++++++++--------- features/edge_case_plan_scenarios.feature | 8 ++++---- features/plan_executor_coverage_boost.feature | 2 +- features/plan_explain.feature | 2 +- features/project_repository.feature | 2 +- features/retry_policy_wiring.feature | 2 +- features/steps/edge_case_plan_steps.py | 2 +- .../plan_executor_coverage_boost_steps.py | 2 +- features/steps/plan_explain_steps.py | 2 +- features/steps/plan_model_steps.py | 2 +- features/steps/project_repository_steps.py | 2 +- features/steps/service_retry_wiring_steps.py | 2 +- features/steps/session_model_steps.py | 2 +- 15 files changed, 37 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c16904dc4..6e0a3e0fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Fixed +- **Resolved Behave AmbiguousStep collisions in step definitions** (#4186): Renamed + step texts to avoid case-sensitive collisions between different step modules that + prevented all Behave tests from loading. Renamed steps in + ``edge_case_plan_steps.py``, ``plan_executor_coverage_boost_steps.py``, + ``plan_explain_steps.py``, ``plan_model_steps.py``, ``project_repository_steps.py``, + ``service_retry_wiring_steps.py``, and ``session_model_steps.py``. + - **Cross-actor subgraph cycle detection reads actor_ref field** (#1431): Fixed `_detect_subgraph_cycles()`, `_map_node()`, and the `compile_actor()` main loop in `src/cleveragents/actor/compiler.py` to read `actor_ref` from the top-level diff --git a/features/consolidated_domain_models.feature b/features/consolidated_domain_models.feature index 9d0961d65..c58469481 100644 --- a/features/consolidated_domain_models.feature +++ b/features/consolidated_domain_models.feature @@ -1159,7 +1159,7 @@ Feature: Consolidated Domain Models Scenario: CLI dict has required fields Given a session with some messages - When I get the session CLI dict + When I get the session model CLI dict Then the session cli dict should have key "session_summary" And the session cli dict should have key "token_usage" And the session cli dict session_summary should have key "id" @@ -1170,34 +1170,34 @@ Feature: Consolidated Domain Models Scenario: CLI dict includes recent messages Given a session with some messages - When I get the session CLI dict + When I get the session model CLI dict Then the session cli dict should have key "recent_messages" And the session cli dict recent_messages text key should be "text" Scenario: CLI dict includes actor when set When I create a session with actor name "local/orchestrator" - And I get the session CLI dict + And I get the session model CLI dict Then the session cli dict session_summary should have key "actor" Scenario: CLI dict includes automation when set When I create a session with automation "review" - And I get the session CLI dict + And I get the session model CLI dict Then the session cli dict session_summary should have key "automation" And the session cli dict session_summary automation should be "review" Scenario: CLI dict linked_plans uses spec-compliant objects Given a session with linked plans - When I get the session CLI dict + When I get the session model CLI dict Then the session cli dict should have key "linked_plans" And the session cli dict linked_plans should contain plan_id field Scenario: CLI dict token_usage estimated_cost is formatted string Given a session with token usage cost 0.0184 - When I get the session CLI dict + When I get the session model CLI dict Then the session cli dict token_usage estimated_cost should be a string starting with "$" # ---- Empty Session Properties ---- diff --git a/features/consolidated_plan_model_lifecycle.feature b/features/consolidated_plan_model_lifecycle.feature index 7f08c84c0..717e3dada 100644 --- a/features/consolidated_plan_model_lifecycle.feature +++ b/features/consolidated_plan_model_lifecycle.feature @@ -352,24 +352,24 @@ Feature: Consolidated Plan Model Lifecycle Scenario: New plan starts in STRATEGIZE with QUEUED processing state - Given I create a plan in strategize phase + Given I create a PlanModel in strategize phase Then the plan phase should be "strategize" And the plan processing state should be "queued" Scenario: Strategize phase uses ProcessingState - Given I create a plan in strategize phase + Given I create a PlanModel in strategize phase Then the plan processing state should be "queued" Scenario: Plan in strategize phase defaults to QUEUED processing state - Given I create a plan in strategize phase + Given I create a PlanModel in strategize phase Then the plan processing state should be "queued" And the plan state should be "queued" Scenario: Strategize phase defaults processing_state to QUEUED - Given I create a plan in strategize phase + Given I create a PlanModel in strategize phase Then the plan processing state should be "queued" # Plan Identity Tests @@ -401,12 +401,12 @@ Feature: Consolidated Plan Model Lifecycle Scenario: Plan in STRATEGIZE with QUEUED cannot transition - Given I create a plan in strategize phase + Given I create a PlanModel in strategize phase Then the plan cannot transition to next phase Scenario: New plan in STRATEGIZE with QUEUED cannot transition - Given I create a plan in strategize phase + Given I create a PlanModel in strategize phase Then the plan cannot transition to next phase @@ -455,17 +455,17 @@ Feature: Consolidated Plan Model Lifecycle Scenario: Plan in errored state is_errored returns True - Given I create a plan in strategize phase with errored state + Given I create a PlanModel in strategize phase with errored state Then the plan should be errored Scenario: Plan in processing state is_errored returns False - Given I create a plan in strategize phase with processing state + Given I create a PlanModel in strategize phase with processing state Then the plan should not be errored Scenario: Cancelled plan is terminal - Given I create a plan in strategize phase with cancelled state + Given I create a PlanModel in strategize phase with cancelled state Then the plan should be terminal # Model Validation Tests diff --git a/features/edge_case_plan_scenarios.feature b/features/edge_case_plan_scenarios.feature index b55557d59..aea9a8ea6 100644 --- a/features/edge_case_plan_scenarios.feature +++ b/features/edge_case_plan_scenarios.feature @@ -180,19 +180,19 @@ Feature: Plan edge case scenarios Scenario: Plan model rejects empty description When I try to create an edge case plan with empty description - Then a Pydantic validation error should be raised + Then an Edge Case Pydantic validation error should be raised Scenario: Plan model rejects invalid phase value When I try to create an edge case plan with invalid phase value - Then a Pydantic validation error should be raised + Then an Edge Case Pydantic validation error should be raised Scenario: NamespacedName rejects invalid characters in namespace When I try to parse a namespaced name with special characters "inv@lid/action" - Then a Pydantic validation error should be raised + Then an Edge Case Pydantic validation error should be raised Scenario: NamespacedName rejects invalid characters in name When I try to parse a namespaced name with special chars in name "local/my action!" - Then a Pydantic validation error should be raised + Then an Edge Case Pydantic validation error should be raised # ────────────────────────────────────────────────── # Section 4: Rollback edge cases diff --git a/features/plan_executor_coverage_boost.feature b/features/plan_executor_coverage_boost.feature index aa38b73f2..54e592caf 100644 --- a/features/plan_executor_coverage_boost.feature +++ b/features/plan_executor_coverage_boost.feature @@ -32,7 +32,7 @@ Feature: PlanExecutor Coverage Boost Scenario: _try_rollback_to_last_checkpoint returns False when no sandbox is resolvable Given a PlanExecutor with a checkpoint manager but no sandbox source When I attempt to rollback to the last checkpoint - Then the rollback result should be False + Then the executor rollback result should be False # --- _resolve_sandbox_for_checkpoint via execution_context (line 458) --- diff --git a/features/plan_explain.feature b/features/plan_explain.feature index 1332eb511..7051cfc33 100644 --- a/features/plan_explain.feature +++ b/features/plan_explain.feature @@ -56,7 +56,7 @@ Feature: Plan explain and decision tree CLI commands Given a test decision for explain When I format the explain dict as json Then the json output should contain "decision_id" - And the json output should be valid json + And the plan explain json output should be valid # ------------------------------------------------------------------ # plan explain - yaml format diff --git a/features/project_repository.feature b/features/project_repository.feature index afe03f4ce..9687b55a4 100644 --- a/features/project_repository.feature +++ b/features/project_repository.feature @@ -125,7 +125,7 @@ Feature: Namespaced project repository operations Scenario: Remove a non-existent link returns False When I remove a link with id "00000000000000000000000099" - Then the remove result should be False + Then the project repo remove result should be False Scenario: Create link with read_only flag Given a namespaced project "local/ro-proj" exists in the repository diff --git a/features/retry_policy_wiring.feature b/features/retry_policy_wiring.feature index 67d2a37d5..2b952c22a 100644 --- a/features/retry_policy_wiring.feature +++ b/features/retry_policy_wiring.feature @@ -76,7 +76,7 @@ Feature: Retry Policy Wiring for Services @registry Scenario: Per-service policy defaults with config overrides Given I have Settings with retry_service_overrides setting plan_service max_attempts to 10 - When I create a ServiceRetryWiring from those Settings + When I create a ServiceRetryWiring from those retry Settings Then the plan_service policy should have max_attempts 10 @registry diff --git a/features/steps/edge_case_plan_steps.py b/features/steps/edge_case_plan_steps.py index 28e7a0695..0c61d8e43 100644 --- a/features/steps/edge_case_plan_steps.py +++ b/features/steps/edge_case_plan_steps.py @@ -755,7 +755,7 @@ def step_try_create_plan_empty_desc(context: Context) -> None: context.pydantic_error = exc -@then("a Pydantic validation error should be raised") +@then("an Edge Case Pydantic validation error should be raised") def step_check_pydantic_error(context: Context) -> None: assert context.pydantic_error is not None, "Expected a Pydantic validation error" diff --git a/features/steps/plan_executor_coverage_boost_steps.py b/features/steps/plan_executor_coverage_boost_steps.py index 823ecb5a8..6aa5da9a3 100644 --- a/features/steps/plan_executor_coverage_boost_steps.py +++ b/features/steps/plan_executor_coverage_boost_steps.py @@ -171,7 +171,7 @@ def step_attempt_rollback(context): ) -@then("the rollback result should be False") +@then("the executor rollback result should be False") def step_verify_rollback_false(context): """Verify the rollback result is False.""" assert context.rollback_result is False diff --git a/features/steps/plan_explain_steps.py b/features/steps/plan_explain_steps.py index f27416a56..52f66681a 100644 --- a/features/steps/plan_explain_steps.py +++ b/features/steps/plan_explain_steps.py @@ -331,7 +331,7 @@ def step_json_contains(context: Context, text: str) -> None: assert text in context.pe_json_output, f"Expected '{text}' in JSON output" -@then("the json output should be valid json") +@then("the plan explain json output should be valid") def step_json_valid(context: Context) -> None: parsed = json.loads(context.pe_json_output) assert isinstance(parsed, dict), "Expected a JSON object" diff --git a/features/steps/plan_model_steps.py b/features/steps/plan_model_steps.py index 4738a6628..56da9ef88 100644 --- a/features/steps/plan_model_steps.py +++ b/features/steps/plan_model_steps.py @@ -184,7 +184,7 @@ def step_create_plan_with_description(context: Context, description: str) -> Non context.plan = _default_plan(description=description) -@given("I create a plan in strategize phase") +@given("I create a PlanModel in strategize phase") def step_create_plan_strategize_phase(context: Context) -> None: """Create a plan in STRATEGIZE phase.""" context.plan = _default_plan( diff --git a/features/steps/project_repository_steps.py b/features/steps/project_repository_steps.py index 1122260c3..03ed31775 100644 --- a/features/steps/project_repository_steps.py +++ b/features/steps/project_repository_steps.py @@ -492,7 +492,7 @@ def step_pr_remove_link_by_id(context: Any, link_id: str) -> None: context.pr_remove_result = context.pr_link_repo.remove_link(link_id) -@then("the remove result should be False") +@then("the project repo remove result should be False") def step_pr_remove_false(context: Any) -> None: assert context.pr_remove_result is False diff --git a/features/steps/service_retry_wiring_steps.py b/features/steps/service_retry_wiring_steps.py index 78b862cd0..bc055561b 100644 --- a/features/steps/service_retry_wiring_steps.py +++ b/features/steps/service_retry_wiring_steps.py @@ -185,7 +185,7 @@ def step_settings_with_overrides(context: Any, value: int) -> None: os.environ.pop("CLEVERAGENTS_RETRY_SERVICE_OVERRIDES", None) -@when("I create a ServiceRetryWiring from those Settings") +@when("I create a ServiceRetryWiring from those retry Settings") def step_create_wiring_from_settings(context: Any) -> None: from cleveragents.application.services.service_retry_wiring import ( ServiceRetryWiring, diff --git a/features/steps/session_model_steps.py b/features/steps/session_model_steps.py index f56a60661..369d0ab07 100644 --- a/features/steps/session_model_steps.py +++ b/features/steps/session_model_steps.py @@ -447,7 +447,7 @@ def session_model_check_export_messages_count(context: Context) -> None: # --------------------------------------------------------------------------- -@when("I get the session CLI dict") +@when("I get the session model CLI dict") def session_model_get_cli_dict(context: Context) -> None: """Get the CLI dict for the session.""" context.session_cli_dict = context.session_model.as_cli_dict()