5cc3da6827
The tui_gateway/run_agent writers now stamp profile_name explicitly, but every OTHER creation path that passes no profile_name (cli.py /new, hermes_cli/main.py --create-if-missing, foreign-session import, ACP adapter, gateway branch/title paths, the #82616 peer self-heal INSERT, and compression children of legacy NULL parents) still minted profile_name = NULL rows. Rows minted NULL after the one-shot #94724 legacy-owner backfill ran stayed NULL forever: profile-keyed consumers (desktop sidebar scope matching, @session:<profile>/<id> deep links, the fail-closed owner ladder) treat NULL as unowned, so the sessions vanished from the sidebar with their transcripts intact (#99222). Fix the class at the choke point instead of chasing call sites: every profile-tree state.db belongs to exactly one profile, so SessionDB._insert_session_row (and the peer self-heal INSERT and the compression-child publisher) derive the store's own profile from db_path when the caller names none — <root>/state.db -> 'default', <root>/profiles/<name>/state.db -> <name>. The same single-match contract backfill_null_session_profiles and the web listing's row_profile stamp already rely on. Explicit profile_name arguments always win; stores outside the profile tree (tests, ad-hoc copies) keep NULL — never guess. E2E-verified with real imports against a temp HERMES_HOME: before (origin/main) a bare create_session on the default store persisted NULL; after, 'default' / '<profile>' land in state.db for the default store, a named-profile store, the peer self-heal insert, and a compression child of a NULL parent, while explicit args and outside-tree stores are unchanged. Refs #99222