# `MimirAnalytics.Mappers.Session`
[🔗](https://github.com/cash-mckeeman/mimir/blob/mimir_analytics-v0.8.1/mimir_analytics/lib/mimir_analytics/mappers/session.ex#L1)

Session JSONL into `runs`, `tool_calls` and optional `events_raw` rows.
Accepts either a `meta`/`result` envelope or a flat run record containing
`run_id`. Flat records are normalized once at ingress. Other shapes raise.

Session identity comes from `result["session_id"]`, with `meta["run_id"]`
as a legacy fallback. Caller-local correlation keys do not override it.
Flat `run_id` values map onto the same identity field.

`terminal` and `stop_reason` retain the producer's vocabulary; a non-string
stop reason is stored with `inspect/1`. `outcome` is the producer's derived
status, and `error_class` is its classification. Raw `error` terms are not
read. Missing measurements, coverage and cost remain null. Cost comes from the source; per-call model rows are
never synthesized.

Custom and server tool uses retain their order. Flat `tool_calls` roll-ups
expand into `count` occurrences with kind `"rollup"`, without invocation
ids or arguments. Missing counts mean one; non-string names and negative
or non-integer counts raise.

Optional envelope events retain `domain` and `seq`; missing sequences use
array order. No per-event wall-clock is invented. Missing events yield no
event rows. The mapper writes no per-turn rows.

A file's rows and content-keyed ingest ledger entry commit together.
Already-ingested contents return `:already_ingested`. Empty files and
read failures return errors; malformed JSON or records raise.

---

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