Feature: Async audit recording (issue #718)
  As a system operator
  I want audit recording to be non-blocking
  So that domain operations are not delayed by SQLite writes

  # ── Non-blocking record() ─────────────────────────────────────

  Scenario: record() returns immediately without blocking in async mode
    Given an async audit service
    When I record a "plan_applied" event in async mode
    Then the record call should return immediately
    And the returned entry should have event_type "plan_applied"

  Scenario: Async record returns placeholder id of -1
    Given an async audit service
    When I record a "plan_applied" event in async mode
    Then the returned entry id should be -1

  Scenario: Entries are persisted after flush
    Given an async audit service
    When I record a "plan_applied" event in async mode
    And I flush the async audit service
    Then the audit log should contain 1 persisted entry

  Scenario: Multiple entries are all persisted after flush
    Given an async audit service
    When I record 5 "plan_applied" events in async mode
    And I flush the async audit service
    Then the audit log should contain 5 persisted entries

  Scenario: Flush waits for all enqueued entries to be written
    Given an async audit service
    When I record 10 "config_changed" events in async mode
    And I flush the async audit service
    Then the audit log should contain 10 persisted entries

  # ── No data loss ──────────────────────────────────────────────

  Scenario: Close flushes all pending entries before shutting down
    Given an async audit service
    When I record 3 "session_created" events in async mode
    And I close the async audit service
    Then the audit log should contain 3 persisted entries after close

  Scenario: Context manager flushes on exit
    Given an async audit service used as context manager
    When I record a "plan_cancelled" event inside the context manager
    Then the audit log should contain 1 persisted entry after context exit

  # ── Synchronous fallback ──────────────────────────────────────

  Scenario: Synchronous mode returns real id immediately
    Given a synchronous audit service
    When I record a "plan_applied" event synchronously
    Then the returned entry id should be a positive integer

  Scenario: Synchronous mode persists immediately without flush
    Given a synchronous audit service
    When I record a "plan_applied" event synchronously
    Then the audit log should contain 1 persisted entry immediately

  # ── Settings ──────────────────────────────────────────────────

  Scenario: Default audit_async setting is True
    Given default settings
    Then audit_async should be True

  Scenario: audit_async can be disabled via settings
    Given settings with audit_async False
    Then audit_async should be False

  Scenario: audit_queue_maxsize default is 10000
    Given default settings
    Then audit_queue_maxsize should be 10000

  # ── Background thread ─────────────────────────────────────────

  Scenario: Background writer thread is started in async mode
    Given an async audit service
    Then the background writer thread should be alive

  Scenario: Background writer thread stops after flush
    Given an async audit service
    When I flush the async audit service
    Then the background writer thread should be stopped

  # ── Ordering guarantees ───────────────────────────────────────

  Scenario: Entries are written in enqueue order
    Given an async audit service
    When I record events with plan_ids "first" "second" "third" in async mode
    And I flush the async audit service
    Then the entries should be persisted in enqueue order

  # ── Error resilience ──────────────────────────────────────────

  Scenario: Invalid event_type raises ValueError immediately in async mode
    Given an async audit service
    When I record an event with invalid type "not_a_real_event" in async mode
    Then a ValueError should be raised immediately

  Scenario: flush() is idempotent
    Given an async audit service
    When I flush the async audit service
    And I flush the async audit service again
    Then no async audit error should be raised

  Scenario: close() is idempotent
    Given an async audit service
    When I close the async audit service
    And I close the async audit service again
    Then no async audit error should be raised
