Symptom
tests/ui/test_ctx_switch.py fails intermittently in CI (never reproduced locally, including with the CI's own --randomly-seed) with:
textual.app.ScreenStackError: No screens on stack
Observed occurrences (both on PR branches whose changes are unrelated to context switching):
Local reruns with the same seeds pass (uv run pytest tests/ui/test_ctx_switch.py -p randomly --randomly-seed=<seed>), and the CI rerun of the failed job passes as well — so this is timing/load-dependent flake, not an ordering dependency.
Impact
Every occurrence costs a full CI rerun (~20 min) on unrelated PRs. Twice within one day.
Hypothesis / where to look
ScreenStackError: No screens on stack from App.screen suggests something in these tests touches app.screen (or pushes/queries a screen) while the app is being torn down, or a worker from the switch races the pilot's shutdown on slow runners. test_switch_cancels_hint_refresh_timer and test_switch_rebinds_helm_wrapper both drive :ctx flows that spawn workers; a worker still running at run_test() exit may hit an empty screen stack.
Investigation should:
- Capture the full CI traceback to identify who reads
app.screen (test body, message handler, or worker callback).
- Check whether the
:ctx switch flow's workers are properly awaited/cancelled before pilot exit in these tests (repo rule: poll with tests/ui/waits.py::until(), no bare pauses).
- Consider guarding the offending
self.screen access with a screen-stack check if it can legitimately run during teardown.
Symptom
tests/ui/test_ctx_switch.pyfails intermittently in CI (never reproduced locally, including with the CI's own--randomly-seed) with:Observed occurrences (both on PR branches whose changes are unrelated to context switching):
test_switch_rebinds_helm_wrapper,test_switch_cancels_hint_refresh_timer(seed 2540732273, py3.12)test_switch_cancels_hint_refresh_timer(seed 1660354188, py3.11)Local reruns with the same seeds pass (
uv run pytest tests/ui/test_ctx_switch.py -p randomly --randomly-seed=<seed>), and the CI rerun of the failed job passes as well — so this is timing/load-dependent flake, not an ordering dependency.Impact
Every occurrence costs a full CI rerun (~20 min) on unrelated PRs. Twice within one day.
Hypothesis / where to look
ScreenStackError: No screens on stackfromApp.screensuggests something in these tests touchesapp.screen(or pushes/queries a screen) while the app is being torn down, or a worker from the switch races the pilot's shutdown on slow runners.test_switch_cancels_hint_refresh_timerandtest_switch_rebinds_helm_wrapperboth drive:ctxflows that spawn workers; a worker still running atrun_test()exit may hit an empty screen stack.Investigation should:
app.screen(test body, message handler, or worker callback).:ctxswitch flow's workers are properly awaited/cancelled before pilot exit in these tests (repo rule: poll withtests/ui/waits.py::until(), no bare pauses).self.screenaccess with a screen-stack check if it can legitimately run during teardown.