The Livebook inspector: inspect/3 composes the four panes -
configuration diagram, datamodel explorer, event injection, event
log - over one shared StatifierUI.Trace.Subscriber, attached with
catch-up (statifier ADR-0049), inside one Kino.Layout.
Compiled only when the optional :kino dependency is present
(ADR-0004); a host without it gets a stub whose inspect/3 raises
with instructions. Nothing else in this package touches Kino.
The scrubber (sui-3gg)
Four buttons above the diagram - First, Prev, Next,
Live - move the diagram and the datamodel explorer from the live
tip to any macrostep in the log and back. Selecting a macrostep draws
the configuration that macrostep settled in, shows the datamodel as it
stood at the end of that macrostep, opens its entry in the event log,
and marks that entry - selected; the note above the diagram says
which point is on screen. StatifierUI.Inspector decides all of it, so the
whole behaviour is testable without Kino - this module only wires
buttons to Updater.scrub/2.
Buttons rather than a click target on the log entry itself: the log
pane is Kino.Markdown, which renders text and cannot carry a click
handler back to the runtime. A directly clickable entry is the
ADR-0008 renderer's to give, not Mermaid-and-Markdown's.
Lifecycle
Every process this module starts - the subscriber and the updater -
goes through Kino.start_child/1, so re-evaluating the cell
terminates them with it. The session notices the dead subscriber
through its own monitor and drops it from its subscriber set: that is
the clean detach, with nothing to unsubscribe by hand. The session
itself is not owned here - it keeps running across cell
re-evaluations, which is exactly what makes catch-up worth having.
Catch-up needs record: true
Start the session with record: true (and trace: true) for the
inspector to reconstruct everything it missed. Without it the
subscriber falls back to live delivery and the status header labels
the panes Live-only - a partial stream is never presented as
whole. Replay cost grows with run length (it re-runs the recording in
the attaching process), so expect cell evaluation on a very long-lived
session to take correspondingly longer.
Summary
Functions
Builds the inspector for session and returns the composed
Kino.Layout for the cell to render.
Reopens a saved trace: the third leg of
StatifierUI.Trace.Capture's record / save / reload.
Renders every bundle a palette discovery found, one panel after another,
as a single Kino.Markdown widget.
Renders one fragment's fixture bundle as its "test this step" panel - its
truth table plus its expectation results (sui-13q) - as a
Kino.Markdown widget.
Renders fixtures' truth table - every expression evaluated across every
dataset (ADR-0006) - as a Kino.Markdown widget.
Functions
@spec inspect(pid(), StatifierUI.Fixtures.t() | nil, keyword()) :: Kino.Layout.t()
Builds the inspector for session and returns the composed
Kino.Layout for the cell to render.
fixtures is a StatifierUI.Fixtures.t/0 (or nil): it feeds the
injection palette's per-event buttons. opts:
:source- the SCXML text, forwarded to the subscriber for thesession.startmanifest.:capacity- the subscriber's buffer capacity (default 1000).
@spec inspect_trace( Path.t() | [StatifierUI.Trace.Message.t()], StatifierUI.Fixtures.t() | nil, keyword() ) :: Kino.Layout.t() | Kino.Markdown.t()
Reopens a saved trace: the third leg of
StatifierUI.Trace.Capture's record / save / reload.
StatifierUI.Kino.inspect_trace("execution.jsonl")trace is a file path (read through
StatifierUI.Trace.Capture.load/1) or an already-loaded
StatifierUI.Trace.Message.t/0 list. fixtures is accepted for
symmetry with inspect/3 and is currently unused - the palette it
feeds is an injection affordance, and there is nothing to inject into.
opts:
:machine- the compiled%Statifier.Machine{}to draw against. Optional: without it the machine is recompiled from the SCXML the trace carries in its ownsession.startmessage, which is whatStatifierUI.Trace.Capture.record/3's:sourceoption puts there. A trace captured without:sourceand reopened without:machinehas no chart to draw and returns aKino.Markdownsaying so rather than a diagram it cannot draw.
Stepping it (sui-2uz)
The layout carries the same |< First / < Prev / Next > / Live
scrubber inspect/3 has, plus a jump to select listing every
macrostep by number and event, and a datamodel diff pane saying what
the selected macrostep changed. A persisted stream has no tip that
moves, so "Live" here means the end of the recording.
Stepping a recording asks the engine for nothing: every configuration
shown was stamped by the engine into the file, and a trace read back
through StatifierUI.Trace.Capture.load/1 got its contents from
statifier ADR-0034 replay re-driving the core at capture time. The
controls move a selection over messages already in hand.
What this is still not
There is no injection form. Injection drives a session, and a file
has none. The fixtures argument stays accepted and unused for that
reason.
@spec palette_panel( StatifierUI.Fixtures.Bundle.discovery(), keyword() ) :: Kino.Markdown.t()
Renders every bundle a palette discovery found, one panel after another,
as a single Kino.Markdown widget.
discovery is what StatifierUI.Fixtures.Bundle.discover/2 or
discover_dir/2 returned.
@spec test_panel( StatifierUI.Fixtures.Bundle.t(), keyword() ) :: Kino.Markdown.t()
Renders one fragment's fixture bundle as its "test this step" panel - its
truth table plus its expectation results (sui-13q) - as a
Kino.Markdown widget.
Like truth_table/2, independent of inspect/3 and of any session: a
bundle is a fact about one palette entry's examples, so this needs no
running chart. opts go to
StatifierUI.Fixtures.Bundle.Markdown.render/2, which forwards each one
to the layer that owns it.
@spec truth_table( StatifierUI.Fixtures.t(), keyword() ) :: Kino.Markdown.t()
Renders fixtures' truth table - every expression evaluated across every
dataset (ADR-0006) - as a Kino.Markdown widget.
Independent of inspect/3 and of any session: a truth table is a fact
about expressions and datasets, so this needs no running chart and no
Phoenix. opts are split by owner - :expressions, :datasets,
:functions, and :providers go to StatifierUI.TruthTable.build/2,
and the rest to StatifierUI.TruthTable.Markdown.render/2.