fix: resolve_seed matches bare names against ()-decorated callable labels

Callable nodes are labeled with a trailing "()" (e.g. classifyProperty()),
so a bare-name query like "classifyProperty" falls through the exact-label
pass and then ties with any prefix sibling (classifyPropertySafe()) in the
contains pass, returning "No unique node match" even though exactly one
callable with that name exists.

Add a bare-name pass between exact-label and exact-source matching that
compares query and label with the trailing "()" stripped from each. Bare
queries now resolve decorated labels and vice versa; genuine duplicates
still return None.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Skyler Southern
2026-06-11 09:14:28 -04:00
parent cce2673021
commit 58efcebd83
2 changed files with 48 additions and 0 deletions
+17
View File
@@ -43,6 +43,12 @@ def _format_location(data: dict) -> str:
return str(source_file)
def _bare_name(label: str) -> str:
"""Lowercased label with the callable decoration (trailing "()") removed."""
label = label.lower()
return label[:-2] if label.endswith("()") else label
def resolve_seed(graph: nx.Graph, query: str) -> str | None:
if query in graph:
return query
@@ -54,6 +60,17 @@ def resolve_seed(graph: nx.Graph, query: str) -> str | None:
]
if len(exact_label_matches) == 1:
return exact_label_matches[0]
# Callable labels are decorated ("name()"), so a bare "name" query falls
# through exact matching and then ties with any "name*" sibling in the
# contains pass. Match on the undecorated name before giving up.
query_bare = _bare_name(query_lower)
bare_name_matches = [
str(node_id)
for node_id, data in graph.nodes(data=True)
if _bare_name(str(data.get("label", ""))) == query_bare
]
if len(bare_name_matches) == 1:
return bare_name_matches[0]
exact_source_matches = [
str(node_id)
for node_id, data in graph.nodes(data=True)
+31
View File
@@ -92,3 +92,34 @@ def test_affected_cli_forces_directed_on_undirected_graph(monkeypatch, tmp_path,
assert "calls" in out
# B is the query node, not an affected node, and the result is not empty.
assert "No affected nodes found." not in out
def test_resolve_seed_bare_name_matches_callable_label():
from graphify.affected import resolve_seed
graph = nx.DiGraph()
graph.add_node("a", label="classifyProperty()", source_file="pkg/entity.py")
graph.add_node("b", label="classifyPropertySafe()", source_file="app/context.py")
assert resolve_seed(graph, "classifyProperty") == "a"
assert resolve_seed(graph, "classifyPropertySafe") == "b"
def test_resolve_seed_decorated_query_matches_bare_label():
from graphify.affected import resolve_seed
graph = nx.DiGraph()
graph.add_node("a", label="Foo", source_file="pkg/foo.py")
graph.add_node("b", label="FooBar", source_file="pkg/foobar.py")
assert resolve_seed(graph, "Foo()") == "a"
def test_resolve_seed_bare_name_tie_still_returns_none():
from graphify.affected import resolve_seed
graph = nx.DiGraph()
graph.add_node("a", label="dup()", source_file="pkg/one.py")
graph.add_node("b", label="dup()", source_file="pkg/two.py")
assert resolve_seed(graph, "dup") is None