diff --git a/gitnexus/src/core/ingestion/call-processor.ts b/gitnexus/src/core/ingestion/call-processor.ts index ac5b6c9c3..b45478f7a 100644 --- a/gitnexus/src/core/ingestion/call-processor.ts +++ b/gitnexus/src/core/ingestion/call-processor.ts @@ -112,15 +112,19 @@ const NOOP_SYMBOL_TABLE: SymbolTableReader = { * stays scoped to a single `processCalls` invocation rather than leaking * across analyze runs (worker uses module-level caching because each worker * process is short-lived; the main thread is not). + * + * Cache key is `${filePath}:${classNode.startIndex}` — startIndex alone is a + * per-file byte offset, so almost every Ruby/Python file's leading class lands + * at byte 0 and would collide across files in the shared map. */ const getFieldInfo = ( classNode: SyntaxNode, provider: LanguageProvider, context: FieldExtractorContext, - cache: Map>, + cache: Map>, ): Map | undefined => { if (!provider.fieldExtractor) return undefined; - const cacheKey = classNode.startIndex; + const cacheKey = `${context.filePath}:${classNode.startIndex}`; const cached = cache.get(cacheKey); if (cached) return cached; const result = provider.fieldExtractor.extract(classNode, context); @@ -922,7 +926,7 @@ export const processCalls = async ( // worker-path block in parse-worker.ts (kind === 'properties') — any // divergence between the two paths breaks the `incremental ≡ --force` // invariant once a repo crosses the worker threshold between runs. - const fieldInfoCache = new Map>(); + const fieldInfoCache = new Map>(); for (const { file, language, provider, matches, typeEnv } of prepared) { const callRouter = provider.callRouter; if (!callRouter) continue;