from app.modules.rag.explain import CodeExplainRetrieverV2, LayeredRetrievalGateway class _ExplodingEmbedder: def embed(self, texts: list[str]) -> list[list[float]]: raise RuntimeError("embedding unavailable") class _RepositoryWithoutFallback: def retrieve(self, *args, **kwargs): raise RuntimeError("vector retrieval unavailable") def retrieve_lexical_code( self, rag_session_id: str, query_text: str, *, limit: int = 5, path_prefixes: list[str] | None = None, exclude_path_prefixes: list[str] | None = None, exclude_like_patterns: list[str] | None = None, prefer_non_tests: bool = False, ): return [] 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_v2_returns_pack_without_fallback_method() -> None: retriever = CodeExplainRetrieverV2( gateway=LayeredRetrievalGateway(_RepositoryWithoutFallback(), _ExplodingEmbedder()), graph_repository=_FakeGraphRepository(), ) pack = retriever.build_pack("rag-1", "Explain get_user") assert pack.code_excerpts == [] assert any(item.startswith("layer:C3_ENTRYPOINTS retrieval_failed") for item in pack.missing) assert any(item.startswith("layer:C1_SYMBOL_CATALOG retrieval_failed") for item in pack.missing) assert "layer:C0 empty" in pack.missing