WORK IN PROGRESSDraft docs — content and examples are still being refined.
Information model

Decisions & resolvers

Every automated and manual ruling in a case is captured as a Decision on state.decisions[]. When a decision needs to be settled — a policy hit approved, a re-run superseded — a decisionResolver links the settling decision to the one it clears. Together they form an auditable chain from 'flagged' to 'resolved'.

The four kinds

What a Decision can be

Each record carries a decisionKind, an output with a result (GREEN / YELLOW / BLUE / RED) and usually a code + policyId, and the input it was evaluated against.

SYSTEM_DECISION

Emitted by the process code itself — screening outcomes, "already approved" shortcuts, derived gates. No DMN table behind it.

DMN_POLICY_DECISION

One per policy rule that fires in a decision table (e.g. evaluate-application). Carries a code and policyId, and a result that gates the case.

HUMAN_DECISION

A caseworker’s explicit ruling — approve or reject a specific hit. Records who decided and, via a resolver, which policy hit it settles.

DMN_BUSINESS_DECISION

Not a gate — a rule that computes an output the process consumes, such as which documents to generate for a channel.

A decisionResolver is a small link — sourceId (the decision doing the resolving) → targetId (the hit being cleared) + a reason. Chains of them let a case re-evaluate safely: a re-fired BLUE hit is resolved by pointing back at the human approval that already cleared its identical predecessor.

Worked example

One case, from start to approved application

A single hit, start to finish: evaluate-stakeholder raises a BLUE INCOME_DEVIATION, a caseworker assesses it, and a resolver links the approval back to the hit — turning it into a settled, auditable outcome.

DECISION KINDS
SYSTEMDMN POLICYDMN BUSINESSHUMAN
RESULT — WHAT IT MEANS
GREEN automatically approvedYELLOW manual handlingBLUE needs a human assessment (not full manual handling)RED automatic rejection
THE CHAIN

Each arrow is a decisionResolver source → target with its reason. Read left-to-right to see a hit assessed, then re-confirmed on re-assessment.

THE RULE

After each assessment the engine looks at every unresolved decision — the terminal end of each resolver chain. If they are all GREEN, the application is approved. Otherwise it acts on what remains: an unresolved BLUE asks a human to assess it, a YELLOW goes to manual handling, a RED rejects.

1 · The tables run — all GREEN except one
screen-partyNO_HITSGREEN
screen-affordabilityNO_HITSGREEN
evaluate-householdNO_HITSGREEN
evaluate-stakeholderINCOME_DEVIATIONBLUE

The screening tables pass cleanly. evaluate-stakeholder raises a BLUE INCOME_DEVIATION — the one thing needing a human.

2 · Assessed once, then re-used across re-assessments
Needs assessmentDMN POLICY
INCOME_DEVIATION
evaluate-stakeholder
incomeDeviationPercent: −14
RESOLVESDocumentation reviewed and approved by caseworker
ApprovedHUMAN
INCOME_DEVIATION
documentation verified
RE-ASSESSEDHit re-evaluated with identical result
Needs assessmentDMN POLICY
INCOME_DEVIATION
evaluate-stakeholder
incomeDeviationPercent: −14
re-fired on re-assessment · same input
RESOLVESPreviously approved by HUMAN_DECISION with identical input
ApprovedSYSTEM
ALREADY_APPROVED_HUMAN_DECISION
approvedByDecisionId → the human decision

The case is re-assessed whenever the picture changes — which can happen many times through the flow. Each re-run re-fires the hit as a fresh record, but isPolicyDecisionApproved() re-uses the caseworker’s approval as long as the DMN input is identical (matched on code::referenceId + unchanged input). Change the basis and the hit re-opens.

Outcome: after resolution every unresolved decision is GREEN — the application is approved, with the whole assessment trail preserved.