@phase1 @domain @plan @coverage Feature: Plan Model Coverage — New Fields and Helpers As a developer I want full test coverage of the plan model's new features So that ProjectLink validation, as_cli_dict output, and edge-case validators are reliable # NamespacedName — invalid name characters Scenario: Invalid name with special characters raises validation error When I try to create a namespaced name with namespace "local" and name "test@action" Then a validation error should be raised # ProjectLink.validate_alias classmethod Scenario: ProjectLink.validate_alias accepts a valid alias When I validate the project link alias "my-service" Then the alias should be valid Scenario: ProjectLink.validate_alias rejects an alias starting with a digit When I validate the project link alias "1bad-alias" Then the alias should be invalid Scenario: ProjectLink.validate_alias rejects an alias with uppercase When I validate the project link alias "BadAlias" Then the alias should be invalid Scenario: ProjectLink.validate_alias rejects an empty alias When I validate an empty project link alias Then the alias should be invalid # ProjectLink field validator — invalid alias on construction Scenario: Creating a ProjectLink with an invalid alias raises validation error When I try to create a project link with alias "INVALID!" Then a validation error should be raised Scenario: Creating a ProjectLink with a valid alias succeeds When I create a project link with alias "api-svc" Then the project link alias should be "api-svc" # Plan — APPLY phase with APPLIED processing_state is terminal Scenario: APPLY phase with APPLIED processing state is terminal When I create a plan in apply phase with applied processing state Then the plan processing state should be "applied" And the plan should be terminal # Plan — duplicate project link alias uniqueness Scenario: Duplicate project link aliases raise validation error When I try to create a plan with duplicate project link aliases Then a validation error should be raised Scenario: Distinct project link aliases are accepted When I create a plan with distinct project link aliases Then the plan should have 2 project links # Plan.as_cli_dict — base fields Scenario: as_cli_dict includes base identification fields Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should contain key "plan_id" And the CLI dict should contain key "name" And the CLI dict should contain key "action" And the CLI dict should contain key "phase" And the CLI dict should contain key "state" And the CLI dict should contain key "description" And the CLI dict should contain key "automation_level" And the CLI dict should contain key "created_at" And the CLI dict should contain key "updated_at" # Plan.as_cli_dict — definition_of_done Scenario: as_cli_dict includes definition_of_done when set Given I create a plan with definition of done "all tests pass" When I call as_cli_dict Then the CLI dict key "definition_of_done" should be "all tests pass" Scenario: as_cli_dict omits definition_of_done when not set Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "definition_of_done" # Plan.as_cli_dict — automation profile provenance Scenario: as_cli_dict includes automation profile with provenance Given I create a plan with automation profile "trusted" from "action" When I call as_cli_dict Then the CLI dict key "automation_profile" should be "trusted" And the CLI dict key "automation_profile_source" should be "action" Scenario: as_cli_dict omits automation profile when not set Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "automation_profile" # Plan.as_cli_dict — project links Scenario: as_cli_dict renders project links with alias and read_only Given I create a plan with project links When I call as_cli_dict Then the CLI dict key "projects" should be a list of length 2 Scenario: as_cli_dict omits projects when none are linked Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "projects" # Plan.as_cli_dict — invariants Scenario: as_cli_dict renders invariants with source tags Given I create a plan with invariants When I call as_cli_dict Then the CLI dict key "invariants" should be a list of length 2 Scenario: as_cli_dict omits invariants when empty Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "invariants" # Plan.as_cli_dict — arguments Scenario: as_cli_dict renders arguments in stable order Given I create a plan with arguments When I call as_cli_dict Then the CLI dict should contain key "arguments" And the CLI dict arguments should preserve order Scenario: as_cli_dict omits arguments when empty Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "arguments" # Plan.as_cli_dict — actor fields Scenario: as_cli_dict includes strategy_actor when set Given I create a plan with strategy actor "local/planner" When I call as_cli_dict Then the CLI dict key "strategy_actor" should be "local/planner" Scenario: as_cli_dict includes execution_actor when set Given I create a plan with execution actor "local/coder" When I call as_cli_dict Then the CLI dict key "execution_actor" should be "local/coder" Scenario: as_cli_dict omits actor fields when not set Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "strategy_actor" And the CLI dict should not contain key "execution_actor" # Plan.as_cli_dict — error message Scenario: as_cli_dict includes error when present Given I create a plan with error message "sandbox timeout" When I call as_cli_dict Then the CLI dict key "error" should be "sandbox timeout" Scenario: as_cli_dict omits error when not present Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "error" # Plan.as_cli_dict — parent plan and subplan count Scenario: as_cli_dict includes parent_plan_id for subplans Given I create a subplan for CLI output When I call as_cli_dict Then the CLI dict should contain key "parent_plan_id" Scenario: as_cli_dict includes subplan_count when subplans exist Given I create a plan with subplan statuses When I call as_cli_dict Then the CLI dict key "subplan_count" should be 1 Scenario: as_cli_dict omits parent and subplan fields for root plan Given I create a plan for CLI output When I call as_cli_dict Then the CLI dict should not contain key "parent_plan_id" And the CLI dict should not contain key "subplan_count" # ---- is_subplan / is_root_plan / depth properties ---- Scenario: Root plan is not a subplan and has depth zero Given I create a plan for CLI output Then the plan should not be a subplan And the plan should be a root plan And the plan depth should be 0 Scenario: Child plan is a subplan and has depth minus one Given I create a child plan with a parent Then the plan should be a subplan And the plan should not be a root plan And the plan depth should be -1 # ---- SubplanFailureHandler.should_stop_others ---- Scenario: Failure handler stops others when fail_fast is true Given a subplan config with fail_fast enabled and sequential mode And a failed subplan status When I check should_stop_others Then should_stop_others should be true Scenario: Failure handler stops others in sequential mode Given a subplan config with fail_fast disabled and sequential mode And a failed subplan status When I check should_stop_others Then should_stop_others should be true Scenario: Failure handler does not stop others in parallel mode without fail_fast Given a subplan config with fail_fast disabled and parallel mode And a failed subplan status When I check should_stop_others Then should_stop_others should be false # ---- SubplanFailureHandler.should_retry ---- Scenario: Failure handler does not retry when retry_failed is false Given a subplan config with retry disabled And a failed subplan status with error "TimeoutError" When I check should_retry Then should_retry should be false Scenario: Failure handler does not retry when max retries exceeded Given a subplan config with max retries 1 And a failed subplan status on attempt 2 with error "TimeoutError" When I check should_retry Then should_retry should be false Scenario: Failure handler retries retriable failure within limit Given a subplan config with retry enabled and max retries 2 And a failed subplan status on attempt 1 with error "TimeoutError" When I check should_retry Then should_retry should be true Scenario: Failure handler does not retry non-retriable error Given a subplan config with retry enabled and max retries 2 And a failed subplan status on attempt 1 with error "ConfigurationError" When I check should_retry Then should_retry should be false Scenario: Failure handler does not retry unknown error Given a subplan config with retry enabled and max retries 2 And a failed subplan status on attempt 1 with error "SomeUnknownError" When I check should_retry Then should_retry should be false