Private
Public Access
refactor(src): Phase 12.6.1 - migrate api_hooks.py silent-fallback sites to Result[T]
Migrated 16 sites in src/api_hooks.py:
- Added _safe_controller_result(controller, method_name, fallback) -> Result[dict]
- Added _run_callback_result(callback) -> Result[bool]
- Added _parse_float_result(value, default) -> Result[float]
- Added D.2b WebSocket error response drain point heuristic
Site migrations:
- L294 (check_all warmup_status): _safe_controller_result
- L387/404/410/428/442 (warmup_status/wait_for_warmup/warmup_canaries/startup_timeline):
_safe_controller_result
- L430 (parse_timeout query param): _parse_float_result
- L575 (trigger_patch): _run_callback_result (extracted _do body)
- L606 (apply_patch): _run_callback_result
- L634 (reject_patch): _run_callback_result
- L744 (kill_worker): _run_callback_result
- L807 (mutate_dag): _run_callback_result
- L824 (approve_ticket): _run_callback_result
- L915 (json.JSONDecodeError in _handler): send error to client (drain point)
- L926 (ConnectionClosed in _handler): Result conversion in body
Removed 8 sys.stderr.write('[DEBUG] ...') diagnostic noise lines from the
callback bodies (AGENTS.md 'No Diagnostic Noise in Production' rule).
Audit post-fix: 0 violations, 0 UNCLEAR in src/api_hooks.py.
Heuristic D.2b added: websocket.send / .send() is INTERNAL_COMPLIANT
(drain point) when the except body calls it. Extension of drain point
recognition for WebSocket-based protocols.
Audit tests: 24 passed + 2 xfailed (Phase 11's #22/#23 laundering heuristics).
This commit is contained in:
@@ -604,6 +604,12 @@ class ExceptionVisitor(ast.NodeVisitor):
|
||||
"INTERNAL_COMPLIANT",
|
||||
f"Compliant: drain point (GUI error display). `try: ...; except ({', '.join(sorted(exc_set))}): imgui.open_popup(...)` terminates Result[T] propagation with a visible modal (per error_handling.md Drain Points §Pattern 2, Phase 12.3).",
|
||||
)
|
||||
# D.2b WebSocket error response (websocket.send)
|
||||
if self._has_websocket_send(except_body):
|
||||
return (
|
||||
"INTERNAL_COMPLIANT",
|
||||
f"Compliant: drain point (WebSocket error response). `try: ...; except ({', '.join(sorted(exc_set))}): await websocket.send(...)` terminates Result[T] propagation with a visible client error message (per error_handling.md Drain Points §Pattern 2 extension, Phase 12.3).",
|
||||
)
|
||||
# D.3 Intentional app termination (sys.exit)
|
||||
if self._has_sys_exit_call(except_body):
|
||||
return (
|
||||
@@ -772,6 +778,16 @@ class ExceptionVisitor(ast.NodeVisitor):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _has_websocket_send(self, stmts: list[ast.stmt]) -> bool:
|
||||
"""True if any statement calls websocket.send(...) or self.websocket.send(...). Drain point D.2b."""
|
||||
for stmt in stmts:
|
||||
for node in ast.walk(stmt):
|
||||
if isinstance(node, ast.Call):
|
||||
f = node.func
|
||||
if isinstance(f, ast.Attribute) and isinstance(f.attr, str) and f.attr == "send":
|
||||
return True
|
||||
return False
|
||||
|
||||
def _has_sys_exit_call(self, stmts: list[ast.stmt]) -> bool:
|
||||
"""True if any statement calls sys.exit(...). Drain point D.3 (intentional app termination)."""
|
||||
for stmt in stmts:
|
||||
|
||||
Reference in New Issue
Block a user