diff --git a/gateway/session.py b/gateway/session.py index 9fa3ed15c7..b0a6c798f4 100644 --- a/gateway/session.py +++ b/gateway/session.py @@ -1425,7 +1425,14 @@ class SessionStore: "Could not resolve profile home for %r: %s", session_key, exc ) home = None - cache[profile] = home + # Only a hit is memoized. A profile directory can appear *after* the + # gateway started — the enrollment bridge provisions profiles// + # at runtime — and caching the miss would pin that profile's rows to + # the ambient store for the life of the process, which is the bug + # this helper exists to prevent. A miss costs one profile_exists() + # stat and only recurs for profiles that genuinely do not exist. + if home is not None: + cache[profile] = home return home def _db_for_key(self, session_key: Optional[str]): diff --git a/tests/gateway/test_multiplex_session_db_profile_scope.py b/tests/gateway/test_multiplex_session_db_profile_scope.py index ca6580ef5f..5980248519 100644 --- a/tests/gateway/test_multiplex_session_db_profile_scope.py +++ b/tests/gateway/test_multiplex_session_db_profile_scope.py @@ -606,3 +606,22 @@ def test_pinned_handle_still_wins_over_key_resolution(multiplex_homes): store._db = sentinel assert store._db_for_key("agent:fitness:telegram:dm:1") is sentinel assert store._db_for_session_id("whatever") is sentinel + + +def test_profile_home_is_not_memoized_before_the_profile_exists(multiplex_homes): + """A profile provisioned after startup must not stay pinned to the root store. + + The enrollment bridge creates ``profiles//`` at runtime, so a key can + be seen before its directory exists. Memoizing that miss would pin the + profile to the ambient store for the life of the process — the exact bug + this helper exists to prevent. + """ + root, _profile = multiplex_homes + store = _multiplex_store(root) + key = "agent:latecomer:telegram:dm:9" + + assert store._profile_home_for_key(key) is None + + (root / "profiles" / "latecomer").mkdir(parents=True) + + assert store._profile_home_for_key(key) == root / "profiles" / "latecomer"