When an allowlist entry and a hard-block rule both match one refund request, what decides the action the decision layer emits?
answer
- conflict is the normal case
- a declared total order, not source order
- precedence is data, versioned with the rules
- exactly one action, winner recorded
- stricter override yes, looser override no
basics
~20 sA precedence order declared in advance - not source order, not whichever rule was authored last. The layer collects the matches, resolves them by that documented ranking, emits exactly one action, and records which branch won.
solid answer
~50 sConflicts stop being exceptions the moment more than one person authors rules, so the layer needs a **total order over outcomes**, stated as data and versioned with the rules themselves. Two workable shapes: first-match-wins over a precedence-sorted list, which is cheap and easy to reason about, and collect-all-matches-then-resolve, which costs a full pass but records every rule that fired rather than only the winner. The ranking is a policy decision rather than an engineering one - typically a hard block written for a legal or contractual reason outranks every allowlist, while a support-issued allowlist outranks a heuristic block and the model's score band. Whatever the order, the invariant is the same: any set of matches maps deterministically to exactly one action, and the same inputs under the same rule and model versions always produce that same action.
code
pseudocode · 12 linesmatches = [r for r in rules if r.matches(request)]
winner = lowest_precedence(matches) // null when matches is empty
if winner != null and winner.action != PASS_TO_MODEL:
return emit(winner.action,
reasons = [winner.id],
fired = ids_of(matches))
score = model.score(request)
return emit(band_of(score),
reasons = ["model_band", model.version],
fired = ids_of(matches))go deeper
Know that more than one rule can match a single request, and that the layer still emits one action. Recall that a declared precedence order decides which one, not the order rules were written.
Explain first-match-wins against collect-all-then-resolve, what each records, and why precedence must live with the rules as versioned data rather than in the evaluation code.
Demonstrate the operating judgment: allowlists with owners and expiry dates, duplicate precedence rejected at publish time, no rule mutating state a later rule reads, and the determinism guarantee a disputed decision is reviewed against.
The ranking is a policy artefact, not an engineering one. Decide who owns it, how a change to it is reviewed, and how the organisation notices when an allowlist has quietly become a standing exemption from a contractual commitment.
## Conflicts are the normal case In a promotion and refund abuse layer, rules come from several authors: a risk analyst adds a block for a redemption pattern, support adds an allowlist entry for a complaining bulk customer, finance adds a hard block that a contract requires. Nothing stops two of them matching the same refund request, and once the set has a few dozen entries, something always does. So the layer cannot treat conflict as an error path. It needs a **resolution policy**: a declared ranking that turns any set of matched rules into exactly one emitted action. ## Two resolution shapes | | First-match-wins | Collect-all, then resolve | |---|---|---| | Evaluation | Stops at the first match in precedence order | Evaluates every rule, then ranks the matches | | Cost | Cheapest | A full pass over the rule set | | What is recorded | The winner only | Every rule that fired, plus the winner | | Good for | Small, stable, strictly ordered sets | Auditing, dead-rule review, overlap analysis | Both produce the correct winner when the list is precedence-sorted; they differ in what they can tell you afterwards. Knowing that four other rules also matched is what makes an overlap or dead-rule review possible at all, which is why larger systems pay for the full pass. ## What the ranking usually looks like Ordered from strongest to weakest, with the lowest precedence number winning: 1. **Hard blocks required by law or contract** - these outrank everything, including any allowlist. An allowlist that can release them is a hole in a commitment. 2. **Compliance and sanction-style blocks** - same reasoning, different owner. 3. **Support-issued allowlists** - a human looked at this account and decided. They outrank heuristic blocks and the score. 4. **Heuristic blocks and challenge triggers** - analyst-authored risk conditions. 5. **The model's score band** - the default path when no rule terminally decided. 6. **Default allow** - what happens when nothing matched at all. The exact order is a policy choice each business makes, but it must be *a* choice, written down, and owned by someone who can defend it. ## The invariants worth stating - **Exactly one action per request.** Two rules may both match; only one action is emitted. Anything else pushes the conflict into whatever consumes the decision. - **Determinism.** The same request, the same rule-set version and the same model version produce the same action. Reproducibility is what makes a disputed decision reviewable. - **A recorded winner.** The record says which branch resolved the decision, not just what the action was. - **No rule mutates shared state that a later rule reads.** That makes the outcome depend on evaluation order rather than on the declared precedence, which is exactly what the precedence table exists to prevent. ## How it goes wrong - **Precedence implied by source order.** The order rules happen to appear in a file is not a policy, and a reordering during a refactor silently changes decisions. - **Precedence living in code while rules live in configuration.** Then changing the ranking needs a deployment, and the two drift apart. - **An allowlist that quietly covers a hard block.** If the allowlist is checked first as a shortcut, every commitment below it is conditional. - **Non-deterministic tie-breaks.** Two rules at the same precedence resolved by iteration order or by a map's ordering give different answers on different days. - **Permanent allowlist entries.** An entry issued for one situation outlives the reason for it. Give each one an owner, a reason and an end date, and let it lapse by default. ## Overrides in both directions A useful sharpening: a score is allowed to make a decision *stricter* than the rules would have, but not looser. A high score escalating a request the rules would have allowed - turning an allow into a challenge - adds friction and costs a little customer patience. A low score releasing a matched hard block deletes the commitment the block was written to enforce. If the block is wrong, the fix is to change the block, under a version, not to let a number talk it down.
- Why is a support-issued allowlist entry usually time-boxed rather than permanent?It was issued for one situation - a wrongly declined customer, a known-good bulk buyer during a promotion - and the reason for it stops being true. Without an expiry the entry becomes a permanent hole that nobody can justify and that abuse eventually finds. Give every entry an owner, a reason and an end date, and let it lapse by default.
- Should the model's score band ever override a rule that matched?In one direction only, and by design. A high score may escalate a request the rules would have allowed, turning an allow into a challenge, because that adds friction rather than removing a guarantee. A low score releasing a matched hard block deletes the commitment the block encodes; if the block is wrong, change the block under a version.
- What breaks if two rules share the same precedence value?The tie is resolved by whatever the engine happens to do - iteration order, a map's ordering, the order of a deployment - so the emitted action can differ between runs on identical input. That destroys the determinism a disputed decision is reviewed against. Treat duplicate precedence as a validation failure at rule-set publish time.
A restaurant that keeps both a barred-patron list and a VIP reservation book has to decide, before service, which one wins when the same name appears on both. A host improvising that call at the door is the failure mode.
saying these in an interview costs you the question
- Whichever rule appears first in the rule file should win
- An allowlist always beats a block, that is what it is for
- Conflicts are rare enough to resolve when they come up
- Precedence belongs in the evaluation code, since rules are just conditions
- Two rules emitting two actions is fine as long as both are logged