diff --git a/hermes_state_sessions.py b/hermes_state_sessions.py index 6155d2d6ef..7974b3cccf 100644 --- a/hermes_state_sessions.py +++ b/hermes_state_sessions.py @@ -878,10 +878,18 @@ class SessionSessionsMixin: def set_session_pinned(self, session_id: str, pinned: bool) -> bool: """Pin/unpin a session and its compression lineage (pins are exempt from the auto_archive sweep). Pinning also clears ``hidden``: a pin means "keep this visible", and a hidden+pinned row is - otherwise absent from both the default listing and the pinned back-fill (see #106171).""" + otherwise absent from both the default listing and the pinned back-fill (see #106171). + Exempt the canonical Bot Chat (hidden + exact registry title): the desktop contract keeps it + hidden and reachable only through the bot row, and unhiding it would also disable the + rename guard in ``_set_session_title`` that protects its identity (see review on #106180).""" result = self._set_lineage_column("pinned", session_id, int(pinned)) if pinned: - self._set_lineage_column("hidden", session_id, 0) + row = self.get_session(session_id) + is_canonical_bot_chat = bool(row) and bool(row.get("hidden")) and ( + (row.get("title") or "") == self.CANONICAL_BOT_CHAT_TITLE + ) + if not is_canonical_bot_chat: + self._set_lineage_column("hidden", session_id, 0) return result def set_session_hidden(self, session_id: str, hidden: bool) -> bool: diff --git a/tests/test_hermes_state.py b/tests/test_hermes_state.py index 6793e80bff..a3013deac8 100644 --- a/tests/test_hermes_state.py +++ b/tests/test_hermes_state.py @@ -4476,7 +4476,17 @@ class TestSessionPinAndStaleArchive: listed_ids = [s["id"] for s in db.list_sessions_rich(min_message_count=1)] assert "s1" in listed_ids + def test_pinning_the_canonical_bot_chat_leaves_it_hidden(self, db): + """The canonical Bot Chat (hidden + exact registry title) is desktop-owned and must stay + hidden even when pinned, or it leaks into the Sessions sidebar and loses its rename guard + (review on #106180). Unlike an ordinary hidden session, pinning must not clear ``hidden``.""" + db.create_session(session_id="bot1", source="desktop") + db.set_session_title("bot1", db.CANONICAL_BOT_CHAT_TITLE) + db.set_session_hidden("bot1", True) + db.set_session_pinned("bot1", True) + + assert db.get_session("bot1")["hidden"] == 1 # ── pinned back-fill past the page window ───────────────────────────── def test_pinned_session_survives_the_limit_window(self, db):