Private
Public Access
0
0

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).
This commit is contained in:
2026-06-18 14:44:25 -04:00
parent d02c6d569c
commit 0f796d7db0
2 changed files with 11 additions and 7 deletions
+1
View File
@@ -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
+10 -7
View File
@@ -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: