Glossary#
Authoritative definitions of the terms used in ESSlivedata code and documentation.
When code, another document, and this glossary disagree, one of them has a bug:
fix it or file an issue.
References name modules (under src/ess/livedata/) rather than line numbers.
Terms are grouped into cross-cutting, backend, and dashboard sections;
dashboard terms live in dashboard/glossary.md, and the documentation build
renders all sections as one page.
The final section, One word, several meanings,
disambiguates overloaded words — consult it before introducing a new name.
Cross-cutting#
Identity and keying#
The naming stack, from the Kafka wire inwards (see ADR 0004 and
design/stream-keying.md):
Instrument — an ESS beamline, and the central per-instrument configuration object (
config/instrument.py) bundling detector/monitor names, streams, and the workflow factory. Registered inconfig/instruments/.Topic — a Kafka topic name (plain
stralias inkafka/stream_mapping.py). The fixed per-instrument livedata topics (commands, data, responses, roi, status) are declared inLivedataTopics.Source name — the producer-declared name inside a FlatBuffers message (EV44/F144 field).
(topic, source_name)(InputStreamKey) is the raw Kafka identity of a message and exists only at the Kafka boundary.Stream name (canonical stream name) — the instrument-facing routing handle, a NeXus-derived name resolved on ingress. All non-boundary code keys inputs by it (ADR 0004). In job context it is often called
source_name— e.g.JobId.source_name,WorkflowSpec.source_names— which refers to the canonical stream name, not the raw Kafka source name.StreamId — internal stream key
(kind: StreamKind, name)(core/message.py), isolating all code from Kafka topic names.StreamKind — enum of stream categories (
core/message.py):monitor_counts,monitor_events,detector_events,area_detector,log,device, thelivedata_*topics,run_control,unknown.StreamMapping — the boundary lookup
(topic, source_name) → stream name(kafka/stream_mapping.py).Synthesized stream — a stream emitted in-process (
topic is None), never read from Kafka, e.g. a chopper cascade or merged device stream (ADR 0001).
Workflow and job identity#
Workflow — the scientific reduction logic: a protocol with
accumulate/finalize/clear(workflows/workflow_factory.py), usually wrapping aness.reduce.streaming.StreamProcessor. A workflow runs as a Job.WorkflowId —
(instrument, name, version); string forminstrument/name/version(config/workflow_spec.py).WorkflowSpec — the declarative description of a workflow: title, source names, aux sources, parameter and output models (
config/workflow_spec.py). Purely declarative; contains no runtime values.WorkflowConfig — runtime parameter values for a spec, sent as a command to start a job. Currently conflates “configure” and “start” (issue #445).
Job — a running instance of a workflow, bound to a
JobIdand its input streams (core/job.py).JobNumber — a
uuid.UUIDminted per commit; the persistent identity component of a job and the generation marker (ADR 0007/0008).JobId —
(source_name, job_number); string formsource_name/job_number.Generation — the epoch defined by one commit’s
job_number: results stamped with an older job number belong to a previous generation and are filtered out; a new generation clears buffers (ADR 0007/0008).ResultKey — wire key of one workflow output:
(workflow_id, job_id, output_name). Embeds the per-commit job number.DataKey — stable identity
(workflow_id, source_name, output_name), i.e. a ResultKey with the job number stripped. The dashboard data plane and NICOS derived devices (ADR 0006) key by DataKey, not ResultKey.OutputView — user-facing presentation of a workflow output, bundling the backend output fields that carry one quantity (
config/workflow_spec.py).Temporality — how one output field’s values relate to time. Every output carries a
timecoord — the instant its value refers to — but what that instant means differs:window(covers[start_time, time],timeis when the window closed, successive windows disjoint),cumulative(value as observed attime,start_timepinned for the generation), orseries(timeis the per-point axis, nostart_time). Declared per field viaAnnotatedon the outputs model. It decides which aggregations over successive messages are valid, and whichWindowingthe field backs — a view states its member fields, and the binding follows (config/workflow_spec.py).Windowing — the user-facing window-mode selector (
since_start/per_update) resolved against a view to pick the backing field. Derived fromTemporality, never declared alongside it (WorkflowSpec.field_for,WorkflowSpec.windowing_options).
Data kinds and services#
Backend services — the four job-based workers:
monitor_data,detector_data,data_reduction,timeseries(services/; run aspython -m ess.livedata.services.<name>).Monitor / detector / area detector / log / device data — the domain data kinds, mirrored by
StreamKind. Logdata (F144 log streams) is the input kind consumed by the timeseries service; the fake producer is accordingly namedfake_logdata.Fake services — synthetic producers for Kafka-based local demos:
fake_monitors,fake_detectors,fake_logdata.Dev mode (
--dev) — simplified Kafka topic structure compatible with the fake producers.Transport — the dashboard’s backend selector:
none(UI only, workflows stay pending),fake(in-process fake backend, no Kafka),kafka(real backend). Also the abstraction name indashboard/transport.py.Run control —
RunStart/RunStopmessages from the ESS filewriter topic (core/message.py), driving job schedule transitions.Heartbeat — periodic (~2 s) status publication from each backend worker: a
ServiceStatusenvelope carrying per-jobJobStatusentries (core/job.py). The dashboard adopts running jobs from heartbeats (ADR 0008).
Backend#
Service layer#
Service — top-level lifecycle manager (
core/service.py): owns a worker thread that calls a Processor in a poll loop, handles signals and shutdown.Processor — the protocol a Service drives:
process()+finalize()(core/processor.py).IdentityProcessoris the passthrough used by fake producers.OrchestratingProcessor — the Processor implementation for job-based services (
core/orchestrating_processor.py): pulls messages, splits command/run-control/data, preprocesses batches, drives the JobManager, and publishes results and heartbeats.ServiceState — worker lifecycle enum:
starting/running/stopped/error.Service name — string identity of a backend worker kind (
'data_reduction','monitor_data','detector_data','timeseries'), matched against a workflow’s registered service. The same literals also nameWorkflowGroups (display grouping in the UI); the coincidence is load-bearing:register_specdefaults a workflow’s service to its group name.
Messages and preprocessing#
Message — the universal internal envelope
(timestamp, stream: StreamId, value)(core/message.py).MessageSource / MessageSink — protocols for consuming/publishing messages; Kafka implementations in
kafka/source.pyandkafka/sink.py.MessageAdapter — converts wire payloads to domain messages (
kafka/message_adapter.py);KafkaAdaptermaps(topic, source_name)toStreamId.MessageBatch / MessageBatcher — a time-windowed batch of messages and the strategies producing them (
core/message_batcher.py).Accumulator — protocol accumulating data over time (
add/get/clear,core/preprocessor.py). Batch accumulators are consumed onget(); context accumulators (is_context = True) are idempotent and retain state.Preprocessor — an Accumulator in its pipeline role: bound to one StreamId, turning raw stream data into workflow input. Created by a PreprocessorFactory (
core/preprocessor.py); the concrete factories are the*PreprocessorFactoryclasses inpreprocessors/. The similarly namedMessagePreprocessoris internal OrchestratingProcessor wiring that owns the accumulators.
Job management#
JobManager — owns all job records; schedules, activates, gates, and finishes jobs, fans data out, gathers results and statuses (
core/job_manager.py).Command — wire type of the
livedata_commandstopic: discriminated unionWorkflowConfig | JobCommand(core/job_manager.py). Dispatched byCommandDispatcher(core/command_dispatcher.py).JobCommand — control message for a running job:
pause/resume/reset/stop(pause/resume unimplemented).JobSchedule — optional start/end times (raw-data timestamps) governing activation and finish.
JobState — wire-facing per-job status enum:
scheduled,active,finishing,pending_context,stopped,error,warning. Not a flat state machine: it mixes lifecycle phase, the finishing overlay, and health into one enum, derived on demand from the internal record.JobPhase — internal lifecycle position only:
scheduled → pending_context → active(core/job_manager.py). Orthogonal to health.Primary / auxiliary / context data — primary streams (the job’s
source_names) trigger computation; auxiliary streams (user-selectedAuxSourcesplus framework context) accumulate and tolerate absence; context streams parametrize the workflow graph and, lacking a safe default, gate the job (ADR 0002/0003).Gating — holding a job in
pending_contextuntil all its gating (context) streams have a value (ADR 0002).ContextBinding — declaration mapping a context stream to a Sciline workflow key for given dependent sources (
config/stream.py, ADR 0003).Device — a synthesized in-process stream merging EPICS substreams (RBV/VAL/DMOV → value/target/idle) into one consistent record (
config/stream.py, ADR 0001/0006).
Dashboard#
Dashboard-specific terms. Cross-cutting terms (Job, DataKey, StreamId, …) and
the disambiguation of overloaded words live in src/ess/livedata/glossary.md.
Data plane#
DataService — dict-like shared store keyed by DataKey, backed by temporal buffers; notifies subscribers with keys-only batched notifications (
dashboard/data_service.py).Subscriber — a
DataServiceSubscriber: registers interest in a key set with per-key extractors; on notification it pulls snapshots (it is never pushed data).DataSubscribergroups pulled data by data role.UpdateExtractor — pull-time transform fixing buffer type and retention per key: latest value, full history, or window aggregation (
dashboard/extractors.py).StreamManager — factory registering a subscriber pipeline for a set of DataKeys; the result is informally called a data stream (
dashboard/stream_manager.py).MessagePump — the dashboard’s Kafka-to-DataService message pump (
dashboard/message_pump.py): pulls from the transport’s MessageSource, filters by active generation, writes into DataService, routes status and acknowledgements. Distinct from JobOrchestrator and PlotOrchestrator.
Job and workflow lifecycle#
JobOrchestrator — owns the two-phase workflow lifecycle (stage → commit → stop): a commit mints one job number, starts the set of per-source jobs sharing it, publishes the commands, and tracks acknowledgements until confirmed or timed out (
dashboard/job_orchestrator.py).JobService — read model of the latest
JobStatusper JobId, with heartbeat staleness detection (dashboard/job_service.py).ActiveJobRegistry — thread-safe record of each workflow’s current generation, gating ingestion against UI-thread commits (
dashboard/active_job_registry.py).WorkflowController — thin interface between widgets and JobOrchestrator (
dashboard/workflow_controller.py).Adoption — deriving the currently-running generation from live heartbeats instead of persisted job identity (ADR 0008).
ServiceRegistry — backend worker health derived from heartbeats (
dashboard/service_registry.py).
Plot hierarchy#
From coarse to fine: grid → cell → layer → plotter → presenter → figure.
Topology — the shared arrangement of plots: which grids exist (order, title, enabled), which cells each grid holds, and which layers each cell holds. Owned by PlotOrchestrator and versioned as one unit (
topology_version); excludes data flow (frames, plotter contents) and anything per-session (widgets, tokens, tab focus).Grid — a titled
nrows × ncolsarrangement of cells (PlotGridConfig); shown as one dashboard tab. Grids are managed by PlotOrchestrator (dashboard/plot_orchestrator.py), which owns topology, persistence, and a version-bump polling contract (ADR 0007).Cell — one position in a grid (
PlotCell: geometry + layers). Multiple layers in a cell are composed into one figure viahv.Overlay. Per-session view:CellWidget(dashboard/widgets/cell.py).Layer — the atomic plotted unit: a layer id plus
PlotConfig(plotter name, params, data sources keyed by data role). When prose says “a plot”, it almost always means a layer.DataSourceConfig — one data role’s configuration within
PlotConfig: workflow id, source names, andview_name(the user-facingOutputViewname). Persisted verbatim in grid templates andConfigStore.ResolvedDataSource —
DataSourceConfigwithview_nameresolved to the backend pydantic field name (output_name) selected by the current window mode, ready to key aDataKey. Built by_build_resolved_data_sourcesat layer-setup time; runtime-only, never persisted (dashboard/plot_orchestrator.py).Plotter — session-shared object producing HoloViews elements from subscribed data (
dashboard/plots.py); subclasses per plot type (LinePlotter,ImagePlotter,SlicerPlotter, …). Registered in PlotterRegistry with a spec, factory, and data requirements.Presenter — per-session bridge from a plotter’s cached state to a HoloViews
DynamicMapvia anhv.streams.Pipe; carries the dirty flag (dashboard/plots.py).Figure — the rendered HoloViews/Bokeh object placed in the document. Reserved for the rendered artifact; not a synonym for plotter or layer.
PlotDataService / LayerState — per-layer shared state machine (
WAITING_FOR_DATA/READY/STOPPED/ERROR) with version counters, read by per-session pollers (dashboard/plot_data_service.py).Grid template / GridSpec — declarative grid layout shipped with an instrument (
config/grid_template.py).
Sessions and updates#
Session — one browser connection (one Bokeh document). Tracked by SessionRegistry with heartbeat-based stale cleanup.
SessionUpdater — per-session driver on the session’s IOLoop: runs update handlers inside a batched (
pn.io.hold+doc.models.freeze) session context (dashboard/session_updater.py). Ticks come from a WakeupHub wake, or from its own 1 s housekeeping callback, which every 5 s runs a full pass (all handlers, no gate) for wall-clock-driven displays.WakeupHub — process-wide, data-free wake-up of registered sessions (
dashboard/wakeup_hub.py): any thread callswake_allafter shared state changes, and each session’s tick is scheduled onto its own IOLoop. Wakes are coalesced per session; a lost or duplicate wake is harmless because ticks are idempotent and version-gated.has_work / pending work — the cheap per-handler predicate deciding whether a wake tick runs a handler at all; when none fires, the tick skips the hold+freeze batch entirely. Not the same as heartbeat staleness — see stale in
src/ess/livedata/glossary.md.SessionLayer — per-session render state for one layer: presenter, pipe, and DynamicMap; doubles as the session’s viewer-interest token (
dashboard/session_layer.py).CellPlan / desired cells — the target widget tree of one session’s reconcile pass:
desired_cells(dashboard/cell_plan.py) is a pure function from topology, layer snapshots, and the session view to one plan per materialized cell. Policy changes go here; the differ/applier inplot_grid_tabs.pyis fixed mechanism.Materialize / deferred — whether a session should hold a built widget for a cell. Materialized cells appear in the plans; a deferred cell (hidden grid, nobody watching) is absent from them and absorbs any number of input changes with zero builds — it is built exactly once on reveal or when a watcher appears (the latter bounded by the 5 s full pass).
Build inputs —
CellBuildInputs: geometry, user title, and per-layer (snapshot, has-plot) a widget was built from, recorded on the widget. The differ rebuilds exactly when the current inputs no longer compare equal — there is no bookkeeping to go stale.Single-writer versioned pull — the dashboard concurrency model: one writer mutates shared state and bumps a version; sessions poll the version and pull snapshots on their own IOLoop (ADR 0007).
Version counter — a plain
inton shared state, incremented by its writer and only ever compared for equality against a session’s last-seen value. Never a timestamp, and never ordered or subtracted: a session asks “did this move since I rendered it?”, not “by how much” or “when”. Python ints are unbounded, so there is no wrap-around to handle.Frame (dashboard) / FrameClock — the frame-gated flush cycle batching plot updates per session (
dashboard/frame_clock.py, ADR 0005). Unrelated to the neutron pulse-frame sense.Reaper — background teardown of dead browser sessions off their own IOLoop (
dashboard/session_updater.py, ADR 0007).
Configuration and transport#
ConfigStore — UI-state persistence (workflow and plot configs, YAML files under the user’s config dir;
dashboard/config_store.py). Not related to backend command handling.ConfigurationAdapter — bridges pydantic parameter models to generic form widgets (
dashboard/configuration_adapter.py); implementations for workflow and plot configuration.DashboardServices — the per-process composition root shared across sessions (
dashboard/dashboard_services.py).lt-*hooks — stable DOM classes for UI automation (.claude/rules/dashboard-widgets.md).
One word, several meanings#
role — two senses: (1) data role: a plot layer’s data-source key —
primary/x_axis/y_axis(dashboard/data_roles.py); (2) aux-input role: the logical name of an auxiliary workflow input a user selects a stream for (AuxSources). Qualify the word when ambiguity is possible. The time-window flavor of an output field (since_start/per_update) isWindowing, not a role, and how its values relate to time isTemporality(config/workflow_spec.py).stream — (1) a Kafka/internal data stream (
StreamId); (2) a dashboard subscriber pipeline (StreamManager.make_stream); (3) anhv.streams.Pipeper-session channel. Sense (1) is the default; qualify the others.source name — raw Kafka FlatBuffers producer name at the boundary, but the canonical stream name everywhere else (see Identity and keying).
view — (1)
OutputView/view_name: user-facing name of a workflow output, held byDataSourceConfig.view_nameand resolved to a backend pydantic field name (ResolvedDataSource.output_name, feedingDataKey.output_name) at layer-setup time — seedashboard/glossary.md; (2) the MVC sense: a widget rendering state (e.g.CellWidget).plot — informal umbrella over grid/cell/layer/plotter/figure; in precise writing name the level, usually layer.
frame — neutron pulse frame (instrument context) vs. the dashboard update-flush cycle (ADR 0005).
orchestrator — backend
OrchestratingProcessor; dashboardJobOrchestrator(workflow lifecycle),PlotOrchestrator(grid topology). The dashboard’s Kafka-to-DataServicemessage pump isMessagePump, not an orchestrator.processor — the Service-driven
Processorprotocol; not a workflow. (ess.reduce.streaming.StreamProcessoris an upstream class a Workflow may wrap.)handler — retired as a backend term: preprocessor factories (
*PreprocessorFactoryinpreprocessors/) andCommandDispatcherreplace what used to be called handlers. Still the standard word for UI/event callbacks (Panel/Bokeh event handlers,SessionUpdatercustom/cleanup handlers, signal handlers) — don’t reuse it for backend concepts.config — spans
WorkflowConfig(runtime start command), instrument configuration (Instrument, YAML), and dashboardConfigStore(UI persistence). Always qualify.state / status —
JobState(wire enum) vsJobPhase(internal lifecycle) vsServiceState(worker lifecycle);JobStatus/ServiceStatusare the heartbeat payloads carrying them.layout —
hv.Layoutcombine-mode subplots; the per-session page layout (create_layout); a grid’s cell arrangement; Bokeh’s layout pass. Qualify.stale — reserved for age: a job or worker status with no recent heartbeat (
is_status_stale), or a browser session the reaper may collect. For “shared state moved on since this session last rendered it” say pending work (has_pending_work, thehas_worktick predicates). The two are independent: staleness sets in by the clock with no version bump behind it, which is why it is rendered by the periodic full pass rather than by a wake.