mixle.epistemic.journal module

EpistemicJournal – an append-only, replayable decision log for a sequence of loop steps.

The program plan’s decision journal (§3.4: “timestamp, model version, belief snapshot hash, options considered with their EIG/cost/risk scores, chosen action, rationale claims…”), following mixle.evolve.ledger.EvolutionLedger’s existing shape (flat, JSON-serializable, append-only, no model objects stored directly) rather than inventing a third bespoke logging pattern.

One deliberate refinement over a hash-only ledger: each record carries the full serialized belief snapshot (portfolio_snapshot, from to_dict()) alongside its content-address (belief_snapshot_hash). A hash alone cannot be reversed back into a portfolio, so “an auditor can reconstruct the full belief trajectory from the ledger alone” (program plan §2) requires the snapshot content to actually be there; the hash is what lets verify() catch tampering/corruption of that stored content, which is the property a bare append-only list doesn’t get for free.

class DecisionRecord(step_index, belief_snapshot_hash, portfolio_snapshot, surprise, action_considered=<factory>, action_chosen=None, action_eig=None, timestamp=None, rationale=None)[source]

Bases: object

One journaled decision: what was believed, what was considered, what was chosen, and why.

Parameters:
  • step_index (int)

  • belief_snapshot_hash (str)

  • portfolio_snapshot (dict)

  • surprise (float)

  • action_considered (list[Any])

  • action_chosen (Any | None)

  • action_eig (float | None)

  • timestamp (float | None)

  • rationale (str | None)

class EpistemicJournal(records=None)[source]

Bases: object

An ordered, JSON-serializable, replayable log of EpistemicSteps.

Parameters:

records (list[DecisionRecord] | None)

append(step, *, action_considered=(), rationale=None, timestamp=None)[source]

Append one record for step and return it. timestamp is caller-supplied, never sampled here.

Parameters:
  • step (EpistemicStep)

  • action_considered (list[Any])

  • rationale (str | None)

  • timestamp (float | None)

Return type:

DecisionRecord

replay(portfolio0=None)[source]

Reconstruct the belief trajectory from the journal’s stored snapshots alone.

portfolio0 is accepted for interface symmetry with the loop’s own step(portfolio, ...) signature but is not required for reconstruction here: every record already carries its own full portfolio_snapshot, so replay is deserialization, not re-simulation (re-simulation would additionally need the original observations and likelihood callables, which are deliberately not journaled – they may not be JSON-serializable, and the snapshot is the thing an audit actually needs). If given, portfolio0 is prepended to the returned trajectory.

Parameters:

portfolio0 (HypothesisPortfolio | None)

Return type:

list[HypothesisPortfolio]

verify()[source]

Return whether every record’s stored snapshot still matches its recorded content-address.

Return type:

bool