FM8 — Schema/Contract Violation
Two expressions believed to be equivalent that are not.
This happens in three ways:
1. Incorrect mental application of equivalence laws.
# Developer believes these are equivalent
# Original: "process if admin OR (editor AND not read_only)"
def can_edit_original(is_admin: bool, is_editor: bool, is_read_only: bool) -> bool:
return is_admin or (is_editor and not is_read_only)
# "Simplified" version: pulls out NOT incorrectly
def can_edit_wrong(is_admin: bool, is_editor: bool, is_read_only: bool) -> bool:
# Developer thinks: factor out "not is_read_only" from the whole expression
# This is NOT the same as the original
return (is_admin or is_editor) and not is_read_only
# Test to reveal the difference
# Inputs: is_admin=False, is_editor=False, is_read_only=False
print(can_edit_original(False, False, False)) # False (not editor, not admin)
print(can_edit_wrong(False, False, False)) # False (same)
# Inputs: is_admin=True, is_editor=False, is_read_only=True
print(can_edit_original(True, False, True)) # True (admin overrides)
print(can_edit_wrong(True, False, True)) # True AND False = False (WRONG)The second version is not equivalent to the first. An admin with
is_read_only=True is incorrectly blocked. The
“simplification” introduced a bug.
2. Equivalence that holds for most data but not all.
SQL query rewrites can fail when NULL values are involved. Classical boolean equivalence does not hold in three-valued SQL logic. The optimizer must account for NULL separately.
-- These are NOT equivalent in SQL due to NULL:
WHERE NOT (status = 'active' AND type = 'premium')
-- vs.
WHERE status != 'active' OR type != 'premium'
-- If status IS NULL:
-- First expression: NOT (NULL AND ...) = NOT NULL = NULL (unknown)
-- Second expression: NULL OR ... = NULL or the other side
-- They may evaluate differently for NULL inputs3. Equivalence that depends on evaluation order (non-commutative systems).
In databases with row-level security, predicates can produce different results depending on which user context they are evaluated in. Two expressions equivalent in one security context may not be equivalent in another.