Feature: EventBus protocol and domain event emission
  As a domain service
  I want to emit typed domain events through an EventBus
  So that audit logging, observability, and reactive subscribers work correctly

  # ---------------------------------------------------------------------------
  # EventType enum
  # ---------------------------------------------------------------------------

  Scenario: EventType enum covers required lifecycle values
    Then EventType should include "plan.created"
    And EventType should include "decision.created"
    And EventType should include "tool.invoked"
    And EventType should include "actor.completed"
    And EventType should include "validation.passed"
    And EventType should include "budget.exceeded"

  Scenario: EventType string values compare equal to their members
    Then EventType member PLAN_CREATED should equal string "plan.created"
    And EventType member DECISION_CREATED should equal string "decision.created"

  # ---------------------------------------------------------------------------
  # DomainEvent model
  # ---------------------------------------------------------------------------

  Scenario: DomainEvent is created with required event_type
    When I create a minimal DomainEvent with event_type "plan.created"
    Then the DomainEvent event_type should be "plan.created"
    And the DomainEvent should have a non-empty correlation_id
    And the DomainEvent should have a timestamp

  Scenario: DomainEvent defaults are applied for optional fields
    When I create a minimal DomainEvent with event_type "decision.created"
    Then the DomainEvent plan_id should be None
    And the DomainEvent actor_name should be None
    And the DomainEvent details should be empty

  Scenario: DomainEvent accepts plan_id and details
    When I create a DomainEvent with event_type "plan.created" plan_id "01ARZ3NDEKTSV4RRFFQ69G5FAV" and details key "phase" value "strategize"
    Then the DomainEvent plan_id should be "01ARZ3NDEKTSV4RRFFQ69G5FAV"
    And the DomainEvent details should contain key "phase"

  Scenario: DomainEvent is immutable (frozen)
    When I create a minimal DomainEvent with event_type "plan.created"
    Then modifying the DomainEvent should raise an error

  # ---------------------------------------------------------------------------
  # EventBus Protocol
  # ---------------------------------------------------------------------------

  Scenario: ReactiveEventBus satisfies the EventBus protocol
    Then ReactiveEventBus should satisfy the EventBus protocol

  Scenario: LoggingEventBus satisfies the EventBus protocol
    Then LoggingEventBus should satisfy the EventBus protocol

  # ---------------------------------------------------------------------------
  # ReactiveEventBus
  # ---------------------------------------------------------------------------

  Scenario: ReactiveEventBus emits events to subscribed handlers
    Given a ReactiveEventBus
    When I subscribe to "plan.created" events
    And I emit a "plan.created" DomainEvent
    Then the handler should have received 1 event
    And the received event type should be "plan.created"

  Scenario: ReactiveEventBus dispatches only to matching event type
    Given a ReactiveEventBus
    When I subscribe to "plan.created" events
    And I emit a "decision.created" DomainEvent
    Then the handler should have received 0 event

  Scenario: ReactiveEventBus supports multiple handlers per event type
    Given a ReactiveEventBus
    When I subscribe two handlers to "plan.created" events
    And I emit a "plan.created" DomainEvent
    Then each handler should have received 1 event

  Scenario: ReactiveEventBus exposes an observable stream
    Given a ReactiveEventBus
    Then the bus should expose an observable stream

  Scenario: ReactiveEventBus rejects non-DomainEvent inputs
    Given a ReactiveEventBus
    Then emitting a non-DomainEvent should raise TypeError

  Scenario: ReactiveEventBus rejects invalid event_type in subscribe
    Given a ReactiveEventBus
    Then subscribing with a non-EventType should raise TypeError

  # ---------------------------------------------------------------------------
  # LoggingEventBus
  # ---------------------------------------------------------------------------

  Scenario: LoggingEventBus emits events to subscribed handlers
    Given a LoggingEventBus
    When I subscribe to "decision.created" events
    And I emit a "decision.created" DomainEvent
    Then the handler should have received 1 event

  Scenario: LoggingEventBus rejects non-DomainEvent inputs
    Given a LoggingEventBus
    Then emitting a non-DomainEvent should raise TypeError

  Scenario: LoggingEventBus rejects invalid event_type in subscribe
    Given a LoggingEventBus
    Then subscribing with a non-EventType should raise TypeError

  Scenario: LoggingEventBus rejects non-callable handler in subscribe
    Given a LoggingEventBus
    Then subscribing with a non-callable handler should raise TypeError

  Scenario: ReactiveEventBus rejects non-callable handler in subscribe
    Given a ReactiveEventBus
    Then subscribing with a non-callable handler should raise TypeError

  Scenario: EventBus Protocol emit and subscribe stubs are executable
    Then the EventBus Protocol stubs should be callable

  # ---------------------------------------------------------------------------
  # DecisionService event emission
  # ---------------------------------------------------------------------------

  Scenario: DecisionService emits DECISION_CREATED when recording a decision
    Given a DecisionService with an injected event bus
    When I call record_decision
    Then the event bus should have received a "decision.created" event
    And the emitted event plan_id should match the decision plan_id

  Scenario: DecisionService works without an event bus (no-op)
    Given a DecisionService without an event bus
    When I call record_decision
    Then no event bus exception should be raised

  # ---------------------------------------------------------------------------
  # PlanLifecycleService event emission
  # ---------------------------------------------------------------------------

  Scenario: PlanLifecycleService emits PLAN_CREATED on use_action
    Given a PlanLifecycleService with an injected event bus
    When I call use_action to create a plan
    Then the event bus should have received a "plan.created" event

  Scenario: PlanLifecycleService emits PLAN_PHASE_CHANGED on execute_plan
    Given a PlanLifecycleService with an injected event bus and a strategized plan
    When I call execute_plan
    Then the event bus should have received a "plan.phase_changed" event

  Scenario: PlanLifecycleService works without an event bus (no-op)
    Given a PlanLifecycleService without an event bus
    When I call use_action to create a plan
    Then no event bus exception should be raised

  # ---------------------------------------------------------------------------
  # DI container
  # ---------------------------------------------------------------------------

  Scenario: Container provides ReactiveEventBus as a Singleton
    When I resolve event_bus from the DI container twice
    Then both resolutions should return the same instance

  Scenario: Container wires event_bus into DecisionService
    When I resolve decision_service from the DI container
    Then the decision_service should have an event_bus attribute
