Browse documentation
Docs/Language

Importing BPMN token workflows

Import a supplied process once, inspect its native NET, and advance an isolated instance through explicit task and gateway steps. The importer reuses native atomic firing, enabled queries,…

Importing BPMN token workflows

Import a supplied process once, inspect its native NET, and advance an isolated instance through explicit task and gateway steps. The importer reuses native atomic firing, enabled queries, reports and saved markings. It installs no BPMN engine, task worker, simulation clock or scheduler.

grid_format_standard::bpmn::import(text, context) returns native Grid source and a source-map manifest. The local adapter prints that source:

cargo run --offline --manifest-path rust/Cargo.toml -p grid-format-standard --example bpmn-to-grid -- examples/workflows/fulfillment.bpmn > /tmp/fulfillment.grid
cat examples/workflows/fulfillment-replay.grid >> /tmp/fulfillment.grid

Compile and load it through the existing native compiler/runtime. The generated module can also be imported through USE "fulfillment.grid" AS fulfillment. Its names are module-local. Reading/importing a definition creates no instance, job, worker or external action. bpmn_net.INITIAL() explicitly creates one immutable instance marking; FIRE proposes a new marking without publishing it.

Admitted control-flow profile

bpmn-2-acyclic-parallel-v1 is a closed control-flow projection of BPMN 2.0.2, using the http://www.omg.org/spec/BPMN/20100524/MODEL namespace. XML namespace prefixes may vary. It accepts one descriptive process with isExecutable="false" or that attribute omitted. It does not claim that an arbitrary executable BPMN process can run unchanged.

Construct Native meaning
One plain start event start consumes the single ready token; no timer/message/signal trigger
Plain task, one incoming and one outgoing flow begin_N consumes the incoming token and creates an active token; complete_N consumes that token and produces the outgoing token
Parallel diverging gateway, one input and at least two outputs One atomic firing produces a token on every outgoing flow
Parallel converging gateway, at least two inputs and one output One atomic firing requires and consumes a token from every incoming flow
One plain end event, one incoming flow finish consumes that flow and produces the completed token
Sequence flow A capacity-one native place, identified in the source map

Flow references must be local and exact. The importer checks unique IDs, source/target binding, node degrees, optional incoming/outgoing reference lists, gateway directions and the whole graph's acyclicity. Every admitted node lies between the sole start and sole end. All branches are parallel: each flow carries at most one token during a valid instance history, and a join waits for all its branches. This is a structural guarantee for the admitted graph, not a general BPMN soundness checker. A caller may leave an enabled task unfinished; there is no fairness or automatic-completion promise.

Tasks represent explicit acknowledgements of work in the model. A successful begin_N does not execute a business action, and complete_N does not prove that packing, payment, delivery or another physical action occurred. Bind any real action to its existing authorized owner separately; service/user/manual/ script/send/receive task types are refused by this first profile.

The importer also refuses exclusive/inclusive/event-based gateways, conditions/default flows, loops, multiple instances, event definitions, intermediate/boundary events, event subprocesses, call activities, compensation, transactions, collaborations/messages, data expressions/associations, lanes, extensions and broader diagram interchange. Unknown attributes/children are refused, not silently discarded. The accepted XML includes plain documentation and optional names; supplied IDs use a bounded ASCII XML-name subset. DTDs and external references are refused. This is not full BPMN conformance or XSD validation.

An embedded subprocess in the parallel profile can contain a plain start, tasks, parallel gateways, further embedded scopes and a plain end. Its enter and leave transitions transfer the token across its boundary. The parent waits for the child end. Cancellation drains the nested marking with the parent. Sequence flows must connect elements in the same scope, and the original node and flow bounds apply to the expanded graph. The source map identifies each scope and its boundary transitions. See embedded fulfillment.

A BPMNDI plane for an admitted process can accompany the source. The manifest preserves the original XML and indexes shape bounds, edge waypoints, labels and label styles with their source positions. Semantic references resolve against the admitted process. Geometry has no execution cost during NET firing.

The separate authored compensation profile imports compensation boundary catches, handler associations and throws around multiple service tasks. Its native scope retains each activity's effect receipts and completion order. Unsupported nested and multi-instance compensation is refused.

Replay, explanations and cancellation

The fulfillment process forks packing and invoicing. Both must complete before dispatch can begin. The replay retains each private marking, demonstrates a disabled premature join, completes the process and compares an alternative cancellation snapshot.

initial = bpmn_net.INITIAL()
started = MATCH(bpmn_net.FIRE(initial, :start), OK(r) -> r.next, ERR(e) -> e)
choices = bpmn_net.ENABLED(started, {})
explanation = bpmn_net.REPORT(started, :gateway_1)

FIRE, ENABLED and REPORT retain the native NET contracts. REPORT returns the same proposed outcome as firing, with attempted checks and place deltas; disabled operations commit nothing. Choosing a transition is explicit, including gateways. A complete empty enabled set at the completed or cancelled marking means terminal state, not a hidden task dispatch.

