Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions tests/test_mcp_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,25 @@ def test_search_unknown_filter_key_returns_failure(monkeypatch, ladybug_graph) -
assert "typo_key" in out.message


def test_search_no_lance_index_returns_failure_envelope(monkeypatch, ladybug_graph, tmp_path) -> None:
"""Real search error path (issue #358): every other search test monkeypatches
run_search, so the genuine `except Exception` envelope in search_v2 was never
exercised. With no Lance vector index present, search returns a structured
failure (success=False, non-empty message, no traceback) while the graph-only
tools still succeed against the same graph — proving the failure is
vector-specific, not a crash."""
empty_index = tmp_path / "no-lance-index"
empty_index.mkdir()
monkeypatch.setenv("JAVA_CODEBASE_RAG_INDEX_DIR", str(empty_index))
out = search_v2("ChatService", graph=ladybug_graph)
assert out.success is False
assert out.message is not None and out.message.strip()
# Graph-only tools still work (the failure is vector-specific, not a crash).
found = find_v2("symbol", {"role": "CONTROLLER"}, graph=ladybug_graph)
assert found.success is True
assert found.results


def test_search_pushes_nodefilter_into_run_search(monkeypatch, ladybug_graph) -> None:
"""search forwards NodeFilter structural fields into run_search so the filter
applies BEFORE pagination, not as a post-filter on the already-paginated page
Expand Down
19 changes: 19 additions & 0 deletions tests/test_search_lancedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ def test_rrf_merge_weights_second_list_by_row() -> None:
assert by_file["b.java"] > by_file["c.java"]


def test_rrf_merge_reinforced_row_across_lists_outranks_singleton() -> None:
"""Multi-list RRF (issue #358): a row reinforced across two ranked lists
accumulates score and outranks a row appearing in only one list. Merging
dedups by (filename, range_start, range_end) and orders by summed score —
the core of multi-table fused ranking, previously covered only for the
weighted two-list case."""
list_a = [{"filename": "a.java", "range_start": 1, "range_end": 5}]
list_b = [{"filename": "a.java", "range_start": 1, "range_end": 5}] # same key, distinct row
list_c = [{"filename": "z.java", "range_start": 9, "range_end": 99}] # singleton, rank 0
merged = _rrf_merge([list_a, list_b, list_c], k=60)
by_file = {m["filename"]: float(m["_rrf_score"]) for m in merged}
# 'a.java' (rank 0 in two lists) sums two contributions; 'z.java' only one.
assert by_file["a.java"] > by_file["z.java"]
# The two a.java entries collapse to one (dedup by row key).
assert len(merged) == 2
# Highest summed score first.
assert merged[0]["filename"] == "a.java"


def test_java_enriched_columns_include_symbol_identity_fields() -> None:
assert "symbol_id" in JAVA_ENRICHED_COLUMNS
assert "metadata" in JAVA_ENRICHED_COLUMNS
Expand Down
Loading