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 from the live tip to any macrostep in the
log and back. Selecting a macrostep draws the configuration that
macrostep settled in, opens its entry in the event log, and marks that
entry - shown in the diagram; 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("run.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.
What this is not
Static, at the trace's live tip. There are no scrubber buttons and
no injection form: both drive a session, and a file has none. Stepping
through a persisted trace - and the datamodel diff between adjacent
steps that makes stepping worth having - is sui-2uz, deliberately
left to decide its own contract.
@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.