Found during dogfooding v3.16.0
Severity: Medium
Command: codegraph build --engine native vs --engine wasm
Reproduction
codegraph build . --engine native --no-incremental
sqlite3 .codegraph/graph.db "SELECT n1.file,n1.name,n1.line,e.kind,n2.file,n2.name,n2.line \
FROM edges e JOIN nodes n1 ON e.source_id=n1.id JOIN nodes n2 ON e.target_id=n2.id \
ORDER BY 1,2,3,4,5,6,7;" | sort > /tmp/edges_native.txt
codegraph build . --engine wasm --no-incremental
sqlite3 .codegraph/graph.db "... same query ..." | sort > /tmp/edges_wasm.txt
comm -23 /tmp/edges_native.txt /tmp/edges_wasm.txt # empty — native has no edges wasm lacks
comm -13 /tmp/edges_native.txt /tmp/edges_wasm.txt # 84 edges wasm has that native lacks
Built against codegraph's own source (993 files): native = 43195 edges, wasm = 43279 edges. Every one of the 84-edge difference is wasm-only (native is a strict subset — no edges are unique to native), so this is a native under-resolution gap, not a wasm over-resolution one, for the dominant pattern below.
Dominant pattern (65 of 84 edges): interface-typed receiver with multiple implementers
src/domain/graph/builder/incremental.ts|backfillIncrementalEdgeTechniques|1187|calls|src/domain/graph/builder/native-db-proxy.ts|NativeDbProxy.prepare|28
src/domain/graph/builder/helpers.ts|runChaPostPass|621|calls|src/domain/graph/builder/native-db-proxy.ts|NativeDbProxy.transaction|82
src/ast-analysis/visitors/cfg-shared.ts|getBodyStatements|136|calls|src/types.ts|TreeSitterNode.namedChild|866
src/shared/hierarchy.ts|resolveViaRepo|29|calls|src/db/repository/in-memory-repository.ts|InMemoryRepository.getClassHierarchy|507
src/shared/hierarchy.ts|resolveViaRepo|29|calls|src/db/repository/native-repository.ts|NativeRepository.getClassHierarchy|441
src/shared/hierarchy.ts|resolveViaRepo|29|calls|src/db/repository/sqlite-repository.ts|SqliteRepository.getClassHierarchy|223
wasm consistently resolves db.prepare(...) / db.transaction(...) calls (receiver statically typed NativeDbProxy, a wrapper mimicking the better-sqlite3 Database shape) across many caller files in src/domain/graph/builder/*.ts. wasm also resolves resolveViaRepo's call to repo.getClassHierarchy() to all three concrete Repository implementers (InMemoryRepository, NativeRepository, SqliteRepository) — exactly the kind of interface-typed, multi-implementer receiver dispatch this project's CHA/RTA logic is supposed to handle. native produces none of these edges. This is a real gap in native's receiver-type resolution for interface/wrapper-typed receivers with multiple concrete implementations.
Secondary observation (6 edges): possible cross-fixture false positives in wasm (needs its own look)
tests/benchmarks/resolution/fixtures/jelly-micro/classes/classes.js|D.constructor|151|calls|tests/benchmarks/resolution/fixtures/jelly-micro/super/super.js|A.constructor|2
tests/benchmarks/resolution/fixtures/jelly-micro/classes/classes.js|D.constructor|151|calls|tests/benchmarks/resolution/fixtures/jelly-micro/super4/super4.js|A.constructor|2
tests/benchmarks/resolution/fixtures/jelly-micro/classes/classes.js|D.constructor|151|calls|tests/benchmarks/resolution/fixtures/jelly-micro/super5/super5.js|A.constructor|2
These are wasm-only edges from the jelly-micro/classes fixture's D.constructor to A.constructor in three separate, unrelated fixture directories (super/, super4/, super5/) that each define their own local, unrelated A class for a different resolution scenario. If these are genuinely unrelated fixtures (not meant to resolve across each other), this looks like wasm over-resolving/bleeding across fixture-directory boundaries rather than native under-resolving — the opposite direction from the dominant pattern above. Flagging for someone closer to the hierarchy-scoping resolver logic to confirm intent before fixing either direction.
Tertiary observation (7 edges): odd zero-line "file calls itself" edges
src/db/connection.ts|wrapInjectedRepo|521|calls|src/db/connection.ts|src/db/connection.ts|0
tests/unit/in-memory-repository.test.ts|tests/unit/in-memory-repository.test.ts|0|calls|tests/integration/triage.test.ts|BrokenRepo.findNodesForTriage|276
A handful of wasm-only edges where the source/target name/line is the file path itself at line 0 (module-level edge?), including one pointing at test-double classes (BrokenRepo, InvalidOptsRepo) defined locally in a different test file. Noted for completeness; lower priority than the two patterns above.
Suggested fix
Focus on the dominant pattern first: audit native's receiver-type resolution path for interface-typed / wrapper-typed receivers where the interface has multiple concrete implementations in scope (the Repository family and NativeDbProxy/TreeSitterNode-style wrapper types) and bring it to parity with wasm's CHA/RTA-based multi-implementer resolution.
Found during dogfooding v3.16.0
Severity: Medium
Command:
codegraph build --engine nativevs--engine wasmReproduction
Built against codegraph's own source (993 files): native = 43195 edges, wasm = 43279 edges. Every one of the 84-edge difference is wasm-only (native is a strict subset — no edges are unique to native), so this is a native under-resolution gap, not a wasm over-resolution one, for the dominant pattern below.
Dominant pattern (65 of 84 edges): interface-typed receiver with multiple implementers
wasm consistently resolves
db.prepare(...)/db.transaction(...)calls (receiver statically typedNativeDbProxy, a wrapper mimicking the better-sqlite3Databaseshape) across many caller files insrc/domain/graph/builder/*.ts. wasm also resolvesresolveViaRepo's call torepo.getClassHierarchy()to all three concreteRepositoryimplementers (InMemoryRepository,NativeRepository,SqliteRepository) — exactly the kind of interface-typed, multi-implementer receiver dispatch this project's CHA/RTA logic is supposed to handle. native produces none of these edges. This is a real gap in native's receiver-type resolution for interface/wrapper-typed receivers with multiple concrete implementations.Secondary observation (6 edges): possible cross-fixture false positives in wasm (needs its own look)
These are wasm-only edges from the
jelly-micro/classesfixture'sD.constructortoA.constructorin three separate, unrelated fixture directories (super/,super4/,super5/) that each define their own local, unrelatedAclass for a different resolution scenario. If these are genuinely unrelated fixtures (not meant to resolve across each other), this looks like wasm over-resolving/bleeding across fixture-directory boundaries rather than native under-resolving — the opposite direction from the dominant pattern above. Flagging for someone closer to the hierarchy-scoping resolver logic to confirm intent before fixing either direction.Tertiary observation (7 edges): odd zero-line "file calls itself" edges
A handful of wasm-only edges where the source/target
name/lineis the file path itself at line 0 (module-level edge?), including one pointing at test-double classes (BrokenRepo,InvalidOptsRepo) defined locally in a different test file. Noted for completeness; lower priority than the two patterns above.Suggested fix
Focus on the dominant pattern first: audit native's receiver-type resolution path for interface-typed / wrapper-typed receivers where the interface has multiple concrete implementations in scope (the
Repositoryfamily andNativeDbProxy/TreeSitterNode-style wrapper types) and bring it to parity with wasm's CHA/RTA-based multi-implementer resolution.