Feature: Invariant Reconciliation Actor
  As a plan strategizer
  I want invariants from all scopes to be reconciled automatically
  So that the Strategize phase operates under a clear, conflict-free invariant set

  Background:
    Given a fresh InvariantService for reconciliation
    And a fresh DecisionService for reconciliation

  # === Single-scope invariants (no conflicts) ===

  @single_scope
  Scenario: Single global invariant with no conflicts
    Given a global invariant "Never delete production data" from source "system"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the reconciled set should contain "Never delete production data"
    And 0 conflicts should be detected
    And 1 invariant_enforced decision should be recorded

  @single_scope
  Scenario: Single plan invariant with no conflicts
    Given a plan invariant "Mock all network calls" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the reconciled set should contain "Mock all network calls"
    And 0 conflicts should be detected

  @single_scope
  Scenario: Multiple global invariants with no conflicts
    Given a global invariant "Never delete production data" from source "system"
    And a global invariant "All APIs must maintain backward compatibility" from source "system"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 2 invariants
    And 0 conflicts should be detected
    And 2 invariant_enforced decisions should be recorded

  # === Multi-scope compatible invariants ===

  @multi_scope
  Scenario: Multi-scope invariants that are all compatible
    Given a global invariant "Never delete production data" from source "system"
    And a project invariant "Use ORM for all queries" from source "local/api-service" for project "local/api-service"
    And a plan invariant "Mock all network calls" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile with-project "local/api-service" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 3 invariants
    And the reconciled set should contain "Never delete production data"
    And the reconciled set should contain "Use ORM for all queries"
    And the reconciled set should contain "Mock all network calls"
    And 0 conflicts should be detected
    And 3 invariant_enforced decisions should be recorded

  @multi_scope
  Scenario: Four-scope invariants all compatible
    Given a global invariant "Never delete production data" from source "system"
    And a project invariant "Use ORM for all queries" from source "local/api-service" for project "local/api-service"
    And an action invariant "Separate commits per file" from source "local/code-coverage" for action "local/code-coverage"
    And a plan invariant "Mock all network calls" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile with-project-action "local/api-service" and "local/code-coverage" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 4 invariants
    And 0 conflicts should be detected
    And 4 invariant_enforced decisions should be recorded

  # === Conflict detection and specificity resolution ===

  @conflict
  Scenario: Plan invariant overrides project invariant on same text
    Given a project invariant "Use REST for all APIs" from source "local/api-service" for project "local/api-service"
    And a plan invariant "Use REST for all APIs" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile with-project "local/api-service" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "use rest for all apis" should be from "plan" scope
    And 1 conflict should be detected

  @conflict
  Scenario: Plan overrides global on same text
    Given a global invariant "All tests must pass" from source "system"
    And a plan invariant "All tests must pass" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "all tests must pass" should be from "plan" scope
    And 1 conflict should be detected

  @conflict
  Scenario: Action invariant overrides project invariant
    Given a project invariant "Coverage above 80%" from source "local/api-service" for project "local/api-service"
    And an action invariant "Coverage above 80%" from source "local/code-coverage" for action "local/code-coverage"
    When I reconcile with-project-action "local/api-service" and "local/code-coverage" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "coverage above 80%" should be from "action" scope
    And 1 conflict should be detected

  @conflict
  Scenario: Project invariant overrides global invariant
    Given a global invariant "Database timeout 10s" from source "system"
    And a project invariant "Database timeout 10s" from source "local/api-service" for project "local/api-service"
    When I reconcile with-project "local/api-service" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "database timeout 10s" should be from "project" scope
    And 1 conflict should be detected

  # === non_overridable global invariant ===

  @non_overridable
  Scenario: Non-overridable global invariant blocks plan override
    Given a non_overridable global invariant "Payment processing must be idempotent" from source "system"
    And a plan invariant "Payment processing must be idempotent" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "payment processing must be idempotent" should be from "global" scope
    And 1 conflict should be detected
    And the conflict reason should mention "non_overridable"

  @non_overridable
  Scenario: Non-overridable global invariant blocks project override
    Given a non_overridable global invariant "Audit logging is mandatory" from source "system"
    And a project invariant "Audit logging is mandatory" from source "local/api-service" for project "local/api-service"
    When I reconcile with-project "local/api-service" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "audit logging is mandatory" should be from "global" scope
    And 1 conflict should be detected
    And the conflict reason should mention "non_overridable"

  @non_overridable
  Scenario: Non-overridable global invariant blocks action override
    Given a non_overridable global invariant "Security scan required" from source "system"
    And an action invariant "Security scan required" from source "local/deploy" for action "local/deploy"
    When I reconcile with-action "local/deploy" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the winning invariant for "security scan required" should be from "global" scope
    And 1 conflict should be detected

  @non_overridable
  Scenario: Regular global invariant can be overridden by plan
    Given a global invariant "Use verbose logging" from source "system"
    And a plan invariant "Use verbose logging" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the winning invariant for "use verbose logging" should be from "plan" scope

  # === invariant_enforced decision recording ===

  @decisions
  Scenario: Each reconciled invariant gets an invariant_enforced decision
    Given a global invariant "Never delete production data" from source "system"
    And a project invariant "Use ORM for all queries" from source "local/api-service" for project "local/api-service"
    And a plan invariant "Mock all network calls" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile with-project "local/api-service" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then 3 invariant_enforced decisions should be recorded
    And all recorded decisions should be of type "invariant_enforced"
    And each decision should reference the plan "01JQAAAAAAAAAAAAAAAAAAAA01"

  @decisions
  Scenario: Decisions include rationale about scope
    Given a global invariant "Never delete production data" from source "system"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the decision rationale should mention "global"

  @decisions
  Scenario: Decision question includes invariant text
    Given a plan invariant "Mock all network calls" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the decision question should contain "Mock all network calls"

  # === Reconciled InvariantSet accessibility ===

  @invariant_set
  Scenario: Reconciled InvariantSet is returned and accessible
    Given a global invariant "Never delete production data" from source "system"
    And a plan invariant "Mock all network calls" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the result should contain a reconciled InvariantSet
    And the InvariantSet should have 2 invariants
    And the InvariantSet invariants should be Invariant model instances

  @invariant_set
  Scenario: Empty scope produces empty reconciled set
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 0 invariants
    And 0 conflicts should be detected
    And 0 invariant_enforced decisions should be recorded

  # === Validation and edge cases ===

  @validation
  Scenario: Empty plan_id raises ValueError
    Then running reconciliation with empty plan_id should raise ValueError

  @validation
  Scenario: Inactive invariants are excluded from reconciliation
    Given a global invariant "Never delete production data" from source "system"
    And an inactive global invariant "Deprecated rule" from source "system"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And the reconciled set should not contain "Deprecated rule"

  @validation
  Scenario: Case-insensitive conflict detection
    Given a global invariant "Use HTTPS only" from source "system"
    And a plan invariant "use https only" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I reconcile plan-only for "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the reconciled set should contain 1 invariant
    And 1 conflict should be detected

  @validation
  Scenario: Parent decision ID is passed to recorded decisions
    Given a global invariant "Never delete production data" from source "system"
    When I reconcile with-parent "01JQBBBBBBBBBBBBBBBBBBBB01" for plan "01JQAAAAAAAAAAAAAAAAAAAA01"
    Then the recorded decisions should have parent "01JQBBBBBBBBBBBBBBBBBBBB01"

  # === Collect invariants separately ===

  @validation
  Scenario: Creating actor with None invariant_service raises ValueError
    Then creating an actor with None invariant_service should raise ValueError

  @validation
  Scenario: Creating actor with None decision_service raises ValueError
    Then creating an actor with None decision_service should raise ValueError

  @validation
  Scenario: Reconciliation with no plan_id scope omits plan invariants
    Given a global invariant "Global rule" from source "system"
    When I reconcile without-plan-id using project "local/api-service"
    Then the collected plan invariants should be empty

  @collection
  Scenario: Collect invariants gathers from all scopes
    Given a global invariant "Global rule" from source "system"
    And a project invariant "Project rule" from source "local/api-service" for project "local/api-service"
    And an action invariant "Action rule" from source "local/deploy" for action "local/deploy"
    And a plan invariant "Plan rule" from source "01JQAAAAAAAAAAAAAAAAAAAA01"
    When I collect invariants for plan "01JQAAAAAAAAAAAAAAAAAAAA01" with project "local/api-service" and action "local/deploy"
    Then the collected scope invariants should have 1 global invariant
    And the collected scope invariants should have 1 project invariant
    And the collected scope invariants should have 1 action invariant
    And the collected scope invariants should have 1 plan invariant
