fix(analyze): exclude npm dep-block keys from god-node selection (#905)
* fix(analyze): exclude npm dep-block keys from god-node selection Extends _JSON_NOISE_LABELS in graphify/analyze.py with the six npm package.json dependency-block keys (dependencies, devDependencies, peerDependencies, optionalDependencies, bundledDependencies, bundleDependencies — lowercased to match the existing .strip().lower() comparison in _is_json_key_node). On JS/TS corpora with non-trivial dependency counts, the dep-block key node accumulates contains+imports edges to every package entry and was surfacing as the top god-node in the report. The fix is a one-line extension of the existing frozenset; no new helpers or code paths. Includes a parametrized regression test in tests/test_analyze.py covering all five npm keys: dependencies, devDependencies, peerDependencies, optionalDependencies, bundledDependencies. Validated live against rsl-siege-manager @ 6085fd66 — zero npm dep-block keys in the top-10 god-nodes after the fix. Pre-existing failures (Windows symlink + SQL tree-sitter): 17, unchanged. Closes #2 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: drop fork-local issue refs from analyze comments --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6018831193
commit
2aaa216825
@@ -68,6 +68,8 @@ def _is_file_node(G: nx.Graph, node_id: str) -> bool:
|
||||
_JSON_NOISE_LABELS: frozenset[str] = frozenset({
|
||||
"start", "end", "name", "id", "type", "properties",
|
||||
"value", "key", "data", "items", "title", "description", "version",
|
||||
"dependencies", "devdependencies", "peerdependencies",
|
||||
"optionaldependencies", "bundleddependencies", "bundledependencies",
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Tests for analyze.py."""
|
||||
import json
|
||||
import networkx as nx
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from graphify.build import build_from_json
|
||||
from graphify.cluster import cluster
|
||||
@@ -457,6 +458,85 @@ def test_is_json_key_node_non_json_file():
|
||||
assert _is_json_key_node(G, "n1") is False
|
||||
|
||||
|
||||
# --- npm dep-block key god-node filtering tests ---
|
||||
|
||||
@pytest.mark.parametrize("dep_key", [
|
||||
"dependencies",
|
||||
"devDependencies",
|
||||
"peerDependencies",
|
||||
"optionalDependencies",
|
||||
"bundledDependencies",
|
||||
])
|
||||
def test_god_nodes_excludes_npm_dep_block_keys(dep_key: str) -> None:
|
||||
"""npm package.json dep-block keys must be filtered from god_nodes output.
|
||||
|
||||
Constructs a small graph with one node labelled with an npm dep-block key
|
||||
(sourced from a .json file) and one real-domain node that has high degree.
|
||||
Asserts that god_nodes() excludes the dep-block node even when it has the
|
||||
highest degree, while the real-domain node is included.
|
||||
|
||||
Args:
|
||||
dep_key: The npm dependency-block key label to test (parametrized).
|
||||
"""
|
||||
G = nx.Graph()
|
||||
# Real-domain node with a realistic source file.
|
||||
G.add_node(
|
||||
"real_node",
|
||||
label="AuthService",
|
||||
source_file="src/auth.py",
|
||||
file_type="code",
|
||||
source_location="L1",
|
||||
)
|
||||
# npm dep-block key node — sourced from a JSON file so _is_json_key_node fires.
|
||||
G.add_node(
|
||||
"dep_node",
|
||||
label=dep_key,
|
||||
source_file="frontend/package.json",
|
||||
file_type="code",
|
||||
source_location="L1",
|
||||
)
|
||||
# Wire up enough edges so dep_node has high degree — it would be a god-node
|
||||
# without the filter.
|
||||
for i in range(20):
|
||||
peer = f"pkg_{i}"
|
||||
G.add_node(
|
||||
peer,
|
||||
label=f"package-{i}",
|
||||
source_file="frontend/package.json",
|
||||
file_type="code",
|
||||
source_location=f"L{i + 2}",
|
||||
)
|
||||
G.add_edge(
|
||||
"dep_node",
|
||||
peer,
|
||||
relation="contains",
|
||||
confidence="EXTRACTED",
|
||||
source_file="frontend/package.json",
|
||||
weight=1.0,
|
||||
)
|
||||
# Give real_node a couple of edges too.
|
||||
G.add_edge(
|
||||
"real_node",
|
||||
"dep_node",
|
||||
relation="imports",
|
||||
confidence="EXTRACTED",
|
||||
source_file="src/auth.py",
|
||||
weight=1.0,
|
||||
)
|
||||
|
||||
result = god_nodes(G, top_n=10)
|
||||
result_ids = [r["id"] for r in result]
|
||||
|
||||
assert "dep_node" not in result_ids, (
|
||||
f"god_nodes() should filter npm dep-block key '{dep_key}' "
|
||||
f"but it appeared in the result: {result}"
|
||||
)
|
||||
assert "real_node" in result_ids, (
|
||||
f"god_nodes() should include real-domain node 'AuthService' "
|
||||
f"but it was absent: {result}"
|
||||
)
|
||||
|
||||
|
||||
def test_is_json_key_node_real_label():
|
||||
G = nx.Graph()
|
||||
G.add_node("j2", label="UserProfile", source_file="schema.json")
|
||||
|
||||
Reference in New Issue
Block a user