Katkat

Validate and Resolve Chained Decision Rules

PlaidSoftware Engineer · Technical Screen

Last updated

Determine if all rules in a chained decision rule set resolve to a terminal 'pass' outcome without cycles or missing references.

Problem Statement

You are building a rule engine for evaluating financial compliance. The system maintains a table of validation rules. Each rule is defined as a pair (rule_name, result):

  • rule_name: A unique identifier for the rule.
  • result: The outcome of the rule, which can be:
    • "pass": The rule succeeds.
    • "fail": The rule fails.
    • Another rule's name: The outcome of this rule delegates to the outcome of the referenced rule.

Write a function all_rules_pass(rules: list[tuple[str, str]]) -> bool that returns True if every rule in the table ultimately resolves to "pass". Return False if any rule:

  • Resolves to "fail",
  • Forms a circular dependency (cycle),
  • References an unknown rule not present in the table.

Function Signature

def all_rules_pass(rules: list[tuple[str, str]]) -> bool:
    pass

Constraints

  • 1 <= len(rules) <= 10^5
  • rule_name is a non-empty string of alphanumeric characters (excluding "pass" and "fail").
  • All rule_name entries in rules are distinct.
  • result is a non-empty string of alphanumeric characters.

Examples

Example 1

rules = [
    ("RuleA", "RuleB"),
    ("RuleB", "RuleC"),
    ("RuleC", "pass"),
    ("RuleD", "RuleC")
]
# Output: True
# Explanation: RuleA -> RuleB -> RuleC -> pass.
# RuleD -> RuleC -> pass. All rules resolve to "pass".

Example 2

rules = [
    ("KYC", "AML"),
    ("AML", "KYC"),
    ("Sanctions", "pass")
]
# Output: False
# Explanation: "KYC" and "AML" form an infinite cycle.

Example 3

rules = [
    ("CreditCheck", "IncomeCheck"),
    ("IncomeCheck", "fail")
]
# Output: False
# Explanation: Both rules resolve to "fail".

Example 4

rules = [
    ("Rule1", "Rule2"),
    ("Rule2", "UnknownRule")
]
# Output: False
# Explanation: "Rule2" references "UnknownRule", which is not defined.

Hints

Hint 1

Model the rules as a directed graph where each rule has at most one outgoing edge.

Hint 2

Use a three-state traversal (e.g., unvisited, visiting, visited) to detect cycles and identify missing references.

Hint 3

Memoize the resolved boolean status of each node so each rule is processed in O(1) amortized time.

Follow-up questions

  • How would you modify the function to return a map of each rule to its specific termination status ('pass', 'fail', 'cycle', or 'missing_reference')?
  • How would your approach adapt if rules supported boolean expressions (e.g., 'RuleA AND (RuleB OR RuleC)') instead of single delegations?
  • In a production system where rules are dynamically updated by multiple services, how would you efficiently validate that an update does not introduce a cycle?