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.