Repository navigation
Agent panel: an interrupted turn that settles during app shutdown raises NoMatches #476
Description
Problem
tests/ui/test_agent_interrupt.py::test_stop_then_immediate_shutdown_injects_cancellation_once failed on test (3.12) in #471's CI (run 39981310444, korvid-runners, four xdist workers):
src/korvid/ui/app.py:1488: in on_unmount
src/korvid/ui/agent_ui_controller.py:1460: in shutdown (await self.wait_for_turn())
src/korvid/ui/agent_ui_controller.py:1335: in run_turn (self._finish_interrupted_turn(session))
src/korvid/ui/agent_ui_controller.py:1396: in _finish_interrupted_turn
self._panel.apply_event(event)
E textual.css.query.NoMatches: No nodes match '#agent-status' on AgentPanel()
Cause
Textual's App._shutdown does three things in order:
- Sets
_running = False. - Removes every screen and widget (
_close_all). - Only then sends the App its
Unmount.
KorvidApp.on_unmount is where begin_shutdown marks the agent session down, so it runs after the panel's children are gone. A turn the user interrupted just before quitting can settle inside step 2. _finish_interrupted_turn then sees _shutting_down still False and calls AgentPanel.apply_event, which queries #agent-status on a panel whose children were pruned. The NoMatches fails the turn task. shutdown() re-raises it from wait_for_turn, and the exception escapes app shutdown. Load widens that window: with four xdist workers on a shared runner node, the test hit it.
This is the same family as #455, where a screen was mounted during shutdown.
Done when
- An agent event that reaches the panel after the app has started shutting down is dropped instead of raising.
- A test reproduces the ordering deterministically: the interrupted turn settles after Textual has pruned the panel and before the App's
Unmount.
Activity
Bundle: three race fixes and the gitpython, virtualenv and filelock s…