# `Dsxir.History`

ETS-backed `inspect_history` developer tool.

Supervised owner of the `:dsxir_history` ETS table. Creates the table at boot
and holds it for the lifetime of the application; a telemetry handler attached
via `enable/0` writes entries on `[:dsxir, :predictor, :stop]`.

The handler runs in the calling process (telemetry's design), so the GenServer
never becomes a write bottleneck. Inserts use a monotonic unique integer key in
an `:ordered_set` ETS table so the newest entry is always `:ets.last/1`.

Trim is driven by an `:atomics`-backed `:counters` reference. On every insert
the counter is incremented; once it exceeds `max_history_size + trim_batch_size`
any caller may attempt a trim of the oldest `trim_batch_size` rows. Trim is
race-tolerant: deletes are idempotent, so concurrent attempts cannot corrupt
the table. Transient overshoot of up to `trim_batch_size` rows is acceptable.

Configuration via `Application.get_env(:dsxir, Dsxir.History, [])`:

  * `:max_history_size` (default `10_000`)
  * `:trim_batch_size` (default `256`)

Distinct from the multi-turn conversation value type `Dsxir.Primitives.History`
(added separately by its own consumer). The name overlap is deliberate — each
matches its DSPy counterpart (`dspy.inspect_history` debug helper vs.
`dspy.History` value type).

# `t`

```elixir
@type t() :: %Dsxir.History{
  counter_ref: :counters.counters_ref(),
  max_size: pos_integer(),
  trim_batch: pos_integer()
}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `disable`

```elixir
@spec disable() :: :ok
```

Detaches the telemetry handler. Idempotent.

# `enable`

```elixir
@spec enable() :: :ok
```

Attaches the telemetry handler to `[:dsxir, :predictor, :stop]`. Idempotent —
calling again replaces the existing attachment with the current configuration.

# `last`

```elixir
@spec last(non_neg_integer()) :: [map()]
```

Returns the last `n` entries, newest first.

# `last`

```elixir
@spec last(
  non_neg_integer(),
  keyword()
) :: [map()]
```

Returns the last `n` entries, newest first.

When `:file` is supplied the rows are also written to disk as one JSON-encoded
entry per line. The `prediction` field is rendered via `inspect/1` so structs
containing functions or PIDs do not break encoding.

# `start_link`

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

Start the history owner as a named singleton.

# `table`

```elixir
@spec table() :: atom()
```

Returns the ETS table identifier for the dev-tool table. Stable across calls.

---

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