fix(path): render arrows in original edge direction (#849)#851
Closed
spindle79 wants to merge 1 commit into
Closed
fix(path): render arrows in original edge direction (#849)#851spindle79 wants to merge 1 commit into
spindle79 wants to merge 1 commit into
Conversation
`graphify path` previously printed every hop as `u --rel--> v` based on traversal order from the undirected `shortest_path` walk, ignoring the actual stored direction of the edge between u and v. When the user queried `path B A` and the stored edge was A→B, the output asserted a backwards call graph. The serialized link.source/link.target fields already encode the caller→callee direction regardless of the top-level "directed" flag the build wrote. Force directed interpretation on read so the renderer can recover and display the correct arrow. - Traverse on `G.to_undirected(as_view=True)` so a path is still found regardless of which direction the user supplied src/tgt in. - For each hop, check `G.has_edge(u, v)` against the directed graph; render `--rel-->` if the stored edge matches traversal direction, `<--rel--` if it points the other way. Distinct from Graphify-Labs#760 (extractor) — verified the extractor emits correct caller→callee directions on the reproducer graph; this is solely a build/render-layer bug. Tests in tests/test_path_cli.py cover both directions.
This was referenced May 13, 2026
Collaborator
|
Thanks for the report! We shipped this fix ourselves in commit 7bb0919 (v0.7.17) — path arrow direction now correctly renders |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #849.
Summary
graphify pathpreviously printed every hop asu --rel--> vbased on traversal order from the undirectedshortest_pathwalk, ignoring the actual stored direction of the edge between u and v. When a user queriedpath B Aand the stored edge was A→B, the output asserted a backwards call graph — the single most user-facing direction bug because of howpathoutput is relayed by assistants.This is distinct from #760 (extractor). Verified on the repro that the extractor emits correct caller→callee directions; the bug is purely at the build/render layer.
Root cause
graph.jsonis serialized with"directed": false(build.py's default), sonx.json_graph.node_link_graphreturns an undirectednx.Graph. The original direction is consumed into edge endpoint positions but the--rel-->arrow at__main__.py:1565was printed in traversal order regardless.Fix
In the
cmd == "path"branch of__main__.py:_raw = {**_raw, "directed": True}) so the loadedGis aDiGraphthat preserves edge direction.shortest_pathonG.to_undirected(as_view=True)so a path is still found regardless of which direction the user supplied src/tgt in.G.has_edge(u, v)against the directed graph. Render--rel-->if the stored edge matches traversal direction,<--rel--if it points the other way.The renderer for
explainis structurally similar but, by always rendering edges as outbound from a fixed queried node, happens to get the right answer when the queried node is the caller and the wrong answer otherwise. Out of scope for this PR — happy to follow up if you'd like, but it warrants its own issue.Tests
tests/test_path_cli.py— two tests, both on a graph.json fixture whose on-disk shape matches whatgraphify updateproduces today (directed: false,links[i].source= caller):test_path_renders_forward_arrow_when_traversal_matches_edge_direction—path createPatchHandler validateSanitySession→createPatchHandler() --calls [EXTRACTED]--> validateSanitySession()test_path_renders_reverse_arrow_when_traversal_opposes_edge_direction—path validateSanitySession createPatchHandler→validateSanitySession() <--calls [EXTRACTED]-- createPatchHandler()(and asserts the old buggy forward output is NOT present)Risk
links[].source/.targetare preserved verbatim bynode_link_graph, and they always represent caller→callee per the existing build conventions (verified inbuild.pyand corroborated byexplainalready relying on this for outbound edge iteration).shortest_pathruns on the undirected view, so paths that previously resolved still resolve.node_link_graphhonors themultigraphflag independently, andedge_data(G, u, v)already handlesMultiDiGraph.Test plan
tree-sitter-sql; one Fortran preprocessed test; two Ollama env-var tests) — zero new failures.graphify pathrenders reversed arrows because graph is undirected (renderer bug, post-#760) #849 now renders correctly with both src/tgt orderings.