Summary
When a called function name is defined in more than one file, the cross-file calls resolution drops the call edge entirely — even when the caller has an explicit, unambiguous named import that identifies exactly which definition is meant. With a single definition the edge resolves correctly (EXTRACTED). Adding any second same-named definition anywhere in the corpus removes the edge.
Net effect: silent false-negative calls edges. For any function whose name is defined 2+ times, call-edge recall is unreliable, and the absence of a calls edge cannot be trusted.
Version: graphify 0.8.35
Minimal reproduction
Three files in an empty directory:
helper.js
export function getThing() { return 1; }
duplicate.js
export function getThing() { return 2; }
caller.js
import { getThing } from './helper.js';
export function useThing() { const x = getThing(); return x; }
Run:
graphify extract . --no-cluster
Expected: a calls edge useThing -> getThing, bound to helper.js's getThing (the named import identifies it unambiguously).
Actual: useThing has no outgoing calls edge at all. Two getThing nodes exist (helper_getthing, duplicate_getthing) and neither lists useThing as a caller. The edge is dropped, not mis-bound.
Control (single definition works)
Delete duplicate.js and re-extract: the useThing -> getThing edge appears, EXTRACTED. Extraction and same-file binding are fine; the drop is triggered purely by the existence of a second same-named definition elsewhere.
Likely area
This looks related to the ambiguous-candidate handling introduced for #543 (which fixed the opposite problem: over-connecting INFERRED edges to every same-named node). That correctly stops over-connection, but a legitimate, import-evidenced EXTRACTED edge is now dropped when the name is multiply defined — the named-import evidence (from './helper.js') is not consulted to disambiguate in this JS/TS path.
Secondary observation: on a larger real corpus the behavior is also inconsistent across callers — with the same duplicate name present, some call sites keep the edge while others drop it, which makes the recall gap easy to miss.
Impact
dependents / callers / impact / trace under-report for any multiply-defined name.
- A missing
calls edge is a false negative, not evidence of "no call".
Summary
When a called function name is defined in more than one file, the cross-file
callsresolution drops the call edge entirely — even when the caller has an explicit, unambiguous named import that identifies exactly which definition is meant. With a single definition the edge resolves correctly (EXTRACTED). Adding any second same-named definition anywhere in the corpus removes the edge.Net effect: silent false-negative
callsedges. For any function whose name is defined 2+ times, call-edge recall is unreliable, and the absence of acallsedge cannot be trusted.Version: graphify 0.8.35
Minimal reproduction
Three files in an empty directory:
helper.jsduplicate.jscaller.jsRun:
Expected: a
callsedgeuseThing -> getThing, bound tohelper.js'sgetThing(the named import identifies it unambiguously).Actual:
useThinghas no outgoingcallsedge at all. TwogetThingnodes exist (helper_getthing,duplicate_getthing) and neither listsuseThingas a caller. The edge is dropped, not mis-bound.Control (single definition works)
Delete
duplicate.jsand re-extract: theuseThing -> getThingedge appears, EXTRACTED. Extraction and same-file binding are fine; the drop is triggered purely by the existence of a second same-named definition elsewhere.Likely area
This looks related to the ambiguous-candidate handling introduced for #543 (which fixed the opposite problem: over-connecting INFERRED edges to every same-named node). That correctly stops over-connection, but a legitimate, import-evidenced EXTRACTED edge is now dropped when the name is multiply defined — the named-import evidence (
from './helper.js') is not consulted to disambiguate in this JS/TS path.Secondary observation: on a larger real corpus the behavior is also inconsistent across callers — with the same duplicate name present, some call sites keep the edge while others drop it, which makes the recall gap easy to miss.
Impact
dependents/callers/impact/traceunder-report for any multiply-defined name.callsedge is a false negative, not evidence of "no call".