Skip to content

Python stdlib import binds to a same-named TypeScript function (cross-language, strategy=unique_name) — poisons hotspots and Louvain clusters #1572

Open

Description

@SQLBImhugh

Environment: v0.10.2, Windows 11, daemon mode. Reproduced on a 2-file synthetic repo and on a real Python+TypeScript monorepo (~41.8k nodes / ~198.8k edges, --mode full).

Symptom

A Python from unittest.mock import patch binds to a TypeScript function named patch, in a different language, in a different top-level package. Every with patch(...) in the repo is then recorded as a CALLS edge into that TSX function.

In my real repo this produced a 4-line React helper with 498 inbound callers, all of them backend Python tests:

// frontend/src/components/gates/reportgate/ReportGatePanel.tsx:151-154
function patch(changes: Partial<ReportGateState>) {
  if (!state) return
  applyEdit({ ...state, ...changes })
}

Minimal reproducer

Two files, no dependencies (24 nodes / 28 edges):

frontend/Panel.tsx

export function Panel() {
  function patch(changes: Partial<State>) {
    applyEdit({ ...changes })
  }
  return patch
}

backend/test_thing.py

from unittest.mock import patch


def test_one():
    with patch("os.getcwd", return_value="/tmp"):
        pass


def test_two():
    with patch("os.getcwd", return_value="/tmp"):
        pass
codebase-memory-mcp cli index_repository --repo-path <repo> --mode fast
codebase-memory-mcp cli trace_path --project <p> --function-name patch \
    --direction inbound --include-evidence true --include-tests true

Result:

function: patch
direction: inbound
callers_total: 2
callers: 2  (rows: name hop strategy confidence)
  test_one 1 heuristic 0.75
  test_two 1 heuristic 0.75

Root cause: the IMPORTS edge is already wrong, and it is not an ambiguity failure

The bad binding happens at the import, not at the call site:

MATCH (a)-[r:IMPORTS]->(b) RETURN a.name, a.file_path, b.qualified_name, r.local_name

  test_thing.py | backend/test_thing.py | <proj>.frontend.Panel.patch | patch

from unittest.mock import patch resolved to a project-local TSX node. The CALLS edges then faithfully follow that import binding.

The edge metadata is the important part:

MATCH (a)-[r:CALLS]->(b) WHERE b.name = 'patch'
RETURN a.file_path, b.file_path, r.strategy, r.confidence, r.candidates

  backend/test_thing.py | frontend/Panel.tsx | unique_name | 0.75 | 1

strategy=unique_name, candidates=1. The resolver is not choosing badly among several candidates — it sees exactly one node named patch in the whole graph and treats that as proof, with no language check and no check that the import specifier (unittest.mock) is external.

This means #1555's proposed fix does not cover this case. That issue asks for better disambiguation when candidates > 1; here candidates == 1, so the ambiguity path is never entered. The two issues are complementary: #1555 is same-language ambiguity, this is a cross-language false positive on a unique name.

Why this is worse than a bad trace hop

The wrong edges silently contaminate the aggregate analyses that agents treat as ground truth:

  1. get_architecture hotspots. The 4-line React helper is reported as the FastAPI empty-path routes not captured #8 hotspot in the repo (fan_in 498), ahead of real infrastructure. Hotspots do not surface confidence, so nothing signals that the entry is fabricated.
  2. Louvain clustering. The node becomes an artificial hub: ~498 backend test functions get pulled into one cluster together with frontend and frontend-mockups, reported at cohesion 0.78. The cluster looks like a genuine architectural seam spanning four packages. It is an artifact.
  3. Dead-code / impact analysis. Anything keying off fan-in inherits the error.

A second instance in the same repo: RuntimeFlagResolver.get reports fan_in 611, whose "callers" are module-level __file__ statements — though that one is at least honestly scored (confidence 0.06, vs 0.95 for the patch edges in the real repo).

Python is especially exposed because stdlib names (patch, get, run, main, setup) collide constantly with short method names in other languages. builtins.* names appear to be handled by a synthetic-node path already; unittest.mock.patch is not a builtin and falls through it.

Suggested fixes

In rough order of value:

  1. Never resolve an import or call across a language boundary. A Python import should not bind to a .tsx node under any strategy. This alone eliminates the whole class.
  2. Treat a resolved import specifier as external when it does not correspond to a project-local module. unittest.mock is not a path in the repo; the specifier is already parsed, since the IMPORTS edge carries local_name. Binding to a synthetic external node (as builtins.* seems to do) would be consistent with existing behavior.
  3. Do not let strategy=unique_name imply high confidence. Uniqueness within the graph is not evidence of a call relationship when the only candidate is in another language/package. Consider capping confidence for cross-package unique_name hits.
  4. Propagate confidence into aggregates. get_architecture hotspots/clusters could exclude or flag edges below a confidence threshold, or expose the weakest strategy contributing to a hotspot. Related: trace_path format=json drops include_evidence strategy and confidence #1542 (strategy/confidence dropped in format=json).

Happy to test a patch against the real repo — the misresolution is deterministic there and easy to re-measure via trace_path --include-evidence.

Activity

  1. added
    parsing/qualityGraph extraction bugs, false positives, missing edges
    ux/behaviorDisplay bugs, docs, adoption UX
    windowsWindows-specific issues
    on Aug 12, 2026
  2. added
    bugSomething isn't working
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Aug 12, 2026
  3. DeusData commented on Aug 12, 2026

    @DeusData
    Owner

    Thank you @SQLBImhugh. Confirmed on current main: the registry's by_name index has no language dimension, and when exactly one simple-name candidate exists, resolve_name_lookup() returns it with strategy unique_name regardless of the caller and candidate languages. Import reachability only lowers confidence; it does not reject the cross-language target.

    This is the same resolver class behind #725 and overlaps the receiver-ambiguity case in #1555, but your deterministic Python-to-TypeScript case is a useful root-level fixture rather than a duplicate. Routed priority/high under #594.

  4. rudi193-cmd commented on Aug 18, 2026

    @rudi193-cmd
    Contributor

    Claiming this as the #1647 follow-on: same language-family guard, now for unique_name (candidates == 1).

    #1647 dropped suffix_match CALLS across language boundaries and left this case alone on purpose. The helper still returns false for unique_name; the two-file Python from unittest.mock import patch / TSX function patch fixture is the red test.

    Plan, one PR:

    Will open after this comment unless someone is already on it.

  5. added 19 commits that reference this issue on Sep 22, 2026
    aecfb31
    6233394
    508e8bd
    5770ed8
    8165c34
    24795fc
    f5ec03f
    492e59a
    9e92e67
    e9339ff
    c06a363
    b46c6d4
    bba986d
    d6e5dc2
    4816c16
    e7ae78f
    a3c3802
    c81ab98
    15a97e9
  6. DeusData commented on Oct 19, 2026

    @DeusData
    Owner

    Thank you for the focused unique_name follow-on plan and for keeping external-specifier handling and receiver disambiguation separate. I have no new review or fix outcome to report here. The two-file Python/TSX example remains the useful check for this specific false edge.

  7. DeusData commented on Oct 25, 2026

    @DeusData
    Owner

    Thank you for the focused unique-name follow-on and Python/TSX fixture. Review of this false cross-language edge remains outstanding, separate from external-module handling. Sorry for the delay; this is waiting on maintainer follow-up, and I’ll follow up soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.ux/behaviorDisplay bugs, docs, adoption UXwindowsWindows-specific issues

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions