Fail open default
The corpus prior¶
Unclear result → return the neutral-looking value.
When a function distinguishes three outcomes, the error path is written last and
inherits whatever "nothing happened" looks like. In Python that is {} or
None — so the error path returns the empty container, which is rarely
neutral.
The tell is in the caller, not the callee:
{} is not "no opinion". It is the most permissive outcome.
Wrong shape¶
# WRONG — `{}` means "no restriction" to every caller
def _resolve_scope_filters(...):
...
for rule in matched_rules:
...
return {} # fell off the end: "no resolvable condition"
# WRONG — reports nothing about whether it UNDERSTOOD the condition
def _extract_condition_filters(condition, user_id, filters, ...):
...
# unrecognised shape -> filters is still {} -> returned as a success
Right shape¶
Reserve the permissive value for the specific condition that means "unrestricted". Everything else denies:
And when one condition legitimately produces no filter from inside a recognised branch, the function must report which branch it took:
# RIGHT — `bool` is "a recognised shape was interpreted"
if not recognised:
logger.warning("Scope condition for %s has an unrecognised shape", entity)
return None
return filters # may legitimately be {}
Why this matters here¶
Two real instances, both in http/runtime/scope_filters.py, both shipped green:
- The fall-through. After trying every path it could, an unresolvable rule
returned
{}— the same valuescope: allreturns. - The successful-but-empty return. An unrecognised condition shape was
indistinguishable from a recognised one that legitimately emits nothing (the
documented
current_contextskip), so the empty dict was returned as success.
Fixing one without the other leaves the bug half-open, which is why the second
needed a bool return rather than another return None.
The three-way distinction¶
The hard case is when two situations both yield "no filters":
| Situation | Correct |
|---|---|
scope: all, or no scopes declared |
{} — permissive, and it means it |
Recognised shape, nothing to emit (current_context, no selection) |
{} |
| Shape not recognised | deny |
| Resolution raised | deny |
The middle row is why "deny when nothing was extracted" is wrong: it breaks a documented behaviour. The resolver cannot distinguish the rows from outside — the extractor can, because the shape knowledge is already there.
Related¶
- duplicated-business-rule — both instances were reachable only because a rule had been duplicated.