Skip to content

JSON extractor: npm package.json dependency-block keys appear as god-nodes #903

Closed

Description

@cbeaulieu-gt

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

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