Evaluation Logic Reference
This comprehensive guide explains the shared evaluation logic used across Rule Sets, Decision Tables, Scorecards, and Decision Trees. Understanding these fundamentals will help you work effectively with any decision logic component in Decisimo.
All evaluation logic components in Decisimo use the same underlying operators and condition evaluation mechanisms, ensuring consistent behavior across the platform.
🎯 Quick Navigation
-
Operators Reference - Complete list of all available operators
-
Condition Types - Simple vs. group conditions
-
Testing Patterns - Unit tests, object tests, and simulation
-
Debugging & Tracing - Understanding verbose output and troubleshooting
Operators Reference
All decision logic components use the same set of operators for evaluating conditions. When you right-click on conditions in Decision Tables, bins in Scorecards, or define conditions in Rule Sets and Decision Trees, you'll see these operators available in the dropdown menus.
Numeric Comparison Operators
These operators compare numeric values and support international number formats, currency symbols, and locale-aware parsing.
| Symbol | Name | Description | Examples |
|---|---|---|---|
| > | Greater than | Value A is greater than Value B | 50000 > 25000, "$1,000.50" > "500" |
| ≥ | Greater than or equal to | Value A is greater than or equal to Value B | 18 ≥ 18, "1,000" ≥ "999" |
| < | Less than | Value A is less than Value B | 25 < 65, 0.15 < 0.30 |
| ≤ | Less than or equal to | Value A is less than or equal to Value B | 65 ≤ 65, "999" ≤ "1000" |
| = | Equal to | Values are exactly equal | "PREMIUM" = "PREMIUM", 100 = 100 |
| ≈ | Loose equal to | Values match with intelligent type conversion and locale handling | 1000 ≈ "1,000.00", "1.234,56" ≈ "1234.56" |
| ≠ | Not equal to | Values are not equal | "BASIC" ≠ "PREMIUM", 25 ≠ 30 |
Examples in Different Components:
Rule Set Conditions:
$.loan_amount > 50000(Loan amount greater than $50,000)$.customer_age ≥ 18(Customer must be 18 or older)
Decision Table Columns:
$.credit_score ≥ 700(Good credit score)$.debt_ratio ≤ 0.43(Acceptable debt-to-income ratio)
Scorecard Bins:
$.income [25000, 50000](Income between $25K-$50K inclusive)$.credit_score (650, 750)(Credit score between 650-750 exclusive)
Decision Tree Nodes:
$.age < 25(Under 25 years old)$.employment_years ≥ 2(At least 2 years employed)
Type Conversion and Boolean Handling
The evaluation engine handles comparisons between different data types intelligently. Understanding these conversion rules helps predict comparison outcomes.
Boolean and Numeric Conversions
| Comparison Type | Result | Example | Explanation |
|---|---|---|---|
| Boolean to Number | ✅ Works | true = 1 → TRUE | Boolean true converts to 1, false converts to 0 |
| Number to Boolean | ✅ Works | 1 = true → TRUE | Number 1 equals boolean true, 0 equals boolean false |
| Boolean to String | ✅ Works | true = "true" → TRUE | Boolean values match their string representations ("true", "false") |
| String to Boolean | ✅ Works | "false" = false → TRUE | String literals "true" and "false" match boolean values |
| Boolean to Any Other Text | ❌ Fails | true = "no" → FALSE | Only "true", "false", 1 and 0 mean a boolean. Any other text never equals true or false |
String and Numeric Conversions
| Comparison Type | Result | Example | Explanation |
|---|---|---|---|
| String Number to Number | ✅ Works | "123" = 123 → TRUE | Numeric strings convert to numbers for comparison |
| Non-numeric String to Number | ❌ Fails | "abc" = 123 → FALSE | Non-numeric strings don't convert to numbers |
| String to String | ✅ Exact Match | "1" = "true" → FALSE | String comparisons are literal - no type conversion |
Important Edge Cases
Leading Zeros Preservation:
- Technical codes like
"007"are preserved and won't equal7 - Currency symbols are stripped:
"$007" = 7→ FALSE (leading zeros detected)
Case Sensitivity:
- Boolean string matching is case-insensitive:
"TRUE" = true→ TRUE - Other string comparisons respect case unless using case-insensitive operators
Comparing a true/false field to text:
- A true/false field accepts
true,false,"true","false",1and0 - Any other text never matches, whether the field is
trueorfalse:true = "yes"→ FALSE, andtrue = "no"→ FALSE - To test that a flag is off, compare it to
false, not to a word like "no"
Null and Empty Values:
null,false, and empty string""normalize to0for numeric comparisons- Use "is null" and "is not null" operators for explicit null checking
- Use "is not a number" to guard numeric logic against non-numeric, empty, or missing input in one condition (it also catches NULL); "is a number" is the opposite check
Practical Examples
// Boolean conversions that work
$.active = true // true = true ✅
$.active = 1 // true = 1 ✅
$.active = "true" // true = "true" ✅
// Text that does NOT mean a boolean
$.active = "yes" // true = "yes" ❌
$.active = "no" // true = "no" ❌ (and false = "no" ❌)
$.active = false // false = false ✅ (this is how you test a flag is off)
// String comparisons that DON'T convert
$.status = "1" // "active" = "1" ❌
$.code = "true" // "001" = "true" ❌
// Numeric string conversions that work
$.amount = "150.50" // 150.50 = "150.50" ✅
$.count = "0" // 0 = "0" ✅
// Leading zero preservation
$.account = "007" // "007" = 7 ❌ (preserved)
$.zip = "01234" // "01234" = 1234 ❌ (preserved)
Text Comparison Operators
Text operators work with string data and are available in both case-sensitive and case-insensitive versions.
| Operator | Case Sensitive | Description | Examples |
|---|---|---|---|
| Equals | Yes | Exact text match | "PREMIUM" equals "PREMIUM" |
Equals (insensitive) =/i | No | Case-insensitive text match | "premium" equals "PREMIUM" |
| Contains | Yes | Text contains substring | "John Smith" contains "Smith" |
| Contains (insensitive) | No | Case-insensitive substring search | "john smith" contains "SMITH" |
| Does not contain | Yes | Text does not contain substring | "Basic Plan" does not contain "Premium" |
| Does not contain (insensitive) | No | Case-insensitive exclusion | "basic plan" does not contain "PREMIUM" |
| Starts with | Yes | Text starts with prefix | "LOAN_001" starts with "LOAN" |
| Starts with (insensitive) | No | Case-insensitive prefix match | "loan_001" starts with "LOAN" |
| Ends with | Yes | Text ends with suffix | "document.pdf" ends with ".pdf" |
| Ends with (insensitive) | No | Case-insensitive suffix match | "DOCUMENT.PDF" ends with ".pdf" |
UI symbol —
=/i: The equals (insensitive) operator is displayed as=/iin the interface. The/isuffix follows the regex convention for case-insensitive matching, making it immediately recognizable to technical users. The symbol is language-neutral — it appears identically regardless of the UI language.
Examples in Different Components:
Rule Set Conditions:
- Customer type equals (insensitive)
"PREMIUM"(matches "premium", "Premium", "PREMIUM") - Product name contains
"Insurance"(case-sensitive match)
Decision Table Columns:
- Product code starts with
"LOAN"(LOAN_001, LOAN_PERSONAL, etc.) - Customer status does not contain
"SUSPENDED"(active customers only)
Scorecard Bins:
- Risk category contains (insensitive)
"HIGH"(matches "high risk", "HIGH_RISK", etc.) - Account type ends with
"_SAVINGS"(BASIC_SAVINGS, PREMIUM_SAVINGS)
Decision Tree Nodes:
- Email ends with (insensitive)
".edu"(educational institutions) - Company name starts with
"ABC"(ABC Corp, ABC Industries, etc.)
Range and Interval Operators
These operators are available in Decision Tables, Scorecards, and Decision Trees for defining ranges of values.
| Notation | Name | Description | Example |
|---|---|---|---|
| [a, b] | Closed interval | Value is between a and b (including both endpoints) | [25, 65] - Age 25 to 65 (including 25 and 65) |
| (a, b) | Open interval | Value is between a and b (excluding both endpoints) | (30000, 50000) - Income between $30K-$50K (not including exact amounts) |
| [a, b) | Left closed, right open | Includes a, excludes b | [700, 800) - Credit score 700-799 (includes 700, excludes 800) |
| (a, b] | Left open, right closed | Excludes a, includes b | (0.03, 0.05] - Interest rate above 3% up to 5% (including 5%) |
Examples in Different Components:
Scorecard Bins:
- Credit score
[650, 750](scores from 650 to 750, including both) - Income
(30000, 100000)(income between $30K-$100K, excluding exact amounts)
Decision Table Columns:
- Loan amount
[10000, 100000)(from $10K up to but not including $100K) - Debt ratio
(0.3, 0.5](above 30% up to and including 50%)
Decision Tree Nodes:
- Age
[25, 65](working age range, including 25 and 65) - Credit utilization
(0, 0.8)(above 0% but less than 80%)
Date and Time Operators
Time operators handle date and time comparisons with intelligent parsing of various date formats.
| Operator | Description | Example |
|---|---|---|
| Time > | Date/time A is after B | Application date after "2024-01-01" |
| Time ≥ | Date/time A is on or after B | Payment date on or after "Jan 1, 2024" |
| Time < | Date/time A is before B | Due date before "2024-12-31" |
| Time ≤ | Date/time A is on or before B | Birth date on or before "1990-01-01" |
| Time = | Date/time A equals B | Transaction date equals "2024-03-15" |
| Time ≠ | Date/time A does not equal B | Last login not equal to "today" |
Supported Date Formats:
- ISO dates:
"2024-01-01","2024-01-01 14:30:00" - Human readable:
"Jan 1, 2024","March 15, 2024" - Time only:
"14:30:00"(combined with current date) - Year only:
"2024"(treated as January 1st) - Unix timestamps:
1704067200 - Relative dates:
"now","today","tomorrow","+1 day"
When a value is not a date
Not every value that reaches a date comparison is a date. A missing value, an empty field, a yes/no flag, a list, or text that cannot be read as a date has no place on a timeline, so the engine does not guess. The comparison reports no match, in both directions.
This matters most when a date is optional. A condition like "verification date is more than 30 days old" does not fire for an applicant who was never verified, because there is no date there to be old. It equally does not fire for "less than 30 days old". If "never happened" is itself a decision, test for the missing value explicitly and branch on that, rather than expecting a date comparison to stand in for it.
Two values that are both missing count as equal to each other.
⚠️ Important Note about "today": The keyword "today" resolves to midnight (00:00:00) at the start of the current day, not the current moment. For conditions like "up to today including current time," use "now" instead.
⚠️ Best Practice for Auditable Decision Logic
While relative date keywords like
"now","today", and"tomorrow"work functionally, it is strongly recommended to pass explicit dates to the decision engine instead of using relative date references.Why explicit dates are better:
- Auditability: Decision results can be reproduced exactly at any point in time
- Transparency: Clear understanding of what date was used in the evaluation
- Testing: Consistent results when testing decision logic with historical data
- Compliance: Regulatory requirements often demand explicit, traceable decision criteria
Recommended approach:
❌ Avoid: Last payment Time ≤ "now" ✅ Better: Last payment Time ≤ "2024-03-15 14:30:00" ❌ Avoid: Application date Time > "today" ✅ Better: Application date Time > "2024-01-01"
Examples in Different Components:
Rule Set Conditions:
- Application date Time >
"2024-01-01"(applications after January 1st, 2024) - Last payment Time ≤
"now"(payments up to the current moment)
Decision Table Columns:
- Birth date Time <
"2000-01-01"(born before year 2000) - Account opening Time ≥
"Jan 1, 2023"(accounts opened since 2023)
Scorecard Bins:
- Last login Time ≠
"never"(has logged in before) - Payment due Time =
"2024-03-15"(due on specific date)
Special Operators
Special-purpose operators for common evaluation scenarios.
| Operator | Description | Use Cases |
|---|---|---|
| Any value | Always matches (always returns true) | Testing, debugging, catch-all conditions |
| Is null | Checks if field is empty or missing | Data validation, handling missing information |
| Is not null | Checks if field has a value | Ensuring required fields are filled |
| Is not a number | Matches when the value cannot be read as a number — non-numeric text, empty, or missing (NULL) | Guarding numeric logic against bad input before ordering/interval comparisons |
| Is a number | Matches when the value can be read as a number | Requiring a usable numeric value before scoring or comparison |
| Regular expression | Pattern matching using regex | Email validation, phone format checking, complex text patterns |
Guarding numeric logic —
is not a number: Ordering operators (>,<) and intervals fall back to text comparison when an input is not numeric (letters sort above digits), and treat missing/empty input as "less than everything" or0. Rather than relying on that behavior, place an is not a number condition first to catch non-numeric, empty, and missing values explicitly and route them where you want them. Because it also catches NULL, a single such condition covers both non-numeric text and missing data.is a numberis the opposite check. In a scorecard, where bins are first-match-wins, "first" is something you set directly — drag the guard bin to the top of its predictor by the handle left of its name. The portal flags a guard bin placed below a bin that would swallow missing or non-numeric input first, so a mis-ordered guard does not stay hidden.
Examples in Different Components:
Rule Set Conditions:
- Email regular expression
"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"(valid email format) - Optional field is not null (ensure field has value)
Decision Table Columns:
- Phone number is not null (phone number required)
- Social security number regular expression
"^\d{3}-\d{2}-\d{4}$"(XXX-XX-XXXX format)
Scorecard Bins:
- Optional income source any value (catch-all for testing)
- Middle name is null (customers without middle names)
Decision Tree Nodes:
- Account status is not null (active accounts only)
- Postal code regular expression
"^\d{5}(-\d{4})?$"(US ZIP code format)
When an Attribute Holds a List
Some attributes carry several values at once. A path written with a wildcard ($.transactions[*].amount), a recursive scan ($..amount), a slice ($.items[0:3]) or a filter returns every match it finds. A plain path holds a list too whenever the data itself carries one, as $.applicant.previous_addresses does.
A single-value operator has no answer to give about a list. "Is [120.50, -80.00, 300.00] greater than 1000" is not a question with a yes or a no in it. The engine treats such a condition as no match in both directions and records the reason, rather than settling on an answer that means nothing. Ask the question that fits the shape of the value instead:
| What you want to know | Operator |
|---|---|
| Is this value one of the entries | array contains, array does not contain, each with a case insensitive variant |
| Does any entry contain this text | array value contains, no array value contains, each with a case insensitive variant |
| Is there anything in the list at all | is not NULL |
| Are two lists the same | =, ≠, ≈, with a list on both sides |
List equality compares entry by entry in order, so [1, 2, 3] and [3, 2, 1] are two different lists. The loose form ≈ relaxes how the two lists are matched and leaves each entry as it is, so ["a"] and [1] stay different.
To ask an ordinary single-value question of every entry in turn, reach for an iterative rule, which runs the conditions once per entry with $.__item pointing at the entry being evaluated. A data flow rule covers the same list when you want aggregation, mapping or window functions across it.
Seeing it in a test run
From verbose level 2 upward, the condition carries its reason in the trace:
{
"condition_type": "greater_than",
"left_side": { "path": "$.transactions[*].amount", "resolved_value": [120.5, -80, 300] },
"right_side": { "value": "1000" },
"comparison_result": false,
"result_reason": "multi_value_operand"
}
A condition reading multi_value_operand is putting a single-value question to a list. Point it at one entry with an iterative rule, or move it to one of the operators in the table above.
Where it is caught
Creating a release raises condition_multi_value_path as a warning for a path written with a wildcard, a recursive scan, a slice or a filter, and testing a decision flow reports the same warning, so those surface in the portal before a decision depends on them. The AI assistant applies the same check to the rules it writes. A plain path that turns out to hold a list is known only once real data arrives, and shows up as multi_value_operand in the trace of a test run. Rule Sets, Decision Tables, Scorecards and Decision Trees all behave this way, since they share one condition evaluator.
Condition Types
Understanding how conditions work is crucial for building effective decision logic.
Simple Conditions
A simple condition compares two values using an operator:
Left Side [OPERATOR] Right Side
Left Side Options:
- Attribute Path:
$.customer.age(gets value from data object) - Direct Value:
25(literal value) - JSON Value:
{"status": "active"}(for complex comparisons)
Right Side Options:
- Attribute Path:
$.minimum_age(compare two data attributes) - Direct Value:
18(compare against literal) - JSON Value:
["A", "B", "C"](compare against array/object)
Examples Across Components:
Rule Set Simple Condition:
Customer credit score ≥ 700
(Attribute: $.customer.credit_score)
Decision Table Column:
Loan amount > 50000
(Attribute: $.loan_amount)
Scorecard Bin:
Monthly income [3000, 8000]
(Attribute: $.monthly_income)
Group Conditions (Hierarchical)
Group conditions combine multiple simple conditions using logical operators.
ALL (AND Logic)
All conditions in the group must be true:
Group: ALL
├── $.age >= 18
├── $.credit_score > 650
└── $.income >= 30000
Result: Customer must be 18+, have credit score >650, AND income >=30K
ANY (OR Logic)
At least one condition in the group must be true:
Group: ANY
├── $.customer_type equals "PREMIUM"
├── $.loyalty_years >= 5
└── $.total_deposits > 100000
Result: Customer qualifies if they're premium OR loyal 5+ years OR have large deposits
Nested Group Conditions
Complex logic with one level of nesting (as supported in UI):
Root Group: ALL
├── $.age >= 21
└── Income Group: ANY
├── $.salary >= 50000
├── $.business_income >= 40000
├── $.part_time_income >= 20000
└── $.other_income >= 15000
Result: Must be 21+ AND have qualifying income from any source
Component-Specific Condition Behavior
Rule Sets
- Support both simple and complex group conditions
- Can have one level of nested groups (as supported in UI)
- Conditions determine if rule "hits" and actions are executed
Decision Tables
- Each column represents one condition
- All conditions in a row must be true (implicit ALL logic)
- Cannot have group conditions within columns
Scorecards
- Each bin has one condition that determines if the bin applies
- Bins are evaluated independently
- First matching bin determines the score for that predictor
Decision Trees
- Each node has conditions that determine the next branch
- Conditions are evaluated in order until one matches
- Supports simple conditions with complex branching logic
Testing Patterns
All decision logic components support consistent testing approaches to validate your logic.
Unit Testing
Unit testing allows you to test individual conditions or rules with specific input values.
How Unit Testing Works
- Define Test Values: Specify exact values for each attribute used in your logic
- Run Test: Execute the logic with your test values
- Review Results: See which conditions matched and what actions were taken
Unit Test Examples
Rule Set Unit Test:
Test Input:
$.customer.age = 25
$.customer.income = 45000
$.customer.credit_score = 720
Expected Result:
✓ Rule "Young Professional" hits
✓ $.customer.segment set to "EMERGING"
Decision Table Unit Test:
Test Input:
$.loan_amount = 75000
$.credit_score = 680
$.debt_ratio = 0.35
Expected Result:
✓ Row 3 matches
✓ $.loan_decision = "MANUAL_REVIEW"
Scorecard Unit Test:
Test Input:
$.credit_score = 720
$.income = 60000
$.debt_ratio = 0.25
Expected Result:
✓ Credit Score Bin: 670-850 (Score: 50, Weight: 0.4) = 20
✓ Income Bin: 50000+ (Score: 30, Weight: 0.3) = 9
✓ Debt Ratio Bin: 0-0.3 (Score: 25, Weight: 0.3) = 7.5
✓ Final Score: 36.5
Object Testing
Object testing uses complete data objects (often saved as Data Objects) to test your logic with realistic data.
Benefits of Object Testing
- Realistic Data: Test with actual data structures you'll encounter
- Comprehensive Coverage: Test multiple conditions simultaneously
- Regression Testing: Save test objects to prevent future bugs
- Documentation: Test objects serve as examples of expected input
Object Test Process
- Select Data Object: Choose a saved data object or upload JSON
- Run Test: Execute your logic against the complete object
- Analyze Results: Review detailed execution trace and results
Creating Test Data Objects
Good Test Data Object:
{
"customer": {
"id": "CUST001",
"name": "John Doe",
"age": 32,
"credit_score": 745,
"employment": {
"status": "EMPLOYED",
"years": 5,
"income": 65000
}
},
"loan": {
"amount": 250000,
"purpose": "HOME_PURCHASE",
"term": 360
},
"accounts": [
{"type": "CHECKING", "balance": 15000},
{"type": "SAVINGS", "balance": 45000}
]
}
Simulation Testing (Decision Tables)
Simulation testing is unique to Decision Tables and helps identify gaps in your decision logic.
What Simulation Tests
- Coverage: Are all possible input combinations handled?
- Gaps: Are there scenarios with no matching rules?
- Overlaps: Do multiple rules match the same scenario?
- Distribution: How are results distributed across scenarios?
Setting Up Simulation
Define Value Ranges:
Credit Score: Range 300-850
Income: Range 25000-150000
Debt Ratio: Range 0.1-0.8
Age: Range 18-75
Simulation Results:
Generated 10,000 test scenarios:
✓ 8,547 scenarios matched rules (85.47%)
⚠ 1,453 scenarios had no matches (14.53%)
📊 Result Distribution:
- APPROVED: 3,245 (32.45%)
- REJECTED: 2,156 (21.56%)
- MANUAL_REVIEW: 3,146 (31.46%)
- NO_MATCH: 1,453 (14.53%)
Testing Best Practices
Create Comprehensive Test Scenarios
// Test edge cases
Minimum values: $.credit_score = 300, $.income = 0
Maximum values: $.credit_score = 850, $.income = 999999
Boundary values: $.age = 17, 18, 65, 66
Null values: $.optional_field = null
Use Realistic Test Data
- Base test objects on actual customer data (anonymized)
- Include common variations and edge cases
- Test with different data types and formats
Document Test Cases
- Name test objects descriptively ("high_income_poor_credit")
- Include comments explaining the test scenario
- Maintain a library of test cases for regression testing
Debugging & Tracing
Understanding execution traces and debugging output helps you troubleshoot and optimize your decision logic.
Verbose Levels
All decision logic components support verbose output levels that provide increasing detail about execution:
| Level | Description | What You Get |
|---|---|---|
| 0 (Off) | No additional output | Just final results |
| 1 (Basic) | Basic execution info | Rules hit, conditions matched, results set |
| 2 (Detailed) | Full execution trace | Attribute resolution, timing, metadata |
Verbose Output Examples
Level 1 Output (Rule Set)
{
"output": {
"credit_evaluation": {
"rules_fired": [
{
"rule_name": "High Credit Score",
"conditions_matched": [
{
"attribute_path": "$.credit_score",
"operator": "greater_than_or_equal_to",
"expected": 700,
"actual": 745
}
]
}
]
}
}
}
Level 2 Output (Scorecard)
{
"output": {
"risk_scorecard": {
"credit_score": {
"bin_hit": "Good Credit (670-799)",
"bin_score": 25,
"bin_weight": 0.4,
"score": 10,
"attribute_value": 745
},
"__result": {
"final_score": 23.5,
"calculation_type": "sum",
"number_of_predictors": 3
},
"__execution": {
"execution_time_ms": 2.15,
"status": "ok"
},
"__info": {
"scorecard_id": "RISK_001",
"revision_id": "rev_123"
}
}
}
}
Common Debugging Scenarios
Condition Not Matching
Problem: Expected condition to match but it didn't
Debug Steps:
- Check attribute resolution: Verify the attribute path returns expected value
- Check data types: Ensure comparison types are compatible
- Check operator: Verify you're using the correct operator
- Use verbose level 2: See exactly what values are being compared
Example Debug Output:
{
"attribute_resolution": {
"$.customer.age": {
"resolved_value": "25", // Note: String, not number
"expected_type": "number",
"path_exists": true
}
}
}
Unexpected Results
Problem: Logic produces unexpected outcomes
Debug Steps:
- Check execution order: Rules execute in sequence, tables evaluate all rows
- Check condition precedence: Group conditions may affect evaluation
- Check data object structure: Ensure all expected fields exist
- Use unit tests: Test with controlled, known values
Performance Issues
Problem: Logic execution is slow
Debug Information Available:
{
"__execution": {
"execution_time_ms": 150.23, // Execution time
"status": "ok",
"rules_evaluated": 25, // Number of rules processed
"conditions_evaluated": 87 // Total conditions checked
}
}
Troubleshooting Guide
Null/Missing Values
// Problem: Null values causing unexpected behavior
$.optional_field > 100 // Null treated as 0
// Solution: Check for null first
$.optional_field is_not_null AND $.optional_field > 100
JSONPath Errors
// Problem: Incorrect path syntax
$.customer..name // Double dots invalid
$.customer[name] // Missing quotes
// Solution: Use correct JSONPath syntax
$.customer.name // Correct
$.customer["name"] // Also correct
Complex Condition Logic
// Problem: Unexpected group condition behavior
Group: ANY
├── $.age >= 65 AND $.retired = true // Invalid: AND within ANY
└── $.income < 20000
// Solution: Use proper nesting
Group: ANY
├── Retirement Group: ALL
│ ├── $.age >= 65
│ └── $.retired = true
└── $.income < 20000
Best Practices for Debugging
- Start Simple: Test basic conditions before building complex logic
- Use Unit Tests: Verify individual conditions work correctly
- Enable Verbose Output: Use level 2 for detailed troubleshooting
- Check Data Types: Ensure consistent data types in comparisons
- Validate JSONPath: Test attribute paths return expected values
- Document Edge Cases: Note special handling for nulls, arrays, etc.
Integration with Decision Logic Components
How Components Use This Logic
Rule Sets
- Support all comparison, text, time, and special operators
- Can create complex group conditions with one level of nesting (AND/OR logic)
- Execute rules sequentially, allowing for cascading logic
- Can record which rules "hit" for audit trails
Decision Tables
- Support all operators including range/interval operators
- Each column represents one condition
- All conditions in a row must be true (implicit AND logic)
- Support CSV import/export for bulk editing
Scorecards
- Use range and comparison operators for bin conditions
- Each predictor has bins with range-based conditions
- Support multiple calculation methods (sum, average, logistic regression)
- Weighted scoring with configurable weights — fixed, or read from the data object at runtime (see Dynamic Weights)
Decision Trees
- Support all operators for node conditions
- Hierarchical branching based on condition evaluation
- First matching condition determines next branch
- Support complex decision flows with multiple endpoints
Cross-Component Examples
Consistent Customer Segmentation
Rule Set Implementation:
Rule: "High Value Customer"
Condition: $.total_deposits > 100000
Action: Set $.segment = "HIGH_VALUE"
Decision Table Implementation:
Column 1: $.total_deposits > 100000
Column 2: $.relationship_years >= 2
Result: $.segment = "HIGH_VALUE"
Scorecard Implementation:
Predictor: Customer Value
Attribute: $.total_deposits
Bin: closed_interval 100000 999999 (Score: 50)
All three approaches use the same underlying evaluation logic for consistent results.
Next Steps
Now that you understand the shared evaluation logic, you can:
-
Explore Component-Specific Features:
- Rule Sets - Sequential rule processing
- Decision Tables - Tabular decision logic
- Scorecards - Weighted scoring systems
- Decision Trees - Hierarchical branching logic
-
Learn Advanced Topics:
- Testing Decision Logic - Comprehensive testing strategies
- JSONPath Guide - Advanced attribute resolution
- Data Objects - Managing test data and input structures
-
Get Hands-On:
- Create simple conditions using the operators reference
- Test your logic with unit tests and data objects
- Use verbose output to understand execution flow
- Build from simple conditions to complex group conditions
Need Help? If you encounter issues with evaluation logic, use the debugging techniques in this guide or refer to component-specific documentation for detailed implementation guidance.