8a31985e4f
Live-test surfaced a real bug: fast-mode results paired the resolved lineage-root session_id with the raw FTS5 row's message_id. The (sid, match_message_id) handle was self-inconsistent because the message lives in the child (delegation/compression) session, not the parent — so the agent's follow-up mode='guided' call hit 'around_message_id N not in session_id ROOT' and the drill failed. Repro: ask the TUI to fast-search a topic that appears in a compressed child session of the current lineage, then ask it to drill in. Today's session is exactly that shape — message 18425 lives in 20260512_102257_d5048c (child) but fast returned its parent 20260511_101921_a7dd34 paired with id=18425. Fix has two layers: 1) Fast-mode output now pairs session_id (raw FTS5 sid) with match_message_id consistently. The lineage root is exposed as a separate parent_session_id field (omitted when there's no delegation/compression above). Dedup grouping still happens by lineage root, so the user still sees one entry per conversation, but the per-entry handle is now a valid pair the agent can hand straight to mode='guided'. - #15909 source-from-parent invariant preserved: source/model/title still promote from the resolved parent for display. 2) Defensive rebind in mode='guided': if (a_sid, a_msg_id) doesn't resolve, look up the actual owning session for a_msg_id. If it's a descendant in the same lineage as a_sid, transparently rebind and refetch. Records the rebind in a warning field on the returned window (also flattened to top level for single-anchor responses). Cross-lineage rebinds are refused — that path stays an error. This keeps the tool forgiving for legacy callers, memory snippets, or any other source that still emits the old (parent_sid, child_id) shape. 3) Schema description tightened: explicit note that the agent must pass (session_id, match_message_id) verbatim from a single fast result — do NOT substitute parent_session_id (it's display-only). Tests: updated the existing #15909 regression to assert the new pair shape, plus four new tests: - test_fast_pair_session_id_with_match_message_id (positive) - test_fast_no_parent_session_id_field_when_session_is_already_root (tidy output for non-delegation case) - test_guided_rebinds_anchor_when_message_lives_in_descendant_session (safety net fires correctly within a lineage) - test_guided_does_not_rebind_across_lineages (refuses cross-lineage rebind — no silent drill into unrelated session) 85/85 session_search + get_messages_around tests passing. Live-DB smoke test against /tmp/state-smoke.db (snapshot of ~/.hermes/state.db) confirms the user's failing case now rebinds: success: True top-level warning: 'around_message_id 18425 lives in 20260512_102257_d5048c (child of 20260511_101921_a7dd34); rebound transparently' returned session_id: 20260512_102257_d5048c window before/after: 5 / 5