diff --git a/src/gui_2.py b/src/gui_2.py index 9562bb89..ff6a3d93 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -598,42 +598,19 @@ class App: def _handle_save_anyway_click(self) -> None: self._pending_save_anyway_click = True -def _post_init_callback_result(app: "App") -> Result[None]: - """Drain-aware variant of App._post_init (L612 INTERNAL_SILENT_SWALLOW). - - Extracts the controller.on_warmup_complete callback registration from - App._post_init into a Result-returning helper. On exception, returns - Result(data=None, errors=[ErrorInfo]) so the legacy wrapper can drain - the error to self._startup_timeline_errors. On success, the lambda - callback is registered and Result(data=None) is returned. - - [C: src/gui_2.py:App._post_init (L612 legacy wrapper)] - """ - #Note(Ed): Exception(Thirdparty) - try: - app.controller.on_warmup_complete(lambda status: _on_warmup_complete_callback(app, status)) - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"on_warmup_complete callback registration failed: {e}", - source="gui_2._post_init_callback_result", - original=e, - )]) - -def _post_init(self) -> None: - theme.apply_current() - # Register warmup completion callback (sub-track 4 of - # startup_speedup_20260606). The callback runs on a background - # _io_pool thread; it only sets primitive state on the App, which - # is safe. The render_warmup_status_indicator() function reads - # the timestamp to show a brief "ready" tag for 3 seconds. - if hasattr(self.controller, "on_warmup_complete"): - cb_result = _post_init_callback_result(self) - if not cb_result.ok: - if not hasattr(self, '_startup_timeline_errors'): self._startup_timeline_errors = [] - self._startup_timeline_errors.append(("_post_init.callback", cb_result.errors[0])) - self._diag_layout_state() + def _post_init(self) -> None: + theme.apply_current() + # Register warmup completion callback (sub-track 4 of + # startup_speedup_20260606). The callback runs on a background + # _io_pool thread; it only sets primitive state on the App, which + # is safe. The render_warmup_status_indicator() function reads + # the timestamp to show a brief "ready" tag for 3 seconds. + if hasattr(self.controller, "on_warmup_complete"): + cb_result = _post_init_callback_result(self) + if not cb_result.ok: + if not hasattr(self, '_startup_timeline_errors'): self._startup_timeline_errors = [] + self._startup_timeline_errors.append(("_post_init.callback", cb_result.errors[0])) + self._diag_layout_state() def _diag_layout_state(self) -> None: """One-shot startup diagnostic: log show_windows state and warn if the @@ -745,43 +722,18 @@ def _post_init(self) -> None: self.runner_params.callbacks.post_init = _profiled_post_init self._fetch_models(self.current_provider) md_options = markdown_helper.get_renderer().options -def _run_immapp_result(app: "App") -> Result[None]: - """Drain-aware variant of App.run immapp.run() call (L728 INTERNAL_SILENT_SWALLOW). - - Extracts the thirdparty immapp.run() invocation from App.run into a - Result-returning helper. On exception (RuntimeError from IM_ASSERT or - other native-bundle errors), converts to ErrorInfo. The legacy run - method sets controller._gui_degraded_reason and _last_imgui_assert - (the canonical degradation drain), appends to _startup_timeline_errors, - and returns. NO logging: logging is NOT a drain per the user's - principle 2026-06-17. - - [C: src/gui_2.py:App.run (L728 legacy wrapper)] - """ - #Note(Ed): Exception(Thirdparty) - try: - immapp.run(app.runner_params, add_ons_params=immapp.AddOnsParams(with_markdown_options=markdown_helper.get_renderer().options)) - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"immapp.run raised {type(e).__name__}: {e}", - source="gui_2._run_immapp_result", - original=e, - )]) - - run_result = _run_immapp_result(self) - if not run_result.ok: - err = run_result.errors[0] - if hasattr(self, "controller") and self.controller is not None: - self.controller._gui_degraded_reason = err.message - self.controller._last_imgui_assert = traceback.format_exception(type(err.original), err.original, err.original.__traceback__) if err.original else "" - if not hasattr(self, '_startup_timeline_errors'): self._startup_timeline_errors = [] - self._startup_timeline_errors.append(("run.immapp", err)) - return - # On exit (only reached on clean shutdown) - self.shutdown() - session_logger.close_session() + run_result = _run_immapp_result(self) + if not run_result.ok: + err = run_result.errors[0] + if hasattr(self, "controller") and self.controller is not None: + self.controller._gui_degraded_reason = err.message + self.controller._last_imgui_assert = traceback.format_exception(type(err.original), err.original, err.original.__traceback__) if err.original else "" + if not hasattr(self, '_startup_timeline_errors'): self._startup_timeline_errors = [] + self._startup_timeline_errors.append(("run.immapp", err)) + return + # On exit (only reached on clean shutdown) + self.shutdown() + session_logger.close_session() def _load_fonts(self) -> None: from src.startup_profiler import startup_profiler @@ -1051,29 +1003,6 @@ def _run_immapp_result(app: "App") -> Result[None]: self._startup_timeline_errors.append(("shutdown.save_ini", ini_result.errors[0])) self.controller.shutdown() -def _shutdown_save_ini_result(app: "App") -> Result[None]: - """Drain-aware variant of App.shutdown save_ini try block (L1052 INTERNAL_SILENT_SWALLOW). - - Extracts the thirdparty imgui.save_ini_settings_to_disk try/except from - App.shutdown into a Result-returning helper. On exception, converts to - ErrorInfo (logging NOT a drain per the user's principle 2026-06-17). The - legacy shutdown method drains to self._startup_timeline_errors. - - [C: src/gui_2.py:App.shutdown (L1052 legacy wrapper)] - """ - #Note(Ed): Exception(Thirdparty) - try: - if hasattr(app, 'runner_params') and app.runner_params.ini_filename: - imgui.save_ini_settings_to_disk(app.runner_params.ini_filename) - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"imgui.save_ini_settings_to_disk failed: {e}", - source="gui_2._shutdown_save_ini_result", - original=e, - )]) - def load_context_preset(self, name: str) -> None: preset = self.controller.load_context_preset(name) from src import models @@ -1168,32 +1097,7 @@ def _shutdown_save_ini_result(app: "App") -> Result[None]: log_result = _gui_func_entry_log_result(self) if not log_result.ok: if not hasattr(self, '_last_request_errors'): self._last_request_errors = [] - self._last_request_errors.append(("_gui_func.entry_log", log_result.errors[0])) - -def _gui_func_entry_log_result(app: "App") -> Result[None]: - """Drain-aware variant of App._gui_func startup-timing log (L1152 INTERNAL_SILENT_SWALLOW). - - Extracts the first-frame startup-timing sys.stderr.write/flush from - App._gui_func into a Result-returning helper. On exception (broken pipe, - OSError on the stderr stream), converts to ErrorInfo (logging NOT a drain - per the user's principle 2026-06-17). The legacy _gui_func method - drains to self._last_request_errors. - - [C: src/gui_2.py:App._gui_func (L1152 legacy wrapper)] - """ - try: - init_ts = getattr(app.controller, "_init_start_ts", None) - if init_ts is not None: - sys.stderr.write(f"[startup] first _gui_func entry at {(time.time() - init_ts) * 1000:.1f}ms after init (window/GL + font/style/post_init callbacks done)\n") - sys.stderr.flush() - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"gui_func entry log failed: {e}", - source="gui_2._gui_func_entry_log_result", - original=e, - )]) + self._last_request_errors.append(('_gui_func.entry_log', log_result.errors[0])) # One-shot: kick off the controller's heavy-module warmup on the shared # io_pool once the FIRST frame has actually been painted. Waiting one frame @@ -1468,32 +1372,9 @@ def _gui_func_entry_log_result(app: "App") -> Result[None]: term_result = _close_vscode_diff_terminate_result(self) if not term_result.ok: if not hasattr(self, '_last_request_errors'): self._last_request_errors = [] - self._last_request_errors.append(("_close_vscode_diff.terminate", term_result.errors[0])) + self._last_request_errors.append(('_close_vscode_diff.terminate', term_result.errors[0])) self._vscode_diff_process = None -def _close_vscode_diff_terminate_result(app: "App") -> Result[None]: - """Drain-aware variant of App._close_vscode_diff terminate try block (L1466 INTERNAL_SILENT_SWALLOW). - - Extracts the self._vscode_diff_process.terminate() try/except from - App._close_vscode_diff into a Result-returning helper. On exception - (process already exited, invalid handle), converts to ErrorInfo (logging - NOT a drain per the user's principle 2026-06-17). The legacy wrapper - drains to self._last_request_errors and proceeds to set - self._vscode_diff_process = None (preserving the original behavior). - - [C: src/gui_2.py:App._close_vscode_diff (L1466 legacy wrapper)] - """ - try: - app._vscode_diff_process.terminate() - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"_vscode_diff_process.terminate failed: {e}", - source="gui_2._close_vscode_diff_terminate_result", - original=e, - )]) - def _apply_pending_patch(self) -> None: if not self._pending_patch_text: self._patch_error_message = "No patch to apply" @@ -1598,6 +1479,275 @@ def _close_vscode_diff_terminate_result(app: "App") -> Result[None]: changed = True self._push_mma_state_update() +def _post_init_callback_result(app: "App") -> Result[None]: + """Drain-aware variant of App._post_init (L612 INTERNAL_SILENT_SWALLOW). + + Extracts the controller.on_warmup_complete callback registration from + App._post_init into a Result-returning helper. On exception, returns + Result(data=None, errors=[ErrorInfo]) so the legacy wrapper can drain + the error to self._startup_timeline_errors. On success, the lambda + callback is registered and Result(data=None) is returned. + + [C: src/gui_2.py:App._post_init (L612 legacy wrapper)] + """ + #Note(Ed): Exception(Thirdparty) + try: + app.controller.on_warmup_complete(lambda status: _on_warmup_complete_callback(app, status)) + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"on_warmup_complete callback registration failed: {e}", + source="gui_2._post_init_callback_result", + original=e, + )]) +def _run_immapp_result(app: "App") -> Result[None]: + """Drain-aware variant of App.run immapp.run() call (L728 INTERNAL_SILENT_SWALLOW). + + Extracts the thirdparty immapp.run() invocation from App.run into a + Result-returning helper. On exception (RuntimeError from IM_ASSERT or + other native-bundle errors), converts to ErrorInfo. The legacy run + method sets controller._gui_degraded_reason and _last_imgui_assert + (the canonical degradation drain), appends to _startup_timeline_errors, + and returns. NO logging: logging is NOT a drain per the user's + principle 2026-06-17. + + [C: src/gui_2.py:App.run (L728 legacy wrapper)] + """ + #Note(Ed): Exception(Thirdparty) + try: + immapp.run(app.runner_params, add_ons_params=immapp.AddOnsParams(with_markdown_options=markdown_helper.get_renderer().options)) + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"immapp.run raised {type(e).__name__}: {e}", + source="gui_2._run_immapp_result", + original=e, + )]) +def _shutdown_save_ini_result(app: "App") -> Result[None]: + """Drain-aware variant of App.shutdown save_ini try block (L1052 INTERNAL_SILENT_SWALLOW). + + Extracts the thirdparty imgui.save_ini_settings_to_disk try/except from + App.shutdown into a Result-returning helper. On exception, converts to + ErrorInfo (logging NOT a drain per the user's principle 2026-06-17). The + legacy shutdown method drains to self._startup_timeline_errors. + + [C: src/gui_2.py:App.shutdown (L1052 legacy wrapper)] + """ + #Note(Ed): Exception(Thirdparty) + try: + if hasattr(app, 'runner_params') and app.runner_params.ini_filename: + imgui.save_ini_settings_to_disk(app.runner_params.ini_filename) + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"imgui.save_ini_settings_to_disk failed: {e}", + source="gui_2._shutdown_save_ini_result", + original=e, + )]) +def _gui_func_entry_log_result(app: "App") -> Result[None]: + """Drain-aware variant of App._gui_func startup-timing log (L1152 INTERNAL_SILENT_SWALLOW). + + Extracts the first-frame startup-timing sys.stderr.write/flush from + App._gui_func into a Result-returning helper. On exception (broken pipe, + OSError on the stderr stream), converts to ErrorInfo (logging NOT a drain + per the user's principle 2026-06-17). The legacy _gui_func method + drains to self._last_request_errors. + + [C: src/gui_2.py:App._gui_func (L1152 legacy wrapper)] + """ + try: + init_ts = getattr(app.controller, "_init_start_ts", None) + if init_ts is not None: + sys.stderr.write(f"[startup] first _gui_func entry at {(time.time() - init_ts) * 1000:.1f}ms after init (window/GL + font/style/post_init callbacks done)\n") + sys.stderr.flush() + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"gui_func entry log failed: {e}", + source="gui_2._gui_func_entry_log_result", + original=e, + )]) +def _close_vscode_diff_terminate_result(app: "App") -> Result[None]: + """Drain-aware variant of App._close_vscode_diff terminate try block (L1466 INTERNAL_SILENT_SWALLOW). + + Extracts the self._vscode_diff_process.terminate() try/except from + App._close_vscode_diff into a Result-returning helper. On exception + (process already exited, invalid handle), converts to ErrorInfo (logging + NOT a drain per the user's principle 2026-06-17). The legacy wrapper + drains to self._last_request_errors and proceeds to set + self._vscode_diff_process = None (preserving the original behavior). + + [C: src/gui_2.py:App._close_vscode_diff (L1466 legacy wrapper)] + """ + try: + app._vscode_diff_process.terminate() + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"_vscode_diff_process.terminate failed: {e}", + source="gui_2._close_vscode_diff_terminate_result", + original=e, + )]) + +def _focus_response_window_result() -> Result[None]: + """Drain-aware variant of render_main_interface imgui.set_window_focus try block (L1647 INTERNAL_SILENT_SWALLOW). + + Extracts the thirdparty imgui.set_window_focus("Response") try/except from + render_main_interface into a Result-returning helper. On exception (native + bundle error, IM_ASSERT), converts to ErrorInfo (logging NOT a drain per + the user's principle 2026-06-17). The caller drains to + app._last_request_errors. + + [C: src/gui_2.py:render_main_interface (L1647 legacy wrapper)] + """ + try: + imgui.set_window_focus("Response") # type: ignore[call-arg] + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"imgui.set_window_focus('Response') failed: {e}", + source="gui_2._focus_response_window_result", + original=e, + )]) +def _autosave_flush_result(app: "App") -> Result[None]: + """Drain-aware variant of render_main_interface auto-save try block (L1693 INTERNAL_SILENT_SWALLOW). + + Extracts the auto-save flush_to_project + flush_to_config + save_config + try/except from render_main_interface into a Result-returning helper. On + exception (disk full, JSON parse error), converts to ErrorInfo (logging + NOT a drain per the user's principle 2026-06-17). The caller drains to + app._last_request_errors and continues with the GUI loop, preserving + the original "don't disrupt the GUI loop" intent via the data plane + rather than silent swallow. + + [C: src/gui_2.py:render_main_interface (L1693 legacy wrapper)] + """ + try: + app._flush_to_project() + app._flush_to_config() + app.save_config() + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"autosave flush failed: {e}", + source="gui_2._autosave_flush_result", + original=e, + )]) +def _on_warmup_complete_callback_result(app: "App", status: dict) -> Result[None]: + """Drain-aware variant of _on_warmup_complete_callback (L4911 INTERNAL_SILENT_SWALLOW). + + Extracts the warmup-completion body from _on_warmup_complete_callback + into a Result-returning helper. On exception (status dict corruption, + lock acquisition failure), converts to ErrorInfo (logging NOT a drain + per the user's principle 2026-06-17). The legacy callback drains to + app.controller._worker_errors with the controller lock acquired on + append (thread-safety critical per sub-track 4 spec). + + [C: src/gui_2.py:_on_warmup_complete_callback (L4911 legacy wrapper)] + """ + try: + app._warmup_completion_ts = time.time() + pending = status.get("pending", []) + completed = status.get("completed", []) + failed = status.get("failed", []) + total = len(pending) + len(completed) + len(failed) + if failed: msg = f"Warmup finished with {len(failed)} failures ({total} modules)" + else: msg = f"All imports ready ({total} modules)" + if not hasattr(app, "_warmup_toast_lock"): + import threading as _threading + app._warmup_toast_lock = _threading.Lock() + with app._warmup_toast_lock: + if not hasattr(app, "_warmup_toast_messages"): app._warmup_toast_messages = [] + app._warmup_toast_messages.append((time.time(), msg)) + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"on_warmup_complete_callback body failed: {e}", + source="gui_2._on_warmup_complete_callback_result", + original=e, + )]) + +def _tier_stream_scroll_sync_result(app: "App", stream_key: str, content: str, imgui_mod) -> Result[None]: + """Drain-aware variant of render_tier_stream_panel scroll-sync try block (L6908 INTERNAL_SILENT_SWALLOW). + + Extracts the narrow-except TypeError/AttributeError from + render_tier_stream_panel into a Result-returning helper. The narrow + except is the audit-classified SILENT_SWALLOW pattern: narrowing + + logging NOT a drain per the user's principle 2026-06-17. On exception, + converts to ErrorInfo. The caller (render_tier_stream_panel) drains + to app._last_request_errors. + + [C: src/gui_2.py:render_tier_stream_panel (L6908 caller)] + """ + try: + if len(content) != app._tier_stream_last_len.get(stream_key, -1): + imgui_mod.set_scroll_here_y(1.0) + app._tier_stream_last_len[stream_key] = len(content) + return Result(data=None) + except Exception as e: + return Result(data=None, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"tier stream scroll sync failed: {e}", + source="gui_2._tier_stream_scroll_sync_result", + original=e, + )]) +def _dag_cycle_check_result(app: "App") -> Result[bool]: + """Drain-aware variant of render_task_dag_panel DAG cycle check (L7271 INTERNAL_SILENT_SWALLOW). + + Extracts the TrackDAG construction + has_cycle check try/except from + render_task_dag_panel into a Result-returning helper. On a valid DAG, + returns Result(data=False). On a cyclic DAG, returns Result(data=True). + On exception (bad ticket dict, dag engine failure), converts to + ErrorInfo (logging NOT a drain per the user's principle 2026-06-17). + The caller drains to app._last_request_errors. + + [C: src/gui_2.py:render_task_dag_panel (L7271 caller)] + """ + from src.dag_engine import TrackDAG + try: + ticket_dicts = [{'id': str(t.get('id', '')), 'depends_on': t.get('depends_on', [])} for t in app.active_tickets] + temp_dag = TrackDAG(ticket_dicts) + has_cycle = temp_dag.has_cycle() + return Result(data=has_cycle) + except Exception as e: + return Result(data=False, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"DAG cycle check failed: {e}", + source="gui_2._dag_cycle_check_result", + original=e, + )]) + +def _ticket_id_max_int_result(tid: str) -> Result[int]: + """Drain-aware variant of render_task_dag_panel ticket-ID parsing (L7315 INTERNAL_SILENT_SWALLOW). + + Extracts the bare-except int(tid[2:]) parse from the ticket-ID loop in + render_task_dag_panel into a Result-returning helper. On success (valid + T-XXX id), returns Result(data=int). On failure (T-abc, T-, etc.), + returns Result(data=0, errors=[ErrorInfo]). The legacy loop skips + malformed tickets via the data plane (logging NOT a drain per the + user's principle 2026-06-17). The caller drains to + app._last_request_errors. + + [C: src/gui_2.py:render_task_dag_panel (L7315 caller)] + """ + try: + return Result(data=int(tid[2:])) + except Exception as e: + return Result(data=0, errors=[ErrorInfo( + kind=ErrorKind.INTERNAL, + message=f"ticket id parse failed for {tid!r}: {e}", + source="gui_2._ticket_id_max_int_result", + original=e, + )]) + def main() -> None: app = App() @@ -1647,29 +1797,7 @@ def render_main_interface(app: App) -> None: focus_result = _focus_response_window_result() if not focus_result.ok: if not hasattr(app, '_last_request_errors'): app._last_request_errors = [] - app._last_request_errors.append(("render_main_interface.focus_response", focus_result.errors[0])) - -def _focus_response_window_result() -> Result[None]: - """Drain-aware variant of render_main_interface imgui.set_window_focus try block (L1647 INTERNAL_SILENT_SWALLOW). - - Extracts the thirdparty imgui.set_window_focus("Response") try/except from - render_main_interface into a Result-returning helper. On exception (native - bundle error, IM_ASSERT), converts to ErrorInfo (logging NOT a drain per - the user's principle 2026-06-17). The caller drains to - app._last_request_errors. - - [C: src/gui_2.py:render_main_interface (L1647 legacy wrapper)] - """ - try: - imgui.set_window_focus("Response") # type: ignore[call-arg] - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"imgui.set_window_focus('Response') failed: {e}", - source="gui_2._focus_response_window_result", - original=e, - )]) + app._last_request_errors.append(('render_main_interface.focus_response', focus_result.errors[0])) #endregion: Process GUI task queue render_track_proposal_modal(app) @@ -1693,33 +1821,7 @@ def _focus_response_window_result() -> Result[None]: autosave_result = _autosave_flush_result(app) if not autosave_result.ok: if not hasattr(app, '_last_request_errors'): app._last_request_errors = [] - app._last_request_errors.append(("render_main_interface.autosave", autosave_result.errors[0])) - -def _autosave_flush_result(app: "App") -> Result[None]: - """Drain-aware variant of render_main_interface auto-save try block (L1693 INTERNAL_SILENT_SWALLOW). - - Extracts the auto-save flush_to_project + flush_to_config + save_config - try/except from render_main_interface into a Result-returning helper. On - exception (disk full, JSON parse error), converts to ErrorInfo (logging - NOT a drain per the user's principle 2026-06-17). The caller drains to - app._last_request_errors and continues with the GUI loop, preserving - the original "don't disrupt the GUI loop" intent via the data plane - rather than silent swallow. - - [C: src/gui_2.py:render_main_interface (L1693 legacy wrapper)] - """ - try: - app._flush_to_project() - app._flush_to_config() - app.save_config() - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"autosave flush failed: {e}", - source="gui_2._autosave_flush_result", - original=e, - )]) + app._last_request_errors.append(('render_main_interface.autosave', autosave_result.errors[0])) # Sync pending comms with app._pending_comms_lock: @@ -4922,42 +5024,7 @@ def _on_warmup_complete_callback(app: App, status: dict) -> None: if controller is not None and hasattr(controller, "_worker_errors_lock"): with controller._worker_errors_lock: if not hasattr(controller, "_worker_errors"): controller._worker_errors = [] - controller._worker_errors.append(("_on_warmup_complete_callback", cb_result.errors[0])) - -def _on_warmup_complete_callback_result(app: "App", status: dict) -> Result[None]: - """Drain-aware variant of _on_warmup_complete_callback (L4911 INTERNAL_SILENT_SWALLOW). - - Extracts the warmup-completion body from _on_warmup_complete_callback - into a Result-returning helper. On exception (status dict corruption, - lock acquisition failure), converts to ErrorInfo (logging NOT a drain - per the user's principle 2026-06-17). The legacy callback drains to - app.controller._worker_errors with the controller lock acquired on - append (thread-safety critical per sub-track 4 spec). - - [C: src/gui_2.py:_on_warmup_complete_callback (L4911 legacy wrapper)] - """ - try: - app._warmup_completion_ts = time.time() - pending = status.get("pending", []) - completed = status.get("completed", []) - failed = status.get("failed", []) - total = len(pending) + len(completed) + len(failed) - if failed: msg = f"Warmup finished with {len(failed)} failures ({total} modules)" - else: msg = f"All imports ready ({total} modules)" - if not hasattr(app, "_warmup_toast_lock"): - import threading as _threading - app._warmup_toast_lock = _threading.Lock() - with app._warmup_toast_lock: - if not hasattr(app, "_warmup_toast_messages"): app._warmup_toast_messages = [] - app._warmup_toast_messages.append((time.time(), msg)) - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"on_warmup_complete_callback body failed: {e}", - source="gui_2._on_warmup_complete_callback_result", - original=e, - )]) + controller._worker_errors.append(('_on_warmup_complete_callback', cb_result.errors[0])) def render_warmup_status_indicator(app: App) -> None: """Renders a transient warmup status indicator in the main interface frame. Shows progress @@ -6915,34 +6982,9 @@ def render_tier_stream_panel(app: App, tier_key: str, stream_key: str | None) -> original=e, ) if not hasattr(app, '_last_request_errors'): app._last_request_errors = [] - app._last_request_errors.append(("render_tier_stream_panel.scroll_sync", err)) + app._last_request_errors.append(('render_tier_stream_panel.scroll_sync', err)) finally: imgui.end_child() - -def _tier_stream_scroll_sync_result(app: "App", stream_key: str, content: str, imgui_mod) -> Result[None]: - """Drain-aware variant of render_tier_stream_panel scroll-sync try block (L6908 INTERNAL_SILENT_SWALLOW). - - Extracts the narrow-except TypeError/AttributeError from - render_tier_stream_panel into a Result-returning helper. The narrow - except is the audit-classified SILENT_SWALLOW pattern: narrowing + - logging NOT a drain per the user's principle 2026-06-17. On exception, - converts to ErrorInfo. The caller (render_tier_stream_panel) drains - to app._last_request_errors. - - [C: src/gui_2.py:render_tier_stream_panel (L6908 caller)] - """ - try: - if len(content) != app._tier_stream_last_len.get(stream_key, -1): - imgui_mod.set_scroll_here_y(1.0) - app._tier_stream_last_len[stream_key] = len(content) - return Result(data=None) - except Exception as e: - return Result(data=None, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"tier stream scroll sync failed: {e}", - source="gui_2._tier_stream_scroll_sync_result", - original=e, - )]) else: tier3_keys = [k for k in app.mma_streams if "Tier 3" in k] if not tier3_keys: @@ -7270,58 +7312,9 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer cycle_result = _dag_cycle_check_result(app) if not cycle_result.ok: if not hasattr(app, '_last_request_errors'): app._last_request_errors = [] - app._last_request_errors.append(("render_task_dag_panel.cycle_check", cycle_result.errors[0])) + app._last_request_errors.append(('render_task_dag_panel.cycle_check', cycle_result.errors[0])) elif cycle_result.data: imgui.open_popup("Cycle Detected!") - -def _dag_cycle_check_result(app: "App") -> Result[bool]: - """Drain-aware variant of render_task_dag_panel DAG cycle check (L7271 INTERNAL_SILENT_SWALLOW). - - Extracts the TrackDAG construction + has_cycle check try/except from - render_task_dag_panel into a Result-returning helper. On a valid DAG, - returns Result(data=False). On a cyclic DAG, returns Result(data=True). - On exception (bad ticket dict, dag engine failure), converts to - ErrorInfo (logging NOT a drain per the user's principle 2026-06-17). - The caller drains to app._last_request_errors. - - [C: src/gui_2.py:render_task_dag_panel (L7271 caller)] - """ - from src.dag_engine import TrackDAG - try: - ticket_dicts = [{'id': str(t.get('id', '')), 'depends_on': t.get('depends_on', [])} for t in app.active_tickets] - temp_dag = TrackDAG(ticket_dicts) - has_cycle = temp_dag.has_cycle() - return Result(data=has_cycle) - except Exception as e: - return Result(data=False, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"DAG cycle check failed: {e}", - source="gui_2._dag_cycle_check_result", - original=e, - )]) - -def _ticket_id_max_int_result(tid: str) -> Result[int]: - """Drain-aware variant of render_task_dag_panel ticket-ID parsing (L7315 INTERNAL_SILENT_SWALLOW). - - Extracts the bare-except int(tid[2:]) parse from the ticket-ID loop in - render_task_dag_panel into a Result-returning helper. On success (valid - T-XXX id), returns Result(data=int). On failure (T-abc, T-, etc.), - returns Result(data=0, errors=[ErrorInfo]). The legacy loop skips - malformed tickets via the data plane (logging NOT a drain per the - user's principle 2026-06-17). The caller drains to - app._last_request_errors. - - [C: src/gui_2.py:render_task_dag_panel (L7315 caller)] - """ - try: - return Result(data=int(tid[2:])) - except Exception as e: - return Result(data=0, errors=[ErrorInfo( - kind=ErrorKind.INTERNAL, - message=f"ticket id parse failed for {tid!r}: {e}", - source="gui_2._ticket_id_max_int_result", - original=e, - )]) ed.end() # 5. Add Ticket Form @@ -7329,7 +7322,7 @@ def _ticket_id_max_int_result(tid: str) -> Result[int]: if imgui.button("Add Ticket"): app._show_add_ticket_form = not app._show_add_ticket_form if app._show_add_ticket_form: - # Default Ticket ID + # Default Ticket ID max_id = 0 for t in app.active_tickets: tid = t.get('id', '') @@ -7339,11 +7332,11 @@ def _ticket_id_max_int_result(tid: str) -> Result[int]: max_id = max(max_id, parse_result.data) else: if not hasattr(app, '_last_request_errors'): app._last_request_errors = [] - app._last_request_errors.append(("render_task_dag_panel.ticket_id_parse", parse_result.errors[0])) - app.ui_new_ticket_id = f"T-{max_id + 1:03d}" - app.ui_new_ticket_desc = "" - app.ui_new_ticket_target = "" - app.ui_new_ticket_deps = "" + app._last_request_errors.append(('render_task_dag_panel.ticket_id_parse', parse_result.errors[0])) + app.ui_new_ticket_id = f"T-{max_id + 1:03d}" + app.ui_new_ticket_desc = "" + app.ui_new_ticket_target = "" + app.ui_new_ticket_deps = "" if app._show_add_ticket_form: imgui.begin_child("add_ticket_form", imgui.ImVec2(-1, 220), True) imgui.text_colored(C_VAL(), "New Ticket Details")