mixle.task.replay module

Replayable execution traces – record each step an executor took (tool, args, seed, result) as a plain JSON-able object, and re-run it later to prove the run was deterministic.

A step is only trustworthy to replay if every source of randomness it used is named and captured – that is the whole point of recording seed per step rather than trusting global RNG state. replay re-invokes each step’s registered tool with the same args and seed and returns a new ExecutionTrace; diff is the per-step comparison (bit-identical or not), never a silent pass.

class TraceStep(tool, args=<factory>, seed=None, result=None, action=None, state_before=None, state_after=None, rng_state_before=None, rng_state_after=None, succeeded=None)[source]

Bases: object

One recorded step: the tool name, the args it ran with, the seed (if any), and its result.

Parameters:
to_json()[source]

Serialize this trace step to JSON-compatible data.

Return type:

dict[str, Any]

classmethod from_json(d)[source]

Reconstruct a trace step from JSON-compatible data.

Parameters:

d (dict[str, Any])

Return type:

TraceStep

class ExecutionTrace(request, steps=<factory>)[source]

Bases: object

An ordered list of TraceStep – JSON-serializable, so it can be stored (e.g. as a mixle.substrate "trace" item) and replayed in a fresh process.

Parameters:
  • request (str)

  • steps (list[TraceStep])

to_json()[source]

Serialize the full execution trace to JSON-compatible data.

Return type:

dict[str, Any]

classmethod from_json(d)[source]

Reconstruct an execution trace from JSON-compatible data.

Parameters:

d (dict[str, Any])

Return type:

ExecutionTrace

dumps()[source]

Serialize the execution trace to a stable JSON string.

Return type:

str

record_step(tools, tool, args, *, seed=None)[source]

Run tools[tool] once with args (and seed, if the tool accepts one), recording the result.

Parameters:
Return type:

TraceStep

failure_result(exc)[source]

The canonical JSON shape a failed step records as its result.

One shape for every recorder (MXR-080-1892): the orchestrator built this dict inline while replay let the exception escape, so a failure recorded one way could never be compared with a failure reproduced the other way.

Parameters:

exc (BaseException)

Return type:

dict[str, Any]

replay(trace, tools)[source]

Re-execute every step of trace against tools with the exact same args and seed.

A step whose tool raises is RECORDED as a failed step rather than aborting the replay (MXR-080-1892): a recorded failure that cannot be re-run is not reproducible evidence, and the orchestrator’s own traces are mostly interesting precisely where a step failed. The error is recorded in the same failure_result() shape the recorder used, so the two are comparable.

Deliberately NOT re-derived: state_before/state_after. Replay calls tools[tool](**args); it never runs the world that produced those snapshots, so recomputing them is impossible and comparing recorded-vs-absent would report a mismatch on every orchestrated trace. They are carried forward as recorded context exactly like action. What replay proves is the TOOL’s determinism – same args, same seed, same entry RNG state -> same result and same exit RNG state – not the world’s.

Parameters:
Return type:

ExecutionTrace

diff(a, b)[source]

Indices + tool names where a and b disagree (JSON-serialized result comparison).

Parameters:
  • a (ExecutionTrace)

  • b (ExecutionTrace)

Return type:

list[tuple[int, str]]

is_bit_identical_replay(trace, tools)[source]

Replay trace and return whether every step reproduces exactly.

Parameters:
Return type:

bool