fix(state): delegate and branch children stop inheriting a compressed parent's gateway routing
_INHERIT_PARENT_ROUTING_SQL copied session_key/chat_id/chat_type/thread_id/user_id/ display_name/origin_json/transport_profile onto ANY child whose parent row ended on 'compression'. A delegate or branch fork of such a parent is not that conversation's continuation, so it must not take over the route: two live rows holding one routing key lets peer recovery repoint gateway traffic into a subagent's transcript (#116322). Exclude children whose `_delegate_from` / `_branched_from` marker names the queried parent id. Value-match rather than presence: a compression continuation inherits model_config verbatim (marker included), so a presence check would misclassify it — the same idiom _NON_CONTINUATION_CHILD_FILTER_SQL already uses. Cherry-picked from #109699 (Lei-k) minus its unrelated tools/delegate_tool_dispatch.py nested-dispatch hunk; test relocated to tests/hermes_state/ where the suite now lives.
This commit is contained in:
@@ -236,6 +236,15 @@ _INHERIT_PARENT_META_SQL = (
|
||||
))
|
||||
+ "\n WHERE id = ? AND parent_session_id IS NOT NULL"
|
||||
)
|
||||
# A delegate/branch fork of a row that happens to have ended on compression is still not that
|
||||
# conversation's continuation. Markers are matched against the QUERIED parent id rather than mere
|
||||
# presence, for the same reason as _NON_CONTINUATION_CHILD_FILTER_SQL: a continuation inherits its
|
||||
# parent's model_config verbatim, so presence-matching would misclassify it as a delegate.
|
||||
_FORK_EDGE_EXCLUSION_SQL = "".join(
|
||||
f"\n AND COALESCE({_sql_json_extract('model_config', f'$.{marker}')}, '')"
|
||||
"\n != parent_session_id"
|
||||
for marker in ("_delegate_from", "_branched_from")
|
||||
)
|
||||
_INHERIT_PARENT_ROUTING_SQL = (
|
||||
"UPDATE sessions\n SET "
|
||||
+ _INHERIT_SEP.join(_inherit_col_sql(c) for c in (
|
||||
@@ -248,6 +257,7 @@ _INHERIT_PARENT_ROUTING_SQL = (
|
||||
" WHERE p.id = sessions.parent_session_id\n"
|
||||
" AND p.end_reason = 'compression'\n"
|
||||
" )"
|
||||
+ _FORK_EDGE_EXCLUSION_SQL
|
||||
)
|
||||
|
||||
|
||||
@@ -276,7 +286,10 @@ class SessionSessionsMixin:
|
||||
"""NULL-fill a child's cwd/git/profile from its parent (profile_name only within the same
|
||||
``agent:<ns>:`` namespace). Gateway routing columns are inherited ONLY by compression forks
|
||||
(a crash before the gateway re-records the peer would strand the child unroutable); delegate
|
||||
children must NOT inherit them (peer recovery could repoint traffic into a subagent's session)."""
|
||||
and branch children must NOT inherit them (peer recovery could repoint traffic into a
|
||||
subagent's session), including when their parent row itself ended on compression — a long
|
||||
batch outlives its coordinator's rotation, and two live rows holding one routing key is the
|
||||
shape reported in #92859."""
|
||||
conn.execute(_INHERIT_PARENT_META_SQL, (session_id,))
|
||||
conn.execute(_INHERIT_PARENT_ROUTING_SQL, (session_id,))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user