Skip to content

[Policy] Apply ​

Evaluates policy thresholds locally and converts typed answers into an action that a Mule Choice router or error handler can consume.

Inputs ​

ParameterRequiredDefaultDescription
DecisionYes—Evaluate-style JSON containing an answers object.
Policy / Question setYes—Exactly one inline policy object or question-set file containing policy.
Raise on reviewNofalseRaise TYPESAFE:BELOW_THRESHOLD for a REVIEW result.
Raise on rejectNofalseRaise TYPESAFE:REJECTED for a REJECT result.

Incoming message attributes are explicit null metadata and are not read.

Output ​

The payload is { action, routeKey, reasons, perQuestion }. The action is the most cautious result across all questions: REJECT wins over REVIEW, which wins over ACCEPT. Output attributes are null.

Policies can test:

  • Choice probability, confidence, margin, no-match behavior, and per-option thresholds / actions (options, otherOptions) so a riskier option can demand more certainty
  • Noul three-band rules (yesAbove / noBelow with onYes / onNo / onUncertain), or legacy acceptAbove / rejectBelow
  • Score accepted and review levels plus confidence

The examples below use support-ticket-triage.json with:

json
"policy": {
  "team": {
    "minProbability": 0.7,
    "minMargin": 0.15,
    "onNoMatch": "REVIEW",
    "options": {
      "other": { "action": "REVIEW", "minConfidence": 0.7 }
    }
  },
  "urgent": {
    "yesAbove": 0.7,
    "noBelow": 0.3,
    "onYes": "ACCEPT",
    "onNo": "ACCEPT",
    "onUncertain": "REVIEW"
  }
}

ACCEPT ​

Decision answers clear both thresholds (billing 0.89, urgent 0.98):

json
{
  "action": "ACCEPT",
  "routeKey": "billing",
  "reasons": [],
  "perQuestion": {
    "team": { "action": "ACCEPT" },
    "urgent": { "action": "ACCEPT" }
  }
}

REVIEW ​

Decision answers fall below thresholds (billing 0.55, urgent 0.55):

json
{
  "action": "REVIEW",
  "routeKey": "billing",
  "reasons": [
    "team: probability 0.55 < 0.7",
    "urgent: noul 0.55 is between 0.3 and 0.7"
  ],
  "perQuestion": {
    "team": {
      "action": "REVIEW",
      "reasons": ["team: probability 0.55 < 0.7"]
    },
    "urgent": {
      "action": "REVIEW",
      "reasons": ["urgent: noul 0.55 is between 0.3 and 0.7"]
    }
  }
}

routeKey is the Choice answer for policy.routeQuestion when that key is set (for example "routeQuestion": "team"), otherwise the first Choice answer in the decision. Reordering questions no longer silently changes the route. A router can still branch on routeKey when the overall action is REVIEW.

Fails closed ​

Since 1.0.2, a policy that has nothing to judge returns REVIEW, never ACCEPT:

SituationReason in the payload
The decision has no answers, for example {} or the wrong variabledecision has no answers to judge
A policy rule's question has no answerurgent: no answer to judge
A rule's keys do not fit the answer's typeteam: rule does not fit a 'choice' answer

The second case catches a common mistake. A shortcut operation (ask-noul, choose, score) returns a single answer, which is judged as the question result. A question-set policy keyed by real question ids therefore finds no answer to judge.

Policy validation ​

The policy is checked before it is applied, and an invalid policy raises TYPESAFE:INVALID_QUESTION_SET listing every problem. A policy from a question-set file is checked against that file's questions. An inline policy is checked for structure only.

  • A rule for a question id that does not exist
  • An unknown or misspelt key, such as minProbabilty
  • A key for a different question type, such as acceptAbove on a Choice
  • A threshold that is not a number from 0 to 1
  • An action (onNoMatch, otherOptions, onYes, onNo, onUncertain) other than ACCEPT, REVIEW, or REJECT
  • Mixing three-band Noul (yesAbove / noBelow) with legacy acceptAbove / rejectBelow, or inverted bands
  • A Score level out of range, not a number, or in both acceptLevels and reviewLevels
  • A Score rule with neither acceptLevels nor reviewLevels, which would reject every answer
  • An options.<id> entry that is not a criteria option, or that carries an unknown key

Run Validate Question Set on the file to see the same errors, plus warnings, before deploying.

Errors ​

ErrorWhen
TYPESAFE:INVALID_QUESTION_SETThe decision or policy is not JSON, both or neither of Policy and Question set are given, the file has no policy block, or the policy fails validation.
TYPESAFE:BELOW_THRESHOLDRaise on review is true and the action is REVIEW.
TYPESAFE:REJECTEDRaise on reject is true and the action is REJECT.

Before 1.0.2, raiseOnReject and raiseOnReview never worked as typed errors: the operation threw TYPESAFE:REJECTED / TYPESAFE:BELOW_THRESHOLD, but those types were not declared on the operation, so Mule raised MULE:UNKNOWN and handlers for the typed errors never matched.

Provider call ​

None. The operation is deterministic and runs entirely inside Mule. It does not read the connection or API version.

XML example ​

xml
<typesafe:apply-policy
    config-ref="TypeSafe_Config"
    questionSet="support-ticket-triage.json"
    target="policyResult">
    <typesafe:decision>#[payload]</typesafe:decision>
</typesafe:apply-policy>

<choice>
    <when expression="#[vars.policyResult.action == 'ACCEPT']">
        <!-- continue automatically -->
    </when>
    <when expression="#[vars.policyResult.action == 'REVIEW']">
        <!-- send to a human -->
    </when>
    <otherwise>
        <!-- reject -->
    </otherwise>
</choice>

The question-set file must declare a policy block.

See also ​

Released under the MIT License.