A trace read model and a provenance map become the canvas's run marks.
The editor already draws run marks - %{active: MapSet.t(block_id), invoke: {block_id, outcome} | nil} threaded down StatifierBlocks.Editor.Canvas
to every StatifierBlocks.Editor.BlockNode - but nothing in this package
produced them: a host holding a run was expected to name the blocks itself.
This is that step, done once and in the open, so the canvas can sit in the
debugger's diagram seat rather than beside it.
The input is a trace read model - statifier-ui's StatifierUI.Live.State,
the struct an ops view already holds - and the provenance map the same
document compiled to. The output is the marks map, or nil when there is
nothing to mark, which is the same "no run over this document" the editor
already threads.
The seam is a read on one side and a resolution on the other
statifier-ui answers where a run is, in the chart's own state ids
(StatifierUI.Inspector.active_configuration_ids/2 and active_invokes/2,
both added in 0.9.0). This package answers which block a state id came
from (StatifierBlocks.Provenance.owners_of_states/2). Neither half knows
the other's vocabulary, and neither needed a callback to be handed one:
the whole of the join is the two reads composed here.
A state id the provenance map has never heard of is dropped rather than
raised on, because owners_of_states/2 drops it - a configuration naming
a state from a different chart marks the blocks it can and no more.
invoke_type, not an outcome
The mark's second element is the canvas's data-invoke-outcome: how a
call came back, nil while it is still out. statifier-ui's read pairs a
live invocation with its invoke_type instead, and says why in its
own docs: the wire format defines no outcome field for an invocation, and
deciding when one has "finished" is the engine's call rather than a read's.
So a live invocation is marked with nil - a call with no answer yet,
which is precisely what a live invocation is - and the type is not stamped
into an attribute that means something else. A block whose invocation has
ended carries no mark at all, because it is no longer live.
Unguarded, and no compile-time dependency on statifier-ui
Like StatifierBlocks.Runtime.FixtureRuns, this module carries no
LiveView presence wrapper and names no LiveView module: it is a pure
function of a read model and a map, and the headless suite - the CI job
that proves this package compiles and passes with LiveView absent -
exercises it directly.
statifier_ui is optional here for the same reason LiveView is, so the
two reads are never named as call targets either. The module is read from
application config and dispatched dynamically, the way
StatifierBlocks.Editor.Field reaches statifier-ui's expression input and
for the same reasons: the compiler stays quiet in a tree without the
package, and a test can point the key at a module of its own to exercise
the resolution with the package absent or present. Without a resolvable
read, from_trace/2 marks nothing.
The read model itself is taken as data - messages, selection and
initial_configuration are public fields of StatifierUI.Live.State, and
reading them costs no dependency at all. That is also why the two reads go
to StatifierUI.Inspector rather than to State.configuration_ids/1:
State wraps the configuration read but exposes no invoke read, so one
module answers both halves from the same options rather than one half
coming from each.
Summary
Types
What the canvas accepts: the blocks a configuration is inside, and the block whose invocation is live.
Functions
The run marks for state's current selection, resolved through provenance.
Types
Functions
@spec from_trace(map(), StatifierBlocks.Provenance.t()) :: t() | nil
The run marks for state's current selection, resolved through provenance.
state is statifier-ui's StatifierUI.Live.State - anything carrying its
messages, selection and initial_configuration fields - and the
selection is whatever the scrubber left there: the live tip, or one
macrostep. A macrostep that stamped no configuration of its own draws the
newest one below it (statifier-ui's carried-configuration rule), so a
carried point marks the same blocks the point it was carried from does.
nil when there is nothing to mark: a stream carrying no session.start
to resolve names through (the late-attach case, and the empty stream),
a configuration naming no block this map owns, or a tree where the read
itself does not resolve.