From 7aae85ec6e2bef3861b95c1d5f56f2540ca54f84 Mon Sep 17 00:00:00 2001 From: Deepjyoti-Sarmah Date: Fri, 23 Oct 2026 19:54:03 +0530 Subject: [PATCH] fix: resolve affected for disambiguated file labels (#4698) A path query matches every node in the file, so resolution ends in _prefer_file_node. Two of its passes compare the label to the bare basename, which #2032's disambiguation rewrote to a unique path suffix (alpha/hooks.py); the third pass trusts L1 uniqueness, which a module docstring (a rationale node on line 1) or a one-line top-level definition also occupies. Accept a label that names its own source_file, using the _is_file_node_label predicate build/analyze already share. Runs before the L1 fallback, so extra L1 nodes no longer decide the result. (cherry picked from commit b80626ed3be94cfb6480d1c13db630bf74e9f764) --- graphify/affected.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/graphify/affected.py b/graphify/affected.py index b011f2756..4999a000f 100644 --- a/graphify/affected.py +++ b/graphify/affected.py @@ -129,6 +129,29 @@ def _prefer_file_node( if len(exact_file_nodes) == 1: return exact_file_nodes[0] + # #2032 relabels colliding basenames to their shortest unique path suffix + # ("alpha/hooks.py"), so neither pass above nor the one below matches a file + # node whose basename is shared. The label is still a path form of the + # node's OWN source_file, which is what _is_file_node_label encodes (the + # predicate build/analyze already treat as "this node names its file"). + # Checked before the L1 fallback because a module docstring (a `rationale` + # node located on the docstring's line) or a one-line top-level definition + # can also sit on L1, leaving that fallback with more than one candidate + # (#4698). + from graphify.build import _is_file_node_label + + path_file_nodes = [ + node_id + for node_id in node_ids + if str(graph.nodes[node_id].get("source_location", "")) == "L1" + and _is_file_node_label( + str(graph.nodes[node_id].get("label", "")), + str(graph.nodes[node_id].get("source_file", "")), + ) + ] + if len(path_file_nodes) == 1: + return path_file_nodes[0] + l1_nodes = [ node_id for node_id in node_ids