Katkat

Design a Data-Driven Expense Rule Evaluator

RipplingSoftware Engineer · Onsite

Last updated

Design an extensible, data-driven expense policy engine that evaluates structured JSON rules against submitted expenses without requiring code deployments.

Scenario

Modern workforce platforms allow company administrators to configure custom expense approval and compliance policies (for example: "Flag any meal over $75 without a receipt" or "Require secondary approval for flights booked within 7 days of departure").

Your task is to design a rule evaluation engine where policies are stored and configured as JSON documents, evaluated dynamically against submitted expense claims.

Core Requirements

  1. Rule Schema: Define a validated JSON schema representing policy conditions and actions. Support basic boolean composition (AND, OR, NOT) and field-level predicates (e.g., eq, gt, in, contains).
  2. Engine Architecture & API: Define the core classes and evaluation interface (e.g., PolicyEvaluator.evaluate(expense: dict, policy: Policy) -> EvaluationResult). Specify how conditions are parsed into an executable Abstract Syntax Tree (AST) or composite pattern.
  3. Result Contract: The engine must return whether the expense passed, along with specific violated rule IDs and human-readable explanation messages for end users.

Example Rule Definition

{
  "policy_id": "pol_meals_receipt",
  "name": "Meal Receipt Requirement",
  "condition": {
    "operator": "AND",
    "rules": [
      {"field": "category", "op": "EQ", "value": "MEALS"},
      {"field": "amount", "op": "GT", "value": 75.00},
      {"field": "has_receipt", "op": "EQ", "value": false}
    ]
  },
  "action": {
    "type": "FLAG_VIOLATION",
    "severity": "BLOCKING",
    "message": "Meals exceeding $75 require an itemized receipt."
  }
}

Key Considerations to Address

  • Invariants & Safety: How do you prevent unsafe execution, infinite recursion in nested rules, or type mismatches (e.g., string comparisons on currency amounts)?
  • Missing/Null Fields: How should the engine evaluate conditions referencing attributes that are absent from the submitted expense payload?
  • Testing Strategy: How would you test individual operators, compound trees, and schema validation independently?
  • Operational Trade-offs: Discuss pre-compiling/caching rule ASTs in memory versus parsing raw JSON per evaluation request.

Hints

Hint 1

Model condition trees using the Composite Pattern where leaf nodes represent predicate comparisons and interior nodes represent boolean logic.

Hint 2

Decide on three-valued logic (True, False, Unknown/Error) to handle null or missing fields deterministically before running predicate comparisons.

Hint 3

Validate incoming JSON rules against a strict schema (e.g., JSON Schema or Pydantic) at write time so the runtime evaluation engine can safely assume valid structure.

Follow-up questions

  • How would you support rules that depend on historical context, such as 'total dining expenses exceeding $500 in a rolling 30-day window'?
  • How would you handle rule versioning when auditing historical expenses submitted under a previous policy version?
  • If two rules generate conflicting actions (e.g., one requires manager approval while another auto-approves), how should priority and conflict resolution be handled?