fix(cron): scheduled posts reach a room the root gateway imported

Greptile "Imported rooms miss scheduled posts": a standalone room the root
gateway imported is fenced in shared-state.db and lives on in the ROOT
home's state.db, but Room settings in a named-profile view advertises
room:<id>@research. The lookup checked only the research store and the
frozen shared copy, so the post failed as "managed by another gateway".
A shared row handed to the gateway store now resolves to the root
gateway's store when that gateway serves it (the same handoff record
tui_gateway/methods_groups_forward routes by).
This commit is contained in:
Teknium committed 2026-11-03 10:28:21 -08:00
1 parent fbe9482716
commit 2e1c0291b8
2 files changed
+34 -3

No files matched your search

+16 -3
View File
@@ -59,11 +59,24 @@ def _find_room_store(room_id: str, profile: Optional[str]) -> Optional[Path]:
the room's owner entry: the shared-store import copies rooms out of ``state.db`` without deleting
them, and nothing serves that leftover copy, so a post there would never reach the visible room."""
from gateway.hosted_rooms import probe_hosted_room
from gateway.session_hosted_service import probe_native_room_owner
session_store, shared_store = _room_stores(profile)
if probe_hosted_room(session_store, room_id=room_id) and probe_native_room_owner(session_store, room_id=room_id):
if _serves(session_store, room_id):
return session_store
return shared_store if probe_hosted_room(shared_store, room_id=room_id) else None
if not probe_hosted_room(shared_store, room_id=room_id):
return None
# A shared room the root gateway imported is fenced here and lives on in the ROOT home's state.db
# (only that gateway imports), whichever profile's view advertised the target.
from gateway.hosted_rooms_gateway_import import handed_room_ids
root_store = shared_store.with_name("state.db")
if room_id in handed_room_ids(shared_store) and _serves(root_store, room_id):
return root_store
return shared_store
def _serves(store: Path, room_id: str) -> bool:
from gateway.hosted_rooms import probe_hosted_room
from gateway.session_hosted_service import probe_native_room_owner
return probe_hosted_room(store, room_id=room_id) and probe_native_room_owner(store, room_id=room_id)
def deliver_to_room(job: dict, content: str, address: str, *, for_failure: bool = False) -> Optional[str]:
+18
View File
@@ -81,6 +81,24 @@ def test_post_goes_to_the_session_store_when_its_gateway_owns_the_room(room_stor
assert _posts(room_store) == []
def test_named_profile_target_reaches_a_room_the_root_gateway_imported(room_store):
"""The root gateway imported the standalone room (shared copy fenced, its own state.db owns it);
Room settings in the research view advertises room:<id>@research, which must post to that store."""
from gateway.hosted_rooms_gateway_import import import_standalone_rooms
root_store = hosted_rooms.default_db_path().with_name("state.db")
with closing(sqlite3.connect(root_store)) as conn, conn: # the root gateway's SessionDB owner table
conn.execute("CREATE TABLE state_meta (key TEXT PRIMARY KEY, value TEXT)")
assert import_standalone_rooms(root_store) == 1
research = get_hermes_home() / "profiles" / "research"
research.mkdir(parents=True)
(research / "config.yaml").write_text("{}\n", encoding="utf-8")
assert delivery._deliver_result(_job(deliver=f"room:{ROOM_ID}@research"), "Digest ready") is None
assert [p["payload"]["text"] for p in _posts(root_store)] == ["Digest ready"]
assert _posts(room_store) == []
def test_room_a_profile_gateway_took_over_names_the_profile_remedy(room_store):
from gateway.hosted_room_replicas import demote_room
state = hosted_rooms.room_state(room_store, room_id=ROOM_ID)