@@ -165,6 +165,28 @@ def generate_query_embedding(self, _query: str) -> list[float]:
165165 return [0.0 ] * 768
166166
167167
168+ class _FakePostgresPhraseMatch (_FakePostgres ):
169+ def execute_query (self , sql : str , params : tuple [Any , ...] | None = None ):
170+ if "plainto_tsquery" in sql and params :
171+ query = params [0 ]
172+ if query == "future barbados" :
173+ return [
174+ (
175+ "kg_future" ,
176+ "schema:Organization" ,
177+ "Future Barbados" ,
178+ ["Future Barbados" ],
179+ 0.8 ,
180+ )
181+ ]
182+ return []
183+
184+ if "FROM kg_nodes" in sql and "WHERE id IN" in sql :
185+ return [("kg_future" , "Future Barbados" , "schema:Organization" )]
186+
187+ return super ().execute_query (sql , params )
188+
189+
168190class _FakePostgresNameMatch (_FakePostgres ):
169191 def execute_query (self , sql : str , params : tuple [Any , ...] | None = None ):
170192 if "FROM kg_nodes" in sql and "embedding <=>" in sql :
@@ -270,6 +292,26 @@ def test_kg_hybrid_graph_rag_prefers_name_substring_matches() -> None:
270292 assert "Tameisha Rochester" not in seed_labels
271293
272294
295+ def test_kg_hybrid_graph_rag_adds_phrase_fulltext_candidates () -> None :
296+ from lib .kg_hybrid_graph_rag import kg_hybrid_graph_rag
297+
298+ postgres = _FakePostgresPhraseMatch ()
299+ embedding = _FakeEmbedding ()
300+
301+ out = kg_hybrid_graph_rag (
302+ postgres = postgres ,
303+ embedding_client = embedding ,
304+ query = "Future Barbados recent 2026 budget debates" ,
305+ hops = 1 ,
306+ seed_k = 5 ,
307+ max_edges = 10 ,
308+ max_citations = 5 ,
309+ )
310+
311+ seed_labels = {s ["label" ] for s in out ["seeds" ]}
312+ assert "Future Barbados" in seed_labels
313+
314+
273315def test_kg_hybrid_graph_rag_respects_bill_citation_limit () -> None :
274316 from lib .kg_hybrid_graph_rag import kg_hybrid_graph_rag_with_bills
275317
0 commit comments