"""Every semantic search hands on the passage that matched (#4243, #4250). Three searches collapse chunk rows to the best one per record, so each of them KNOWS which passage earned the hit. Each used to drop it, leaving every door to preview the head of the document instead — a span the search had already scored lower, with nothing saying so. These pin the mechanism (`report["best_chunk"]` from all three searches) and each surface that reads it, because the failure mode is silent: a door that quietly reverts to the body's opening still returns a plausible-looking string and no test that only checks "a preview exists" would notice. """ from unittest.mock import AsyncMock, MagicMock, patch import pytest from scribe.services import embeddings as emb from scribe.services.text import ( BODY_OPENING, MATCHED_PASSAGE, excerpt_fields, matched_excerpt, ) from tests.helpers import make_mock_session def _searching(rows): """A patched session whose one query returns `rows` — the shared make_mock_session (#2834) rather than a third local copy of the __aenter__/__aexit__ dance.""" session = make_mock_session() result = MagicMock() result.all.return_value = rows session.execute = AsyncMock(return_value=result) return session # --------------------------------------------------------------------------- # The shared choice of span # --------------------------------------------------------------------------- def test_the_matched_passage_wins_over_the_opening(): body = "An opening about nothing much. " * 20 + " THE ANSWER." text, kind, _cut = matched_excerpt(body, {"index": 4, "text": "THE ANSWER."}, 1000) assert text == "THE ANSWER." assert kind == MATCHED_PASSAGE def test_without_a_chunk_the_opening_is_named_as_the_opening(): """The fallback is legitimate — a plain listing matched nothing — but it must not pass for the passage that matched.""" text, kind, _cut = matched_excerpt("just a body", None, 1000) assert kind == BODY_OPENING def test_an_empty_chunk_is_not_mistaken_for_a_passage(): """A record embedded from its title alone stores an empty body chunk; rendering that as "the passage that matched" would be a blank line presented as evidence.""" _t, kind, _c = matched_excerpt("real body", {"index": 0, "text": " "}, 1000) assert kind == BODY_OPENING def test_the_field_names_travel_together(): """A door renames the text field to keep its consumers working; the label has to follow it, or a row carries an excerpt under one name and its meaning under another.""" out = excerpt_fields("b" * 500, {"index": 1, "text": "hit"}, 100, key="snippet") assert out["snippet"] == "hit" assert out["snippet_is"] == MATCHED_PASSAGE assert out["body_length"] == 500 assert "read_full" in out def test_a_record_shown_whole_advertises_nothing_further(): out = excerpt_fields("short", None, 1000) assert out["excerpt"] == "short" assert "read_full" not in out # --------------------------------------------------------------------------- # All three searches publish the winning chunk # --------------------------------------------------------------------------- @pytest.mark.asyncio async def test_rule_search_reports_the_clause_that_matched(): """A rule's `why` and `how_to_apply` run long. A caller shown only the head cannot see the clause the query actually hit.""" r1, r2 = MagicMock(id=1), MagicMock(id=2) session = _searching([ (r1, 0.10, 2, "the clause that matched"), (r2, 0.20, 0, "r2 best"), (r1, 0.40, 9, "a worse clause of r1"), ]) report: dict = {} with ( patch.object(emb, "async_session", return_value=session), patch.object(emb, "get_embedding", AsyncMock(return_value=[0.0] * 384)), patch.object(emb, "can_read_project", AsyncMock(return_value=True)), ): out = await emb.semantic_search_rules(1, "q", limit=5, threshold=0.0, report=report) assert [r.id for _s, r in out] == [1, 2] assert report["best_chunk"][1] == {"index": 2, "text": "the clause that matched"} @pytest.mark.asyncio async def test_milestone_search_reports_the_passage_of_the_plan_that_matched(): """A milestone's body IS the plan and search shows its short description, which need not mention the part the query was about.""" m1 = MagicMock(id=7) session = _searching([(m1, 0.15, 5, "step 6 — the acceptance case")]) report: dict = {} with ( patch.object(emb, "async_session", return_value=session), patch.object(emb, "get_embedding", AsyncMock(return_value=[0.0] * 384)), patch.object(emb, "can_read_project", AsyncMock(return_value=True)), ): out = await emb.semantic_search_milestones( 1, "acceptance", limit=5, threshold=0.0, report=report, ) assert [m.id for _s, m in out] == [7] assert report["best_chunk"][7]["text"] == "step 6 — the acceptance case" @pytest.mark.asyncio async def test_a_caller_that_passes_no_report_still_works(): """Every one of these searches fails open by design — a recall aid must never break the call it serves — and that includes the chunk channel.""" session = _searching([(MagicMock(id=1), 0.1, 0, "text")]) with ( patch.object(emb, "async_session", return_value=session), patch.object(emb, "get_embedding", AsyncMock(return_value=[0.0] * 384)), patch.object(emb, "can_read_project", AsyncMock(return_value=True)), ): out = await emb.semantic_search_milestones(1, "q", limit=5, threshold=0.0) assert len(out) == 1 def test_record_best_chunk_on_no_report_is_a_no_op(): emb.record_best_chunk(None, {1: {"index": 0, "text": "x"}}) # must not raise # --------------------------------------------------------------------------- # Only what survived the bar is published # --------------------------------------------------------------------------- @pytest.mark.asyncio async def test_chunks_are_published_only_for_results_that_came_back(): """Keyed off the returned rows, so a caller can look up every result it has and never holds passages for records it was not shown.""" keep, drop = MagicMock(id=1), MagicMock(id=2) session = _searching([ (keep, 0.10, 0, "kept"), (drop, 0.95, 0, "below the bar"), ]) report: dict = {} with ( patch.object(emb, "async_session", return_value=session), patch.object(emb, "get_embedding", AsyncMock(return_value=[0.0] * 384)), patch.object(emb, "can_read_project", AsyncMock(return_value=True)), ): await emb.semantic_search_milestones( 1, "q", limit=5, threshold=0.5, report=report, ) assert set(report["best_chunk"]) == {1}