fix(gateway): route truncation writes + /undo to the profile database - #91150
fix(gateway): route truncation writes + /undo to the profile database#91150glitchbunny0 wants to merge 3 commits into
Conversation
Same class as the prompt.submit truncation write (re-landed from 0640fe7): a global-remote desktop session owned by a non-launch profile persists into that profile's state.db, but command.dispatch's /undo read the launch-profile DB — which has no rows for the session key — so /undo failed with 'no user messages to undo' and a rewind would silently no-op against the wrong database. Route through _session_db(session) like every other session-scoped DB touchpoint.
Codex review of the profile-DB truncation routing flagged two follow-ons: - prompt.submit truncation: _session_db(session) can yield None when a profile-owned session's own state.db cannot be opened. The old 'if db is not None' skip then truncated memory while the profile DB kept the old tail — durable zombie history, the exact class this PR fixes. Refuse the turn (5008) for profile-owned sessions; memory-only sessions (no profile_home, launch db unavailable) keep the legacy skip since nothing durable can diverge. - /undo: a failed post-rewind history reload previously published an empty transcript into live memory. The flush-pointer reset would then re-append every surviving row, resurrecting the soft-archived turns. Keep the pre-rewind in-memory history on reload failure; the DB is the source of truth and the next resume/reload converges to it. Both paths get regression tests (2 new, full file 589 passed). (cherry picked from commit 9eb1fb8b2ce3a99f0499ee9b9f50303764fef6a0)
|
Codex review of this PR flagged two follow-on issues in the new code — both fixed in 9eb1fb8b2c (pushed to this branch): 1. High — truncation could still fail open. 2. Medium — /undo wiped live memory on post-rewind reload failure. Two regression tests added (fail-closed truncation + reload-failure memory preservation). Suite: 589 passed (was 587). Review verdict from Codex: root-cause claim valid, routing fix correct, tests called out as the right kind of regression coverage. |
What this fixes
Editing an earlier user message in Desktop on a global-remote profile session (a non-launch profile's chat hosted by the same backend) fails with:
Root cause chain (from a live incident,
logs/gui.log):truncate_before_row_id=1105correctly — the durable read path (_load_durable_truncation_history) is profile-aware via_session_db(session)._get_db()— always the launch profile'sstate.db— andreplace_messagesINSERTs rows for a session key that has nosessionsrow in that DB →sqlite3.IntegrityError: FOREIGN KEY constraint failed→ error 5008, turn refused.The fix
This is a re-land of 0640fe7 ("fix(gateway): route truncation writes to profile database", authorship preserved via cherry-pick), which was reverted in 3863de3 purely for scope ("keep profile truncation routing out of scope" of PR #86649) — not because it was wrong. It never got re-landed while the FK bug remained on main.
Plus the sibling of the same class found while fixing:
tui_gateway/methods_tools.py—command.dispatch/undoread the launch-profile DB for remote-profile sessions → always "no user messages to undo" / silent no-op rewind. Now routed through_session_db(session)with the body scoped inside the handle's lifetime (it closes profile handles on exit).Tests
test_prompt_submit_row_id_truncates_profile_owned_history(from the reverted commit; monkeypatches_get_dbto fail the test if the launch DB is touched — proves routing, not just outcome)test_cli_undo_routes_profile_owned_session_db(same probe pattern for/undo)tests/test_tui_gateway_server.py: 587 passed on this branch.Verification
Reproduced on a live install (songbird profile hosting, default-profile backend): edit → 5008 FK failure → 4030 on every retry. After the fix, the same edit persisted the truncated transcript into the profile's own
state.dband the turn ran.