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
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
| Policy | Meaning |
|---|---|
first | Return the first matching rule |
unique | At most one explicit rule may match |
any | Multiple explicit rules may match only if they produce equal outputs |
collect | Return 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.
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.
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
- Learn schema constraints in Schema & I/O.
- See branch behavior in Operator & Graph.
- Read the full grammar in Full Specification.