Spectre.Journal.Record (Spectre v0.3.0)

Copy Markdown View Source

Versioned, privacy-aware explanation record for one runtime decision.

Input and reply content are absent by default. Applications must opt in to content recording through their journal configuration.

Summary

Functions

Builds a journal record and derives a stable record identifier from its turn, phase, sequence, and agent.

Restores a persisted schema-v1 record while tolerating unknown additive fields. Legacy maps without a schema version are migrated to version 1.

Converts a record into a JSON-safe, string-keyed map for persistence.

Types

t()

@type t() :: %Spectre.Journal.Record{
  agent: module() | nil,
  agent_version: term(),
  conversation_id: term(),
  decision: map(),
  duration_native: integer() | nil,
  effect: map() | nil,
  evidence: [map()],
  id: String.t(),
  input: map() | nil,
  metadata: map(),
  occurred_at: DateTime.t(),
  phase: atom(),
  policy: map() | nil,
  reason: map(),
  reply: String.t() | nil,
  schema_version: pos_integer(),
  sequence: non_neg_integer(),
  state_revision: non_neg_integer() | nil,
  trace_id: term(),
  transition: map() | nil,
  turn_id: term()
}

Functions

new(attrs)

@spec new(map() | keyword()) :: t()

Builds a journal record and derives a stable record identifier from its turn, phase, sequence, and agent.

restore(record)

@spec restore(t() | map()) :: {:ok, t()} | {:error, term()}

Restores a persisted schema-v1 record while tolerating unknown additive fields. Legacy maps without a schema version are migrated to version 1.

to_json_map(record)

@spec to_json_map(t()) :: map()

Converts a record into a JSON-safe, string-keyed map for persistence.

Record fields carry arbitrary runtime terms — atoms, tuples, structs, DateTimes — that JSON columns cannot store. This conversion is lossy but total: atoms become strings, tuples become lists, structs lose their module, calendar types render ISO-8601, and anything else falls back to inspect/2. Journal store adapters can persist the result directly:

def append(record, _opts) do
  record |> Record.to_json_map() |> MyRepo.insert_journal_row()
end