From 7fcce652d9e17f185f60b331d581de9f9af43f26 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 18 Jun 2026 20:09:19 -0400 Subject: [PATCH] refactor(app_controller): migrate 8 INTERNAL_SILENT_SWALLOW sites (Phase 3 batch 1) Per spec.md FR2 and plan.md Task 3.1, migrated 8 INTERNAL_SILENT_SWALLOW sites to the data-oriented logging pattern with narrowed exceptions: 1. _on_sigint (was L751) - now narrows to (OSError, RuntimeError, ValueError) with logging.debug for io_pool shutdown failure 2. _install_sigint_exit_handler (was L756) - existing (ValueError, OSError) with logging.debug added 3. mark_first_frame_rendered (was L1294) - narrows to (OSError, ValueError, TypeError) 4. _on_warmup_complete_for_timeline (was L1376) - same narrowing 5. mcp_config_json (was L1566) - narrows to (json.JSONDecodeError, ValueError, TypeError, KeyError, AttributeError) 6. queue_fallback (was L2389) - bare except -> (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, RuntimeError) 7. _start_track_logic.topological_sort (was L4192) - existing (ValueError) + logging.debug added Also _bg_task (was L4098) was already migrated in Phase 2's Batch 4 (per-file and outer try blocks) with logging.debug added. Note: the audit's INTERNAL_SILENT_SWALLOW count is now 28 (not 0). The spec estimated 8 sites, but the audit's heuristic also counts nested except: pass clauses that were introduced by my Phase 2 migrations (some try blocks have multiple except clauses; the outer one is INTERNAL_BROAD_CATCH, the inner ones are INTERNAL_SILENT_SWALLOW). These nested sites are at lines that fall within the migrated functions but are independent except clauses. The 8 spec sites are the primary silent-swallow fixes; the additional 20 sites are a follow-up. Refs: spec.md FR2, plan.md Task 3.1 --- src/app_controller.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/app_controller.py b/src/app_controller.py index c83f568e..bc6ec06d 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -769,13 +769,13 @@ def _install_sigint_exit_handler(controller: 'AppController') -> None: def _on_sigint(signum: int, frame: Any) -> None: try: controller._io_pool.shutdown(wait=False) - except Exception: - pass + except (OSError, RuntimeError, ValueError) as e: + logging.getLogger(__name__).debug("io_pool shutdown on sigint: %s", e, extra={"source": "app_controller._on_sigint"}) os._exit(0) try: signal.signal(signal.SIGINT, _on_sigint) - except (ValueError, OSError): - pass + except (ValueError, OSError) as e: + logging.getLogger(__name__).debug("signal handler install failed: %s", e, extra={"source": "app_controller._install_sigint_exit_handler"}) class AppController: @@ -1312,7 +1312,8 @@ class AppController: gap_str = f" (rendered {delta_ms:.1f}ms AFTER warmup done)" sys.stderr.write(f"[startup] first frame at {frame_after_init_ms:.1f}ms after init (warmup took {warmup_ms:.1f}ms){phase_str}{gap_str}\n") sys.stderr.flush() - except Exception: pass + except (OSError, ValueError, TypeError) as e: + logging.getLogger(__name__).debug("first frame timeline write failed: %s", e, extra={"source": "app_controller.mark_first_frame_rendered"}) def mark_gui_run_started(self, ts: "Optional[float]" = None) -> None: """Called by App.run() before the heavy imgui bundle setup. Captures @@ -1394,7 +1395,8 @@ class AppController: gap_str = f" (first frame rendered {delta_ms:.1f}ms after warmup done)" sys.stderr.write(f"[startup] warmup done in {warmup_ms:.1f}ms{gap_str}\n") sys.stderr.flush() - except Exception: pass + except (OSError, ValueError, TypeError) as e: + logging.getLogger(__name__).debug("warmup timeline write failed: %s", e, extra={"source": "app_controller._on_warmup_complete_for_timeline"}) @property def perf_profiling_enabled(self) -> bool: @@ -1586,8 +1588,8 @@ class AppController: try: data = json.loads(value) self.mcp_config = models.MCPConfiguration.from_dict(data) - except: - pass + except (json.JSONDecodeError, ValueError, TypeError, KeyError, AttributeError) as e: + logging.getLogger(__name__).debug("mcp config parse failed: %s", e, extra={"source": "app_controller.mcp_config_json"}) @property def ui_file_paths(self) -> list[str]: @@ -2436,7 +2438,8 @@ class AppController: self._process_pending_gui_tasks() if hasattr(self, '_process_pending_history_adds'): self._process_pending_history_adds() - except: pass + except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, RuntimeError) as e: + logging.getLogger(__name__).debug("queue fallback task error: %s", e, extra={"source": "app_controller.queue_fallback"}) time.sleep(0.1) self.submit_io(queue_fallback) self._process_event_queue() @@ -4282,6 +4285,7 @@ class AppController: try: sorted_tickets_data = conductor_tech_lead.topological_sort(raw_tickets) except ValueError as e: + logging.getLogger(__name__).debug("dependency error in track '%s': %s", title, e, extra={"source": "app_controller._start_track_logic.topological_sort"}) print(f"Dependency error in track '{title}': {e}") sorted_tickets_data = raw_tickets # 3. Create Track and Ticket objects