"""/api/search — the kind filter it offers, and what it does with a bad one. This route used to carry its own two-value map (`note`/`task`/everything else is `all`), which made it the third hand-kept copy of a vocabulary that lives in one table. Both halves of #4250 are pinned here: every declared kind is reachable, and a kind that does not exist is refused rather than widened. """ import pytest from scribe.services.knowledge import FACET_TYPES, content_type_filters def test_the_three_historical_values_still_mean_what_they_meant(): assert content_type_filters("all") == {"is_task": None} assert content_type_filters("task")["is_task"] is True # BROAD on purpose: any non-task, so snippets and lessons stay in scope. assert content_type_filters("note") == {"is_task": False} @pytest.mark.parametrize("facet", sorted(FACET_TYPES)) def test_every_declared_kind_is_reachable_through_this_door(facet): """The engine took `note_type` and `task_kind` all along — the route was simply unable to say them.""" filters = content_type_filters(facet) assert "is_task" in filters if facet not in ("all", "note", "task"): assert filters.get("note_type") == facet or filters.get("task_kind") == facet def test_an_unknown_kind_is_refused_instead_of_silently_widening(): """The old map read anything unrecognised as "no filter", so `?content_type=snippets` returned the whole corpus while looking like a narrowed search — the failure mode that answers a question nobody asked.""" with pytest.raises(ValueError) as err: content_type_filters("snippets") assert "snippets" in str(err.value) assert "snippet" in str(err.value) # names the real ones def test_a_doors_refusal_lists_only_what_that_door_accepts(): """`rule` and `milestone` are the MCP tool's own searches. This route has neither, so offering them in its error would send a caller at a parameter that does not work here.""" with pytest.raises(ValueError) as plain: content_type_filters("nonsense") assert "rule" not in str(plain.value) with pytest.raises(ValueError) as extra: content_type_filters("nonsense", extra=("rule", "milestone")) assert "rule" in str(extra.value) and "milestone" in str(extra.value)