You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pruning a source file leaves its external-import nodes behind as permanent orphans: no source_file means no prune can ever match them #2807
prune_sources matches nodes on their source_file. Extractors create per-file nodes for imported external symbols — Path from pathlib, Counter from collections, Graph from networkx — and those carry no source_file, because they are defined outside the corpus. Every edge they have points at symbols in the one file they were created for.
So when that file is deleted or excluded, the prune removes the file's own nodes and leaves these behind: degree 0, named after a file the corpus no longer contains, and unreachable by any future prune, since there is no source_file to match on.
Reproduce
graphify's own package, 2287 nodes / 5396 edges, pruning one real file:
after pruning 'graphify/callflow_html.py': 2147 nodes, 5120 edges
[graphify] Pruned 137 node(s) from 1 deleted or excluded source file(s).
orphaned (degree-0) nodes now: 3 (new: 2)
'graphify_callflow_html_py_path' label='Path' source_file=''
'graphify_callflow_html_py_counter' label='Counter' source_file=''
nodes still named after the pruned file: 2
'graphify_callflow_html_py_path' label='Path' source_file='' deg=0
'graphify_callflow_html_py_counter' label='Counter' source_file='' deg=0
137 of the file's 139 nodes go; 2 stay forever.
This corpus has 97 source-less nodes across 81 files, so roughly one to two per file are candidates. Excluding a directory of any size leaves a proportional residue, and each subsequent prune adds more — they cannot be cleaned up by re-running anything.
Why it matters
They are counted.GRAPH_REPORT.md opens with N nodes · M edges · K communities, computed off the graph, so the totals drift upward from reality with every prune.
They are exported.to_obsidian writes one note per node, and the wiki and graph.json carry them too, so a vault keeps a Path.md for a file that is no longer in the corpus.
Scoping it to nodes this prune isolated matters: a source-less node that was already isolated before the prune is someone else's business, and this graph had one such node that should not be swept up by a fix for a different problem.
A node with no source_file and no edges carries no information — it cannot be located in the corpus and it connects nothing — so removing it loses nothing, whereas keeping it inflates every count that reads the graph.
I have this working with tests and will open a PR shortly.
Activity
fix(build): sweep external-import nodes a prune leaves orphaned (#2807)
test(build): pin shrink-guard safety and shared-stub survival for orp…
chore: bump to 0.9.46
safishamsi commentedon Aug 17, 2026
Fixed in v0.9.46 (on PyPI now) via #2809, thanks @abhay-codes07. Closing.
fix(build): sweep source-less placeholders orphaned by re-extraction (#…