5ab74737e0
Symptom: switching between bots forked a brand-new "Bot Chat" for the
returned-to bot on EVERY switch, burying the user's real forever-chat
(one report: a 930-message chat displaced by 7 forks in one morning).
Root cause is a self-perpetuating loop between three parties:
- state.db enforces UNIQUE(title): the first fork permanently squats
the "Bot Chat" title; every later mint's title request is silently
dropped by set_session_title (returns 0, no error to the caller).
- The post-turn LLM auto-titler then names the untitled fork from its
kickoff content ("Assistant introduction request #2", ...).
- openBotCanonicalChat's identity check is title-string matching, so
the renamed fork reads as "not plumbing" -> corrupted metadata ->
clear pin -> mint again. Grandfathered pre-convention chats (real
history, derived titles) hit the same branch and are forked away
from immediately.
Fix, two invariants:
1. Adopt-before-mint: createCanonicalChat first scans the profile via
session.list include_hidden:true for an existing "Bot Chat" row and
re-pins it instead of creating. The UNIQUE index makes this an exact
registry lookup (at most one match), not a heuristic. Older gateways
without include_hidden find nothing and fall through to mint.
2. A pin that resolves to a NON-plumbing session carrying real history
is the user's conversation - keep it and open it (title drift is
metadata damage, not ownership loss). Only a pin resolving to an
EMPTY stray draft is treated as corrupted and replaced (which now
goes through adoption first).
Also removes the right-click -> Sessions per-bot stored-session browser
(ProfileSessionsWorkspace and its atoms/query/rows). Bot Mode's product
contract is ONE forever-chat per bot; a browser listing every hidden
plumbing session contradicts that and confused users into opening dead
forks. The Sessions workspace test goes with it; the include_hidden
source-shape test now pins the adoption scan instead, and a new suite
(canonical-chat-adopt-before-mint.test.mjs) covers both invariants plus
the older-gateway fallback.