Address gate-review blockers from nesquena-hermes:
1. Wrong title-authority API: replace `db.set_session_title()` with
`db.set_auto_title_if_empty()` so auto-generated titles never
overwrite a manual rename (set_session_title writes with 'user'
authority; set_auto_title_if_empty only populates NULL titles).
2. Null profile fallback: pass `or 'default'` at both streaming.py
call sites so background title workers (which lack request TLS)
always resolve to the correct state.db instead of falling through
to the process-global active profile.
Neutralize the new `sync_session_title` call in
`test_cleared_title_allows_initial_auto_generation` to prevent state.db
side effects from leaking into shared test state, matching the existing
pattern of mocking collaborators in this test.
Background title generation (`_run_background_title_update` and
`_run_background_title_refresh`) writes the title to the WebUI sidecar
JSON but never syncs it back to hermes-agent's `state.db`. This causes
`hermes sessions list` to show blank titles for all WebUI-originated
sessions.
The existing `sync_session_usage` path is gated by the `sync_to_insights`
setting (default: off) and executes before the background title thread
completes, so it cannot cover this case.
Fix: add `sync_session_title()` to `state_sync.py` — an unconditional
(not gated by `sync_to_insights`) title-only sync — and call it from both
title generation paths immediately after persisting the title to the
sidecar.