You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Running the full extraction pipeline on a ~420-file JS/TS project, graphify.diagnostics.diagnose_extraction reports 586 dangling-endpoint edges. I traced the indirect_call subset (58 edges, all with a missing source) to a concrete bug in the id-remap pass in extract.py.
Confirmed bug: id_remap is applied to all_nodes/all_edges but never to all_raw_calls
extractors/engine.py:2342 creates a whole-file "module" node: file_nid = _make_id(str(path)), i.e. an id derived directly from the (often absolute) filesystem path.
That file_nid is used as scope_nid/caller_nid for indirect_call edges emitted from module-top-level code (calls not inside any function), e.g. via _emit_indirect_ref(ident, file_nid, js_module_bound, "collection") around engine.py:4468-4502. These go through raw_calls (all_raw_calls) for cross-file resolution.
extract.py:4661-4753 builds an id_remap dict that maps exactly this absolute-path-derived id (_make_id(str(path)) / _make_id(str(path.resolve()))) to the canonical relative form _file_node_id(rel) — this is the fix for graph.json edge endpoints still leak absolute-path-derived file ids #502.
extract.py:4754-4762 applies id_remap to all_nodes and all_edges only:
The other remap (sym_remap, built from prefix_remap) does patch raw_calls[caller_nid] (extract.py:4820-4823), but sym_remap is keyed off _file_node_id(path) (the relative-form prefix), which never matches the absolute-form file_nid. So neither remap pass fixes raw_calls[caller_nid] for this id shape.
Net effect: when a raw_calls entry with caller_nid = file_nid (absolute-derived) is later resolved into a real indirect_call edge, its source keeps the stale absolute-path id — which matches no node in all_nodes (those were remapped), so it dangles.
Expected source id: src_index (matches the canonical file-node id used everywhere else).
Secondary observation (not root-caused, flagging for investigation)
Also saw ~50 dangling edges where an imports edge targets a barrel/re-export index.js file's re-exported symbol id instead of the file where the symbol is actually defined, e.g.:
createBackendAdapter is defined in a sibling file under shared/backend/ and re-exported through index.js. There's existing re_exports/edge_alias_candidates repoint logic around extract.py:4824-4858 that looks like it's meant to handle exactly this shape, but I haven't traced why it doesn't catch this case — didn't want to guess, so flagging separately from the confirmed bug above.
Environment
graphify (graphifyy) installed via uv tool install
OS: Windows 11
Corpus: ~422 JS/TS files, extracted via graphify.extract.extract(code_files, cache_root=Path('.')) with absolute Path inputs from graphify.detect.detect()
Summary
Running the full extraction pipeline on a ~420-file JS/TS project,
graphify.diagnostics.diagnose_extractionreports 586 dangling-endpoint edges. I traced theindirect_callsubset (58 edges, all with a missing source) to a concrete bug in the id-remap pass inextract.py.Confirmed bug:
id_remapis applied toall_nodes/all_edgesbut never toall_raw_callsextractors/engine.py:2342creates a whole-file "module" node:file_nid = _make_id(str(path)), i.e. an id derived directly from the (often absolute) filesystem path.file_nidis used asscope_nid/caller_nidforindirect_calledges emitted from module-top-level code (calls not inside any function), e.g. via_emit_indirect_ref(ident, file_nid, js_module_bound, "collection")aroundengine.py:4468-4502. These go throughraw_calls(all_raw_calls) for cross-file resolution.extract.py:4661-4753builds anid_remapdict that maps exactly this absolute-path-derived id (_make_id(str(path))/_make_id(str(path.resolve()))) to the canonical relative form_file_node_id(rel)— this is the fix for graph.json edge endpoints still leak absolute-path-derived file ids #502.extract.py:4754-4762appliesid_remaptoall_nodesandall_edgesonly:all_raw_callsis never touched by this loop.sym_remap, built fromprefix_remap) does patchraw_calls[caller_nid](extract.py:4820-4823), butsym_remapis keyed off_file_node_id(path)(the relative-form prefix), which never matches the absolute-formfile_nid. So neither remap pass fixesraw_calls[caller_nid]for this id shape.raw_callsentry withcaller_nid = file_nid(absolute-derived) is later resolved into a realindirect_calledge, itssourcekeeps the stale absolute-path id — which matches no node inall_nodes(those were remapped), so it dangles.Example (Windows, absolute input paths)
Expected source id:
src_index(matches the canonical file-node id used everywhere else).Secondary observation (not root-caused, flagging for investigation)
Also saw ~50 dangling edges where an
importsedge targets a barrel/re-exportindex.jsfile's re-exported symbol id instead of the file where the symbol is actually defined, e.g.:createBackendAdapteris defined in a sibling file undershared/backend/and re-exported throughindex.js. There's existingre_exports/edge_alias_candidatesrepoint logic aroundextract.py:4824-4858that looks like it's meant to handle exactly this shape, but I haven't traced why it doesn't catch this case — didn't want to guess, so flagging separately from the confirmed bug above.Environment
graphifyy) installed viauv tool installgraphify.extract.extract(code_files, cache_root=Path('.'))with absolutePathinputs fromgraphify.detect.detect()graphify.diagnostics.diagnose_extraction(extraction, directed=False, root='.')