Summary
_find_node (and therefore graphify explain) cannot resolve any node ID that contains punctuation. In our graph this silently disabled lookup for 2,327 of 2,327 concept/overlay nodes (concept:domain:*, concept:class:*, entity:*, commit:*), while IDs without punctuation resolved 400/400.
The docstring states the intent clearly, so this looks like an oversight rather than a design decision:
Return node IDs whose label or ID matches the search term (diacritic-insensitive).
[...] Node-ID exact matches are grouped with label exact matches.
find_node_ambiguity's user-facing hint also assumes ID lookup works:
Retry with the repo-relative path or the full node id.
Version: graphifyy 0.9.32
Reproduction
import networkx as nx
from graphify.serve import _find_node
G = nx.DiGraph()
G.add_node("concept:domain:gosu", label="Gosu") # id contains ':'
G.add_node("plain_node_id", label="Plain") # id has no punctuation
print("colon id ->", _find_node(G, "concept:domain:gosu"))
print("plain id ->", _find_node(G, "plain_node_id"))
print("by label ->", _find_node(G, "Gosu"))
Actual:
colon id -> []
plain id -> ['plain_node_id']
by label -> ['concept:domain:gosu']
Expected: the first line resolves to ['concept:domain:gosu'].
Same through the CLI:
$ graphify explain "concept:domain:gosu"
No node matching 'concept:domain:gosu' found. # node exists in the graph
Root cause
In graphify/serve.py, _find_node_tiers builds two normalizations of the query:
term = " ".join(_search_tokens(label)) # \w+ tokens -> punctuation becomes a space
norm_query = _strip_diacritics(str(label)).lower().strip() # punctuation preserved
The exact-match tier compares the node ID against term only:
elif (
term == norm_label or term == bare_label or term == label_tokens or term == nid_lower
or norm_query == norm_label or norm_query == bare_label
):
For concept:domain:gosu:
| value |
|
term |
concept domain gosu |
norm_query |
concept:domain:gosu |
nid_lower |
concept:domain:gosu |
term == nid_lower is always False once the ID contains punctuation. norm_query — which already holds the correct form and is even part of the trigram prefilter (_trigram_candidates(G, [term, norm_query])) — is never compared against nid_lower.
norm_query appears to have been introduced for punctuated labels (the comment references #1704); it just wasn't extended to node IDs.
Suggested fix
One additional clause in the exact tier:
elif (
term == norm_label or term == bare_label or term == label_tokens or term == nid_lower
or norm_query == norm_label or norm_query == bare_label or norm_query == nid_lower
):
Why this is worse than a plain lookup failure
The natural workaround — calling explain with the node's label instead of its ID — resolves to the wrong node silently. Across our 35 concept nodes, only 4 resolved correctly; 31 landed on a same-named code node:
| query |
resolves to |
intended |
Repository |
data_repository_feedrepository_ts |
concept:class:Repository |
API |
api_apitypehelper_ts |
concept:class:API |
Gosu |
entity:Gosu |
concept:domain:gosu |
So users get a plausible-looking wrong answer rather than an error, which is hard to notice in downstream reasoning.
Summary
_find_node(and thereforegraphify explain) cannot resolve any node ID that contains punctuation. In our graph this silently disabled lookup for 2,327 of 2,327 concept/overlay nodes (concept:domain:*,concept:class:*,entity:*,commit:*), while IDs without punctuation resolved 400/400.The docstring states the intent clearly, so this looks like an oversight rather than a design decision:
find_node_ambiguity's user-facing hint also assumes ID lookup works:Version:
graphifyy 0.9.32Reproduction
Actual:
Expected: the first line resolves to
['concept:domain:gosu'].Same through the CLI:
Root cause
In
graphify/serve.py,_find_node_tiersbuilds two normalizations of the query:The exact-match tier compares the node ID against
termonly:For
concept:domain:gosu:termconcept domain gosunorm_queryconcept:domain:gosunid_lowerconcept:domain:gosuterm == nid_loweris always False once the ID contains punctuation.norm_query— which already holds the correct form and is even part of the trigram prefilter (_trigram_candidates(G, [term, norm_query])) — is never compared againstnid_lower.norm_queryappears to have been introduced for punctuated labels (the comment references #1704); it just wasn't extended to node IDs.Suggested fix
One additional clause in the exact tier:
Why this is worse than a plain lookup failure
The natural workaround — calling
explainwith the node's label instead of its ID — resolves to the wrong node silently. Across our 35 concept nodes, only 4 resolved correctly; 31 landed on a same-named code node:Repositorydata_repository_feedrepository_tsconcept:class:RepositoryAPIapi_apitypehelper_tsconcept:class:APIGosuentity:Gosuconcept:domain:gosuSo users get a plausible-looking wrong answer rather than an error, which is hard to notice in downstream reasoning.