dfc40a50a9
_finalize_session decides whether the TUI backend ends the state.db row (gateway-owned source → no; another backend holds the lease → no; automatic Desktop reclaim → no, #105588). _teardown_session then calls agent.close(), whose _finalize_owned_session_row ends the same row as "agent_close" through the agent's own handle whenever _end_session_on_close is still True — so every spare decision was undone one call later. Verified with real SessionDB + AIAgent.close(): with only the #105620 guard a Desktop ws_orphan_reap still lands ended_at + end_reason="agent_close" (the #105588 follow-up report). One seam after the lifecycle decision now clears agent._end_session_on_close whenever the row was spared, replacing the gateway-owned-only assignment from #111145 so the lease-held and Desktop-reclaim cases get the same treatment. The five mocked _finalize_session tests from #105620 are replaced by two real-DB _teardown_session tests beside the #111145 harness (red on both origin/main and the bare cherry-picks, green on the stack).