Repository navigation
JSON extractor: npm package.json dependency-block keys appear as god-nodes #903
Description
Summary
The JSON extractor (graphify/extract.py extract_json, line 5928) emits a node for every JSON object key, including devDependencies / dependencies / peerDependencies / optionalDependencies / bundledDependencies. On any JS/TS corpus with non-trivial dependency counts, the parent dep-block key accumulates contains + imports edges to every sibling entry and surfaces as a god-node in GRAPH_REPORT.md.
_JSON_NOISE_LABELS (graphify/analyze.py:68) already filters generic JSON keys (properties, items, name, etc.) from god-node selection — but the npm package.json dep-block keys are not in the set, so devDependencies still appears.
Repro
Corpus: glitchwerks/rsl-siege-manager @ 6085fd66 (Python + TypeScript monorepo, ~25 devDependencies in frontend/package.json).
.graphifyignore:
backend/tests/
frontend/src/**/__tests__/
frontend/src/test/
bot/tests/
Run on v8 @ b4c0f01:
graphify extract . --backend claude-cli
Observed — top-10 god-nodes
1. BoardPage() - 54 edges
2. SiegeMember - 52 edges
3. postsTab - 30 edges
4. cn() - 30 edges
5. MembersPage() - 28 edges
6. PostsPage() - 28 edges
7. devDependencies - 25 edges ← npm manifest key, noise
8. BuildingType - 23 edges
9. MemberRole - 22 edges
10. Position - 22 edges
devDependencies at #7 is the JSON object key from frontend/package.json. Its 25 edges are the JSON extractor's imports-edge tree — exactly the class of noise _JSON_NOISE_LABELS was scoped to filter.
Expected
devDependencies / dependencies / peerDependencies / optionalDependencies / bundledDependencies filtered from god_nodes the same way properties / items / name already are.
Proposed fix
Extend _JSON_NOISE_LABELS (graphify/analyze.py:68) with the npm dep-block keys, lowercased to match the existing .strip().lower() comparison in _is_json_key_node:
_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",
})Both bundledDependencies and bundleDependencies spellings (matching _DEP_KEYS at extract.py:5959-5962).
Verification
After the patch, the same corpus + .graphifyignore produces:
1. BoardPage() - 54 edges
2. SiegeMember - 52 edges
3. postsTab - 30 edges
4. cn() - 30 edges
5. MembersPage() - 28 edges
6. PostsPage() - 28 edges
7. BuildingType - 23 edges
8. MemberRole - 22 edges
9. Position - 22 edges
10. NotificationBatchResponse - 22 edges
devDependencies filtered; a real domain node takes the slot.
PR
#905 — patch + parametrized regression tests covering all 5 npm keys; live-validated against the repro corpus above; no-regression checks against worked/example, worked/mixed-corpus, worked/httpx (byte-identical outputs since none contain package.json).
🤖 Generated by Claude Code on behalf of @cbeaulieu-gt
Activity