A review checklist for decision rules (for analysts and reviewers)
A checklist for reviewing a decision rule before it ships, written for analysts and reviewers rather than programmers. Each item names a page in this reference where the engine shows the check, and the entry rule below carries the independence pairs that most of the items rely on.
Names and meaning. Every condition has a name that reads as a statement and a one-line description in the glossary; no two names look alike or differ only by case; thresholds are threshold inputs with their comparison recorded, or named conditions decided outside the rule, and dates are decided outside the rule. Structure. Every mixed group of AND and OR is bracketed; every exception is an AND NOT at the level it must override; “or” is inclusive unless the rule says otherwise; “only if” and “unless” were translated with the condition on the right side of the arrow.
Behaviour. The rule is neither always true nor always false, and the checks say so without a vacuous flag; the assumptions, if any, are consistent; the truth table's TRUE rows match the owner's list of who qualifies, and its FALSE rows match the list of who does not; any previous version was compared and the differing rows were reviewed against the change request. Tests. Each condition has an independence pair (the report below shows the pairs for the entry rule, four scenarios for three conditions); expected results came from the requirement; past counterexamples are in the suite; a mutation run leaves no surviving non-equivalent mutant.
Delivery. The exported code carries the digest of the rule it was generated from; a “Not determined” result anywhere in the pipeline is treated as a failure to decide, not as a pass; the rule's owner has confirmed the plain-language reading. None of these items requires the reviewer to compute anything: the engine computes, the reviewer compares.
Example
allow := (member OR invited) AND NOT banned · output
Exact checks
Truth table (8 rows)
| # | member | invited | banned | allow |
|---|---|---|---|---|
| 0 | FALSE | FALSE | FALSE | FALSE |
| 1 | FALSE | FALSE | TRUE | FALSE |
| 2 | FALSE | TRUE | FALSE | TRUE |
| 3 | FALSE | TRUE | TRUE | FALSE |
| 4 | TRUE | FALSE | FALSE | TRUE |
| 5 | TRUE | FALSE | TRUE | FALSE |
| 6 | TRUE | TRUE | FALSE | TRUE |
| 7 | TRUE | TRUE | TRUE | FALSE |
Plain-language reading
Beginnerallow is true exactly when both of the following hold:
1. at least one of member or invited is true (both may be true)
2. banned is false
In every other case, allow is false.
About the operators:
- AND is true only when all of its parts are true.
- OR is inclusive: it is true when at least one part is true, including when several are.
- NOT reverses a value: true becomes false and false becomes true.
Intermediateallow is true exactly when both of the following hold:
1. at least one of member or invited is true (both may be true)
2. banned is false
In every other case, allow is false.
Advancedallow is true exactly when both of the following hold [conjunction ∧]:
1. at least one of member or invited is true (both may be true) [inclusive disjunction ∨]
2. banned is false [negation ¬]
In every other case, allow is false.
Formal notation: (member ∨ invited) ∧ ¬banned
Logic diagram
MC/DC
| Input | Status | Independence pair (only that input changes) |
|---|---|---|
| member | found | member=F, invited=F, banned=F → F | member=T, invited=F, banned=F → T |
| invited | found | member=F, invited=F, banned=F → F | member=F, invited=T, banned=F → T |
| banned | found | member=F, invited=T, banned=F → T | member=F, invited=T, banned=T → F |
The common slip
Reviewing the rule by reading it and nodding. Every item on the list is a comparison between what the rule does and what someone meant, and the first half of that comparison is a table the reviewer did not have to build.
Questions
Which items can be automated?
The behavioural and test items: checks, consistency, comparison of versions, independence pairs and mutation runs are all engine output, and the CLI runs them in continuous integration. Names, meaning and the owner's confirmation are human work.
What is the minimum for a small rule?
Bracket the mixed groups, confirm the TRUE rows with the owner, and keep one test per independence pair. For three conditions that is four tests, and the entry rule's report below is the template.
Related
See also
- Writing business rules in plain English that translate to logic
- MC/DC independence pairs, worked example with the engine’s coverage report
- Regression tests for decision rules that change
- Mutation testing for Boolean rules: operator, negation and literal mutants
- Confusable names: l, 1, I, O and 0 in variable names
- Inconsistent assumptions make every test pass
- A timeout is not a pass: “Not determined” results
- Boolean expression to Python, SQL, SMT-LIB and LaTeX
Testing and rules
Generated from the Tangibool engine, semantics tangibool-semantics/1, engine 1.0.0, build . Every table, map, simplification and verdict on these pages was computed by the Tangibool engine when the site was built, and every claim was re-checked by the same exact checker the app uses. Limits are stated where they apply. © 2026 Foreranger LTD.