Chat Mode polish and test-quality improvements. ``chat/routes.py`` adopts the shared ``@require_json_body(error_format="success")`` decorator on the three POST/PATCH endpoints (``create_session``, ``generate_session_title``, ``update_session``), replacing 4-block inline ``isinstance(data, dict)`` guards. ``UserActiveResearch`` stale-row reclaim is extracted from both ``chat.routes.send_message`` and ``research_routes.start_research`` into a shared ``reclaim_stale_user_active_research(db, username, *, grace_cutoff_dt=None, logger=None)`` helper in ``web/routes/globals.py`` — chat passes a 30s grace cutoff (because chat send can race with its own concurrent sibling), research_routes passes None (matching its pre-existing behaviour). ``ChatService.delete_session`` now imports ``set_termination_flag`` at module top-level instead of inside the function body (no circular import requires the deferred import). The dummy ``"I understand. What else would you like to know?"`` assistant bubble that ``chat.js`` injected when the server returned no ``research_id`` is gone — the thinking indicator is now cleared without injecting a placeholder reply. ``chat.js::loadSession`` now focuses the input on completion, matching ``startNewChat``. Three brittle test patterns are replaced: the seven copy-pasted ``captured_username`` + ``@contextmanager`` blocks in ``test_chat_user_isolation.py`` are consolidated under a single ``username_capturing_db`` fixture; the 16 inline ``SocketIOService._instance = None`` reset lines in ``test_chat_socket_events.py`` become a single autouse fixture that runs in setup AND teardown regardless of test outcome; ``test_chat_settings_integration.py``'s three tautological dict-assertion tests are replaced with four real tests that exercise ``_load_settings`` against patched ``SettingsManager`` and validate every snapshot-extraction key still exists in ``default_settings.json``. ``test_chat_send_message_reclaim.py``'s three source-grep tests against ``chat/routes.py`` are replaced with eight behaviour tests that drive the new shared reclaim helper against a real SQLite session (covering grace-window respect, live-thread skip, username scoping, and the without-cutoff immediate-reclaim mode used by research_routes). ``test_chat_service.py`` drops three ``if hasattr(...)`` assertion guards that would have silently passed when a real model regressed; the ``get_in_progress_research_id`` DB-error test inverts to assert propagation now that the service re-raises instead of returning None. ``test_chat_api.py``'s ordering assertion no longer hides behind ``if len(sessions) >= 2:``.
