Feature: Validation-gated apply pipeline
  As a plan executor
  I want apply to be gated by validation results
  So that changes are only committed when all required validations pass

  Background:
    Given an apply pipeline test environment

  # -- Successful apply --------------------------------------------------

  Scenario: Apply succeeds when all required validations pass
    Given a plan with changeset containing 3 files
    And the plan has validation summary with 2 required passed and 0 failed
    When I apply the plan with validation gate
    Then the apply outcome should be "applied"
    And the apply result files changed should be 3
    And the apply result validations total should be 2
    And the apply result message should contain "applied successfully"

  Scenario: Apply succeeds with no validations
    Given a plan with changeset containing 1 files
    And the plan has no validation summary
    When I apply the plan with validation gate
    Then the apply outcome should be "applied"
    And the apply result validations total should be 0

  # -- Blocked by validation failure ------------------------------------

  Scenario: Apply blocked when required validations fail
    Given a plan with changeset containing 5 files
    And the plan has validation summary with 1 required passed and 2 failed
    When I apply the plan with validation gate
    Then the apply outcome should be "constrained"
    And the apply result validations failed should be 2
    And the apply result message should contain "Apply refused"
    And the apply result message should contain "2 required"

  # -- Idempotent re-apply blocking -------------------------------------

  Scenario: Re-apply on already applied plan returns already_applied
    Given a plan that is already applied
    When I apply the plan with validation gate
    Then the apply outcome should be "already_applied"
    And the apply result message should contain "already been applied"

  Scenario: Apply on errored plan returns constrained
    Given a plan that is in errored state
    When I apply the plan with validation gate
    Then the apply outcome should be "constrained"
    And the apply result message should contain "terminal state"

  Scenario: Apply on cancelled plan returns constrained
    Given a plan that is in cancelled state
    When I apply the plan with validation gate
    Then the apply outcome should be "constrained"
    And the apply result message should contain "terminal state"

  # -- Empty changeset guard --------------------------------------------

  Scenario: Apply blocked on empty changeset without allow_empty
    Given a plan with empty changeset
    When I apply the plan with validation gate
    Then the apply outcome should be "blocked_empty"
    And the apply result message should contain "empty ChangeSet"

  Scenario: Apply blocked when plan has no changeset
    Given an apply plan with no changeset assigned
    When I apply the plan with validation gate
    Then the apply outcome should be "blocked_empty"
    And the apply result message should contain "empty ChangeSet"

  Scenario: Apply succeeds on empty changeset with allow_empty
    Given a plan with empty changeset
    And the plan has no validation summary
    When I apply the plan with validation gate and allow_empty
    Then the apply outcome should be "applied"

  # -- External validation summary override -----------------------------

  Scenario: External validation summary overrides plan stored summary
    Given a plan with changeset containing 2 files
    And the plan has validation summary with 0 required passed and 0 failed
    When I apply the plan with external validation summary having 1 passed and 1 failed
    Then the apply outcome should be "constrained"
    And the apply result validations failed should be 1

  # -- Validation count extraction --------------------------------------

  Scenario: Validation counts extracted correctly from summary
    Given a plan with changeset containing 1 files
    And the plan has validation summary with 3 required passed and 0 failed and 2 informational
    When I apply the plan with validation gate
    Then the apply outcome should be "applied"
    And the apply result validations total should be 5

  # -- ApplyResult model checks -----------------------------------------

  Scenario: ApplyResult model has correct fields
    Given a plan with changeset containing 1 files
    And the plan has no validation summary
    When I apply the plan with validation gate
    Then the apply result plan_id should match the plan ID
