5248877c61
Addresses the egilewski/CodeRabbit and teknium1 reviews on PR #52355. 1) Persisted-row chat scope (egilewski/CodeRabbit). The sessions table stored only source + user_id, so an identity-bearing caller could resume/list an INACTIVE persisted row that matched source+user_id but belonged to a DIFFERENT chat (probe: same user moves `same_user_chat_b` into chat-a). Persist the messaging origin and compare it: - schema: sessions gains origin_chat_id / origin_thread_id (declarative auto-migration via the existing column reconciler). - SessionDB._insert_session_row accepts + writes the two columns. - the gateway records them at every origin-bearing creation: both SessionStore create paths (get_or_create_session + reset/switch) and the /title path that materializes a store-only session into the DB. - _resume_target_allowed's identity branch now also requires origin_chat_id AND origin_thread_id to match the caller. Legacy rows with NULL origin (created before this change) cannot prove chat origin and fail closed — resume them via a live session or an admin --all override. The /sessions listing inherits the fix (non-Matrix rows route through the same helper). 2) DM key-contract mirror (teknium1). _same_origin_chat's DM branch only compared user_id and allowed when either side was missing, diverging from build_session_key (no-chat_id DM keys are built from user_id_alt or user_id). It now: treats an equal non-blank chat_id as sufficient (the DM key IS the chat_id when present), and otherwise compares the effective participant id (user_id_alt or user_id), failing closed on a missing/different participant so two no-chat_id DM origins are never conflated. Tests: add same-user/different-chat (e2e + unit) and chat-scope unit cases; add DM no-chat_id / user_id_alt / no-identity / same-chat_id cases; update existing fixtures to record origin_chat_id like the gateway does; make the cross-room `/resume --all` listing test run as admin (cross-room listing is admin-gated) and give the boundary-state resume runner a live same-origin so its post-resume clearing assertions exercise an authorized resume. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>