The added cancel transition is an explicit instance-control operation, not a BPMN Cancel Event or Terminate End Event implementation. Before completion it atomically drains ready, flow and active-task places and sets cancelled=1. No task completion or later gateway firing succeeds afterward. Cancellation before start is allowed; repeated cancellation and cancellation after completion are disabled. It neither interrupts external work nor compensates its effects. This distinction matters if an application binds modeled steps to real actions.

Each INITIAL() result is independent. Formula snapshots remain private and immutable. Live applications can explicitly select the existing Host NET owner for revision-checked marking/receipt commits and reopening. No new persistence schema, Process service, task-execution authority or scheduling path is added. The focused importer tests do not constitute a fresh full-Host durability test.

Source identity, edits and limits

bpmn_import retains the exact supplied XML, profile, process identity and mapping of flow IDs to native places and node IDs to native transition names. Half-open byte spans locate each original XML element. Join report changes to that revision's map to explain the source flow/activity. Synthetic names are based on document order; authored names remain data, never executable fragments.

Reimport edited XML to create a new definition. The ordinary NET semantic identity prevents a changed topology from reinterpreting an old marking. Metadata-only edits may preserve that semantic identity; provenance remains revision-specific. Save the native source or LIR together with its marking and manifest. Owning-source serialization, stripped LIR and native Value marking serialization preserve the workflow without reopening the XML file. Direct edits to generated source make the retained XML provenance, not a claim that it still regenerates the edited source.

Admission allows at most 128 KiB of XML, 2,048 XML events/nodes, depth 8, 8 flow nodes, 8 flows and 1 MiB accounted output. At least one task is required. Tighter caller budgets and cancellation are honored; existing native compiler, marking, report and execution limits still apply. The focused native compiler check uses an 8 MiB thread stack; the default 2 MiB Rust test-thread stack is insufficient for this generated count-NET source. This bound is not a claim of fresh Host or UI validation. Import and topology checks run once at explicit ingress. Ordinary runtime evaluation has no new profile branch, catalog lookup, worker, allocation or I/O attributable to this importer; selected firings use ordinary NET semantics.

For a supplied DMN policy and one exclusive split/merge pair, use the separate decision-routing profile. It freezes decision inputs and the selected route in each native instance.

Edit and reopen a BPMN model

Use the native model editor when a process, collaboration or choreography document needs a source-preserving edit. For example, rename a task in the fulfillment model and write the result to another file.

cargo run --manifest-path rust/Cargo.toml -p grid-format-standard --example bpmn-model -- \
  examples/workflows/fulfillment.bpmn --name Pack "Prepare parcel" > revised.bpmn

Use --position SHAPE_ID X Y to move a single diagram shape, or --message FLOW_ID MESSAGE_ID to bind a message flow to a declared local message. Edits can be combined in one invocation. With no edits the command returns the input bytes. The Rust API is bpmn::interchange::Document::{parse,edit,xml}. It accepts UTF-8 source text, enforces caller limits and cancellation, resolves local references, and preserves extension markup. It reports a conflicting edit or invalid target before returning the revised document. Diagram positions are addressed by shape ID so moving one representation of a participant leaves other representations in place.

Execution has its own admission step. Feed the edited XML to the process importer to compile a supported process to its native NET. A process-name or shape edit alone has no effect on its token flow. Interchange accepts a wider set of models than execution. Full schema validation, diagram rendering and choreography authoring remain open.

Wait for a message or an interrupting timer

In the payment example, an order enters WaitForPayment with a five-second deadline. A matching Payment completes the task and reaches Paid. If the timer fires first, it interrupts the task and reaches Expired. Explicit instance cancellation is a third terminal outcome. All three consume the same waiting token.

Import the executable XML with bpmn::import (or the bpmn-to-grid example) and compile the returned source to LIR. The manifest names the activity, message, boundary event and both authored end events. For durable delivery, prepare grid_runtime_host::net_owner::receive::ReceiveOwner with the compiled module and use the instance's model database:

Operation Effect
enter(db, instance, correlation, entered_ms) Atomically activates the task and retains its message, correlation key and absolute UTC deadline. Identical admission resumes the instance.
deliver(db, instance, delivery_id, message, correlation) Checks both the message ID and the instance key. A matching delivery can consume the active token once.
fire_due(db, instance, observed_ms) Returns no firing before the retained deadline. At or after it, the timer competes for the same token.
cancel(db, instance) / snapshot(db, instance) Cancels an active wait or reads its durable version and marking.

A host dispatcher supplies messages and timer wake-ups. Reopen the same compiled process and database after restart; the wait keeps its original deadline. The first committed firing wins. Retry an uncertain delivery with the same delivery ID, or repeat a due timeout or cancellation, to recover the winning receipt. A distinct late operation cannot change the outcome. A correlation key selects an instance's expected message; it does not grant transport authorization.

This profile admits one executable process, one local message, one receive task, and one interrupting duration timer with distinct terminal flows. Fixed day/time durations must fit 0–4,294,967,295 milliseconds exactly. Calendar years/months, repeating timers, external message payloads and multiple simultaneous subscriptions remain outside the profile. The semantics follow the receive task and interrupting boundary event in the BPMN 2.0.2 specification.

For a wait after a decision-approved service effect, use the payment and compensation composition. A timeout addresses the inverse operation to the original effect receipt and retains its consumer confirmation.