Feature: Invariant Reconciliation Actor Auto-Invocation
  As a plan lifecycle manager
  I want invariant reconciliation to run automatically at phase transitions
  So that invariant violations are detected before they propagate

  Background:
    Given a fresh PlanLifecycleService with invariant reconciliation wired

  # === Auto-invocation at Strategize start ===

  @autowire @strategize
  Scenario: Reconciliation runs at start_strategize when invariant_actor is set
    Given a plan in Strategize/QUEUED with invariant_actor "builtin/invariant-reconciliation"
    And a global invariant "All tests must pass" is registered
    When I call start_strategize on the plan
    Then the plan should transition to Strategize/PROCESSING
    And invariant reconciliation should have been invoked
    And an INVARIANT_RECONCILED event should have been emitted

  @autowire @strategize
  Scenario: Reconciliation is skipped at start_strategize when invariant_actor is None
    Given a plan in Strategize/QUEUED with invariant_actor unset
    When I call start_strategize on the plan
    Then the plan should transition to Strategize/PROCESSING
    And invariant reconciliation should not have been invoked

  @autowire @strategize
  Scenario: Reconciliation is skipped when invariant_actor is "__optional__"
    Given a plan in Strategize/QUEUED with invariant_actor "__optional__"
    When I call start_strategize on the plan
    Then the plan should transition to Strategize/PROCESSING
    And invariant reconciliation should not have been invoked

  # === Auto-invocation at Execute transition ===

  @autowire @execute
  Scenario: Reconciliation runs at execute_plan transition
    Given a plan in Strategize/COMPLETE with invariant_actor "builtin/invariant-reconciliation"
    And a global invariant "No unsafe operations" is registered
    When I call execute_plan on the plan
    Then the plan should transition to Execute/QUEUED
    And invariant reconciliation should have been invoked

  # === Auto-invocation at Apply transition ===

  @autowire @apply
  Scenario: Reconciliation runs at apply_plan transition
    Given a plan in Execute/COMPLETE with invariant_actor "builtin/invariant-reconciliation"
    And a global invariant "Review before merge" is registered
    When I call apply_plan on the plan
    Then the plan should transition to Apply/QUEUED
    And invariant reconciliation should have been invoked

  # === Transition blocking on failure ===

  @autowire @blocking
  Scenario: Reconciliation failure blocks start_strategize
    Given a plan in Strategize/QUEUED with invariant_actor "builtin/invariant-reconciliation"
    And the invariant service is configured to raise an error
    When I attempt to call start_strategize on the plan
    Then a ReconciliationBlockedError should be raised
    And the plan should remain in Strategize/QUEUED
    And an INVARIANT_VIOLATED event should have been emitted

  @autowire @blocking
  Scenario: Reconciliation failure blocks execute_plan
    Given a plan in Strategize/COMPLETE with invariant_actor "builtin/invariant-reconciliation"
    And the invariant service is configured to raise an error
    When I attempt to call execute_plan on the plan
    Then a ReconciliationBlockedError should be raised
    And the plan should remain in Strategize/COMPLETE

  @autowire @blocking
  Scenario: Reconciliation failure blocks apply_plan
    Given a plan in Execute/COMPLETE with invariant_actor "builtin/invariant-reconciliation"
    And the invariant service is configured to raise an error
    When I attempt to call apply_plan on the plan
    Then a ReconciliationBlockedError should be raised
    And the plan should remain in Execute/COMPLETE

  # === Decision recording ===

  @autowire @decisions
  Scenario: Reconciliation records invariant_enforced decisions in decision tree
    Given a plan in Strategize/QUEUED with invariant_actor "builtin/invariant-reconciliation"
    And a global invariant "Maintain backward compatibility" is registered
    And a plan invariant "Use Python 3.12 only" is registered for the plan
    When I call start_strategize on the plan without mocking
    Then 2 invariant_enforced decisions should be recorded for the plan

  # === Post-correction reconciliation ===

  @autowire @correction
  Scenario: Reconciliation runs after correction is applied via event subscription
    Given a plan in Strategize/PROCESSING with invariant_actor "builtin/invariant-reconciliation"
    And a global invariant "All tests must pass" is registered
    When a CORRECTION_APPLIED event is emitted for the plan
    Then invariant reconciliation should have been invoked for the plan
