fix(state): inherit git_branch + gateway origin columns on compression children
Follow-ups on top of #64731's cwd/git_repo_root inheritance:
- git_branch joins the parent-row backfill (same NULL-only COALESCE hop):
the Desktop sidebar branch chip otherwise vanishes at every compaction
boundary even though the workspace didn't change.
- Belt-and-suspenders for #59527: compression forks (parent already ended
with end_reason='compression') also inherit the gateway origin columns
(user_id/session_key/chat_id/chat_type/thread_id/display_name/
origin_json) at DB-level child creation. The gateway re-records the peer
after rotation (d5b4879d4), but a hard crash in the window between child
creation and that write left the child unrecoverable by
find_latest_gateway_session_for_peer. Scoped to compression forks only —
delegate/subagent children (parent still live) must NOT inherit routing
keys, or peer recovery could repoint gateway traffic into a subagent's
session.
- Behavioral test driving the real _compress_context rotation path,
asserting the child row carries cwd/git_repo_root/git_branch and the
origin columns.
This commit is contained in:
+59
-9
@@ -2730,14 +2730,19 @@ class SessionDB:
|
||||
no chat/thread to compare).
|
||||
|
||||
When ``parent_session_id`` is set (compression fork, delegate/subagent
|
||||
spawn, branch continuation) and this row's own ``cwd``/``git_repo_root``
|
||||
are still NULL after the insert, they are backfilled from the parent
|
||||
row. Callers of ``create_session`` for a child session historically
|
||||
didn't propagate these fields themselves (e.g. the compression-fork
|
||||
path), so a lineage could silently lose its working directory and drop
|
||||
out of the project sidebar every time it forked (#64709). This only
|
||||
fills NULLs — an explicit ``cwd``/``git_repo_root`` on the child is
|
||||
never overwritten.
|
||||
spawn, branch continuation) and this row's own ``cwd``/``git_repo_root``/
|
||||
``git_branch`` are still NULL after the insert, they are backfilled from
|
||||
the parent row. Callers of ``create_session`` for a child session
|
||||
historically didn't propagate these fields themselves (e.g. the
|
||||
compression-fork path), so a lineage could silently lose its working
|
||||
directory and drop out of the project sidebar every time it forked
|
||||
(#64709). This only fills NULLs — an explicit ``cwd``/``git_repo_root``
|
||||
on the child is never overwritten. For compression forks specifically
|
||||
(parent ended with ``end_reason='compression'``), the gateway origin
|
||||
columns (``user_id``/``session_key``/``chat_id``/``chat_type``/
|
||||
``thread_id``/``display_name``/``origin_json``) are inherited too, so a
|
||||
crash before the gateway re-records the peer can't strand the child
|
||||
without a recoverable routing mapping (#59527).
|
||||
"""
|
||||
def _do(conn):
|
||||
conn.execute(
|
||||
@@ -2785,10 +2790,55 @@ class SessionDB:
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
git_repo_root = COALESCE(sessions.git_repo_root,
|
||||
(SELECT p.git_repo_root FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id))
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
git_branch = COALESCE(sessions.git_branch,
|
||||
(SELECT p.git_branch FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id))
|
||||
WHERE id = ? AND parent_session_id IS NOT NULL""",
|
||||
(session_id,),
|
||||
)
|
||||
# Belt-and-suspenders for gateway routing metadata (#59527):
|
||||
# the gateway re-records the peer on the child after rotation
|
||||
# (d5b4879d4), but a hard crash between child creation and that
|
||||
# write leaves the child row without origin columns, so
|
||||
# ``find_latest_gateway_session_for_peer`` can't recover the
|
||||
# mapping on restart. Inherit them from the parent at creation
|
||||
# time — but ONLY for compression forks (parent already ended
|
||||
# with end_reason='compression'). Delegate/subagent children
|
||||
# are spawned while the parent is still live and must NOT
|
||||
# inherit routing keys, or peer recovery could repoint gateway
|
||||
# traffic into a subagent's session.
|
||||
conn.execute(
|
||||
"""UPDATE sessions
|
||||
SET user_id = COALESCE(sessions.user_id,
|
||||
(SELECT p.user_id FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
session_key = COALESCE(sessions.session_key,
|
||||
(SELECT p.session_key FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
chat_id = COALESCE(sessions.chat_id,
|
||||
(SELECT p.chat_id FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
chat_type = COALESCE(sessions.chat_type,
|
||||
(SELECT p.chat_type FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
thread_id = COALESCE(sessions.thread_id,
|
||||
(SELECT p.thread_id FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
display_name = COALESCE(sessions.display_name,
|
||||
(SELECT p.display_name FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id)),
|
||||
origin_json = COALESCE(sessions.origin_json,
|
||||
(SELECT p.origin_json FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id))
|
||||
WHERE id = ? AND parent_session_id IS NOT NULL
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM sessions p
|
||||
WHERE p.id = sessions.parent_session_id
|
||||
AND p.end_reason = 'compression'
|
||||
)""",
|
||||
(session_id,),
|
||||
)
|
||||
self._execute_write(_do)
|
||||
|
||||
def create_session(self, session_id: str, source: str, **kwargs) -> str:
|
||||
|
||||
Reference in New Issue
Block a user