Compare commits

...

1 Commits

Author SHA1 Message Date
Brooklyn Nicholson
976f5e1b15 fix(desktop): bump backend contract to 2 so profile-routing skew is surfaced
#39921/#39993 added per-session profile routing to the WS backend
(session.create / session.resume accept `profile`; the backend builds the agent
and persists against that profile's home/state.db). The desktop already sends
`profile`, but a backend on OLD code silently ignores it — new chats land in the
launch profile and "who are you" answers as the wrong profile.

This bites anyone whose backend is a SEPARATE install from the desktop — the
common remote case: update the desktop app, but the remote VM's Hermes is still
old. Both still reported DESKTOP_BACKEND_CONTRACT = 1, so the desktop's existing
skew guard (reportBackendContract → "Backend out of date" toast with one-click
update) never fired. The user just sees silent cross-profile leakage with no clue
why.

Bump the contract on both sides to 2:
- tui_gateway/server.py: DESKTOP_BACKEND_CONTRACT = 2 (with version history note).
- apps/desktop/src/store/updates.ts: REQUIRED_BACKEND_CONTRACT = 2.

Now a profile-routing-aware desktop pointed at a pre-#39921 backend sees the
backend report contract 1 < required 2 → the "Backend out of date" warning fires
instead of silently misrouting sessions. No behavior change when desktop and
backend are updated together (the single-machine case).
2026-06-05 13:18:09 -05:00
2 changed files with 16 additions and 2 deletions

View File

@@ -69,7 +69,13 @@ function isUpdateToastSnoozed(): boolean {
// Must match tui_gateway's DESKTOP_BACKEND_CONTRACT that this build was written
// against. The backend reports its own value in session runtime info; a lower
// value (or none — a pre-GUI checkout) means GUI<->backend skew.
const REQUIRED_BACKEND_CONTRACT = 1
//
// 2 — requires the backend to support per-session profile routing
// (session.create / session.resume `profile` param, #39921/#39993). A
// contract-1 backend silently leaks new chats into the launch profile, so
// a contract-2 desktop must warn when pointed at one (e.g. a remote VM the
// user updated the desktop but not the backend on).
const REQUIRED_BACKEND_CONTRACT = 2
const SKEW_TOAST_ID = 'backend-contract-skew'
/**

View File

@@ -1740,7 +1740,15 @@ def _current_profile_name() -> str:
# backend reporting less than its required value (or none at all — a pre-GUI
# checkout), surfacing a one-click "update to align" prompt instead of failing
# cryptically downstream. Bump whenever the desktop's backend contract changes.
DESKTOP_BACKEND_CONTRACT = 1
#
# Version history:
# 1 — initial GUI<->backend contract.
# 2 — per-session profile routing: session.create / session.resume accept a
# `profile` param and the backend builds the agent + persists against that
# profile's home/state.db (#39921, #39993). A desktop that sends `profile`
# to a contract-1 backend gets silent cross-profile leakage (new chats land
# in the launch profile), so the skew must be surfaced.
DESKTOP_BACKEND_CONTRACT = 2
def _session_info(agent, session: dict | None = None) -> dict: