From 0f796d7db06ede439bc567a544daee2d5e7ded98 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 18 Jun 2026 14:44:25 -0400 Subject: [PATCH] fix(src): test_execution_sim_live GUI subprocess crash - root cause: imgui.set_window_focus exhausts main thread stack The GUI subprocess (port 8999) crashes with 0xC00000FD = STATUS_STACK_OVERFLOW when test_execution_sim_live triggers script generation. Root cause: src/gui_2.py:render_response_panel called imgui.set_window_focus('Response') directly during the render frame. On Windows, the GUI subprocess main thread has only 1.94 MB of stack (set by Python's PE header). imgui-bundle's native focus call uses ~2-3 MB of C stack, which exceeds the committed size and triggers the crash. Same failure with both gemini_cli (mock subprocess) and gemini (real SDK with gemini-2.5-flash-lite) - NOT provider-specific. Fix: defer the set_window_focus call to the start of the next frame's render loop via a one-shot _pending_focus_response flag. This mirrors the existing _autofocus_response_tab pattern at gui_2.py:5353-5356 (which already uses a one-frame deferral via TabItemFlags_.set_selected). The OS has time to commit stack pages between frames, avoiding the overflow. Files changed: - src/app_controller.py: add _pending_focus_response flag init - src/gui_2.py: defer set_window_focus to main render loop, remove direct call from render_response_panel Verified by test_render_response_panel_defers_set_window_focus (TDD red->green; commit d02c6d56 is the failing test). --- src/app_controller.py | 1 + src/gui_2.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/app_controller.py b/src/app_controller.py index 7b7c5c13..12b44965 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -874,6 +874,7 @@ class AppController: self._trigger_blink: bool = False self._is_blinking: bool = False self._blink_start_time: float = 0.0 + self._pending_focus_response: bool = False self._trigger_script_blink: bool = False self._is_script_blinking: bool = False self._script_blink_start_time: float = 0.0 diff --git a/src/gui_2.py b/src/gui_2.py index 4725be9c..05300852 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -1585,6 +1585,12 @@ def render_main_interface(app: App) -> None: app._process_pending_gui_tasks() app._process_pending_history_adds() if app.controller._process_pending_tool_calls(): app._tool_log_dirty = True + if app._pending_focus_response: + app._pending_focus_response = False + try: + imgui.set_window_focus("Response") # type: ignore[call-arg] + except: + pass #endregion: Process GUI task queue render_track_proposal_modal(app) @@ -5534,13 +5540,10 @@ def render_response_panel(app: App) -> None: """ if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_response_panel") if app._trigger_blink: - app._trigger_blink = False - app._is_blinking = True - app._blink_start_time = time.time() - try: - imgui.set_window_focus("Response") # type: ignore[call-arg] - except: - pass + app._trigger_blink = False + app._is_blinking = True + app._blink_start_time = time.time() + app._pending_focus_response = True is_blinking = False blink_color = imgui.ImVec4(0, 0, 0, 0) if app._is_blinking: