An import of something the project does not contain — a Node built-in, an npm
package — is unresolvable, so the name-matcher falls back to finding any node with
that name. Import names are short and generic (path, url, join, events,
default), so a class property or interface method with the same name is almost
always present somewhere, and the import binds to it.
Nothing in any supported language lets an import bind to a member that only exists
inside a type. You import the type.
Environment
- codegraph: 1.5.0 (npm), reproduced on
main @ c6aaa20
- Backend: node:sqlite (WAL)
- Platform: Linux x64
src/resolution/ only — no kernel counterpart, both extraction paths identical
Repro
src/types.ts
export class Request {
path = '';
url = '';
}
src/run.ts
import * as path from 'node:path';
export function run() {
return path.join('a', 'b');
}
codegraph init .
sqlite3 .codegraph/codegraph.db "
SELECT s.file_path, t.kind, t.qualified_name
FROM edges e JOIN nodes s ON s.id=e.source JOIN nodes t ON t.id=e.target
WHERE e.kind='imports';"
Expected
No imports edge — node:path is not in the project.
Actual
src/run.ts | property | Request::path
Impact (measured on this repository, 571 files)
imports target kind |
edges |
correct? |
method |
19 |
no — all 19 |
property |
4 |
no — all 4 |
Every one is a coincidence:
Walker::join @codegraph-kernel/src/rustlang.rs × 15
Telemetry::events @src/telemetry/index.ts × 2
FetchCall::url @__tests__/telemetry.test.ts × 2
PipelineRequest::path @__tests__/fixtures/…/pipeline/types.ts
Tables::default @codegraph-kernel/src/buffers.rs
…
A second project — a 2,669-node Rust/TypeScript app — carries 28 more of the
same, every one an imports edge landing on a method.
These are phantom file-to-file dependencies. They feed codegraph_explore's file
ranking and impact radius as if the importing file genuinely depended on the file
that happens to declare a member of that name.
The count scales with how many member nodes the graph holds, so it is not fixed at
23. Prototyping TS interface-member extraction (interface methods and properties as
nodes) took imports → property on this repository from 4 to 377 in a single
re-index — the same bug, simply given more surface to hit.
Cause
Same root as #1536 — matchByExactName applies no kind constraint to its candidate
pool, and scoreCandidate treats kind as a bonus rather than a requirement. For
imports there is no bonus of any kind, so a member ranks exactly like a top-level
definition, and the single-candidate shortcut takes it outright at confidence 0.9.
Fixed by the same mechanism as #1536, which is why one PR closes both.
An import of something the project does not contain — a Node built-in, an npm
package — is unresolvable, so the name-matcher falls back to finding any node with
that name. Import names are short and generic (
path,url,join,events,default), so a class property or interface method with the same name is almostalways present somewhere, and the import binds to it.
Nothing in any supported language lets an import bind to a member that only exists
inside a type. You import the type.
Environment
main@c6aaa20src/resolution/only — no kernel counterpart, both extraction paths identicalRepro
src/types.tssrc/run.tsExpected
No
importsedge —node:pathis not in the project.Actual
Impact (measured on this repository, 571 files)
importstarget kindmethodpropertyEvery one is a coincidence:
A second project — a 2,669-node Rust/TypeScript app — carries 28 more of the
same, every one an
importsedge landing on amethod.These are phantom file-to-file dependencies. They feed
codegraph_explore's fileranking and impact radius as if the importing file genuinely depended on the file
that happens to declare a member of that name.
The count scales with how many member nodes the graph holds, so it is not fixed at
23. Prototyping TS interface-member extraction (interface methods and properties as
nodes) took
imports → propertyon this repository from 4 to 377 in a singlere-index — the same bug, simply given more surface to hit.
Cause
Same root as #1536 —
matchByExactNameapplies no kind constraint to its candidatepool, and
scoreCandidatetreats kind as a bonus rather than a requirement. Forimportsthere is no bonus of any kind, so a member ranks exactly like a top-leveldefinition, and the single-candidate shortcut takes it outright at confidence 0.9.
Fixed by the same mechanism as #1536, which is why one PR closes both.