graphify version: 0.7.15
Symptom
Call graphs are inherently directed (caller → callee), but graphify path / query traverse both directions indistinguishably. graphify path "A" "B" can return a "valid" reverse path even when no forward dependency chain exists.
Suspected root cause
Three places combine to make directed mode effectively unreachable:
-
build.py:74 — build_from_json already supports directed=True (docstring: "directed=False (default) produces an undirected Graph for backward compatibility").
-
No --directed flag on the CLI — __main__.py:1670-1671 only reads the directed field from an existing graph.json. update / extract cannot pass the option through on a fresh build:
_directed = bool(_raw.get("directed", False))
G = build_from_json(_raw, directed=_directed)
-
serve.py:147 _dfs (and _bfs at 131) iterate G.neighbors(node) — on a DiGraph, this returns both successors and predecessors, so even a directed graph is traversed in both directions.
Reproducer
Every graph.json produced by graphify update . has "directed": false. graphify path "Caller" "Callee" and graphify path "Callee" "Caller" return symmetric paths.
Possible directions
- Expose
--directed on update / extract / init (forward to the existing build.py option)
- In
serve.py, branch on G.is_directed() and use successors for DiGraph
- Optionally, a query-time
--reverse flag (predecessors traversal) for "who calls X?" queries
cluster.py already calls to_undirected() before Louvain/Leiden, so community detection is unaffected.
Environment
Production Android browser fork (Chromium-derived), Java + Kotlin, 19,668 nodes / 50,881 edges (0.7.15). Full environment in the companion issue (substring _find_node, #828).
Impact
graphify path / query cannot reliably answer "is there a forward dependency chain from A to B?" — the most common path-search question. The directed code path today is half-implemented: build supports it, but serve and CLI don't.
graphify version: 0.7.15
Symptom
Call graphs are inherently directed (
caller → callee), butgraphify path/querytraverse both directions indistinguishably.graphify path "A" "B"can return a "valid" reverse path even when no forward dependency chain exists.Suspected root cause
Three places combine to make directed mode effectively unreachable:
build.py:74—build_from_jsonalready supportsdirected=True(docstring: "directed=False (default) produces an undirected Graph for backward compatibility").No
--directedflag on the CLI —__main__.py:1670-1671only reads thedirectedfield from an existinggraph.json.update/extractcannot pass the option through on a fresh build:serve.py:147_dfs(and_bfsat 131) iterateG.neighbors(node)— on aDiGraph, this returns both successors and predecessors, so even a directed graph is traversed in both directions.Reproducer
Every
graph.jsonproduced bygraphify update .has"directed": false.graphify path "Caller" "Callee"andgraphify path "Callee" "Caller"return symmetric paths.Possible directions
--directedonupdate/extract/init(forward to the existingbuild.pyoption)serve.py, branch onG.is_directed()and usesuccessorsforDiGraph--reverseflag (predecessors traversal) for "who calls X?" queriescluster.pyalready callsto_undirected()before Louvain/Leiden, so community detection is unaffected.Environment
Production Android browser fork (Chromium-derived), Java + Kotlin, 19,668 nodes / 50,881 edges (0.7.15). Full environment in the companion issue (substring
_find_node, #828).Impact
graphify path/querycannot reliably answer "is there a forward dependency chain from A to B?" — the most common path-search question. The directed code path today is half-implemented: build supports it, but serve and CLI don't.