fix(gateway): routing entries persist the receiving bot; restored lanes deliver through it or fail closed
After a restart the routing index rebuilt every lane from `SessionEntry.origin`, which carries the runtime profile (key namespace) but not the bot that received the conversation. Delivery then fell to `_is_shared_bot_satellite`: a lane owned by a secondary bot whose runtime profile is ALSO a satellite of the default bot was handed to the default bot, and authorization read the wrong allowlist. - `SessionEntry.transport_profile` (routing JSON) + nullable `sessions.transport_profile` (SCHEMA_SQL, reconciled by the existing column path; `agent:main` keys untouched, standalone gateways write nothing). Stamped from the pinned `RoutingIdentity` at create, reset/switch, DB recovery and every peer refresh; compression forks inherit it like the other routing columns. - `session_identity.restore_identity()` re-pins a `RoutingIdentity(transport=None)` from the persisted transport profile; `authz_mixin._restored_source(entry)` is the one seam every revive path uses (auto-resume, heartbeat restore, plugin injection, background-process events). - `_adapter_for_source` / `_adapter_profile_for_source` honour a restored identity: the persisted bot's adapter or None — never the default bot by heuristic. Entries written before the column exist keep the old chain. Phase 5 of #88715.
This commit is contained in:
@@ -213,7 +213,7 @@ _SAME_KEY_NAMESPACE_SQL = (
|
||||
_UPSERT_KEEP_EXISTING_SQL = ",\n".join(
|
||||
f" {col} = COALESCE(sessions.{col}, excluded.{col})" for col in (
|
||||
"session_key", "chat_id", "chat_type", "thread_id", "parent_session_id", "cwd", "profile_name",
|
||||
"git_repo_root", "origin_json", "display_name",
|
||||
"transport_profile", "git_repo_root", "origin_json", "display_name",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -240,6 +240,7 @@ _INHERIT_PARENT_ROUTING_SQL = (
|
||||
"UPDATE sessions\n SET "
|
||||
+ _INHERIT_SEP.join(_inherit_col_sql(c) for c in (
|
||||
"user_id", "session_key", "chat_id", "chat_type", "thread_id", "display_name", "origin_json",
|
||||
"transport_profile",
|
||||
))
|
||||
+ "\n WHERE id = ? AND parent_session_id IS NOT NULL\n"
|
||||
" AND EXISTS (\n"
|
||||
@@ -285,6 +286,7 @@ class SessionSessionsMixin:
|
||||
chat_id: str = None, chat_type: str = None, thread_id: str = None,
|
||||
parent_session_id: str = None, cwd: str = None, profile_name: Optional[str] = None,
|
||||
git_repo_root: str = None, origin_json: str = None, display_name: str = None,
|
||||
transport_profile: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Upsert a session row, never overwriting what an earlier writer set (the gateway creates a
|
||||
bare row before create_session carries the real model/prompt) — the one exception is the
|
||||
@@ -323,10 +325,10 @@ class SessionSessionsMixin:
|
||||
"""INSERT INTO sessions (
|
||||
id, source, user_id, session_key, chat_id, chat_type, thread_id,
|
||||
model, model_config, system_prompt, system_prompt_hash,
|
||||
parent_session_id, cwd, profile_name, git_repo_root,
|
||||
parent_session_id, cwd, profile_name, transport_profile, git_repo_root,
|
||||
origin_json, display_name, started_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
source = CASE
|
||||
WHEN sessions.source = 'unknown'
|
||||
@@ -367,8 +369,8 @@ class SessionSessionsMixin:
|
||||
(
|
||||
session_id, source, user_id, session_key, chat_id, chat_type, thread_id, model,
|
||||
json.dumps(model_config) if model_config else None, system_prompt_hash,
|
||||
parent_session_id, cwd, profile_name, git_repo_root, origin_json, display_name,
|
||||
time.time(),
|
||||
parent_session_id, cwd, profile_name, transport_profile, git_repo_root, origin_json,
|
||||
display_name, time.time(),
|
||||
),
|
||||
)
|
||||
if system_prompt_hash is not None:
|
||||
|
||||
Reference in New Issue
Block a user