diff --git a/scripts/audit_exception_handling.py b/scripts/audit_exception_handling.py index 1b94c31a..3b2d5f50 100644 --- a/scripts/audit_exception_handling.py +++ b/scripts/audit_exception_handling.py @@ -1028,6 +1028,21 @@ class ExceptionVisitor(ast.NodeVisitor): f"Compliant: `raise {exc_short}` inside `if is None:` is the canonical validation/precondition-check pattern (per result_migration_review_pass_20260617).", ) + # Heuristic added by result_migration_gui_2_20260619 (Phase 11): + # Bare `raise AttributeError(...)` or `raise NameError(...)` in a dunder + # method (__getattr__/__getattribute__/__setattr__/__delattr__) is the + # canonical Python dunder-method programmer-error pattern. Per the + # styleguide "Re-Raise Patterns" (error_handling.md lines 625-690), bare + # raises are reserved for programmer errors / impossible states / + # canonical dunder method behaviors. The Python data-model contract for + # these dunders explicitly raises AttributeError when an attribute does + # not exist or is not settable. + if exc_short in {"AttributeError", "NameError"} and self._current_func_name() in {"__getattr__", "__getattribute__", "__setattr__", "__delattr__"}: + return ( + "INTERNAL_PROGRAMMER_RAISE", + f"Compliant: `raise {exc_short}` in `{self._current_func_name()}` is the canonical dunder-method programmer-error pattern (per styleguide 'Re-Raise Patterns' and Phase 11 result_migration_gui_2_20260619).", + ) + return ( "INTERNAL_RETHROW", f"Review: `raise {exc_name}` in internal code. Confirm this is a programmer error (assertion) and not a runtime failure (which should be a Result).",