Skip to content

Monorepo cross-project name collisions: platform imports, npm package names, and minified-bundle symbols bind to unrelated same-named nodes #3237

Description

@Kenza3000

Summary

In a monorepo holding several independent projects (merged from separate repos via git subtree), name-based cross-file resolution produces cross-project edges between symbols that merely share a name. Three distinct classes, found by auditing all 25 cross-project edges in a 9.3k-node graph (v0.9.53); 20 of the 25 were artifacts of these classes, and most carry EXTRACTED / confidence_score 1.0.

Class 1 — platform/stdlib imports bind to unrelated same-named symbols in another project

Kotlin files importing JVM/AndroidX platform symbols get calls/imports edges to same-named user symbols in a different project:

  • import android.graphics.Color and import androidx.compose.ui.graphics.Color (project A) → edge to project B's ui/theme/Color.kt node. EXTRACTED 1.0.
  • import java.util.UUID in five project-B Kotlin files → edge to the bare node uuid, whose source_file is project A's package.json (the npm uuid dependency). EXTRACTED 1.0.
  • override suspend fun doWork(): Result (androidx.work's Result) → edge to an unrelated data class Result in project A. EXTRACTED 1.0.
  • androidx.compose.material3.Typography (imported at top of file) → edge to project A's object Typography. INFERRED 0.85.

Expected: an identifier that resolves to an import outside the repo (android.*, androidx.*, java.*, kotlin.*) should never bind to a repo-local node, and bare-name nodes like uuid shouldn't attract both an npm dependency and java.util.UUID. Same disease as the (fixed, TS-specific) name-only type matching in #2553, surfacing in the Kotlin/JVM path.

Class 2 — package.json entries across projects joined by registry name as imports

Seven imports edges (EXTRACTED 1.0) connect one project's package.json dependency entry to another project's entry for the same npm package (typescript, tailwindcss, @types/react, @types/node, @supabase/supabase-js, @vitejs/plugin-vue) — including one pair pinned to different majors (^5.2.4 vs 6.0.8). Neither project imports anything from the other; they independently install the same third-party package. Suggestion: model registry packages as shared external nodes (e.g. npm:typescript) instead of edging one project's declaration to another's. (Related to the json_config modeling discussed in #1764, but these edges do resolve — to the wrong thing.)

Class 3 — minified bundles mint one-letter symbol nodes that attract foreign loop variables

A single-line minified Vite bundle (public/assets/index-*.js) produced function nodes named m, o, s, v, w. The s() node then received indirect_call INFERRED 0.85 edges from ordinary for (const s of …) loop variables in other projects' scripts, and the bundle nodes pulled a three-project community together. Suggestion: detect minified artifacts (single line over N KB, or 1–2-char symbol names at high density) and skip them or quarantine their symbols from cross-file name matching. (We've locally excluded the folder via .graphifyignore, which works as a workaround.)

Environment

  • graphifyy 0.9.53 (uv tool install, Python 3.12, macOS)
  • Corpus: ~1.4k files, 5 projects, Kotlin/Swift/TS/Vue/Python mix, graph built with the default undirected pipeline

Happy to provide fuller edge dumps for any of the three classes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions