You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On main, session.close can pop and tear down a session while _run_prompt_submit() is between message.start and worker publication.
Because the pop did not mark the session as closing, the worker could still
start against resources that teardown had already closed. Close also finalized
the session without waiting for the recorded _run_thread, even when the turn
was only unwinding its post-terminal tail.
Both ownership decisions now use _sessions_lock: close publishes _closing
before detaching, and prompt dispatch rechecks that state while publishing and
starting its worker. Once a close has claimed the record, ordinary teardown
waits up to five seconds for that exact worker, outside the registry and resume
locks.
Tests
Both new behavior tests were verified red on upstream bb4f680f22b8d6ac66cecd0dec310c5a68f6b556:
2 failed, 573 deselected
They pass at this PR head:
2 passed, 573 deselected
Related lifecycle and dispatch selection:
18 passed, 557 deselected
Full changed test file:
575 passed
After the review delta, both changed test files pass together:
606 passed
Commands:
scripts/run_tests.sh tests/test_tui_gateway_server.py \
-k 'session_close_settles_active_turn_before_teardown or run_prompt_submit_rejects_worker_when_close_wins_publication'
scripts/run_tests.sh tests/test_tui_gateway_server.py \
-k 'session_close or close_session or run_prompt_submit'
scripts/run_tests.sh tests/test_tui_gateway_server.py
scripts/run_tests.sh \
tests/test_tui_gateway_queue_on_busy.py \
tests/test_tui_gateway_server.py
This is source-and-test proof at commit f0bcb3de7cab72f63e925da31e78f5d3b376f0b5. It does not claim merge, release,
deployment, or runtime/customer proof. No configuration, dependency, protocol,
or persisted-data format changes are included.
AI code review — automated review for reference, author can ignore or act on any point.
fix(tui): settle session close against active turns
_pop_session_by_id (server.py ~lines 964–976) now unconditionally sets session["_closing"] = True on every pop, not just on close. Today all three callers (close, close-with-predicate, WS orphan reaper) are terminal teardown paths, so it is safe — but the flag becomes a permanent property of the dict, so any future non-terminal reuse of _pop_session_by_id (e.g. detach-and-reattach for resume) would permanently block that session from starting turns. Worth documenting the invariant (or making the pop teardown-only).
The reject path in _run_prompt_submit (~lines 10308–10311) returns False after message.start may already have been emitted, without emitting a terminal event (message.error/complete). In the close race the UI is closing anyway, so it is mostly moot — but any other caller observing _closing mid-dispatch would leave the client's running state unresolved.
_teardown_popped_session (~lines 983–998) joins the turn thread for up to _TURN_SETTLE_BEFORE_CLOSE_SECONDS (5s) — and _close_sessions_for_transport iterates sessions, so N mid-turn sessions on transport disconnect block the disconnect handler for up to N×5s sequentially. After the timeout, teardown proceeds while the turn thread is still alive and can still emit on a closing transport; the warning acknowledges it, but a comment on expected turn-thread behavior once _closing is observed would help.
Minor: session.get("_run_thread") is read without _sessions_lock in the teardown path while the write happens under it — benign (miss → skip join) but inconsistent with the locked write.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
comp/tuiTerminal UI (ui-tui/ + tui_gateway/)P2Medium — degraded but workaround existssweeper:risk-session-stateSweeper risk: may lose/corrupt/mis-associate session or context statetype/bugSomething isn't working
4 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ordinary teardown closes its agent and related resources
completion arrives after close has claimed the session
tui_shutdownCloses #86932.
Why
On
main,session.closecan pop and tear down a session while_run_prompt_submit()is betweenmessage.startand worker publication.Because the pop did not mark the session as closing, the worker could still
start against resources that teardown had already closed. Close also finalized
the session without waiting for the recorded
_run_thread, even when the turnwas only unwinding its post-terminal tail.
Both ownership decisions now use
_sessions_lock: close publishes_closingbefore detaching, and prompt dispatch rechecks that state while publishing and
starting its worker. Once a close has claimed the record, ordinary teardown
waits up to five seconds for that exact worker, outside the registry and resume
locks.
Tests
Both new behavior tests were verified red on upstream
bb4f680f22b8d6ac66cecd0dec310c5a68f6b556:They pass at this PR head:
Related lifecycle and dispatch selection:
Full changed test file:
After the review delta, both changed test files pass together:
Commands:
Additional checks:
Related work
that path's hard deadline and fixes user-initiated close plus other ordinary
teardown callers.
with prompt worker publication.
this close/publication settlement.
Scope
This is source-and-test proof at commit
f0bcb3de7cab72f63e925da31e78f5d3b376f0b5. It does not claim merge, release,deployment, or runtime/customer proof. No configuration, dependency, protocol,
or persisted-data format changes are included.