test(tests): TDD for test_execution_sim_live GUI subprocess crash (failing test)
Captures the structural root cause of the test_execution_sim_live failure: src/gui_2.py:render_response_panel calls imgui.set_window_focus directly during the render frame. On Windows, the GUI subprocess main thread has only 1.94 MB of stack; the focus call exhausts it and crashes the GUI with 0xC00000FD = STATUS_STACK_OVERFLOW. This test enforces the fix's contract: the render body must NOT call imgui.set_window_focus directly; it must defer the call via a _pending_focus_response flag to the next frame's idle phase. Mirrors the existing _autofocus_response_tab pattern at gui_2.py:5353-5356. Test currently FAILS on this commit. Will pass after the fix in src/gui_2.py:render_response_panel and the deferred handler in the main render loop.
This commit is contained in:
@@ -69,4 +69,73 @@ def test_execution_sim_live(live_gui: Any) -> None:
|
||||
client.set_value('auto_add_history', True)
|
||||
sim.run()
|
||||
time.sleep(2)
|
||||
sim.teardown()
|
||||
sim.teardown()
|
||||
|
||||
def test_render_response_panel_defers_set_window_focus() -> None:
|
||||
"""Regression test for the GUI subprocess STATUS_STACK_OVERFLOW crash.
|
||||
|
||||
Captures the root cause of the `test_execution_sim_live` failure: the
|
||||
`render_response_panel` function used to call
|
||||
`imgui.set_window_focus("Response")` directly during the render frame.
|
||||
On Windows, the GUI subprocess's 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
|
||||
`0xC00000FD = STATUS_STACK_OVERFLOW`.
|
||||
|
||||
The contract enforced here: the render body MUST defer the call to the
|
||||
next frame's idle phase via a one-shot `_pending_focus_response` flag.
|
||||
The fix mirrors the existing `_autofocus_response_tab` pattern
|
||||
(see `src/gui_2.py:5353-5356`).
|
||||
|
||||
Note: the source function is `render_response_panel` (no underscore).
|
||||
The `_render_response_panel` label in the bug report is the perf-monitor
|
||||
component name, not the function name.
|
||||
"""
|
||||
import re
|
||||
gui_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src", "gui_2.py"))
|
||||
with open(gui_path, "r", encoding="utf-8") as f:
|
||||
src = f.read()
|
||||
|
||||
# Extract the render_response_panel function body. Non-greedy match up
|
||||
# to the next top-level def (or end of file) so nested defs/comments
|
||||
# inside the body are not treated as the boundary.
|
||||
match = re.search(
|
||||
r"def render_response_panel\(app: App\) -> None:.*?(?=\ndef |\Z)",
|
||||
src,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match is not None, "render_response_panel function not found in src/gui_2.py"
|
||||
body = match.group(0)
|
||||
rest = src[:match.start()] + src[match.end():]
|
||||
|
||||
# 1. The render body MUST NOT call imgui.set_window_focus("Response")
|
||||
# directly. A direct call during the render frame exhausts the 1.94 MB
|
||||
# main thread stack of the GUI subprocess and causes STATUS_STACK_OVERFLOW.
|
||||
assert 'imgui.set_window_focus("Response")' not in body, (
|
||||
"render_response_panel still calls imgui.set_window_focus('Response') directly. "
|
||||
"This exhausts the 1.94 MB main thread stack of the GUI subprocess and causes "
|
||||
"STATUS_STACK_OVERFLOW (0xC00000FD). Defer the call to the next frame's idle "
|
||||
"phase by setting app._pending_focus_response = True and handling it in the "
|
||||
"main render loop, mirroring the _autofocus_response_tab pattern."
|
||||
)
|
||||
|
||||
# 2. The render body MUST signal the deferral by setting the flag.
|
||||
assert "_pending_focus_response = True" in body, (
|
||||
"render_response_panel must set _pending_focus_response = True (e.g. "
|
||||
"app._pending_focus_response = True) when _trigger_blink fires. The deferred "
|
||||
"handler in the main render loop will consume the flag on the next frame's "
|
||||
"idle phase and then clear it."
|
||||
)
|
||||
|
||||
# 3. The main render flow (everything outside render_response_panel) MUST
|
||||
# contain a deferred handler that reads the flag and calls
|
||||
# imgui.set_window_focus("Response") when the flag is set.
|
||||
assert "app._pending_focus_response" in rest, (
|
||||
"No reference to app._pending_focus_response found outside render_response_panel. "
|
||||
"The main render loop must read the flag and call imgui.set_window_focus('Response') "
|
||||
"when it is set, then clear the flag."
|
||||
)
|
||||
assert 'imgui.set_window_focus("Response")' in rest, (
|
||||
"No imgui.set_window_focus('Response') call found outside render_response_panel. "
|
||||
"The deferred handler in the main render flow must invoke it when the flag is set."
|
||||
)
|
||||
Reference in New Issue
Block a user