@@ -55,6 +55,25 @@ async def find_by_ids(self, ids: list[int]):
5555 self .calls .append (ids )
5656 return [self .entities_by_id [i ] for i in ids if i in self .entities_by_id ]
5757
58+ async def find_by_ids_for_hydration (self , ids : list [int ]):
59+ self .calls .append (ids )
60+ return [self .entities_by_id [i ] for i in ids if i in self .entities_by_id ]
61+
62+
63+ class LightweightOnlyEntityRepository :
64+ """Raises if graph hydration uses the eager-loading repository method."""
65+
66+ def __init__ (self , entities_by_id : dict [int , SimpleNamespace ]):
67+ self .entities_by_id = entities_by_id
68+ self .hydration_calls : list [list [int ]] = []
69+
70+ async def find_by_ids (self , ids : list [int ]):
71+ raise AssertionError ("graph hydration must use the lightweight hydration lookup" )
72+
73+ async def find_by_ids_for_hydration (self , ids : list [int ]):
74+ self .hydration_calls .append (ids )
75+ return [self .entities_by_id [i ] for i in ids if i in self .entities_by_id ]
76+
5877
5978# --- Single batch fetch (N+1 elimination) ---
6079
@@ -198,3 +217,63 @@ async def test_to_graph_context_empty_results_skip_entity_lookup():
198217
199218 assert repo .calls == []
200219 assert list (graph .results ) == []
220+
221+
222+ @pytest .mark .asyncio
223+ async def test_to_graph_context_uses_lightweight_hydration_lookup ():
224+ """Hydration should not load observations/relations when only entity fields are needed."""
225+ repo = LightweightOnlyEntityRepository (
226+ {
227+ 1 : _make_entity (1 , "Root" , "ext-root" ),
228+ 2 : _make_entity (2 , "Child" , "ext-child" ),
229+ }
230+ )
231+ now = datetime .now (timezone .utc )
232+
233+ context = ServiceContextResult (
234+ results = [
235+ ContextResultItem (
236+ primary_result = _make_row (
237+ type = "entity" ,
238+ id = 1 ,
239+ root_id = 1 ,
240+ title = "Root" ,
241+ permalink = "notes/root" ,
242+ file_path = "notes/root.md" ,
243+ created_at = now ,
244+ ),
245+ observations = [],
246+ related_results = [
247+ _make_row (
248+ type = "relation" ,
249+ id = 20 ,
250+ root_id = 1 ,
251+ title = "links_to: Child" ,
252+ permalink = "notes/root" ,
253+ file_path = "notes/root.md" ,
254+ relation_type = "links_to" ,
255+ from_id = 1 ,
256+ to_id = 2 ,
257+ depth = 1 ,
258+ created_at = now ,
259+ )
260+ ],
261+ )
262+ ],
263+ metadata = ContextMetadata (
264+ types = [SearchItemType .ENTITY , SearchItemType .RELATION ],
265+ depth = 1 ,
266+ primary_count = 1 ,
267+ related_count = 1 ,
268+ total_relations = 1 ,
269+ ),
270+ )
271+
272+ graph = await to_graph_context (context , entity_repository = repo )
273+
274+ assert len (repo .hydration_calls ) == 1
275+ assert set (repo .hydration_calls [0 ]) == {1 , 2 }
276+ relation = graph .results [0 ].related_results [0 ]
277+ assert isinstance (relation , RelationSummary )
278+ assert relation .from_entity_external_id == "ext-root"
279+ assert relation .to_entity_external_id == "ext-child"
0 commit comments