refactor(tui-gateway): _rebind_live_transport lives with the reattach contract in session_lifecycle

It is lifecycle logic (detached sentinel, reap cancel) and its siblings
_reattach_refusal / _cancel_ws_orphan_reap are already there; server.py is the
facade and gets no new definitions. Also trims the _claim_or_reuse_live comment
to point at where the reap cancel now happens.
This commit is contained in:
kshitijk4poor
2026-09-06 14:06:12 +05:30
committed by kshitij
parent 212ed99d96
commit 01ae7a5668
2 changed files with 16 additions and 16 deletions

View File

@@ -2444,8 +2444,8 @@ def _claim_or_reuse_live(sid: str, session_key: str, record: dict, lease) -> tup
if live is not None:
if lease is not None:
lease.release()
# Guarded reuse cancels the reap only after accepting reattachment;
# a rejected resume must leave an in-flight orphan interrupt polling.
# The reap is cancelled by the guarded reuse (_reattach_refusal), not here: a rejected
# reattach must leave an in-flight orphan interrupt polling.
return live
with _sessions_lock:
_sessions[sid] = record
@@ -2686,17 +2686,6 @@ def _live_visible_history(session: dict, db, in_memory_fallback: list[dict]) ->
return in_memory_fallback
def _rebind_live_transport(sid: str, session: dict, transport: Transport) -> None:
"""Point a live session at ``transport`` (caller holds ``history_lock``)."""
session["transport"] = transport
# Every transport that showed this session (pop-outs resume the same sid); on disconnect the last
# viewer becomes the transport instead of the drop sentinel.
session.setdefault("viewers", {})[transport] = time.time()
# See #83716.
if transport is not _detached_ws_transport:
_cancel_ws_orphan_reap(sid) # the client is back — a pending ws-orphan reap must not fire
def _live_session_payload(
sid: str, session: dict, *, cols: int | None = None, touch: bool = False,
transport: Transport | None = None, omit_messages: bool = False) -> dict:

View File

@@ -444,9 +444,9 @@ def _cancel_ws_orphan_reap(sid: str) -> None:
def _reattach_refusal(rid, sid: str, session: dict) -> dict | None:
"""Under ``_session_resume_lock``: the error a reattaching RPC (resume/activate/prompt.submit) must return
instead of rebinding — ``session`` is no longer the live record for ``sid``, or a client-gone interrupt is
still settling and the reap Timer must keep polling. None when the reattach may proceed."""
"""Under ``_session_resume_lock``: why a reattaching RPC (resume/activate/prompt.submit) must NOT rebind
``session`` — it is stale, or a client-gone interrupt is still settling and the reap Timer must keep
polling. None when the reattach may proceed."""
if _sessions.get(sid) is not session:
return _err(rid, 4007, "session no longer live; retry resume")
if session.get("_client_gone_interrupt_requested"):
@@ -454,6 +454,17 @@ def _reattach_refusal(rid, sid: str, session: dict) -> dict | None:
return None
def _rebind_live_transport(sid: str, session: dict, transport: Transport) -> None:
"""Point a live session at ``transport`` (caller holds ``history_lock``)."""
session["transport"] = transport
# Every transport that showed this session (pop-outs resume the same sid); on disconnect the last
# viewer becomes the transport instead of the drop sentinel.
session.setdefault("viewers", {})[transport] = time.time()
# See #83716.
if transport is not _detached_ws_transport:
_cancel_ws_orphan_reap(sid) # the client is back — a pending ws-orphan reap must not fire
def _ws_orphan_turn_activity_is_fresh(session: dict) -> bool:
"""Whether a detached RUNNING turn's activity clock (``_touch_activity``) is still fresh — the reaper must NOT
interrupt healthy detached work (closed laptop). Conservative: disabled threshold, missing/opaque agent, unreadable