fix: prevent fuzzy dedup from collapsing distinct same-named symbols on --update (#1178)
Three-part fix: dedup.py: Pass 1 exact-merge now skips nodes with an empty source_file. Previously all no-source_file nodes with the same label landed in one bucket and were merged, destroying distinct symbols (third-party deps, standalone functions) that happened to share a short name. update.md (skillgen + all 13 host variants): the --update merge now passes both deleted AND changed files to prune_sources, mirroring what watch._rebuild_code already does correctly. Old nodes for re-extracted files are pruned before fresh AST is inserted — no fuzzy reconciliation needed, no cross-file collapse possible. export.py: anti-shrink guard message now names fuzzy dedup as a possible cause (not only "missing chunk files"), and advises a full rebuild as the safe recovery path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
3744e6e220
commit
12a9b5e812
+5
-1
@@ -186,7 +186,11 @@ def deduplicate_entities(
|
||||
for node in group:
|
||||
sf = node.get("source_file") or ""
|
||||
by_file[sf].append(node)
|
||||
for file_group in by_file.values():
|
||||
for sf, file_group in by_file.items():
|
||||
if not sf:
|
||||
# No source_file — cannot prove same symbol; skip to avoid
|
||||
# collapsing distinct nodes that happen to share a label (#1178).
|
||||
continue
|
||||
if len(file_group) > 1:
|
||||
winner = _pick_winner(file_group)
|
||||
for node in file_group:
|
||||
|
||||
+6
-3
@@ -493,9 +493,12 @@ def to_json(G: nx.Graph, communities: dict[int, list[str]], output_path: str, *,
|
||||
import sys as _sys
|
||||
print(
|
||||
f"[graphify] WARNING: new graph has {new_n} nodes but existing "
|
||||
f"graph.json has {existing_n}. Refusing to overwrite — you may be "
|
||||
f"missing chunk files from a previous session. "
|
||||
f"Pass force=True to override.",
|
||||
f"graph.json has {existing_n} (net -{existing_n - new_n}). "
|
||||
f"Refusing to overwrite. Possible causes: missing chunk files from "
|
||||
f"a previous session, or fuzzy dedup collapsed same-named symbols "
|
||||
f"across files during an --update on an already-current graph. "
|
||||
f"Run a full rebuild (/graphify .) to be safe, or pass force=True "
|
||||
f"only if you have verified the reduction is legitimate.",
|
||||
file=_sys.stderr,
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
@@ -93,13 +93,18 @@ from graphify.detect import save_manifest
|
||||
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
||||
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
||||
deleted = list(incremental.get('deleted_files', []))
|
||||
# Also prune old nodes for re-extracted (changed) files before inserting fresh AST.
|
||||
# Without this, build_merge's dedup pass tries to reconcile old and new versions of
|
||||
# the same file's nodes and can collapse same-named symbols across files (#1178).
|
||||
changed = [f for files in incremental.get('new_files', {}).values() for f in files]
|
||||
prune = list(dict.fromkeys(deleted + changed)) or None
|
||||
|
||||
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
||||
# so edge direction (calls, implements, imports) is always preserved (#801).
|
||||
G = build_merge(
|
||||
[new_extraction],
|
||||
graph_path='graphify-out/graph.json',
|
||||
prune_sources=deleted or None,
|
||||
prune_sources=prune,
|
||||
)
|
||||
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user