# `Chronicle.EventSequences.EventLog`
[🔗](https://github.com/Cratis/Chronicle.Elixir/blob/main/lib/chronicle/event_sequences/event_log.ex#L4)

Appends and queries events in a Chronicle event log.

The event log is the primary `EventSequence` in Chronicle. Use `append/3` to
record domain events for a given event source (such as an aggregate root).

## Usage

    :ok = Chronicle.EventSequences.EventLog.append("account-1", %MyApp.Events.AccountOpened{
      account_id: "account-1",
      owner_name: "Alice",
      initial_balance: 500
    })

To append to a specific client:

    :ok = Chronicle.EventSequences.EventLog.append("account-1", event, client: :my_chronicle)

## Multiple events

    events = [
      %MyApp.Events.AccountOpened{account_id: "1", owner_name: "Alice"},
      %MyApp.Events.FundsDeposited{account_id: "1", amount: 500}
    ]
    :ok = Chronicle.EventSequences.EventLog.append_many("account-1", events)

## Transactions

When a `Chronicle.Transactions.UnitOfWork` is active, append operations are
buffered locally and only sent to Chronicle when the unit of work is committed.

# `append`

```elixir
@spec append(String.t(), struct(), keyword()) :: :ok | {:error, term()}
```

Appends a single event to the event log for the given event source.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)
  * `:timeout` — gRPC deadline in milliseconds or `:infinity` (default: `60_000`)
  * `:event_source_type` — explicit event source type, otherwise resolved by the kernel
  * `:event_stream_type` — explicit event stream type, otherwise resolved by the kernel
  * `:event_stream_id` — explicit event stream ID, otherwise resolved by the kernel
  * `:occurred` — explicit `DateTime`; omission leaves the timestamp to the kernel
  * `:tags` — list of tag strings
  * `:subject` — the identity subject string
  * `:correlation_id` — correlation id override (`Chronicle.Correlation.CorrelationId` or string)
  * `:identity` — identity override (`Chronicle.Identity`)
  * `:causation` — causation chain override (list of `Chronicle.Auditing.CausationEntry`)
  * `:concurrency_scope` — `Chronicle.Events.ConcurrencyScope` or keyword options with
    `:sequence_number`, `:event_source_id`, `:event_stream_type`, `:event_stream_id`,
    `:event_source_type`, and `:event_types`

  * `:event_source` — a `Chronicle.EventSources.EventSource` module (or its name) the
    append goes through. Its name becomes the event source type and `EventSource`
    metadata of the event, and its concurrency dimensions apply when no explicit
    `:concurrency_scope` is given
  * `:event_stream` — the name of a stream declared by `:event_source`; written as the
    event stream type. Unknown sources/streams and contradicting
    `:event_source_type`/`:event_stream_type` values return
    `{:error, {:unknown_event_source, _}}`,
    `{:error, {:event_stream_does_not_belong_to_event_source, _, _}}` or
    `{:error, {:event_routing_contradicts_event_source, _, _, _, _}}`

Omitted, `nil`, and empty routing values travel as empty strings. The kernel
resolves these to `"Default"` / `"All"` / `"Default"`; nonempty values are exact.
Concurrency filters are independent of routing and are never filled from it.

Returns `:ok` on success or `{:error, reason}` on failure, including concurrency
and validation rejection. Append requests require a successful descriptor
compatibility check before they are sent. A successful check is shared by all
callers on that connection until it reconnects. Failed checks are retried on
the next append.

The check uses the installed 18.3.0 contract descriptor. It does not yet
distinguish older kernels from kernels implementing canonical append metadata;
that requires a future contracts pin carrying the new contract.

# `append_and_wait_for_completion`

```elixir
@spec append_and_wait_for_completion(String.t(), struct(), keyword()) ::
  {:ok, %{success: boolean(), failed_partitions: list()}} | {:error, term()}
```

Appends a single event, then waits for every observer (reactor, reducer, ++)
affected by the append to either reach the appended sequence number or fail.

This is additive rather than a change to `append/3`'s return shape: `append/3`
and `append_many/3` return only `:ok | {:error, term()}` today (no
`AppendResult`-equivalent carrying a sequence number), so building
`WaitForCompletion` on top of them would either be a breaking change to their
return contract or require a second round-trip to re-discover the sequence
number. This function does the append and the wait as one call instead.

Mirrors the C# client's `AppendResult.WaitForCompletion()` extension.

