Coming from DMN
In short: a DMN decision table is a set of rows plus a hit policy
that says what happens when several rows match. In Arxo there is no
table-wide hit policy: each row is a defeasible rule, and what DMN
decides through the hit policy is written where it applies. Rows that
agree simply support the same conclusion; rows that disagree both fire
until a priority says which wins; first-hit order is an
explicit guard; a default output is a closure over the cases on file;
and a missing input is an answer of its own, NEITHER. This page
follows the portable table of the DMN comparison.
The Arxo package quoted here passes law engine check; its scenarios and
the DMN engines of the experiment have not been run yet, so the page
shows how the table is written, not measured outcomes.
Concept map
Section titled “Concept map”| DMN | Arxo | What changes for you |
|---|---|---|
| A row of a decision table | A rule … defeasible: the input entries become the when condition, the output entry becomes the head | Each row has a name, and an answer can say which rows supported it |
| UNIQUE or ANY: rows overlap and disagree (a runtime incident in the table engines) | Two rules that both fire for the case, with no priority between them; Arxo’s tabular form reports the same overlap statically, before execution | A violated hit policy is something you see in the answer or in a diagnostic, rather than an engine failure |
| COLLECT with rows that agree | Several rules with the same head: each is an independent support | Agreement needs no policy |
| FIRST | The later row carries a guard, not <earlier conclusion>, that encodes the order of the source table | Row order is spelled out in the rule that depends on it |
| PRIORITY (excluded from the portable baseline) | Precedence between particular rules is a priority with a reason | There is no table-wide ordering of outputs |
| Default output entry, no match | A closure over the cases on file: a case in the domain with no supporting row gets an explicit negative | The default applies only to the cases the register covers |
| Null input | Absent facts: a predicate without a closure answers NEITHER; a closed predicate answers FALSE_ONLY | The difference between “unknown” and “no” is chosen per predicate, not per engine |
| A table edit that changes a threshold | An exception rule with a priority and reason explicit_exception; it needs the revision fact to fire | Cases under the old revision are untouched by the new rule |
| COLLECT aggregation (SUM, MIN, MAX, COUNT) and list outputs | Not built by this package: it names which rows fired; the aggregated values stay in the neutral case bank | Parity here is observed, not computed |
A row is a rule
Section titled “A row is a rule”Here is a table from the DMN conformance test suite that the experiment uses as an input: two rows, a COLLECT policy with MAX aggregation, and a default output of 0.
<decisionTable aggregation="MAX" hitPolicy="COLLECT"> <input id="d_Extra_days_case_1_dt_i_age" label="Age"> <inputExpression typeRef="number"> <text>Age</text> </inputExpression> </input> <input id="d_Extra_days_case_1_dt_i_years" label="Years of Service"> <inputExpression typeRef="number"> <text>Years of Service</text> </inputExpression> </input> <output id="d_Extra_days_case_1_dt_o" label="Extra days"> <defaultOutputEntry> <text>0</text> </defaultOutputEntry> </output> <rule id="d_Extra_days_case_1_dt_r1"> <inputEntry id="d_Extra_days_case_1_dt_r1_i1"> <text><18,>=60</text> </inputEntry> <inputEntry id="d_Extra_days_case_1_dt_r1_i2"> <text>-</text> </inputEntry> <outputEntry id="d_Extra_days_case_1_dt_r1_o1"> <text>5</text> </outputEntry> </rule> <rule id="d_Extra_days_case_1_dt_r2"> <inputEntry id="d_Extra_days_case_1_dt_r2_i1"> <text>-</text> </inputEntry> <inputEntry id="d_Extra_days_case_1_dt_r2_i2"> <text>>=30</text> </inputEntry> <outputEntry id="d_Extra_days_case_1_dt_r2_o1"> <text>5</text> </outputEntry> </rule> </decisionTable>The Arxo package encodes the experiment’s own portable table rather than
this file line by line, but the closest pair of rows looks like this: two
rows granting the same extra amount, one for long service and one for a
young employee. In this package the input bands arrive as facts about the
case (years_long, age_minor), so the FEEL tests do not appear in the
rule bodies; and the package covers only the under-18 band of the first
row above.
rule ExtraVeteran defeasible { for c: Case; when years_long(c); then extra5(c);}
rule ExtraYoung defeasible { for c: Case; when age_minor(c); then extra5(c);}When both rows match, both rules support extra5(c). There is nothing to
reconcile, so there is no hit policy to choose.
Overlap that disagrees
Section titled “Overlap that disagrees”Under UNIQUE or ANY, two matching rows with different outputs are an error in the table engines. In Arxo the same situation is two rules with different conclusions for one case and no priority between them:
rule ConflictA defeasible { for c: Case; when overlap_case(c); then award_standard(c);}
rule ConflictB defeasible { for c: Case; when overlap_case(c); then award_senior(c);}Both rules fire, and nothing in the package picks one: the priority is left out on purpose, so the overlap stays in the answer for a person to resolve. For the same table in Arxo’s tabular form, the overlap is reported before execution. The DMN comparison calls this a difference of stage, not of meaning.
First hit as an explicit guard
Section titled “First hit as an explicit guard”FIRST makes the order of rows part of the table’s meaning. In Arxo the
order is written into the rule that depends on it: the second row only
fires when the first row’s outcome is established false, which here
comes from the closure on award_standard shown below.
rule FirstRow1 defeasible { for c: Case; when first_case(c); then award_standard(c);}
rule FirstRow2 defeasible { for c: Case; when first_case(c) and not award_standard(c); then award_senior(c);}A negative literal in a body needs the fact to be established false, so
when FirstRow1 fires, FirstRow2 stays silent. The experiment also
switches one table from a conflicting policy to FIRST; on the Arxo side
the same pair of rules covers the switched revision.
Default output and edits
Section titled “Default output and edits”A default output entry answers when no row matches. The Arxo counterpart is a closure: a statement that the register of cases is complete as of a given time, so a case in it with no supporting row is explicitly not awarded the standard outcome. Rules that do support it are not affected.
closure AwardDefault { predicate award_standard; domain case_on_file; snapshot "urn:stand:dmn-hitoverlap:cases:2026-09-30"; complete_as_of @2026-09-30T00:00:00Z; derive_explicit_negative true;}A table edit that moves an age threshold from 18 to 21 becomes an exception rule that only fires with the revision fact, plus a priority over the row it overrides:
rule Threshold21Exception defeasible { for c: Case; when rev_b_threshold_21(c) and age_young_edge(c); then not award_standard(c);}
priority Threshold21OverStd { prefer Threshold21Exception over RowStd; reason explicit_exception;}What you gain, what you give up
Section titled “What you gain, what you give up”- Gain: a named policy per conflict. Instead of one hit policy for the whole table, each overlap is either agreement, a declared priority with a reason, or a conflict kept visible.
- Gain: “unknown” separate from “no”. A missing input does not have to be folded into the default; the DMN comparison notes that the standard leaves no match and null input open and engines diverge.
- Give up: the table as the reading surface. Analysts read a DMN table directly, in mature editors, and exchange it between engines through a shared interchange file with a community conformance suite. This page shows the rule form, and this package does not compute aggregations or list outputs.
- Combining rather than replacing. The comparison’s combined pattern keeps the tabular fragment in DMN and lets Arxo frame it with editions, conflicts and review trails.
Next steps
Section titled “Next steps”- DMN: the full comparison, the studied engines and what is still open.
- Defeasible rules and unless, Priority, Negation and truth statuses: the constructs used on this page.
- Missing and conflicting facts:
NEITHERandBOTHin a worked example. - Guide: getting started with Arxo.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.