Conversation
…reason
_top_level_dir() returned the whole path when it had no "/", so two
files at the scan root (a flat folder of notes, or README.md and
setup.py) got different "top-level dirs". Every such cross-file edge
(other than suppressed INFERRED calls/uses) received +2 and the reason
"connects across different repos/directories" in surprising_connections,
which is false.
- A path without "/" now maps to the scan root ("."). "." rather than ""
keeps root files distinct from an absolute path outside the scan root,
whose first component is "".
- Backslashes and a leading "./" are normalized first: build_from_json
converts backslashes but keeps "./", and serve.py's _load_graph() and
API callers can skip build_from_json altogether.
- The comparison key is (node "repo", top-level dir). merge-graphs and
global add keep source_file repo-relative and tag nodes with "repo",
so two repos can share directory names; single-repo graphs have no
"repo" and are unaffected. On merged graphs a cross-repo edge now gets
the bonus whenever the repos differ; before, it depended on whether
the top-level directory names happened to differ.
Tests: the flat case (fails on d6eaa8a), merged graphs, backslash and
"./" paths, plus pins for what must not change (root vs subdirectory,
root vs out-of-root absolute path).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Thanks for the pull request, @neo1777. A maintainer will review it soon. Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions. A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic. |
safishamsi
added a commit
that referenced
this pull request
Sep 30, 2026
Solidity free functions (#3906), VB.NET qualified calls (#3909), Astro frontmatter-only AST pass (#3902), surprise bonus/reason alignment (#3934), exclude-hubs stranded-neighbour (#3933), graph-DB push index (#3957), label retry keep-named (#3956), stale-hook status (#3951), virtual-workspace Cargo.toml skip (#3930), and symlinked-instructions install/uninstall handling (#3950/#3953). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Member
|
Shipped in v0.9.73 (now on PyPI) via an authorship-preserving cherry-pick, so your commit keeps contributor-graph credit. Thanks @neo1777! Release: https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.73 |
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.
What does this PR do?
surprising_connectionsgives an edge +2 and the reason "connects across different repos/directories" when its two endpoints have different top-level directories. The helper that computes the directory,_top_level_dir(), returns the whole path when there is no/:So two files at the scan root always have "different top-level directories". I noticed it on a flat folder of Markdown notes, where every surprise carried that reason. Any surprising edge between two root-level files gets it, e.g. between a function in
main.pyand one inutils.py, unless the existing suppression of INFERREDcalls/usesedges applies. Minimal reproducer, AST only, on 0.9.71:(
cross-file semantic connectionis the existing fallback text when no bonus applies,analyze.py#L345.)The change, all in
analyze.py:/maps to"."(the scan root). I use"."rather than""on purpose._norm_source_file(build.py#L375-L399) leaves a file outside the scan root absolute, and its first component is"". A root file and an out-of-root file must stay distinct, as they are today../are normalized inside the helper.build_from_jsonalready converts backslashes (it keeps./), butserve.py's_load_graph()callsnode_link_graphdirectly (serve.py#L73). Without this,pkg\a.pyandlib\b.pywould both become"."after change 1.(node["repo"], top-level dir)(analyze.py#L266-L269).merge-graphsandglobal addkeepsource_filerepo-relative and tag each node withrepo(build.py#L2391), so two repos can share directory names. The tag is set inprefix_graph_for_global(). Without this, change 1 would drop the bonus on a real cross-repo edge between two root-level files, which today gets it only because the filenames differ.Type of change
Verification & Invariants
Invariant: the bonus, and the reason text, apply only when the two endpoints really are in different top-level directories, or in different repos.
What changes in behaviour:
Single-repo graphs. Edges between root-level files no longer get +2 and the false reason. Nodes have no
repo, and a plaindir/filepath gives the same top-level directory as before. The only other differences are two rare path forms:v8compared as whole strings (build_from_jsonconverts them anyway;_load_graph()doesn't);./dir/filepaths, which onv8all mapped to".".extractdoesn't produce them.Both now resolve to their real top-level directory.
Merged graphs. A cross-repo edge now gets the bonus whenever the two repos differ. On
v8it depended on directory names:src/x.py(repo A) →src/y.py(repo B) didn't get it, whilesrc/x.py→lib/y.pydid. Edges between two root-level files of the same repo stop getting it, as in single-repo graphs. This changes the surprise ranking of merged graphs. I think it's the behaviour the reason text describes, but it's your call.Read CONTRIBUTING.md.
Reproduced the issue and identified the invariant.
Smallest fix I could find that doesn't regress merged graphs (one helper, one comparison).
Regression tests in
tests/test_analyze.py:v8;./paths, which also fail onv8;Description kept in sync with the implementation.
Limitations: a
./-prefixed path is treated like its unprefixed form.externalnodes of merged graphs have norepo(same as today).No existing issue: I found this while testing on a flat corpus. I searched the title, body and comments of all issues and PRs, open and closed (for
_top_level_dir, surprise score, cross-repo, flat directory and root-level files), and the code of every PR branch that touches_top_level_dir; none changes its behaviour.How was this tested?
The full-suite failures are the Erlang, R, Solidity, VB.NET and ollama tests: I ran
uv syncwithout--all-extras, soopenaiand the optional grammars are missing. They fail identically on a cleanv8checkout. The new tests also pass underPYTHONHASHSEED0, 1, 2 and 42.The branch is based on
v8at1cd9a36(0.9.72); the reproducer above ran on 0.9.71 (d6eaa8a), andanalyze.pyis unchanged between the two.Environment: Python 3.12.3, uv 0.11.23, Linux Mint 22.3;
graphifyy0.9.71 from PyPI for the reproducer (Leiden viagraspologic-native1.3.1, and the same output with the Louvain fallback).Graphify-specific checklist
Generated skill artifacts: not touched.Co-Authored-By).