Фиксация изменений
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from app.modules.rag.explain.models import CodeLocation, LayeredRetrievalItem
|
||||
from app.modules.rag.explain.retriever_v2 import CodeExplainRetrieverV2
|
||||
|
||||
|
||||
class _ProductionFirstGateway:
|
||||
def __init__(self) -> None:
|
||||
self.lexical_calls: list[bool] = []
|
||||
|
||||
def retrieve_layer(
|
||||
self,
|
||||
rag_session_id: str,
|
||||
query: str,
|
||||
layer: str,
|
||||
*,
|
||||
limit: int,
|
||||
path_prefixes: list[str] | None = None,
|
||||
exclude_tests: bool = True,
|
||||
prefer_non_tests: bool = False,
|
||||
include_spans: bool = False,
|
||||
):
|
||||
if layer == "C3_ENTRYPOINTS":
|
||||
return SimpleNamespace(items=[], missing=[])
|
||||
if layer == "C1_SYMBOL_CATALOG":
|
||||
return SimpleNamespace(items=[], missing=[])
|
||||
raise AssertionError(layer)
|
||||
|
||||
def retrieve_lexical_code(
|
||||
self,
|
||||
rag_session_id: str,
|
||||
query: str,
|
||||
*,
|
||||
limit: int,
|
||||
path_prefixes: list[str] | None = None,
|
||||
exclude_tests: bool = True,
|
||||
include_spans: bool = False,
|
||||
):
|
||||
self.lexical_calls.append(exclude_tests)
|
||||
if exclude_tests:
|
||||
return SimpleNamespace(
|
||||
items=[
|
||||
LayeredRetrievalItem(
|
||||
source="app/users/service.py",
|
||||
content="def get_user():\n return repo.get_user()",
|
||||
layer="C0_SOURCE_CHUNKS",
|
||||
title="get_user",
|
||||
metadata={"symbol_id": "user-service", "is_test": False},
|
||||
location=CodeLocation(path="app/users/service.py", start_line=10, end_line=11),
|
||||
),
|
||||
LayeredRetrievalItem(
|
||||
source="app/users/repository.py",
|
||||
content="def get_user_repo():\n return {}",
|
||||
layer="C0_SOURCE_CHUNKS",
|
||||
title="get_user_repo",
|
||||
metadata={"symbol_id": "user-repo", "is_test": False},
|
||||
location=CodeLocation(path="app/users/repository.py", start_line=20, end_line=21),
|
||||
),
|
||||
],
|
||||
missing=[],
|
||||
)
|
||||
return SimpleNamespace(
|
||||
items=[
|
||||
LayeredRetrievalItem(
|
||||
source="tests/test_users.py",
|
||||
content="def test_get_user():\n assert service.get_user()",
|
||||
layer="C0_SOURCE_CHUNKS",
|
||||
title="test_get_user",
|
||||
metadata={"symbol_id": "test-user", "is_test": True},
|
||||
location=CodeLocation(path="tests/test_users.py", start_line=5, end_line=6),
|
||||
)
|
||||
],
|
||||
missing=[],
|
||||
)
|
||||
|
||||
|
||||
class _TestsOnlyGateway(_ProductionFirstGateway):
|
||||
def retrieve_lexical_code(
|
||||
self,
|
||||
rag_session_id: str,
|
||||
query: str,
|
||||
*,
|
||||
limit: int,
|
||||
path_prefixes: list[str] | None = None,
|
||||
exclude_tests: bool = True,
|
||||
include_spans: bool = False,
|
||||
):
|
||||
self.lexical_calls.append(exclude_tests)
|
||||
if exclude_tests:
|
||||
return SimpleNamespace(items=[], missing=[])
|
||||
return SimpleNamespace(
|
||||
items=[
|
||||
LayeredRetrievalItem(
|
||||
source="tests/test_users.py",
|
||||
content="def test_get_user():\n assert service.get_user()",
|
||||
layer="C0_SOURCE_CHUNKS",
|
||||
title="test_get_user",
|
||||
metadata={"symbol_id": "test-user", "is_test": True},
|
||||
location=CodeLocation(path="tests/test_users.py", start_line=5, end_line=6),
|
||||
)
|
||||
],
|
||||
missing=[],
|
||||
)
|
||||
|
||||
|
||||
class _FakeGraphRepository:
|
||||
def get_symbols_by_ids(self, rag_session_id: str, symbol_ids: list[str]):
|
||||
return []
|
||||
|
||||
def get_chunks_by_symbol_ids(self, rag_session_id: str, symbol_ids: list[str], prefer_chunk_type: str = "symbol_block"):
|
||||
return []
|
||||
|
||||
def get_out_edges(self, rag_session_id: str, src_symbol_ids: list[str], edge_types: list[str], limit_per_src: int):
|
||||
return []
|
||||
|
||||
def resolve_symbol_by_ref(self, rag_session_id: str, dst_ref: str, package_hint: str | None = None):
|
||||
return None
|
||||
|
||||
|
||||
def test_retriever_prefers_prod_chunks_and_skips_test_fallback_when_enough_evidence() -> None:
|
||||
gateway = _ProductionFirstGateway()
|
||||
retriever = CodeExplainRetrieverV2(gateway=gateway, graph_repository=_FakeGraphRepository())
|
||||
|
||||
pack = retriever.build_pack("rag-1", "Explain get_user")
|
||||
|
||||
assert gateway.lexical_calls == [True]
|
||||
assert [excerpt.path for excerpt in pack.code_excerpts] == [
|
||||
"app/users/service.py",
|
||||
"app/users/repository.py",
|
||||
]
|
||||
assert all(not excerpt.focus.startswith("test:") for excerpt in pack.code_excerpts)
|
||||
|
||||
|
||||
def test_retriever_uses_test_fallback_when_production_evidence_is_missing() -> None:
|
||||
gateway = _TestsOnlyGateway()
|
||||
retriever = CodeExplainRetrieverV2(gateway=gateway, graph_repository=_FakeGraphRepository())
|
||||
|
||||
pack = retriever.build_pack("rag-1", "Explain get_user")
|
||||
|
||||
assert gateway.lexical_calls == [True, False]
|
||||
assert [excerpt.path for excerpt in pack.code_excerpts] == ["tests/test_users.py"]
|
||||
assert pack.code_excerpts[0].focus == "test:lexical"
|
||||
Reference in New Issue
Block a user