Returns `{:ok, %{success: boolean(), failed_partitions: [Chronicle.FailedPartitions.FailedPartition.t()]}}`
on success (whether or not every observer completed — check `:success`), or
`{:error, reason}` if the append itself failed.

## Options

Same as `append/3`, plus:

  * `:timeout` — how long to wait for observer completion, in milliseconds
    (default: `5_000`, matching the C# client's default).

# `append_many`

```elixir
@spec append_many(String.t(), [struct()], keyword()) :: :ok | {:error, term()}
```

Appends multiple events to the event log for the given event source.

All events are appended atomically. Each event must be a struct that
`use Chronicle.Events.EventType`.

## Options

Same as `append/3`, including `:event_sequence_id` and `:concurrency_scope`.

# `append_many_for_event_sources`

```elixir
@spec append_many_for_event_sources(
  [Chronicle.EventSequences.EventForEventSourceId.t()],
  keyword()
) ::
  :ok | {:error, term()}
```

Appends a list of `Chronicle.EventSequences.EventForEventSourceId` entries as a
single atomic append-many, each carrying its own target event source id (and
other per-event metadata such as stream type/id, subject, tags, and occurred
time). Identity and causation are batch-level; see
`Chronicle.EventSequences.EventForEventSourceId` for their precedence.

Use this when a batch of events needs to target several, possibly different,
event source ids in one transaction — e.g. reactor side-effect dispatch (see
`Chronicle.Reactors.Handler`).

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)
  * `:timeout` — gRPC deadline in milliseconds or `:infinity` (default: `60_000`)

# `append_many_with_result`

```elixir
@spec append_many_with_result(String.t(), [struct()], keyword()) ::
  {:ok, Chronicle.EventSequences.AppendResult.t()}
  | {:error, Chronicle.EventSequences.AppendResult.t() | term()}
```

Appends events atomically for one event source and returns the detailed outcome with every
assigned sequence number. See `append_with_result/3`.

# `append_prepared`

```elixir
@spec append_prepared(
  String.t(),
  Chronicle.EventSequences.PreparedEvent.t(),
  keyword()
) ::
  :ok | {:error, term()}
```

Appends a `prepare/2`d event. Accepts the options of `append/3`. The event was serialized once,
at preparation time - this never re-serializes it.

Returns `{:error, :prepared_event_belongs_to_another_sequence}` when `prepared_event` was
prepared for a different client, namespace, or event sequence than this call targets.

# `append_with_result`

```elixir
@spec append_with_result(String.t(), struct(), keyword()) ::
  {:ok, Chronicle.EventSequences.AppendResult.t()}
  | {:error, Chronicle.EventSequences.AppendResult.t() | term()}
```

Appends a single event and returns the detailed outcome.

Unlike `append/3` (which returns `:ok | {:error, term}`), this returns a
`Chronicle.EventSequences.AppendResult` carrying the assigned sequence number and, on a
rejection, the structured constraint and concurrency violations:

    case Chronicle.EventSequences.EventLog.append_with_result("acc-1", %Opened{}) do
      {:ok, %{sequence_number: n}} -> n
      {:error, %{constraint_violations: [violation | _]}} -> violation.message
      {:error, %{concurrency_violations: _}} -> :retry
      {:error, other} -> other
    end

Accepts the options of `append/3`. `{:error, result}` is returned for a kernel rejection;
transport and client errors are returned as `{:error, reason}` with a non-result term.

# `complete_stream`

```elixir
@spec complete_stream(String.t(), String.t(), keyword()) ::
  {:ok, non_neg_integer()}
  | {:error, :default_stream_cannot_be_completed | :already_completed | term()}
```

Completes a named, non-default stream so that no further events can be
appended to it.

The default stream (event stream type `"All"` paired with the default event
stream id) can never be completed. Completing an already-completed stream
leaves it in its completed state.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)

Returns `{:ok, tail_sequence_number}` on success, or
`{:error, :default_stream_cannot_be_completed | :already_completed}`.

# `get_for_event_source`

```elixir
@spec get_for_event_source(String.t(), keyword()) :: {:ok, list()} | {:error, term()}
```

Returns events for the given event source ID from the event log.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)
  * `:event_types` — list of event type modules to filter by (default: all)
  * `:event_source_type` — the event source type to filter by (default: all)
  * `:event_stream_type` — the event stream type to filter by (default: all)
  * `:event_stream_id` — the event stream id to filter by (default: all)

  * `:decode` — when `true`, returns `Chronicle.Events.AppendedEvent` structs whose `:event`
    is the event struct (default: `false`, the raw wire events)

