feat(scripts): Heuristic A - Result-returning recovery = INTERNAL_COMPLIANT

Phase 11.2. Adds the LEGITIMATE heuristic that recognizes the canonical
data-oriented pattern: \	ry: ...; except: return Result(data=...,
errors=[...])\ is the convention's canonical recovery pattern.

Detection:
- New _returns_result(stmts) helper on ExceptionVisitor
- New step 0 in _classify_except (BEFORE BOUNDARY_CONVERSION check)
- Classifies as INTERNAL_COMPLIANT with a hint that names the pattern

The function-name-not-ending-in-_result is documented as a smell
(rename to xxx_result for canonical naming), but the pattern itself
is compliant.

Tests:
- 2 new tests in test_audit_exception_handling_heuristics.py:
  - test_result_returning_recovery_in_non_result_named_function_is_compliant
  - test_result_returning_recovery_in_result_named_function_is_compliant
- Both pass; the 2 REJECTED tests (#22, #23) remain xfailed.

Per conductor/tracks/result_migration_small_files_20260617/plan.md
section 11.2.
This commit is contained in:
ed
2026-06-18 00:00:42 -04:00
parent 37872544d5
commit 3c839c910a
6 changed files with 262 additions and 0 deletions
@@ -337,3 +337,61 @@ def test_narrow_except_uses_error_inline_is_compliant():
assert excepts[0]["category"] == "INTERNAL_COMPLIANT", (
f"narrow except using error inline should be INTERNAL_COMPLIANT, got {excepts[0]['category']}"
)
# ---------------------------------------------------------------------------
# Heuristic A: Result-returning recovery in non-*_result function (Phase 11.2)
# ---------------------------------------------------------------------------
def test_result_returning_recovery_in_non_result_named_function_is_compliant():
"""try: ...; except SpecificError: return Result(data=..., errors=[ErrorInfo(...)]) is compliant.
The function returns a Result with errors= on failure (the canonical Result
recovery pattern). The convention requires Result[T] for try/except sites
that can fail; this pattern satisfies the requirement. The function name
not ending in '_result' is a smell (the function should be renamed to
'xxx_result') but the pattern itself is compliant.
This is the pattern used by src/hot_reloader.py:reload(),
src/warmup.py:on_complete/_record_success/_record_failure, and the
other 17 sites migrated in Phase 11.3.
"""
src = '''
from src.result_types import Result, ErrorInfo, ErrorKind
def reload(module_name):
try:
importlib.reload(sys.modules[module_name])
return Result(data=True)
except (ImportError, ModuleNotFoundError) as e:
return Result(data=False, errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="hot_reloader.reload", original=e)])
'''
data = _run_audit_on_fixture(src)
findings = _classifications_for_file(data, "audit_heuristic_fixture.py")
excepts = [f for f in findings if f["kind"] == "EXCEPT"]
assert len(excepts) == 1
assert excepts[0]["category"] == "INTERNAL_COMPLIANT", (
f"Result-returning recovery in non-*_result function should be INTERNAL_COMPLIANT, got {excepts[0]['category']}"
)
def test_result_returning_recovery_in_result_named_function_is_compliant():
"""Same pattern but with a function name ending in '_result' is also compliant (and ideal).
This is the canonical naming: functions that return Result should end in '_result'.
"""
src = '''
from src.result_types import Result, ErrorInfo, ErrorKind
def reload_result(module_name):
try:
importlib.reload(sys.modules[module_name])
return Result(data=True)
except (ImportError, ModuleNotFoundError) as e:
return Result(data=False, errors=[ErrorInfo(kind=ErrorKind.INTERNAL, message=str(e), source="hot_reloader.reload_result", original=e)])
'''
data = _run_audit_on_fixture(src)
findings = _classifications_for_file(data, "audit_heuristic_fixture.py")
excepts = [f for f in findings if f["kind"] == "EXCEPT"]
assert len(excepts) == 1
assert excepts[0]["category"] == "INTERNAL_COMPLIANT", (
f"Result-returning recovery in *_result function should be INTERNAL_COMPLIANT, got {excepts[0]['category']}"
)