@@ -198,14 +198,20 @@ def query_graph(
198198 node = candidates [0 ]
199199 target = node .qualified_name
200200 elif len (candidates ) > 1 :
201- return {
202- "status" : "ambiguous" ,
203- "summary" : (
204- f"Multiple matches for '{ target } '. "
205- "Please use a qualified name."
206- ),
207- "candidates" : [node_to_dict (c ) for c in candidates ],
208- }
201+ # Prefer non-test nodes when exactly one production candidate
202+ non_test = [c for c in candidates if not c .is_test ]
203+ if len (non_test ) == 1 :
204+ node = non_test [0 ]
205+ target = node .qualified_name
206+ else :
207+ return {
208+ "status" : "ambiguous" ,
209+ "summary" : (
210+ f"Multiple matches for '{ target } '. "
211+ "Please use a qualified name."
212+ ),
213+ "candidates" : [node_to_dict (c ) for c in candidates ],
214+ }
209215
210216 if not node and pattern != "file_summary" :
211217 return {
@@ -216,10 +222,12 @@ def query_graph(
216222 qn = node .qualified_name if node else target
217223
218224 if pattern == "callers_of" :
225+ seen_qn : set [str ] = set ()
219226 for e in store .get_edges_by_target (qn ):
220227 if e .kind == "CALLS" :
221228 caller = store .get_node (e .source_qualified )
222- if caller :
229+ if caller and caller .qualified_name not in seen_qn :
230+ seen_qn .add (caller .qualified_name )
223231 results .append (node_to_dict (caller ))
224232 edges_out .append (edge_to_dict (e ))
225233 # Fallback: CALLS edges store unqualified target names
@@ -228,15 +236,18 @@ def query_graph(
228236 if not results and node :
229237 for e in store .search_edges_by_target_name (node .name ):
230238 caller = store .get_node (e .source_qualified )
231- if caller :
239+ if caller and caller .qualified_name not in seen_qn :
240+ seen_qn .add (caller .qualified_name )
232241 results .append (node_to_dict (caller ))
233242 edges_out .append (edge_to_dict (e ))
234243
235244 elif pattern == "callees_of" :
245+ seen_callee : set [str ] = set ()
236246 for e in store .get_edges_by_source (qn ):
237247 if e .kind == "CALLS" :
238248 callee = store .get_node (e .target_qualified )
239- if callee :
249+ if callee and callee .qualified_name not in seen_callee :
250+ seen_callee .add (callee .qualified_name )
240251 results .append (node_to_dict (callee ))
241252 edges_out .append (edge_to_dict (e ))
242253
@@ -270,25 +281,27 @@ def query_graph(
270281 results .append (node_to_dict (child ))
271282
272283 elif pattern == "tests_for" :
273- for e in store . get_edges_by_target ( qn ):
274- if e . kind == "TESTED_BY" :
275- test = store . get_node ( e . source_qualified )
276- if test :
277- results .append (node_to_dict ( test ) )
284+ # Use transitive lookup: direct TESTED_BY + 1-hop CALLS->TESTED_BY
285+ transitive = store . get_transitive_tests ( qn )
286+ seen = { r [ "qualified_name" ] for r in transitive }
287+ for r in transitive :
288+ results .append (r )
278289 # Also search by naming convention
279290 name = node .name if node else target
280291 test_nodes = store .search_nodes (f"test_{ name } " , limit = 10 )
281292 test_nodes += store .search_nodes (f"Test{ name } " , limit = 10 )
282- seen = {r .get ("qualified_name" ) for r in results }
283293 for t in test_nodes :
284294 if t .qualified_name not in seen and t .is_test :
285295 results .append (node_to_dict (t ))
296+ seen .add (t .qualified_name )
286297
287298 elif pattern == "inheritors_of" :
299+ seen_inheritor : set [str ] = set ()
288300 for e in store .get_edges_by_target (qn ):
289301 if e .kind in ("INHERITS" , "IMPLEMENTS" ):
290302 child = store .get_node (e .source_qualified )
291- if child :
303+ if child and child .qualified_name not in seen_inheritor :
304+ seen_inheritor .add (child .qualified_name )
292305 results .append (node_to_dict (child ))
293306 edges_out .append (edge_to_dict (e ))
294307 # Fallback: INHERITS/IMPLEMENTS edges store unqualified base names
0 commit comments