Returns `{:ok, [appended_event]}` or `{:error, reason}`.

# `get_from_sequence_number`

```elixir
@spec get_from_sequence_number(non_neg_integer(), keyword()) ::
  {:ok, list()} | {:error, term()}
```

Returns events from (and including) the given sequence number onward.

Mirrors the Chronicle C# and TypeScript clients' `GetFromSequenceNumber()`.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)
  * `:event_source_id` — optional event source id to filter by (default: all)
  * `:event_types` — list of event type modules to filter by (default: all)
  * `:decode` — when `true`, returns `Chronicle.Events.AppendedEvent` structs whose `:event`
    is the event struct (default: `false`, the raw wire events)

Returns `{:ok, [appended_event]}` or `{:error, reason}`.

# `get_next_sequence_number`

```elixir
@spec get_next_sequence_number(String.t() | nil, keyword()) ::
  {:ok, non_neg_integer()} | {:error, term()}
```

Returns the sequence number that will be assigned to the next appended event.

Mirrors the Chronicle C# and TypeScript clients' `GetNextSequenceNumber()`.

## Options

Same as `get_tail_sequence_number/2`.

# `get_tail_sequence_number`

```elixir
@spec get_tail_sequence_number(String.t() | nil, keyword()) ::
  {:ok, non_neg_integer()} | {:error, term()}
```

Returns the tail sequence number for an event sequence.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)
  * `:event_source_type` — the event source type to filter by (default: all)
  * `:event_stream_type` — the event stream type to filter by (default: all)
  * `:event_stream_id` — the event stream id to filter by (default: all)
  * `:event_types` — list of event type modules to filter by (default: all)

# `get_tail_sequence_number_for_observer`

```elixir
@spec get_tail_sequence_number_for_observer(module(), keyword()) ::
  {:ok, non_neg_integer()} | {:error, term()}
```

Returns the tail sequence number scoped to only the event types that the
given reactor or reducer module subscribes to (its `@handles` declarations).

Mirrors the Chronicle C# client's `GetTailSequenceNumberForObserver()`.

## Options

Same as `get_tail_sequence_number/2`, minus `:event_types` (derived from
`observer_module`).

# `has_events_for?`

```elixir
@spec has_events_for?(String.t(), keyword()) :: {:ok, boolean()} | {:error, term()}
```

Checks whether an event sequence has events for an event source id.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)

# `prepare`

```elixir
@spec prepare(struct(), keyword()) ::
  {:ok, Chronicle.EventSequences.PreparedEvent.t()} | {:error, term()}
```

Serializes `event` once and returns a `Chronicle.EventSequences.PreparedEvent` bound to this
client, namespace and event sequence, for reuse with `append_prepared/3` and
`Chronicle.EventSequences.Streams.verify_content/3`. Mutating `event` afterward has no effect -
the content was captured at preparation time.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)

Returns `{:error, {:unknown_event_type, module}}` when `event` does not
`use Chronicle.Events.EventType`.

# `redact`

```elixir
@spec redact(non_neg_integer(), String.t(), keyword()) :: :ok | {:error, term()}
```

Redacts a single event at a specific sequence number, permanently replacing
its content for compliance/GDPR erasure. This is destructive and irreversible.

## Options

  * `:client` — the client name (default: `Chronicle.Client`)
  * `:namespace` — overrides the client's default namespace
  * `:event_sequence_id` — event sequence id (default: `"event-log"`)

# `redact_for_event_source`

```elixir
@spec redact_for_event_source(String.t(), String.t(), [module()], keyword()) ::
  :ok | {:error, term()}
```

Redacts all events for a given event source, optionally filtered to
specific event types. Permanently replaces content for compliance/GDPR
erasure. This is destructive and irreversible.

## Options

Same as `redact/3`.

# `wait_for_sequence_number`

```elixir
@spec wait_for_sequence_number(non_neg_integer(), keyword()) ::
  {:ok, map()} | {:error, term()}
```

Waits for every observer affected by events up to `sequence_number` to reach it or fail.

Options: `:client`, `:namespace`, `:event_sequence_id` and `:timeout`.
Returns `{:ok, %{success: boolean(), failed_partitions: [...]}}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
