graphify per-language AST extractors strip member-expression callees
(`x.foo()`, `obj.bar()`, `Pkg::baz()`) down to the trailing identifier,
queue them in `raw_calls`, and the cross-file resolver matches by bare
lowercase name against a global symbol table. When any file in the
corpus exposes a top-level helper with a common method name (e.g. a
`function log(...)` in a one-off smoke-test script), every unrelated
`Logger.log(...)` / `this.x.find(...)` / `Pkg::baz(...)` call across the
codebase resolves to that single helper, producing phantom god nodes
with hundreds of bogus INFERRED edges.
This patch:
* Adds `_MEMBER_CALL_NODE_TYPES` enumerating member-expression AST
node types across all supported languages.
* Tags every `raw_calls.append(...)` site with `callee_node_type`.
* Skips entries whose `callee_node_type` is in
`_MEMBER_CALL_NODE_TYPES` from the cross-file resolver in
`extract()`. In-file resolution behaviour is intentionally
preserved.
On a real production codebase (~1,668 TS/JS files, NestJS + Nuxt) this
eliminates 1,262 phantom edges and removes a phantom `log()` god node
that previously sat at #2 with 265 inbound edges (255 of them bogus).
Includes 3 regression tests that fail on the original code and pass with
this patch.
AST and semantic entries now write to cache/ast/ and cache/semantic/
respectively. Previously both used the flat cache/ dir causing semantic
results to overwrite AST entries for code files on mixed corpora, making
the shrink guard fire on every subsequent update run.
Migration: load_cached falls back to legacy flat cache/ for AST reads
so existing cache entries are not lost on upgrade.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Grep and Glob tools removed in CC v2.1.117; searches now go through Bash.
Hook now reads stdin tool_input and pattern-matches on search commands.
Uninstall/reinstall handles both old and new matcher for clean upgrades.
Closes#578
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- #550: _file_stem() includes parent dir to prevent node ID collisions for same-named files
- #555: extract() relativizes source_file paths before returning for cross-machine portability
- #562: to_json() returns bool; _rebuild_code() writes report/html only if json succeeded
- #563: skill prompts store rationale as node attribute, not separate node; enforce calls direction
- #566: Show All / Hide All buttons added to HTML community panel
- #575: _import_js() resolves tsconfig.json compilerOptions.paths aliases before external fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- analyze.py: add seed=42 to betweenness_centrality() — eliminates non-deterministic GRAPH_REPORT.md diffs on graphs >1000 nodes (#499)
- extract.py: fix common-root inference to stop at first diverging segment not sum of all matches (#502)
- extract.py: resolve root to absolute path; post-process file node IDs to project-relative after extraction so graph.json edge endpoints are stable across machines (#502)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>