Importing DMN decisions
Import a supplied DMN table once, inspect its native source, and use it in ordinary calculations or an isolated EXPERIMENT. Decision tables lower to existing DECISION callables. DMN 1.6…
Importing DMN decisions
Import a supplied DMN table once, inspect its native source, and use it in ordinary calculations or an isolated EXPERIMENT. Decision tables lower to existing DECISION callables. DMN 1.6 numeric and Boolean literal-expression graphs lower to native callables on the same LIR runtime.
The explicit Rust API is grid_format_standard::dmn::import(text, context).
The maintained local adapter prints editable Grid source:
cargo run --offline --manifest-path rust/Cargo.toml -p grid-format-standard --example dmn-to-grid -- examples/decisions/shipping.dmn > /tmp/shipping.grid
cat examples/decisions/shipping-study.grid >> /tmp/shipping.grid
The source can also be a library loaded through ordinary USE ... AS ....
The fixed generated names live in that module. Run the generated source through
the existing native compiler and runtime; importing or reading a definition
starts no study job.
Decision table profiles
The importer selects dmn-1.5-scalar-decision-v1 or dmn-1.6-scalar-decision-v1 from the model namespace. An explicit FEEL namespace must match that version. Both admit the same bounded decision-table values and unary tests. DMN 1.5 · DMN 1.6
The model and FEEL namespace dates are 20230324 for 1.5 and 20240513 for 1.6.
XML prefixes may vary; namespace identity may not. XML text, predefined/numeric
entities and CDATA carry the same bounded FEEL entry text. DTDs are refused.
| Input | Supported meaning |
|---|---|
| Model | One decision table, explicit inputData variables and local requiredInput references; one input column per variable |
| Types | Non-null strings, booleans and exact integers from −9,007,199,254,740,991 through +9,007,199,254,740,991 |
| Unary tests | -, a typed literal, numeric <, <=, >, >=, =, ranges such as [0..5] and (5..100], literal/comparison/range alternatives separated by commas, and not(...) over those alternatives |
| Strings | Case-sensitive equality, Unicode text, and quote/backslash/newline/carriage-return/tab escapes |
| Outputs | Declared scalar types with literal values; multiple output columns become a record |
| Hit policies | UNIQUE (the default), FIRST, ANY, PRIORITY, RULE ORDER, OUTPUT ORDER and COLLECT |
| Default | Literal defaultOutputEntry for every output, or none |
Inputs to this profile are plain native scalar values. Native refinements and
encoded object carriers are not FEEL inputs and are not normalized by the importer.
Numeric literals use signed decimal integer spelling, without decimal points
or exponents. No decimal arithmetic or implicit coercion is introduced. Numeric strings,
fractions, nonfinite numbers, null/Option inputs and wrong input types fail
before matching. Runtime profile failures return native #N/A; import
failures return located GRID_DMN_PROFILE diagnostics or the existing XML/
parser-limit diagnostic. Compiler/runtime errors remain explicit.
RULE ORDER preserves authored order and duplicate hits. OUTPUT ORDER sorts matches by declared output priorities, comparing ranked columns from left to right. PRIORITY selects the highest ranked match, comparing ranked columns left to right. COLLECT returns a vector or applies COUNT, SUM, MIN or MAX to a single column. Numeric aggregation accepts exact integers. SUM bounds the total absolute magnitude before admitting the table. An unmatched input returns the authored default or NONE. The manifest records the authored hit policy and aggregation. The native report records the policy used by the emitted DECISION callable.
An input clause may restrict values with supported unary tests. An output clause may declare an ordered list of permitted literals. A single unnamed output can inherit the decision name and its declared type. Named primitive and list aliases resolve during admission. Structural declarations can accompany a model, but executable structural operands, general expressions, nullable logic, temporal values and cross-decision references in tables remain open. The source retains supported DMNDI geometry and style-neutral metadata, including the schema location as inert text.
Native values and explanations
The checked entrypoints take positional arguments in input-column order:
quote = dmn_decision(8, FALSE, "US")
explanation = dmn_report(8, FALSE, "US")
price = MATCH(quote, SOME(value) -> value.output_0, NONE() -> -1)
A present single output becomes SOME(value). For a list-valued decision, value is the vector of matching outputs. Multiple outputs become
SOME({output_0: ..., output_1: ...}), preserving XML column order. The manifest
maps these field names to the authored output names. With no matching rule and
no default, the result is NONE(); FEEL null is not silently converted to zero,
an empty string or a missing cell. A supplied default becomes SOME(default).
Null output literals are refused in this profile.
dmn_report uses the original native .REPORT companion: matched/evaluated
rules, matching completeness, defaults and Result outcomes retain their usual
meaning. UNIQUE overlaps and ANY disagreement produce DECISION_CONFLICT.
FIRST stops on the first match. A missing result uses the generated ELSE NONE() and therefore reports native status default. This represents a DMN
no-result, not a matched row. Input-profile failures happen before the table
call and are ordinary errors rather than successful report records.
dmn_table is the generated internal DECISION definition. Use the checked
entrypoints to retain the import's input contract. Table evaluation uses the native decision kernel.
Source identity, edits and studies
dmn_import retains the profile, original XML, decision identity and positional
input/output/rule mapping. Each rule maps its original XML ID to a unique
dmn_rule_N label and half-open original byte span. Explanations use these
native labels; join them to the manifest to locate the authored rule. Rule
labels follow source order, so retain the manifest belonging to that revision.
The shipping XML and study compare weights 2 and 8, retaining prices, services, selected rules and matching completeness. Project records and Options to scalar observations for the existing retained Frame workflow. Study isolation, cancellation and explicit job ownership are reused.
Reimport edited XML to produce a new native definition. Existing source/LIR snapshots retain their old table and manifest. Native owning-source serialization and stripped LIR preserve values, explanations and source mapping without reopening the XML file or fetching anything. Generated source is editable too; if you edit it directly, the retained XML is provenance, not a claim that it still regenerates that modified definition.
Admission caps supplied text at 256 KiB, XML events/nodes at 8,192, depth at 16, inputs/outputs at 16 each, rows at 256, each FEEL entry at 4,096 bytes/256 tokens, and accounted emitted data at 2 MiB. Tighter caller limits and cancellation are honored. Existing compiler, native decision/report and study limits remain active after admission.
Decimal and nullable decision graphs
The DMN 1.6 graph profile evaluates local requiredDecision dependencies. The invoice example declares its release decision first in the XML. It computes a subtotal, compares the exact subtotal with 0.30, then checks eligibility and the hold flag. The report exposes each decision by the native field listed in dmn_import.mapping. Invoice DMN · Grid caller
cargo run --offline --manifest-path rust/Cargo.toml -p grid-format-standard --example dmn-to-grid -- examples/decisions/decimal-invoice.dmn > /tmp/invoice.grid
cat examples/decisions/decimal-invoice.grid >> /tmp/invoice.grid
Supply numeric inputs with dmn_decimal("0.1"), Boolean inputs with SOME(FALSE) or SOME(TRUE), and explicit FEEL null with NONE(). Arguments follow XML input declaration order. In the example, 0.1 produces a subtotal of 0.3 and releases the invoice. A price of 0.1000000000000000000000000000000001 changes eligibility to false. An unknown hold makes an otherwise eligible release null. Compare, project and retain the result through ordinary LIR. dmn_decimal_text(value) returns optional canonical decimal text for display or interchange.
Numbers use 34 significant decimal digits, round to nearest with ties to even, and support finite subnormals down to 1E-6176. Addition, subtraction, multiplication, division and comparisons preserve decimal precision. Overflow and division by zero yield FEEL null. Malformed decimal text and incorrectly bound values produce native errors. A decimal value travels as an Option containing a tuple of four exact integers through saved LIR and native value serialization. Use the conversion functions at the boundary. DMN 1.6, FEEL semantics
The profile admits up to 16 number or Boolean inputs and 32 literal-expression decisions with a single terminal decision. Names resolve through explicit, acyclic local requirements. Expressions admit arithmetic, comparisons, and, or, not(...) and if … then … else …. Equality treats two nulls as equal. Ordered comparisons with null return null. False determines a conjunction and true determines a disjunction even if the other operand is null. A null condition takes the else branch. See the linked profile below for document imports and collections. Temporal values and the full FEEL function library remain open.
A decision table inside a decimal graph
In the discount invoice, Subtotal adds 0.2 to the supplied price. Discount applies a DMN UNIQUE table to that subtotal. Final amount subtracts the selected discount. At a price of 0.1 the threshold rule selects 0.01 and the final amount is 0.29. Raising the price to 0.1000000000000000000000000000000001 selects the next rule, which discounts 0.02. Import the model with dmn-to-grid and append its caller as in the preceding example. Discount invoice DMN · Grid caller
The mixed DMN 1.6 profile admits one single-column, single-output numeric table alongside local literal-expression decisions. The input expression names a numeric input or decision declared as a requirement. A rule can use a decimal equality or ordered threshold, null or the wildcard -. Its output is a decimal literal or null. A missing hit policy defaults to UNIQUE. Authored defaults, compound unary tests and other hit policies in this profile remain open.
Use dmn_decision for the terminal value. Use dmn_report to inspect intermediate decisions and the native table_report. Join its matched_rules labels to the table's rules in dmn_import.mapping for original XML IDs and byte spans. A matched null carries a rule label. No match carries an empty list and a null result from the implicit fallback. On overlapping rules, the value call raises DECISION_CONFLICT; the report retains both labels and the completed predecessors. Evaluation stops before the downstream expression.
Return an invoice quote as a boxed context
The quote invoice uses a terminal DMN context to return a native record with three fields. Its first two named entries read the subtotal and discount decisions. Its third entry computes subtotal - discount using those earlier entries. At a price of 0.1 the three values are 0.3, 0.01 and 0.29. A caller can keep the entire quote or project a single field. Quote DMN · Grid caller
quote = dmn_decision(dmn_decimal("0.1"))
amount = dmn_decimal_text(quote.amountDue)
The dmn-1.6-flat-context-graph-v1 profile admits one terminal context with 1–16 named literal-expression entries. Each entry can use declared graph requirements and earlier entries. Names are case-sensitive. Duplicate names and unresolved references fail during import. Numeric, Boolean and null values retain their native representations. Entry types can be inferred or explicitly declared as number or boolean. A context result can omit its type or declare context or Any. The manifest records the ordered field names, types and source spans.
With no discount match, the quote still contains all three fields. The subtotal stays available, while discount and amountDue are null. On a UNIQUE conflict, evaluation stops before constructing the quote and the table report retains its matched rules. Nested contexts, anonymous final entries and passing a context to another DMN decision remain open.
Call the named invoice decision service
The DMN Invoice Quote service declares Price as its input data and Quote as its output decision. Subtotal and Discount are encapsulated decisions. The service returns their values as authored fields of the quote, alongside amountDue. At a price of 0.1, the amount due is 0.29. Service DMN · Grid caller
quote = dmn_service_invoice_quote(dmn_decimal("0.1"))
amount = dmn_decimal_text(quote.amountDue)
Import the XML with dmn-to-grid as above. The callable name is dmn_service_ followed by the lowercased service name with spaces converted to underscores. dmn_import.decisionService records that name, the input and output bindings, and the original encapsulated decision IDs. The service takes one positional typed decimal or explicit null. A bare Grid number is a binding error. Null retains all three quote fields. Overlapping UNIQUE rows propagate DECISION_CONFLICT to the caller.
The dmn-1.6-quote-service-v1 profile admits one local service over the complete graph, with one required numeric input and one terminal boxed-context output. Every other decision must appear exactly once in encapsulatedDecision. The importer checks fragment targets and requires the declared roles to match the graph. Intermediate bindings, the table and its report stay within the service call. Multiple services or outputs, supplied input decisions, cross-model references and declared function types remain open.
Link decision requirements across supplied models
dmn-to-grid accepts a primary model followed by its dependency documents. For example, this imports the upstream greeting decision with the document that defines the person type and the greeting function.
fixtures=rust/grid-format-standard/tests/fixtures/dmn-tck/0086-import
cargo run --offline --manifest-path rust/Cargo.toml -p grid-format-standard --example dmn-to-grid -- "$fixtures/0086-import.dmn" "$fixtures/Imported_Model.dmn" > /tmp/greeting.grid
The Rust API is dmn::import_with_dependencies(source, dependencies, context). Supply XML text directly. The linker matches each declared import by namespace, resolves local and qualified references, and checks dependency cycles and reference roles. All source documents remain in the manifest for provenance. The linked profile admits DMN 1.5 and 1.6 models with business knowledge models, document imports or multiple services. DMN 1.5 expression graphs also use this path.
For linked models, look up the authored decision or service name in dmn_import.entries. Its native field names the callable. Read inputs and inputNamespaces together for each positional argument’s name and source namespace. A named import makes directly required data and decisions visible through its alias. An unnamed import makes them visible without a prefix. Multiple import paths to the same input share its identity. A decision computes its transitive prerequisites once per call. A service binds its input data and supplied decisions within its own call scope. A single service output returns its value directly. Multiple outputs return a record keyed by their authored names.
Numeric and Boolean scalars use the same nullable native bindings as the quote workflow. Supply a string as SOME("text"), null as NONE(), and a structured input as a native RECORD keyed by the item component names. Boxed contexts can return a nested record or the value of an anonymous final entry. Both boxed invocations and named or positional FEEL calls lower to ordinary LIR callables.
A collection input is a native VECTOR whose members retain their FEEL types. The portfolio example passes a list of loan records into for i in Loans return PMT2(i), calls the authored payment model with each record and returns a vector of exact decimal payments. The employee example filters a typed record list by department and projects employee names. Boxed lists, relations, filters, for, some and every use the same LIR records, vectors and folds. Quantifiers validate the predicate for every item. On an empty list, some returns false and every returns true. Loan portfolio · Employee filter
Linked tables currently cover single-output UNIQUE, FIRST, literal-ranked PRIORITY and decimal COLLECT SUM, MIN and MAX. A standalone table with fractional literal outputs in one of those aggregations also uses decimal lowering. Linked graphs support three-valued conjunction and disjunction, boxed conditionals, FEEL comments and the string length and case functions. Finite Decimal128 integer powers support absolute exponents through 4096 with a single final rounding. Fractional powers, full FEEL temporal and collection semantics, more table profiles and full diagram interchange remain open. Pinned independent models
Route a process instance
The bounded BPMN decision-routing profile connects a single-output DMN policy to explicit exclusive flow bindings. Evaluate once at instance creation, retain the report and inputs, then complete, explain, cancel or reopen the instance using the existing native NET owner.