Skip to content

Decision Tables ​

Decision tables are rule nodes for cases where a branch expression is too small and a custom operator is too opaque. They keep business classification logic visible in the DSL while compiling back into the normal BLOGE graph model.

Basic Shape ​

bloge
decision_table loan_terms(
  score = applicant.output.score,
  amount = loan.output.amount
) hit=unique -> { rate: Decimal, maxTerm: Int } {
  rule (score: score >= 750, amount: amount <= 500000) -> { rate: 3.5, maxTerm: 30 }
  rule (score: score >= 680, amount: amount <= 200000) -> { rate: 4.5, maxTerm: 20 }
  otherwise -> { rate: 6.0, maxTerm: 5 }
}

node priceLoan : PriceLoanOperator {
  input {
    rate = loan_terms.output.rate
    term = loan_terms.output.maxTerm
  }
}

The parameter list binds local rule names to ctx or upstream output expressions. Those bindings are where dependency inference happens.

Hit Policies ​

PolicyMeaning
firstReturn the first matching rule
uniqueAt most one explicit rule may match
anyMultiple explicit rules may match only if they produce equal outputs
collectReturn all matching rule outputs

For first, unique, and any, scalar output is read through node.output.value. Named object outputs are read through node.output.<field>. For collect, matching outputs are exposed through node.output.items.

Rule Conditions ​

Rule expressions can use the local parameters declared in the decision table header.

bloge
decision_table routing(
  tier = customer.output.tier,
  sentiment = analysis.output.sentiment
) hit=first -> String {
  rule (tier: tier == "vip") -> "vipQueue"
  rule (sentiment: sentiment == "angry") -> "priorityQueue"
  otherwise -> "standardQueue"
}

Rule bodies should not directly read ctx.* or upstream node outputs. Bind those values as named parameters first so dependency inference remains centralized and auditable.

Membership Conditions ​

Decision table conditions support in membership checks. The right side can be a literal array or a collection-valued table parameter.

bloge
decision_table customer_route(
  type = customer.output.type,
  allowed = ctx.allowedCustomerTypes
) hit=first -> String {
  rule (type: type in ["vip", "enterprise"]) -> "priority"
  rule (type: type in allowed) -> "standard"
  otherwise -> "manual"
}

If a dynamic in right-hand side does not resolve to a collection, runtime raises a stable decision-table violation code instead of a generic argument error.

Output Shape Rules ​

Within one table, all rule rows and the otherwise row must use compatible output shape:

  • all scalar outputs, or
  • all object outputs with the same field set.

This prevents downstream nodes from depending on a field that only exists for some matching rules.

When To Use ​

Use decision tables when:

  • routing logic has many explicit rules
  • business reviewers need to see rule rows directly
  • hit-policy semantics matter
  • output shape should remain schema-visible

Use a normal operator when:

  • the logic is algorithmic rather than rule-shaped
  • rules need external data access
  • the decision owns a separate SLA or side effect

Next Steps ​