Ctrl K
ComunidadGuías…

tests/test_xkb_relevance.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
from __future__ import annotations


import re
import sys
import unittest
from pathlib import Path
from unittest import mock

sys.path.insert(0, str(Path(__file__).resolve().parent))
from _isolation import clean_env

SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
if str(SCRIPTS) not in sys.path:
    sys.path.insert(0, str(SCRIPTS))

# Import normally rather than via importlib: loading a second copy under the
# same name would give the modules under test a different object than the one
# these tests patch, and the patches would silently do nothing.
import xkb_relevance as rel  # noqa: E402


class VectorKeyTests(unittest.TestCase):
    def test_slug_gets_the_index_suffix(self) -> None:
        self.assertEqual(rel.vector_key("01-topic/12345"), "01-topic/12345.md")
        self.assertEqual(rel.vector_key("01-topic/12345.md"), "01-topic/12345.md")

    def test_things_that_are_not_cards_are_not_guessed_at(self) -> None:
        for value in ("https://x.com/i/status/1", "semantic:3", "", "   "):
            self.assertEqual(rel.vector_key(value), "")


class FilterTests(unittest.TestCase):
    def test_below_the_floor_is_dropped(self) -> None:
        items = [{"id": "a/1", "score": 0.88}, {"id": "a/2", "score": 0.87}]
        with mock.patch.object(rel, "similarities", return_value={"a/1.md": 0.72, "a/2.md": 0.30}):
            kept, dropped, _ = rel.filter_irrelevant(items=items, query="q", key_of=lambda i: i["id"])
        self.assertEqual(dropped, 1)
        self.assertEqual([i["id"] for i in kept], ["a/1"])

    def test_rank_score_is_preserved_but_no_longer_the_score(self) -> None:
        """The rank score must stop being mistaken for relevance."""
        items = [{"id": "a/1", "score": 0.88}]
        with mock.patch.object(rel, "similarities", return_value={"a/1.md": 0.72}):
            kept, _, _ = rel.filter_irrelevant(items=items, query="q", key_of=lambda i: i["id"])
        self.assertEqual(kept[0]["score"], 0.72)
        self.assertEqual(kept[0]["rank_score"], 0.88)

    def test_unknown_similarity_is_not_treated_as_irrelevant(self) -> None:
        """A missing index is a config problem, not an empty knowledge base."""
        items = [{"id": "a/1", "score": 0.88}]
        with mock.patch.object(rel, "similarities", return_value=None):
            kept, dropped, _ = rel.filter_irrelevant(items=items, query="q", key_of=lambda i: i["id"])
        self.assertEqual((len(kept), dropped), (1, 0))
        with mock.patch.object(rel, "similarities", return_value={}):
            kept, dropped, _ = rel.filter_irrelevant(items=items, query="q", key_of=lambda i: i["id"])
        self.assertEqual((len(kept), dropped), (1, 0))

    def test_items_without_a_resolvable_key_pass_through(self) -> None:
        items = [{"id": "https://x.com/i/status/1", "score": 0.9}]
        with mock.patch.object(rel, "similarities", return_value={"a/1.md": 0.9}):
            kept, dropped, _ = rel.filter_irrelevant(items=items, query="q", key_of=lambda i: i["id"])
        self.assertEqual((len(kept), dropped), (1, 0))

    def test_results_are_ordered_by_measured_relevance(self) -> None:
        items = [{"id": "a/1", "score": 0.9}, {"id": "a/2", "score": 0.8}]
        with mock.patch.object(rel, "similarities", return_value={"a/1.md": 0.60, "a/2.md": 0.85}):
            kept, _, _ = rel.filter_irrelevant(items=items, query="q", key_of=lambda i: i["id"])
        self.assertEqual([i["id"] for i in kept], ["a/2", "a/1"])


class SingleSourceOfTruthTests(unittest.TestCase):
    """The rank-score mistake was made twice because the fix lived in one file.

    These guard the structural fix rather than the behaviour: nothing outside
    this module may define its own relevance threshold or re-implement the
    similarity filter.
    """

    CALLERS = ("recall_router.py", "xkb_memory_service.py")

    def test_callers_do_not_define_their_own_threshold(self) -> None:
        for name in self.CALLERS:
            source = (SCRIPTS / name).read_text(encoding="utf-8")
            offenders = re.findall(r"^[A-Z_]*(?:MIN_SIMILARITY|MIN_RELEVANCE)[A-Z_]*\s*=", source, re.M)
            self.assertEqual(offenders, [], f"{name} redefines the relevance threshold; use xkb_relevance")

    def test_callers_go_through_the_shared_module(self) -> None:
        for name in self.CALLERS:
            source = (SCRIPTS / name).read_text(encoding="utf-8")
            self.assertIn("xkb_relevance", source, f"{name} should filter via xkb_relevance")

    def test_threshold_honours_the_legacy_variable_names(self) -> None:
        for name in ("XKB_MIN_SIMILARITY", "XKB_SERVICE_MIN_RELEVANCE", "XKB_CARD_MIN_SIMILARITY"):
            with mock.patch.dict("os.environ", {**clean_env(), name: "0.71"}, clear=True):
                self.assertAlmostEqual(rel.min_similarity(), 0.71)
        with mock.patch.dict("os.environ", {**clean_env(), }, clear=True):
            self.assertAlmostEqual(rel.min_similarity(), rel.DEFAULT_MIN_SIMILARITY)


if __name__ == "__main__":
    unittest.main()