Skip to content
DMN templates

DMN — Loan Risk Category (complete, no overlap)

The canonical worked example: a decision requirement diagram feeding a UNIQUE-hit table whose rules cover the whole declared input space exactly once. Copy this one — it is the shape a decision table is supposed to have, and the engine reports it as complete because it is, not because nothing was checked.

Template previewDMN
Consumer loan riskLending policy 2026Applicant detailsCredit bureau fileScorecard v4Risk categoryOffer decisioninformation requirementknowledge requirementauthority requirementRisk category — UniqueUAge[18..120]Score[300..850]Band{ Low, Medium, High }AnnotationR1[18..30)[300..600)Highyoung file, thin historyR2[18..30)[600..850]MediumR3[30..120][300..550)HighR4[30..120][550..700)MediumR5[30..120][700..850]LowOffer decision — UniqueUBand{ Low, Medium, High }Ltv[0..100]Result{ Approve, Refer, Decline }R1Low[0..85)ApproveR2Low[85..100]ReferR3Medium[0..75)ApproveR4Medium[75..100]ReferR5High[0..60)ReferR6High[60..100]DeclineNo overlaps and no gaps over the declared input space · 2 decisions · 2 input data · 1 knowledge model · 1 knowledge source · 2 tables · …Every rule pair is disjoint and every declared input combination matches a rule.

Make it your own.

title "Consumer loan risk"

input     Applicant "Applicant details"
input     Bureau    "Credit bureau file"
source    Policy    "Lending policy 2026"
bkm       Scoring   "Scorecard v4"
decision  Risk      "Risk category"
decision  Offer     "Offer decision"

Applicant -> Risk
Bureau    -> Risk
Scoring   -> Risk
Policy    -> Scoring
Risk      -> Offer
Policy    -> Offer

decision Risk "Risk category" {
  hit U
  input  Age    number [18..120]
  input  Score  number [300..850]
  output Band   enum   { Low, Medium, High }

  // Half-open on purpose. A number column is a CONTINUOUS domain here, so
  // [18..29] and [30..120] leave the sliver (29..30) uncovered and the
  // checker is right to say so — writing an integer partition as though
  // the domain were integral is the commonest way a table that looks
  // complete is not.
  rule [18..30)  | [300..600) -> High    // young file, thin history
  rule [18..30)  | [600..850] -> Medium
  rule [30..120] | [300..550) -> High
  rule [30..120] | [550..700) -> Medium
  rule [30..120] | [700..850] -> Low
}

decision Offer "Offer decision" {
  hit U
  input  Band enum   { Low, Medium, High }
  input  Ltv  number [0..100]
  output Result enum { Approve, Refer, Decline }

  rule Low    | [0..85)   -> Approve
  rule Low    | [85..100] -> Refer
  rule Medium | [0..75)   -> Approve
  rule Medium | [75..100] -> Refer
  rule High   | [0..60)   -> Refer
  rule High   | [60..100] -> Decline
}