Feature: Event System Domain Event Taxonomy
  As a platform operator
  I want a complete domain event taxonomy with typed event types and a reactive bus
  So that I can audit, observe, and react to all system events consistently

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

  Scenario: EventType enum has at least 43 members
    Then the EventType enum should have at least 43 members

  Scenario: EventType covers the Plan lifecycle domain
    Then EventType should contain "plan.created"
    And EventType should contain "plan.phase_changed"
    And EventType should contain "plan.state_changed"
    And EventType should contain "plan.applied"
    And EventType should contain "plan.cancelled"
    And EventType should contain "plan.errored"

  Scenario: EventType covers the Decision domain
    Then EventType should contain "decision.created"
    And EventType should contain "decision.approved"
    And EventType should contain "decision.corrected"
    And EventType should contain "decision.superseded"

  Scenario: EventType covers the Invariant domain
    Then EventType should contain "invariant.reconciled"
    And EventType should contain "invariant.violated"
    And EventType should contain "invariant.enforced"

  Scenario: EventType covers the Actor domain
    Then EventType should contain "actor.invoked"
    And EventType should contain "actor.completed"
    And EventType should contain "actor.errored"
    And EventType should contain "actor.escalated"

  Scenario: EventType covers the Tool domain
    Then EventType should contain "tool.invoked"
    And EventType should contain "tool.completed"
    And EventType should contain "tool.errored"
    And EventType should contain "tool.retried"

  Scenario: EventType covers the Resource domain
    Then EventType should contain "resource.accessed"
    And EventType should contain "resource.modified"
    And EventType should contain "resource.indexed"

  Scenario: EventType covers the Correction domain
    Then EventType should contain "correction.applied"

  Scenario: EventType covers the Configuration domain
    Then EventType should contain "config.changed"

  Scenario: EventType covers the Entity lifecycle domain
    Then EventType should contain "entity.deleted"

  Scenario: EventType covers the Authentication domain
    Then EventType should contain "auth.success"
    And EventType should contain "auth.failure"

  Scenario: EventType covers the Sandbox domain
    Then EventType should contain "sandbox.created"
    And EventType should contain "sandbox.committed"
    And EventType should contain "sandbox.rolled_back"

  Scenario: EventType covers the Checkpoint domain
    Then EventType should contain "checkpoint.created"
    And EventType should contain "checkpoint.restored"

  Scenario: EventType covers the Context domain
    Then EventType should contain "context.built"
    And EventType should contain "context.query_executed"

  Scenario: EventType covers the Validation domain
    Then EventType should contain "validation.started"
    And EventType should contain "validation.passed"
    And EventType should contain "validation.failed"

  Scenario: EventType covers the Session domain
    Then EventType should contain "session.created"
    And EventType should contain "session.message_sent"

  Scenario: EventType covers the Budget domain
    Then EventType should contain "budget.warning"
    And EventType should contain "budget.exceeded"

  Scenario: EventType uses StrEnum with dot-separated values
    Then every EventType value should match the pattern "<domain>.<action>"

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

  Scenario: DomainEvent has all required fields
    When I create a DomainEvent for taxonomy with event_type "plan.created"
    Then the taxonomy event should have field "event_type"
    And the taxonomy event should have field "timestamp"
    And the taxonomy event should have field "correlation_id"
    And the taxonomy event should have field "plan_id"
    And the taxonomy event should have field "root_plan_id"
    And the taxonomy event should have field "session_id"
    And the taxonomy event should have field "actor_name"
    And the taxonomy event should have field "project_name"
    And the taxonomy event should have field "user_identity"
    And the taxonomy event should have field "details"

  Scenario: DomainEvent correlation_id is a 26-char ULID string
    When I create a DomainEvent for taxonomy with event_type "plan.created"
    Then the taxonomy event correlation_id should be 26 characters long

  Scenario: DomainEvent timestamp is timezone-aware UTC
    When I create a DomainEvent for taxonomy with event_type "plan.created"
    Then the taxonomy event timestamp should be UTC

  Scenario: DomainEvent is frozen (immutable)
    When I create a DomainEvent for taxonomy with event_type "plan.created"
    Then mutating the taxonomy event should raise a validation error

  Scenario: DomainEvent serializes to JSON round-trip
    When I create a DomainEvent for taxonomy with all fields populated
    Then the taxonomy event should serialize to JSON and deserialize back identically

  Scenario: DomainEvent correlation fields accept ULID strings
    When I create a DomainEvent for taxonomy with correlation fields
    Then the taxonomy event plan_id should be set
    And the taxonomy event root_plan_id should be set
    And the taxonomy event session_id should be set

  Scenario: DomainEvent details dict preserves custom keys
    When I create a DomainEvent for taxonomy with typed details
    Then the taxonomy event details should contain the expected keys

  Scenario: DomainEvent user_identity defaults to None
    When I create a DomainEvent for taxonomy with event_type "plan.created"
    Then the taxonomy event user_identity should be None

  Scenario: DomainEvent accepts explicit user_identity
    When I create a DomainEvent for taxonomy with user_identity "alice@example.com"
    Then the taxonomy event user_identity should be "alice@example.com"

  Scenario: DomainEvent with user_identity serializes to JSON round-trip
    When I create a DomainEvent for taxonomy with user_identity "bob@example.com"
    Then the taxonomy event should serialize to JSON and deserialize back identically

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

  Scenario: EventBus Protocol defines emit and subscribe
    Then the EventBus Protocol should define method "emit"
    And the EventBus Protocol should define method "subscribe"

  Scenario: ReactiveEventBus satisfies the EventBus Protocol
    Then a ReactiveEventBus instance should satisfy the EventBus Protocol

  Scenario: LoggingEventBus satisfies the EventBus Protocol
    Then a LoggingEventBus instance should satisfy the EventBus Protocol

  Scenario: LoggingEventBus emits to subscribed handlers
    Given a fresh LoggingEventBus for taxonomy tests
    When I logging-taxonomy-subscribe to "plan.created" events
    And I logging-taxonomy-emit a "plan.created" DomainEvent
    Then the logging taxonomy handler should have received 1 event(s)

  Scenario: LoggingEventBus continues dispatching when a handler raises
    Given a fresh LoggingEventBus for taxonomy tests
    When I logging-taxonomy-subscribe a failing handler and a normal handler to "plan.created" events
    And I logging-taxonomy-emit a "plan.created" DomainEvent
    Then the logging taxonomy normal handler should have received 1 event(s)

  Scenario: LoggingEventBus rejects non-DomainEvent on emit
    Given a fresh LoggingEventBus for taxonomy tests
    Then logging-taxonomy-emitting a non-DomainEvent should raise TypeError

  Scenario: LoggingEventBus rejects non-EventType on subscribe
    Given a fresh LoggingEventBus for taxonomy tests
    Then logging-taxonomy-subscribing with a non-EventType should raise TypeError

  Scenario: LoggingEventBus rejects non-callable handler on subscribe
    Given a fresh LoggingEventBus for taxonomy tests
    Then logging-taxonomy-subscribing with a non-callable should raise TypeError

  # ---------------------------------------------------------------------------
  # ReactiveEventBus — emit / subscribe / stream
  # ---------------------------------------------------------------------------

  Scenario: ReactiveEventBus emits to subscribed handlers
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-subscribe to "plan.created" events
    And I taxonomy-emit a "plan.created" DomainEvent
    Then the taxonomy handler should have received 1 event(s)

  Scenario: ReactiveEventBus does not dispatch to non-matching types
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-subscribe to "plan.created" events
    And I taxonomy-emit a "decision.created" DomainEvent
    Then the taxonomy handler should have received 0 event(s)

  Scenario: ReactiveEventBus supports multiple handlers per type
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-subscribe two handlers to "tool.invoked" events
    And I taxonomy-emit a "tool.invoked" DomainEvent
    Then each taxonomy handler should have received 1 event

  Scenario: ReactiveEventBus continues dispatching when a handler raises
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-subscribe a failing handler and a normal handler to "plan.created" events
    And I taxonomy-emit a "plan.created" DomainEvent
    Then the taxonomy normal handler should have received 1 event(s)
    And the audit_log should contain 1 events

  Scenario: ReactiveEventBus exposes an rx.Observable stream
    Given a fresh ReactiveEventBus for taxonomy tests
    Then the taxonomy bus stream should be an Observable

  Scenario: ReactiveEventBus stream is read-only
    Given a fresh ReactiveEventBus for taxonomy tests
    Then the taxonomy bus stream should not expose method "on_next"

  Scenario: ReactiveEventBus observable stream receives emitted events
    Given a fresh ReactiveEventBus for taxonomy tests
    When I observe the taxonomy bus stream and emit a "plan.created" event
    Then the stream observer should have captured the event

  Scenario: ReactiveEventBus continues when a stream observer raises
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-subscribe to "plan.created" events
    And I observe taxonomy stream with a failing observer and emit a "plan.created" event
    Then the taxonomy handler should have received 1 event(s)
    And the audit_log should contain 1 events

  Scenario: ReactiveEventBus rejects non-DomainEvent on emit
    Given a fresh ReactiveEventBus for taxonomy tests
    Then taxonomy-emitting a non-DomainEvent should raise TypeError

  Scenario: ReactiveEventBus rejects non-EventType on subscribe
    Given a fresh ReactiveEventBus for taxonomy tests
    Then taxonomy-subscribing with a non-EventType should raise TypeError

  Scenario: ReactiveEventBus rejects non-callable handler on subscribe
    Given a fresh ReactiveEventBus for taxonomy tests
    Then taxonomy-subscribing with a non-callable should raise TypeError

  # ---------------------------------------------------------------------------
  # In-memory event trail (audit_log)
  # ---------------------------------------------------------------------------

  Scenario: ReactiveEventBus audit_log captures all emitted events
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-emit a "plan.created" DomainEvent
    And I taxonomy-emit a "decision.created" DomainEvent
    Then the audit_log should contain 2 events
    And the audit_log should include event types "plan.created,decision.created"

  Scenario: ReactiveEventBus audit_log preserves event order
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-emit a "plan.created" DomainEvent
    And I taxonomy-emit a "decision.created" DomainEvent
    And I taxonomy-emit a "tool.invoked" DomainEvent
    Then the audit_log events should be in order "plan.created,decision.created,tool.invoked"

  Scenario: ReactiveEventBus audit_log returns a defensive copy
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-emit a "plan.created" DomainEvent
    Then mutating the returned audit_log should not affect the bus

  Scenario: ReactiveEventBus can cap in-memory audit_log retention
    Given a ReactiveEventBus for taxonomy tests with max_audit_log_size 2
    When I taxonomy-emit a "plan.created" DomainEvent
    And I taxonomy-emit a "decision.created" DomainEvent
    And I taxonomy-emit a "tool.invoked" DomainEvent
    Then the audit_log should contain 2 events
    And the audit_log should include event types "decision.created,tool.invoked"

  Scenario: ReactiveEventBus clear_audit_log removes retained events
    Given a fresh ReactiveEventBus for taxonomy tests
    When I taxonomy-emit a "plan.created" DomainEvent
    And I clear the taxonomy bus audit_log
    Then the audit_log should contain 0 events

  Scenario: ReactiveEventBus rejects invalid max_audit_log_size
    Then creating a ReactiveEventBus with max_audit_log_size 0 should raise ValueError

  # ---------------------------------------------------------------------------
  # Log correlation
  # ---------------------------------------------------------------------------

  Scenario: Events sharing a correlation_id are traceable
    Given a fresh ReactiveEventBus for taxonomy tests
    When I emit two taxonomy events with the same correlation_id
    Then both events in the audit_log should share the same correlation_id

  Scenario: Independent DomainEvents get unique correlation_ids by default
    When I create two independent DomainEvents for taxonomy
    Then the two taxonomy events should have different correlation_ids
