Replay

Requires the replay extra (pip install "longeron[replay]").

The replay widget itself lives in longeron.widgets.replay; this module is the kernel-side timeline recorder.

Replay state-machine and action executions over rendered diagrams.

record_timeline() drives a StateMachine through the same event protocol as Interpreter.simulate while observing every step through the machine’s on_step hook, producing a Timeline: per-state activation keyframes plus fired-transition instants, addressed by instance-qualified names – the machine’s qualified name extended along the active-state path (the same :: ids the diagrams and headless SVG use, unique per typed-submachine expansion site). record_action_timeline() does the same for action executions via the executor’s step observer: the active node is the currently-executing named action step, fired records are the traversed successions, and the axis is always the step index.

The replay widget itself lives in longeron.widgets.replay (replay_widget() bakes the matching diagram to SVG and animates the timeline over it); this module is the kernel-side recorder and needs no widget toolkit. Importing replay_widget from here still works but is deprecated.

class longeron.replay.FiredTransition(t, source, target, event)[source]

Bases: object

A fired transition, addressed by model qualified names.

class longeron.replay.Timeline(t_start, t_end, step_mode, n_steps, tracks, fired, final_state, trace, ignored_events, env, sends, time=0.0, active_states=<factory>, parents=<factory>, env_steps=<factory>)[source]

Bases: object

A recorded simulation, keyed for replay over the state diagram.

Track keyframes and fired times use sim time, except in step mode (t_end == t_start, a pure event cascade): then the key is the step index, and the front-end scrubs over steps instead of time (see the matching stepMode logic in the widget’s _ESM).

tracks: dict[str, list[tuple[float, bool]]]

per-state keyframes [(t_or_index, active)], recorded on change only

parents: dict[str, str]

parent relation between recorded nodes (child qname -> parent qname): the recorded truth the front-end tints composite ancestors with – keys are instance-qualified, so it now agrees with the “::” prefix relation, but it stays authoritative (and keeps older front-end payload handling honest)

env_steps: list[tuple[float, dict[str, Any]]]

per-step scalar env snapshots [(t_or_index, {name: value})], shown as the readout line under the widget’s controls (step semantics, like tracks)

to_json()[source]

The replay payload (times and float values rounded to 3 decimals).

Return type:

str

longeron.replay.record_action_timeline(interpreter, action, events=None, *, inputs=None)[source]

Run an action and record a replayable Timeline.

Mirrors Interpreter.run_action semantics (events feed accept statements), observing every named action step through the executor’s on_step hook. The axis is always the step index (step_mode is True): step k is the k-th named step entered, active while it executes (nested steps nest, like composite states), and consecutive same-depth steps yield fired records for the traversed successions – routed through intermediate control nodes (decide/merge/fork/join), so each drawn edge on the path pulses. Fired records are matched against the action diagram’s edges by the front-end; records with no matching edge (e.g. across fork branches) are inert.

Return type:

Timeline

longeron.replay.record_timeline(interpreter, state_machine, events=None, *, inputs=None, max_steps=1000)[source]

Simulate a state machine and record a replayable Timeline.

Mirrors Interpreter.simulate semantics: events entries are event names or (name, payload) tuples; plain numbers advance the clock.

Return type:

Timeline