Skip to content

graphify label / cluster-only silently drops parallel edges (rebuilds the graph as a simple nx.Graph and writes it back) #3999

Description

@Josezaldua

Version: graphifyy 0.9.73 (also seen on 0.9.16)

What happens

graphify label . and graphify cluster-only . reload graph.json with
build_from_json(_raw, directed=_directed) (cli.py, around line 2101), which creates
a simple nx.Graph() (build.py, around line 1031). A simple graph keeps one edge
per node pair
, so when graph.json contains two edges between the same pair
(for example an imports edge and a calls edge between the same two nodes, or
edges added by an external tool), all but one are lost when the command writes
graph.json back. Nothing is printed about it.

This looks like the same root cause that #2074 fixed for graphify path (loading
with "multigraph": True so parallel links "survive load instead of being silently
collapsed last-writer-wins"), but the cluster-only / label path still loads a
simple graph and then writes it back to disk, so the loss is persistent.

Minimal reproduction (0.9.73)

mkdir -p repro/graphify-out && cd repro
cat > graphify-out/graph.json <<'JSON'
{"directed": false, "multigraph": false, "graph": {}, "nodes": [
 {"id": "a", "label": "a", "file_type": "code", "source_file": "a.py"},
 {"id": "b", "label": "b", "file_type": "code", "source_file": "a.py"},
 {"id": "c", "label": "c", "file_type": "code", "source_file": "a.py"}],
 "links": [
 {"source": "a", "target": "b", "relation": "imports", "confidence": "EXTRACTED", "source_file": "a.py"},
 {"source": "a", "target": "b", "relation": "calls",   "confidence": "EXTRACTED", "source_file": "a.py"},
 {"source": "b", "target": "c", "relation": "calls",   "confidence": "EXTRACTED", "source_file": "a.py"}]}
JSON
uvx --from graphifyy==0.9.73 graphify cluster-only .

Output says Graph: 3 nodes, 2 edges. Before: 3 links. After: 2 links —
(a, b, calls) is gone from graph.json.

Measured on a real graph (~45,600 nodes, 0.9.16, label): 69,784 edges before,
69,462 after. 322 edges lost, none with a missing endpoint, and every one of them
was a second edge on a node pair that stayed connected by another edge.

Expected

Re-clustering / labeling should not change the edge set. Either keep parallel
edges (load into a MultiGraph as #2074 does, or cluster on a simple projection
and write the original link list back), or at least warn with the number of edges
that will be collapsed.

Workaround we use: re-adding the extra edges after every label run.

Side note (separate, minor): running the command via uvx --from graphifyy==<newer>
also rewrote the user's installed Claude skill (~/.claude/skills/graphify/SKILL.md
and references/) to the newer packaged version. SKILL.md got a .bak, but
references/ did not. It was unexpected for a cluster-only run. Happy to open
that as its own issue if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions