A NestJS-style monorepo has one UserService/UserModule/UserRepository per app; with no package concept for TS they share one global name scope and agents visibly warned that CodeGraph was mixing unrelated classes. Two distinct problems, two fixes: 1. TOOL AGGREGATION. callers/callees returned one merged list across every same-named match, and impact merged all their blast radii into a single overstated subgraph. Now: matches group into DISTINCT DEFINITIONS (filePath + qualifiedName — same-file overloads still merge, that's the overload feature) and render one file-labeled section per definition; a new `file` argument (path or suffix, like codegraph_node's) narrows to one definition, suppressing the stale aggregation note; a non-matching `file` falls back to all definitions with a note. server-instructions documents the behavior. 2. RESOLUTION WRONG EDGES. Auditing a real monorepo (amplication, 54k nodes) found 1,036 cross-package `references` edges into duplicated names. Root cause: the React framework resolver ran PascalCase component resolution on refs from PLAIN .ts FILES (a GraphQL types file's own `Account` type alias lost to an arbitrary same-named CLASS in another package — the resolver's blind `components[0]` fallback at confidence 0.8 outranked the name-matcher's proximity-correct 0.7). Component resolution is now gated to JSX-capable refs (tsx/jsx) and never guesses among multiple candidates without a positional signal (same-dir / component-dir / unique). Cross-package wrong edges: 1,036 -> 40 (-96%; the remainder are genuine shared-model imports and codegen template scaffolds), with the freed refs re-resolving to the correct same-file/same-package targets. excalidraw (a real React repo) is a zero-delta control — legitimate component refs all carry same-dir/component-dir signals. Graph-level separation was verified correct on a fixture before any changes (import + proximity resolution keeps apps apart) — the conflation was tool-level plus the react-resolver edge class. Tests: 6-test e2e suite (grouped callers/callees, per-definition impact radii, file narrowing, fallback note, cross-app edge isolation) + react resolver unit tests updated to production reality (tsx refs resolve, plain-ts refs decline). Full suite 1398 passed. EXTRACTION_VERSION 23 -> 24 (re-index to drop the wrong cross-package edges). Closes #764 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
dce61a5f4a
commit
222af6b87c
@@ -32,8 +32,19 @@ export const reactResolver: FrameworkResolver = {
|
||||
},
|
||||
|
||||
resolve(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null {
|
||||
// Pattern 1: Component references (PascalCase)
|
||||
if (isPascalCase(ref.referenceName) && !isBuiltInType(ref.referenceName)) {
|
||||
// Pattern 1: Component references (PascalCase). Only from JSX-capable
|
||||
// files — a component is USED in markup, which only parses in .tsx/.jsx.
|
||||
// Without this gate, every PascalCase TYPE reference in plain .ts files
|
||||
// went through component resolution: in a monorepo with same-named
|
||||
// classes per package (#764, amplication), a `.ts` GraphQL-types file's
|
||||
// own `Account` type alias lost to an arbitrary `Account` CLASS in
|
||||
// another package (the framework's 0.8 outranked the name-matcher's
|
||||
// proximity-correct 0.7).
|
||||
if (
|
||||
(ref.language === 'tsx' || ref.language === 'jsx') &&
|
||||
isPascalCase(ref.referenceName) &&
|
||||
!isBuiltInType(ref.referenceName)
|
||||
) {
|
||||
const result = resolveComponent(ref.referenceName, ref.filePath, context);
|
||||
if (result) {
|
||||
return {
|
||||
@@ -305,7 +316,10 @@ function resolveComponent(
|
||||
);
|
||||
if (preferred.length > 0) return preferred[0]!.id;
|
||||
|
||||
return components[0]!.id;
|
||||
// No positional signal: only an UNAMBIGUOUS name may resolve. Returning
|
||||
// components[0] here picked an arbitrary same-named class anywhere in the
|
||||
// repo (#764) — let the name-matcher's proximity scoring decide instead.
|
||||
return components.length === 1 ? components[0]!.id : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user