From 917fab9fbbb54aa5af731fe59e6a63462de2765e Mon Sep 17 00:00:00 2001 From: Mahaboob pasha Date: Tue, 6 Oct 2026 21:20:06 +0530 Subject: [PATCH] fix(analyze): keep edge direction in graph_diff graph_diff keyed undirected edges by their sorted endpoints, so a call that reversed (a->b became b->a) dropped out of the --update summary. When both snapshots carry _src/_tgt and they differ, the edge is now reported as one removed and one new edge, with source/target taken from the markers. Graphs without the markers diff as before. The skill's diff step loaded the old graph.json with a plain node_link_graph call, which drops the stored direction, so it now uses paths.load_node_link_graph (#4066/#4088). Skills regenerated with skillgen, and the aider/devin monolith round-trip allows the changed lines. Closes #4067 Co-Authored-By: Grok Bot --- graphify/analyze.py | 35 +++++++++++++------ graphify/skill-aider.md | 4 +-- graphify/skill-devin.md | 4 +-- graphify/skills/agents/references/update.md | 4 +-- graphify/skills/amp/references/update.md | 4 +-- graphify/skills/claude/references/update.md | 4 +-- graphify/skills/claw/references/update.md | 4 +-- graphify/skills/codex/references/update.md | 4 +-- graphify/skills/copilot/references/update.md | 4 +-- graphify/skills/droid/references/update.md | 4 +-- graphify/skills/kilo/references/update.md | 4 +-- graphify/skills/kiro/references/update.md | 4 +-- graphify/skills/opencode/references/update.md | 4 +-- graphify/skills/pi/references/update.md | 4 +-- graphify/skills/trae/references/update.md | 4 +-- graphify/skills/vscode/references/update.md | 4 +-- graphify/skills/windows/references/update.md | 4 +-- tests/test_analyze.py | 33 +++++++++++++++++ .../expected/graphify__skill-aider.md | 4 +-- .../expected/graphify__skill-devin.md | 4 +-- ...ify__skills__agents__references__update.md | 4 +-- ...aphify__skills__amp__references__update.md | 4 +-- ...ify__skills__claude__references__update.md | 4 +-- ...phify__skills__claw__references__update.md | 4 +-- ...hify__skills__codex__references__update.md | 4 +-- ...fy__skills__copilot__references__update.md | 4 +-- ...hify__skills__droid__references__update.md | 4 +-- ...phify__skills__kilo__references__update.md | 4 +-- ...phify__skills__kiro__references__update.md | 4 +-- ...y__skills__opencode__references__update.md | 4 +-- ...raphify__skills__pi__references__update.md | 4 +-- ...phify__skills__trae__references__update.md | 4 +-- ...ify__skills__vscode__references__update.md | 4 +-- ...fy__skills__windows__references__update.md | 4 +-- tools/skillgen/fragments/core/aider.md | 4 +-- tools/skillgen/fragments/core/devin.md | 4 +-- .../fragments/references/shared/update.md | 4 +-- tools/skillgen/gen.py | 18 ++++++++++ 38 files changed, 146 insertions(+), 80 deletions(-) diff --git a/graphify/analyze.py b/graphify/analyze.py index aa56e03fb..ef4154ed5 100644 --- a/graphify/analyze.py +++ b/graphify/analyze.py @@ -630,24 +630,39 @@ def graph_diff(G_old: nx.Graph, G_new: nx.Graph) -> dict: return (u, v, data.get("relation", "")) return (min(u, v), max(u, v), data.get("relation", "")) - old_edge_keys = { - edge_key(G_old, u, v, d) + def edge_dir(data: dict) -> tuple | None: + # Stored direction of an undirected edge (build_from_json, load_node_link_graph). + if "_src" in data and "_tgt" in data: + return (data["_src"], data["_tgt"]) + return None + + old_edge_dirs = { + edge_key(G_old, u, v, d): edge_dir(d) for u, v, d in G_old.edges(data=True) } - new_edge_keys = { - edge_key(G_new, u, v, d) + new_edge_dirs = { + edge_key(G_new, u, v, d): edge_dir(d) for u, v, d in G_new.edges(data=True) } + old_edge_keys = set(old_edge_dirs) + new_edge_keys = set(new_edge_dirs) - added_edge_keys = new_edge_keys - old_edge_keys - removed_edge_keys = old_edge_keys - new_edge_keys + # A reversed edge (a->b became b->a) keeps its undirected key. Report it as + # removed + added only when both snapshots carry _src/_tgt and they differ, + # so graphs without the markers diff exactly as before (#4067). + reversed_edge_keys = { + k for k in old_edge_keys & new_edge_keys + if old_edge_dirs[k] and new_edge_dirs[k] and old_edge_dirs[k] != new_edge_dirs[k] + } + added_edge_keys = (new_edge_keys - old_edge_keys) | reversed_edge_keys + removed_edge_keys = (old_edge_keys - new_edge_keys) | reversed_edge_keys new_edges_list = [] for u, v, d in G_new.edges(data=True): if edge_key(G_new, u, v, d) in added_edge_keys: new_edges_list.append({ - "source": u, - "target": v, + "source": d.get("_src", u), + "target": d.get("_tgt", v), "relation": d.get("relation", ""), "confidence": d.get("confidence", ""), }) @@ -656,8 +671,8 @@ def graph_diff(G_old: nx.Graph, G_new: nx.Graph) -> dict: for u, v, d in G_old.edges(data=True): if edge_key(G_old, u, v, d) in removed_edge_keys: removed_edges_list.append({ - "source": u, - "target": v, + "source": d.get("_src", u), + "target": d.get("_tgt", v), "relation": d.get("relation", ""), "confidence": d.get("confidence", ""), }) diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 6e459945a..97c3afb59 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -856,7 +856,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -866,7 +866,7 @@ new_extract = json.loads(Path('.graphify_extract.json').read_text()) G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index 9bd1f0dc7..af7e532c4 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -993,7 +993,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -1002,7 +1002,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text() G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/agents/references/update.md b/graphify/skills/agents/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/agents/references/update.md +++ b/graphify/skills/agents/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/amp/references/update.md b/graphify/skills/amp/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/amp/references/update.md +++ b/graphify/skills/amp/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/claude/references/update.md b/graphify/skills/claude/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/claude/references/update.md +++ b/graphify/skills/claude/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/claw/references/update.md b/graphify/skills/claw/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/claw/references/update.md +++ b/graphify/skills/claw/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/codex/references/update.md b/graphify/skills/codex/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/codex/references/update.md +++ b/graphify/skills/codex/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/copilot/references/update.md b/graphify/skills/copilot/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/copilot/references/update.md +++ b/graphify/skills/copilot/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/droid/references/update.md b/graphify/skills/droid/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/droid/references/update.md +++ b/graphify/skills/droid/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/kilo/references/update.md b/graphify/skills/kilo/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/kilo/references/update.md +++ b/graphify/skills/kilo/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/kiro/references/update.md b/graphify/skills/kiro/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/kiro/references/update.md +++ b/graphify/skills/kiro/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/opencode/references/update.md b/graphify/skills/opencode/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/opencode/references/update.md +++ b/graphify/skills/opencode/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/pi/references/update.md b/graphify/skills/pi/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/pi/references/update.md +++ b/graphify/skills/pi/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/trae/references/update.md b/graphify/skills/trae/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/trae/references/update.md +++ b/graphify/skills/trae/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/vscode/references/update.md b/graphify/skills/vscode/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/vscode/references/update.md +++ b/graphify/skills/vscode/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/graphify/skills/windows/references/update.md b/graphify/skills/windows/references/update.md index 3632fd412..bd8e659d3 100644 --- a/graphify/skills/windows/references/update.md +++ b/graphify/skills/windows/references/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tests/test_analyze.py b/tests/test_analyze.py index 518739d05..4e6bb1073 100644 --- a/tests/test_analyze.py +++ b/tests/test_analyze.py @@ -347,6 +347,39 @@ def test_graph_diff_empty_diff(): assert diff["summary"] == "no changes" +def _make_marked_graph(src, tgt): + """Helper: undirected graph whose one edge stores its direction in _src/_tgt.""" + G = nx.Graph() + G.add_node("n1", label="Alpha") + G.add_node("n2", label="Beta") + G.add_edge(src, tgt, relation="calls", confidence="EXTRACTED", _src=src, _tgt=tgt) + return G + + +def test_graph_diff_reversed_edge_reported(): + # #4067: n1 calls n2 becoming n2 calls n1 must not vanish from the diff. + diff = graph_diff(_make_marked_graph("n1", "n2"), _make_marked_graph("n2", "n1")) + assert [(e["source"], e["target"]) for e in diff["new_edges"]] == [("n2", "n1")] + assert [(e["source"], e["target"]) for e in diff["removed_edges"]] == [("n1", "n2")] + assert diff["summary"] == "1 new edge, 1 edge removed" + + +def test_graph_diff_unchanged_direction_no_changes(): + diff = graph_diff(_make_marked_graph("n2", "n1"), _make_marked_graph("n2", "n1")) + assert diff["new_edges"] == [] + assert diff["removed_edges"] == [] + assert diff["summary"] == "no changes" + + +def test_graph_diff_reversed_edge_without_markers_unchanged(): + # Without _src/_tgt on both sides the edge is keyed by its endpoints, as before. + nodes = [("n1", "Alpha"), ("n2", "Beta")] + G_old = _make_simple_graph(nodes, [("n1", "n2", "calls", "EXTRACTED")]) + G_new = _make_simple_graph(nodes, [("n2", "n1", "calls", "EXTRACTED")]) + assert graph_diff(G_old, G_new)["summary"] == "no changes" + assert graph_diff(G_old, _make_marked_graph("n2", "n1"))["summary"] == "no changes" + + # --- code↔doc INFERRED suppression tests --- def _make_code_doc_graph(): diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 6e459945a..97c3afb59 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -856,7 +856,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -866,7 +866,7 @@ new_extract = json.loads(Path('.graphify_extract.json').read_text()) G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index 9bd1f0dc7..af7e532c4 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -993,7 +993,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -1002,7 +1002,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text() G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__agents__references__update.md b/tools/skillgen/expected/graphify__skills__agents__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__update.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__amp__references__update.md b/tools/skillgen/expected/graphify__skills__amp__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__update.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__claude__references__update.md b/tools/skillgen/expected/graphify__skills__claude__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__claw__references__update.md b/tools/skillgen/expected/graphify__skills__claw__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__codex__references__update.md b/tools/skillgen/expected/graphify__skills__codex__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__update.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__update.md b/tools/skillgen/expected/graphify__skills__copilot__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__update.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__droid__references__update.md b/tools/skillgen/expected/graphify__skills__droid__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__update.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__update.md b/tools/skillgen/expected/graphify__skills__kilo__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__update.md b/tools/skillgen/expected/graphify__skills__kiro__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__update.md b/tools/skillgen/expected/graphify__skills__opencode__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__pi__references__update.md b/tools/skillgen/expected/graphify__skills__pi__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__update.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__trae__references__update.md b/tools/skillgen/expected/graphify__skills__trae__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__update.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__update.md b/tools/skillgen/expected/graphify__skills__vscode__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/expected/graphify__skills__windows__references__update.md b/tools/skillgen/expected/graphify__skills__windows__references__update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__update.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 6e459945a..97c3afb59 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -856,7 +856,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -866,7 +866,7 @@ new_extract = json.loads(Path('.graphify_extract.json').read_text()) G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index 9bd1f0dc7..af7e532c4 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -993,7 +993,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -1002,7 +1002,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text() G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/fragments/references/shared/update.md b/tools/skillgen/fragments/references/shared/update.md index 3632fd412..bd8e659d3 100644 --- a/tools/skillgen/fragments/references/shared/update.md +++ b/tools/skillgen/fragments/references/shared/update.md @@ -174,7 +174,7 @@ $(cat graphify-out/.graphify_python) -c " import json from graphify.analyze import graph_diff from graphify.build import build_from_json -from networkx.readwrite import json_graph +from graphify.paths import load_node_link_graph import networkx as nx from pathlib import Path @@ -184,7 +184,7 @@ new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(e G_new = build_from_json(new_extract, directed=IS_DIRECTED) if old_data: - G_old = json_graph.node_link_graph(old_data, edges='links') + G_old = load_node_link_graph(old_data) diff = graph_diff(G_old, G_new) print(diff['summary']) if diff['new_nodes']: diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 6c30a0847..bda0ab2e4 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -1180,6 +1180,23 @@ def _is_watch_injection_fix_line(line: str) -> bool: ) +def _is_graph_diff_direction_fix_line(line: str) -> bool: + """Whether a line is part of the --update graph-diff direction fix (#4067). + + The diff step loaded the old graph.json with a plain ``node_link_graph``, + which drops the stored edge direction, so a reversed call showed as "no + changes". It now loads through ``paths.load_node_link_graph`` (#4066). Both + the removed import/load lines and the added ones match here. + """ + stripped = line.strip() + return stripped in ( + "from networkx.readwrite import json_graph", + "G_old = json_graph.node_link_graph(old_data, edges='links')", + "from graphify.paths import load_node_link_graph", + "G_old = load_node_link_graph(old_data)", + ) + + # Every line that may differ between a rendered monolith and its pristine v8 # baseline. Each predicate documents one sanctioned change-class; a blank line is # allowed because the multi-line fix blocks insert spacing. Anything else failing @@ -1203,6 +1220,7 @@ _SANCTIONED_MONOLITH_DIFFS = ( _is_community_label_export_fix_line, _is_step1_root_marker_fix_line, _is_watch_injection_fix_line, + _is_graph_diff_direction_fix_line, )