# `Mead.Session.History`
[🔗](https://github.com/albertosca/mead/blob/main/lib/mead/session/history.ex#L1)

Keeps the turns of one conversation, and writes them through `Mead.Session.Store` when the
session has a storage directory.

The state holds the turns with the newest first and the directory, or `nil` when persistence
is off. Only `append/2` is write-first: a turn that cannot be recorded is refused and memory is
left untouched, so a conversation never accepts a turn it would forget. `update_last/2` and
`mark_interrupted/1` always change memory and then try to write, because the caller already
holds the answer; a closed turn that never reached the disk comes back after a restart as an
interrupted one, which is accurate.

When the file passes `:compact_after_bytes` the history rewrites it from memory with
`Mead.Session.Store.compact/3`; a failed rewrite is logged and never fails a write.

The agent is started before the session server, so a server crash leaves the history untouched.

# `persistence_error`

```elixir
@type persistence_error() :: {:error, {:persistence, term()}}
```

# `all`

```elixir
@spec all(String.t()) :: [Mead.Session.Turn.t()]
```

Returns all turns in chronological order.

# `append`

```elixir
@spec append(String.t(), Mead.Session.Turn.t()) :: :ok | persistence_error()
```

Records a turn as the newest one, or refuses it when it cannot be written.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `compact`

```elixir
@spec compact(String.t()) ::
  {:ok, %{bytes_before: non_neg_integer(), bytes_after: non_neg_integer()}}
  | {:error, :not_found | :corrupt_history | {:persistence, term()}}
```

Rewrites the file of the session as one record per turn, from the turns in memory.

Returns the sizes before and after, `{:error, :not_found}` when there is no storage or no file
yet, or the persistence error; the original file is untouched on an error.

# `mark_interrupted`

```elixir
@spec mark_interrupted(String.t()) :: :ok | persistence_error()
```

Marks every turn still in progress as interrupted, and records that when there was one.

# `start_link`

```elixir
@spec start_link(keyword()) :: Agent.on_start()
```

Starts the history for `options[:session_id]`, registered under `Mead.Registry`.

`:directory` is where to write (or `nil`), `:resume` is a list of turns in chronological
order to start from, and `:compact_after_bytes` is the file size from which the file is
compacted (absent means never). `:max_turns` is how many of the newest turns a compaction keeps
(absent means all).

# `update_last`

```elixir
@spec update_last(String.t(), (Mead.Session.Turn.t() -&gt; Mead.Session.Turn.t())) ::
  :ok | persistence_error()
```

Replaces the newest turn with the result of `function` applied to it.

Memory changes even when the write fails; the error tells the caller the disk is behind.

---

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