Architecture
This page describes the combined branch implementation; see current contracts for release status and compatibility boundaries.
Design principles
- Stateless execution: state in, updated state out. No persistence, background threads, or framework.
- Host durability: the host stores definitions and instance JSON, serializes concurrent deliveries, schedules timers, and provides idempotent external work.
- Explicit wiring: executors, listeners, and error handler are constructor dependencies.
- Owned JSON snapshots: nested maps/lists are read-only; Jackson trees are copied on ingress/read. Opaque Java objects remain host-owned immutable references. No-op calls may return the input instance.
- Two expression environments: Java uses Jakarta EL; browser simulation uses a verified subset. Conformance limits are explicit.
Engine internals
Public operations
| Category | Methods |
|---|---|
| Lifecycle | startWorkflow, completeNode, completeCurrentNode, cancelWorkflow |
| Correlation | matchesEvent, including a node-addressed overload |
| Expressions | resolveExpression |
| Parked-node info | getActionInfo, getHumanTaskInfo, getReceiveEventInfo, getWaitInfo; each has a node-addressed overload |
startWorkflow validates the definition and initial inputs. The call-local branch work queue then advances
all runnable branches until they park or the instance terminates. Calls and executor invocations are
synchronous; parallel tokens do not imply concurrent executor threads.
Enter node → notify listener → resolve inputs / perform node work
ACTION: invoke executor → COMPLETED / FAILED / PENDING
HUMAN_TASK / RECEIVE_EVENT / WAIT: park for external completion
END: complete the instance
Successful completion → validate/map output → history/context update → onNodeCompleted
→ choose priority/default edge OR dispatch all fork edges
→ onEdgeFollowed → join-arrival accounting / next node entry
Forks and joins are derived from validated topology, without dedicated node kinds. Join arrivals use incoming edge IDs; each branch must reach its join through one distinct arrival edge. Unsupported crossing, unbalanced, or cyclic regions are rejected before executors run. A fail-fast branch failure terminates the instance; END terminates sibling work. See Parallel Fork/Join.
An action returning PENDING parks like other external-input nodes. Completing one node resumes that
branch, not unanswered siblings. Read-only info calls require an active parked node in a WAITING
instance. Each child edge move consumes one unit of the 100-unit driver budget; successful fork selection
adds no charge. Recovery entries, external action retries, and unsuccessful routing also consume driver
units. Each local action execution retry loop allows ten retries after its initial attempt. Routing RETRY
re-evaluates edges without repeating the completed action. These guards are not a durable backoff policy.
See Engine errors for structured failures and callback ordering, and indexed architecture for graph indexes, value resolution, cache ownership, and measured benchmark evidence.
Validation and expressions
Both validators perform shape preflight before semantic traversal, followed by graph structure, connectivity, conditions, semantic configuration, and parallel-region checks. Do not infer coverage from a manually maintained rule total: codes may appear in several phases and severities depend on the failure. Validation links to the authoritative implementations and shared fixtures.
Java binds context for routing/input resolution and both context and event for event correlation and
output mappings. Blank conditions are unconditional; a conditional edge selects only boolean true.
The browser classifies expressions as supported, malformed subset syntax, or unsupported dialect.
UI internals
WorkflowEditor (ReactFlowProvider)
useEditorState → editorReducer → owned document / past / future / presentation
ReactFlow canvas + palette + context menu + import/export/image controls
PropertiesPanel → node-kind forms + stable draft rows + value editors
ProblemsPanel ← built-in + asynchronous host validation
SimulationPanel → subset evaluator + branch-aware simulator
WorkflowViewer (ReactFlowProvider)
read-only canvas + state/definition panel + visit/branch selection + host menu
WorkflowDiffViewer (ReactFlowProvider)
ID-based comparison + combined canvas + field comparison panel
The editor initializes its graph from the mount prop. Subsequent metadata updates apply to that graph;
host-driven graph replacement requires a React key remount. Document commands commit atomically and
publish onChange once per committed revision. Selection, measurements, and drag frames are presentation
state. Semantic document identity excludes layout-only revisions, avoiding unnecessary validation and
parallel-analysis reruns. Import and undo/redo preserve workflow metadata with the graph.
Document history restores panel and canvas selection together, while selection-only actions remain
presentation state. Host validators receive read-only semantic snapshots with retained coordinates, even
if a new callback reference causes a run; position-sensitive work uses the current onChange document.
Viewer and diff props update live; pass fresh object/array references rather than mutating them in place. Neither component edits the host document. Layout can render definitions with absent positions.
Fast Vitest suites cover pure logic; real-browser contracts cover ReactFlow event ordering, focus, async host responses, and a packed-library consumer with CSS.