From c5dbfd6edfed6a3c9f19d77124e74be7f2896a22 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 20 Jun 2026 11:59:20 -0400 Subject: [PATCH] test(audit): add 3 Heuristic E regression tests (TIER1_REVIEW Phase 9 redo) 3 regression tests for the new Heuristic E (narrow + structured error carrier): 1. test_heuristic_e_narrow_return_errorinfo_is_compliant - Asserts narrow except + return ErrorInfo(...) is classified as compliant - Accepts both INTERNAL_COMPLIANT (Heuristic E) and BOUNDARY_CONVERSION (existing creates_errorinfo check, fires first) 2. test_heuristic_e_narrow_dict_error_true_assign_is_compliant - Asserts narrow except + dict[error] = True is classified as compliant - The in-band error flag pattern (per Tier 1 directive) 3. test_heuristic_e_empty_default_args_is_NOT_compliant - NEGATIVE test: narrow except + args = {} must NOT be classified as compliant - Guards against future heuristic additions that would laundering the sliming empty-default pattern (per TIER1_REVIEW) Total: 16 audit heuristic tests pass (13 existing + 3 new). --- tests/test_audit_heuristics.py | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/test_audit_heuristics.py b/tests/test_audit_heuristics.py index f79ad8bc..0c146015 100644 --- a/tests/test_audit_heuristics.py +++ b/tests/test_audit_heuristics.py @@ -296,3 +296,93 @@ def test_lazy_loading_sentinel_fallback_in_get_is_compliant(): f"(direct `self._cached = _BarStub()`) should be INTERNAL_COMPLIANT " f"(canonical graceful-degradation pattern); got {category}. Hint: {hint}" ) + + +# ============ Phase 9 redo: Heuristic E regression tests (TIER1_REVIEW) ============ + +def test_heuristic_e_narrow_return_errorinfo_is_compliant(): + """Phase 9 redo: narrow except + return ErrorInfo(...) is a true drain. + + Per TIER1_REVIEW_phase9_dilemma_20260620: a narrow except body that + returns a structured ErrorInfo carries the original exception and is + the function's contract. This is NOT sliming (the error context is + preserved in `original=e`). + """ + src = ( + "def _classify_anthropic_error(exc, source):\n" + " try:\n" + " err_data = exc.response.json()\n" + " except (ValueError, AttributeError) as e:\n" + " return ErrorInfo(kind=ErrorKind.UNKNOWN, message=str(e), source=source, original=e)\n" + ) + visitor = _make_visitor(src, "_classify_anthropic_error") + try_node = _find_handler(visitor) + handler = try_node.handlers[0] + category, hint = visitor._classify_except(handler, try_node) + assert category in ("INTERNAL_COMPLIANT", "BOUNDARY_CONVERSION"), ( + f"Heuristic E regression: narrow except + return ErrorInfo(...) " + f"should be a compliant classification (INTERNAL_COMPLIANT via Heuristic E " + f"or BOUNDARY_CONVERSION via existing creates_errorinfo check); got {category}. Hint: {hint}" + ) + + +def test_heuristic_e_narrow_dict_error_true_assign_is_compliant(): + """Phase 9 redo: narrow except + dict[error] = True is a true drain (in-band flag). + + Per TIER1_REVIEW: `except (NarrowType) as e: item["error"] = True` + is a structured error carrier. The caller is expected to inspect the + `error` flag (per-site decision documented in track notes; the audit + does NOT verify caller reads the flag). + """ + src = ( + "def _reread_file_items(file_items):\n" + " try:\n" + " content = p.read_text()\n" + " new_item = {**item, 'content': content}\n" + " except (OSError, UnicodeDecodeError) as e:\n" + " err_item = {**item, 'content': f'ERROR: {e}'}\n" + " err_item['error'] = True\n" + " refreshed.append(err_item)\n" + ) + visitor = _make_visitor(src, "_reread_file_items") + try_node = _find_handler(visitor) + handler = try_node.handlers[0] + category, hint = visitor._classify_except(handler, try_node) + assert category == "INTERNAL_COMPLIANT", ( + f"Heuristic E regression: narrow except + dict['error'] = True " + f"should be INTERNAL_COMPLIANT (in-band error flag carrier); got {category}. Hint: {hint}" + ) + + +def test_heuristic_e_empty_default_args_is_NOT_compliant(): + """Phase 9 redo: narrow except + args = {} is NOT a drain (sliming). + + Per TIER1_REVIEW: the empty-default pattern loses error context. The + caller cannot distinguish success from failure. Heuristic E + explicitly does NOT match this pattern (this test is a regression + guard against future "helpful" heuristic additions that would + laundering this sliming pattern). + + Structure: extract into a helper function so the try is at the top + level of the function body (required by _find_handler test helper). + """ + src = ( + "def _parse_tool_args(tool_args_str):\n" + " try:\n" + " args = json.loads(tool_args_str)\n" + " except (ValueError, TypeError):\n" + " args = {}\n" + " return args\n" + ) + visitor = _make_visitor(src, "_parse_tool_args") + try_node = _find_handler(visitor) + handler = try_node.handlers[0] + category, hint = visitor._classify_except(handler, try_node) + # The site is narrow + non-broad but the body is empty-default. + # Heuristic E should NOT classify as COMPLIANT. May be INTERNAL_BROAD_CATCH + # (no drain) or UNCLEAR. NOT INTERNAL_COMPLIANT or BOUNDARY_CONVERSION. + assert category not in ("INTERNAL_COMPLIANT", "BOUNDARY_CONVERSION"), ( + f"Heuristic E regression: narrow except + args = {{}} (empty default) " + f"must NOT be classified as compliant (INTERNAL_COMPLIANT or BOUNDARY_CONVERSION " + f"would be sliming per TIER1_REVIEW). Got {category} which would laundering the pattern. Hint: {hint}" + )