From 7aa5200e91ee0eff7e9daf8c88f66d4d39433ec4 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 1 Nov 2026 20:41:39 -0800 Subject: [PATCH] fix(sessions): hermes sessions adopt offers login-stamped phone chats adoptable_sessions validated each row with no subject, so a phone chat stamped with the dashboard login (basic:admin) was dropped although the host owner the adoption resumes as can adopt it. Judge rows for host_owner_subject(). The test now also registers Platform(mobile) first: a routeless row with that label still adopts while the hermes-mobile plugin is loaded. --- hermes_cli/sessions_adopt.py | 5 ++++- tests/gateway/test_legacy_client_label_adoption.py | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hermes_cli/sessions_adopt.py b/hermes_cli/sessions_adopt.py index 957596fd51..1623b4ceda 100644 --- a/hermes_cli/sessions_adopt.py +++ b/hermes_cli/sessions_adopt.py @@ -24,6 +24,7 @@ def adoptable_sessions(path) -> list[dict]: count a dry run reports is what an adoption run attempts. A row the owner already bound is not offered again, which makes a second run a no-op.""" from hermes_state import SessionDB + from gateway.owner_identity import host_owner_subject from hermes_state_local import POLICY_PREFIX from hermes_state_local_migration import LEGACY_LOCAL_SOURCES, LEGACY_PREFIX, not_client_labels, validate_legacy_row from hermes_state_runtime import RuntimeStoreError @@ -53,7 +54,9 @@ def adoptable_sessions(path) -> list[dict]: if tip is None or POLICY_PREFIX + key in bound or LEGACY_PREFIX + key in bound: continue try: - validate_legacy_row(db, tip) + # The host runs this command: judge each row for the owner the adoption resumes as, so a + # chat a phone app stored under the dashboard login (``basic:admin``) is offered too. + validate_legacy_row(db, tip, subject=host_owner_subject()) except RuntimeStoreError: continue found.append(tip) diff --git a/tests/gateway/test_legacy_client_label_adoption.py b/tests/gateway/test_legacy_client_label_adoption.py index d9fb703546..c6fc436005 100644 --- a/tests/gateway/test_legacy_client_label_adoption.py +++ b/tests/gateway/test_legacy_client_label_adoption.py @@ -45,6 +45,12 @@ async def test_a_phone_apps_own_label_resumes_writable_and_a_webui_row_stays_rea db.create_session(sid, source=source, model='m', cwd=str(tmp_path), user_id=user_id) db.append_message(sid, role='user', content='hi from ' + sid) db.end_session(sid, 'ws_orphan_reap') + # hermes-mobile installed registers Platform('mobile'): a routeless row with that label still adopts. + from gateway.config import Platform + Platform._add_pseudo_member('mobile') + from hermes_cli.sessions_adopt import adoptable_sessions + offered = {row['id'] for row in adoptable_sessions(db.db_path)} + assert {'phone-mobile', 'phone-ios'} <= offered and not offered & {'webui-row', 'teams-row', 'curator-row'} for i, sid in enumerate(('phone-mobile', 'phone-ios')): resumed = await desktop.dispatch({'id': i, 'method': 'session.resume', 'params': {'session_id': sid}}) assert resumed.get('result', {}).get('session_id') == sid, resumed