WorkflowExecution +
WorkflowNodeExecution tables.
Ingress requires an environment-bound workflow. Cloud-owned executions
keep using their existing task runner; selecting a model or a Control service
does not transfer execution ownership to an edge reporter.
MQTT topics
A publisher that reports a node after the fact should send
started_at / finished_at (ISO-8601, or epoch seconds) so the timeline
shows when the node ran rather than when the event was received. The
backend ignores a reported time that falls outside the execution’s own
span, so an unsynchronised clock degrades to receipt time instead of
placing a node in the future. reporter.node_started(..., started_at=...) and node_finished(..., finished_at=...) take a
datetime, epoch seconds, or a formatted string.
A reported finish before the recorded start also falls back to receipt time.
Generated workers omit these arguments for an older SDK reporter, preserving
existing lifecycle events without requiring a coordinated device upgrade.
Publishers should set source_type to one of edge, sim, tele,
or edit for lineage. Authentication is broker-level (consistent with
other Cyberwave MQTT ingress such as
cyberwave/twin/{uuid}/navigate/status).
Idempotency is enforced on the backend:
- Repeat
startedwith the sameexecution_uuidreturns the existing row without re-seeding node children. - Node events for a node already in a terminal state (
success/error/skipped) are ignored — first terminal write wins. finishedon an already-terminal execution is a no-op.
Python SDK
client.workflow_executions.start(...) returns a
WorkflowExecutionReporter that owns a single execution and publishes
over MQTT. The client must be connected to a Cyberwave-backed MQTT
broker — the reporter raises on construction if not.
with client.workflow_executions.start(...) as r:)
marks success on clean exit and error on exception, so workers
don’t have to repeat the try/except shape.
The initial started publish is always strict: if it fails, later
node events would reference an execution the backend never saw. Pass
strict=True to start(...) to surface later publish failures as
well (the default swallows them after logging, so a transient broker
blip doesn’t poison a running workflow).
Generated worker modules
Mission workflows compiled withrun_on_edge=true ship a generated
wf_*.py that already wires the reporter around every emitted node.
Each step in compiled_payload.steps carries the emitting node’s
node_uuid so runners that consume the payload directly (cloud-side
or custom edge runners) can produce the same events without parsing
the generated Python source.
The generated worker holds its node events until the end of a tick, so
that a frame-driven trigger stays quiet on idle frames, and timestamps
each one as it happens — a run’s timeline reflects the node durations,
not the moment the batch was published.