From 9c2275ad828af1a6d9916ad29b71bb27057c3a00 Mon Sep 17 00:00:00 2001 From: Safi Date: Sat, 18 Apr 2026 10:54:39 +0100 Subject: [PATCH] fix #432 to_html crash on large graphs, fix #431 Go import node ID collision --- CHANGELOG.md | 2 ++ graphify/extract.py | 8 ++++---- graphify/watch.py | 16 ++++++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42ef88c..86dc8f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Full release notes with details on each version: [GitHub Releases](https://githu - Fix: stale skill version warning persists after running `graphify install` when multiple platforms were previously installed — `graphify install` now refreshes `.graphify_version` in all other known skill directories so the warning clears across the board (#178) - Fix: `.html` files silently skipped during detection — added `.html` to `DOC_EXTENSIONS`; HTML pages, docs, and web project content now indexed correctly (#260) +- Fix: `_rebuild_code` (watch/update/hook) fails entirely on graphs > 5000 nodes because `to_html` raises `ValueError` — wrapped in its own try/except so `graph.json` and `GRAPH_REPORT.md` always land; stale `graph.html` from a previous smaller run is removed (#432) +- Fix: Go stdlib imports (e.g. `"context"`) produced `imports_from` edges pointing at local files of the same basename — Go import node IDs now prefixed `go_pkg_` using the full import path, eliminating false cycle-dependency pairs (#431) ## 0.4.22 (2026-04-18) diff --git a/graphify/extract.py b/graphify/extract.py index cac6bf7..f1c02f3 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -1947,15 +1947,15 @@ def extract_go(path: Path) -> dict: path_node = spec.child_by_field_name("path") if path_node: raw = _read_text(path_node, source).strip('"') - module_name = raw.split("/")[-1] - tgt_nid = _make_id(module_name) + # Prefix with go_pkg_ so stdlib names (e.g. "context") + # don't collide with local files of the same basename. + tgt_nid = _make_id("go", "pkg", raw) add_edge(file_nid, tgt_nid, "imports_from", spec.start_point[0] + 1) elif child.type == "import_spec": path_node = child.child_by_field_name("path") if path_node: raw = _read_text(path_node, source).strip('"') - module_name = raw.split("/")[-1] - tgt_nid = _make_id(module_name) + tgt_nid = _make_id("go", "pkg", raw) add_edge(file_nid, tgt_nid, "imports_from", child.start_point[0] + 1) return diff --git a/graphify/watch.py b/graphify/watch.py index 3bd08ec..537746c 100644 --- a/graphify/watch.py +++ b/graphify/watch.py @@ -78,7 +78,18 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool: {"input": 0, "output": 0}, str(watch_path), suggested_questions=questions) (out / "GRAPH_REPORT.md").write_text(report, encoding="utf-8") to_json(G, communities, str(out / "graph.json")) - to_html(G, communities, str(out / "graph.html"), community_labels=labels or None) + + # to_html raises ValueError for graphs > MAX_NODES_FOR_VIZ (5000). + # Wrap so core outputs (graph.json + GRAPH_REPORT.md) always land. + html_written = False + try: + to_html(G, communities, str(out / "graph.html"), community_labels=labels or None) + html_written = True + except ValueError as viz_err: + print(f"[graphify watch] Skipped graph.html: {viz_err}") + stale = out / "graph.html" + if stale.exists(): + stale.unlink() # clear stale needs_update flag if present flag = out / "needs_update" @@ -87,7 +98,8 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool: print(f"[graphify watch] Rebuilt: {G.number_of_nodes()} nodes, " f"{G.number_of_edges()} edges, {len(communities)} communities") - print(f"[graphify watch] graph.json, graph.html and GRAPH_REPORT.md updated in {out}") + products = "graph.json" + (", graph.html" if html_written else "") + " and GRAPH_REPORT.md" + print(f"[graphify watch] {products} updated in {out}") return True except Exception as exc: