Enterprise guide · DMN 1.5
Decision tables for people who inherit COBOL.
Decision Model and Notation turns procedural rules into tables business owners can read and engines can execute. This guide covers the parts that matter when the rules come out of legacy code.
DECISION REQUIREMENTS DIAGRAM · AUTO RATING
The standard
Three layers, one model.
DMN is an Object Management Group standard for describing business decisions so that people can review them and engines can execute them. Version 1.5 is the current release. It has three layers, and extracted legacy rules use all three.
Decision requirements diagrams (DRDs) show the structure: which decisions depend on which input data and on which other decisions. A rating engine is a DRD with a premium decision at the top, factor decisions below it, and policy and driver data at the bottom. Business knowledge models package reusable logic, and knowledge sources record the authority behind a decision, such as a rate filing or a regulation.
Decision tables are the workhorse. Each row is a rule: input entries on the left, output entries on the right, and a hit policy that says what happens when more than one row matches. Nested IF statements and EVALUATE blocks map naturally onto them.
FEEL, the Friendly Enough Expression Language, fills the cells and the formula decisions. It has ranges, lists, contexts, date arithmetic and a deliberately simple null semantics: most operations on a missing value return null rather than failing, which is convenient for authors and dangerous for extracted rules that relied on a default.
For legacy work, the value of DMN is not the notation. It is that a rule extracted from a 1988 program becomes an artifact with a defined meaning, testable in an engine and readable by the people who own the policy.
Hit policies
Seven ways to resolve overlapping rules.
The hit policy is the single most important property of an extracted table. Choose it to match the legacy semantics first and readability second.
| Code | Policy | Type | Semantics | For extracted legacy rules |
|---|---|---|---|---|
| U | Unique | Single hit | Rules must not overlap. At most one rule matches any input; overlapping matches make the result invalid. | Preferred target for extracted rules once disjointness is proven. Each row reads on its own. |
| A | Any | Single hit | Rules may overlap, but every matching rule must produce the same output. Differing outputs are an error. | Useful when several legacy branches converge on the same value, such as several waivers that all set the fee to zero. |
| P | Priority | Single hit | Rules may overlap with different outputs. The output listed first in the output column's ordered values wins. | Fits severity or tiering logic where the most restrictive outcome wins. Requires an explicit ordered list of output values. |
| F | First | Single hit | Rules are evaluated in order and the first match wins. | Faithful to COBOL EVALUATE and IF ... ELSE IF chains when the order cannot be removed. Reviewers must read rows in sequence. |
| C | Collect | Multiple hit | All matching outputs, in no guaranteed order. Optional aggregators: + sum, < min, > max, # count. | Additive surcharges and discounts, or lists of applicable edits and reason codes. |
| R | Rule order | Multiple hit | All matching outputs as a list in rule order. | When downstream code consumes results in the sequence the legacy program produced them. |
| O | Output order | Multiple hit | All matching outputs as a list sorted by the output column's priority order. | Ranked results, such as every applicable reason code ordered by severity. |
Interactive
Same table, eleven answers.
One discount table, evaluated live under every hit policy and Collect aggregator. Pick Gold with an order of $1,200 and watch Unique fail while First, Priority and Collect each return something different.
Customer tier
Decision: Order discount · hit policy U
4 of 5 match| # | Tier | Order amount | Discount |
|---|---|---|---|
| R1 | "Gold" | >= 1000 | 15% |
| R2 | "Gold" | - | 10% |
| R3 | - | >= 1000 | 5% |
| R4 | "Silver" | - | 5% |
| R5 | - | - | 0% |
Output values in priority order: 15%, 10%, 5%, 0%. Inputs: tier as string, amount as number.
UNIQUE · RESULT
invalid
4 rules matched (R1, R2, R3, R5). A Unique table must not overlap.
No overlap allowed: at most one rule may match any input. If several match, the table is invalid for that input.
FEEL basics
Enough FEEL to review an extracted table.
Input cells hold unary tests: a comparison, a range, a list of values, a negated list or a dash for any value. Ranges use square brackets for inclusive and round brackets for exclusive bounds, so [21..25) means 21 up to but not including 25.
Formula decisions use literal expressions. FEEL numbers are decimal, not binary floating point, which is why extracted money arithmetic can be expressed exactly. Rounding is explicit: round half up(x, 2) matches COBOL ROUNDED, while decimal(x, 2) rounds half to even.
Watch not(...). A legacy ELSE catches every value, including invalid codes. not("B", "P") preserves that; listing the declared 88-level values instead silently narrows the rule.
1// Unary tests: what goes in an input cell2< 21 // less than 213[21..25) // 21 inclusive to 25 exclusive4"B", "P" // either value5not("B", "P") // any other value, including codes nobody declared6- // irrelevant: matches anything7null // input is missing89// Literal expressions: decisions that are formulas10round half up(basePremium * territoryFactor, 2)11if goodStudent then 0.90 else 1.0012date("2026-01-01") <= policy.effectiveDate13sum(for c in claims return c.paidAmount)
From procedure to table
How nested IFs become rows.
Each path through the decision becomes a row whose input entries are that path's conditions. The interesting rows are the ones nobody expected.
1 2400-COPAY.2 IF PLAN-HMO3 IF SVC-EMERGENCY AND NOT CLM-ADMITTED4 MOVE 250.00 TO WS-COPAY5 ELSE6 IF SVC-SPECIALIST7 MOVE 40.00 TO WS-COPAY8 ELSE9 MOVE 20.00 TO WS-COPAY10 END-IF11 END-IF12 ELSE13 MOVE ZERO TO WS-COPAY14 END-IF.
Decision: Copay · hit policy UNIQUE
5 rules| # | Plan | Service | Admitted | Copay |
|---|---|---|---|---|
| R1 | "HMO" | "ER" | false | 250.00 |
| R2review | "HMO" | "ER" | true | 20.00 |
| R3 | "HMO" | "SPEC" | - | 40.00 |
| R4 | "HMO" | not("ER","SPEC") | - | 20.00 |
| R5 | not("HMO") | - | - | 0.00 |
R2: an emergency visit that leads to admission falls into the inner ELSE and is charged the 20.00 office copay. The path is real; whether it is policy is a question for the plan owner.
- 01
Enumerate paths
Walk the control-flow graph of the paragraph from entry to every assignment of the output field.
- 02
Collect conditions
Each path's branch predicates, resolved through 88-levels, become the input entries for one row.
- 03
Pick the hit policy
Disjoint paths give a Unique table naturally. Order-dependent EVALUATE logic stays First until proven.
- 04
Attach the source
Every row keeps the file and line range of its path, so reviewers can check it against the code.
Validation
Before a table reaches production.
Five checks, in order. PYD ENTERPRISES runs the first two on export; the rest belong in your delivery pipeline.
- 1Validate against the DMN 1.5 schemaCheck the exported XML against the OMG DMN 1.5 XSD before anything else. Schema errors usually mean a typeRef or namespace mismatch, and every engine will reject them.
- 2Analyze the table for gaps and overlapsRun static decision table analysis. Drools ships a DMN validator that reports gaps and overlapping rules, and modeling tools flag structural problems. A Unique table with an overlap is a defect; a gap means some input returns null.
- 3Deploy into the target engineImport into the engine your services will call, such as Camunda or Drools, and confirm every hit policy you used is supported there. Not every engine implements Priority and Output order.
- 4Run the equivalence fixtures through the engineEvaluate the generated fixtures through the engine's own API (Camunda's decision evaluation REST endpoint, or the KIE DMN runtime in Drools) and compare results to the legacy program's outputs at the legacy field's scale.
- 5Sign off rule by ruleBusiness owners approve each row beside its source lines. Rewrites the extractor made, such as converting First to Unique, are listed with their justification and approved explicitly.
Common extraction pitfalls
Seven ways a correct-looking table is wrong.
- 01Dropping order dependenceAn EVALUATE converted to a Unique table without proving the WHEN conditions are disjoint changes behavior wherever they overlap. Keep First, or prove and rewrite.
- 02Losing the default rowWHEN OTHER and the final ELSE are rules. Leaving them out turns a defined result into null, and null propagates silently through FEEL arithmetic.
- 03Ignoring the data divisionRange boundaries depend on the PICTURE clause. [25..69] is complete for PIC 9(03) and leaves a gap for PIC 9(03)V9.
- 04Changing roundingCOBOL ROUNDED rounds half away from zero. FEEL decimal() rounds half to even. Use round half up() and round where the COBOL rounds, not once at the end.
- 05Hard-coding table-driven valuesFactors read from VSAM or DB2 tables belong in a data source with effective dates, not frozen into output cells on the day of extraction.
- 06Mixing plumbing into decisionsAbend paths, return codes for I/O errors and logging are not business outputs. Keep them out of decision tables and document them as interface behavior.
- 07Comparing padded stringsPIC X fields carry trailing spaces and EBCDIC collation. Trim and normalize before string tests, and never translate alphanumeric range tests without checking the collating sequence.
FAQ
Questions from architecture reviews.
Which DMN version should we target?
DMN 1.5 is the current OMG release and the one PYD ENTERPRISES exports. It is backward compatible in most practical respects with 1.3 and 1.4 models, and mainstream engines support the decision table and FEEL features covered in this guide. Confirm specific function support, such as the rounding functions added in 1.4, in your engine's documentation.
Should every extracted rule become a decision table?
No. Decisions with discrete conditions and outputs suit tables. Calculations suit literal FEEL expressions or boxed contexts, and orchestration logic (which program runs next) belongs in the service or workflow, not in DMN. PYD ENTERPRISES exports formulas and tables separately for that reason.
Unique or First for extracted COBOL logic?
Start from First, because it matches the COBOL semantics exactly. Convert to Unique only when the extractor or an analyst can prove the conditions are disjoint for every possible input, considering field types. Unique tables are easier for business owners to review and to change safely.
Can actuaries and analysts edit the exported tables directly?
Yes, in any DMN modeler. Changes should go back through the equivalence suite: a modified row produces new expected values, and the old fixtures are kept as superseded so the change is documented as a decision rather than a regression.
Get your decision tables from the code, not from memory.
Run PYD ENTERPRISES on up to 100,000 lines in your VPC and export DMN 1.5 tables with every row linked to its source lines.