Encodes Temper.Records as history lines and decodes them back.
Each line is one self-contained JSON object (schema v1): the run
context is denormalized into every line so a history file can be
read without joins, and run_id groups lines from the same run.
decode/1 never raises — corrupt or foreign input (truncated CI
cache tails, future schema versions, non-test lines) comes back as
a tagged {:error, reason} so readers can count and skip it.
This module is part of Temper's functional core: strings in, records out, no side effects.
Summary
Functions
Decodes one history line back into a Temper.Record.
Encodes a record as a single JSON line, without a trailing newline.
Encodes the end-of-run suite summary as a single JSON line.
Types
Functions
@spec decode(String.t()) :: {:ok, Temper.Record.t()} | {:error, decode_error()}
Decodes one history line back into a Temper.Record.
Returns {:error, reason} for malformed JSON, unknown schema
versions, non-test kinds (e.g. future "suite" summary lines),
missing required keys or unknown statuses. Never raises.
@spec encode(Temper.Record.t()) :: String.t()
Encodes a record as a single JSON line, without a trailing newline.
@spec encode_suite(Temper.RunContext.t(), %{ tests: non_neg_integer(), times_us: map() | nil }) :: String.t()
Encodes the end-of-run suite summary as a single JSON line.
Suite lines share the schema stamp but use kind "suite"; decode/1
rejects them with {:error, {:unsupported_kind, "suite"}} so readers
that only want test outcomes skip them without treating them as
corruption.