Version
codebase-memory-mcp 0.9.1-rc.1
Platform
macOS (Apple Silicon)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
When a called name can't be resolved to a definition, the unique_name / qualified_suffix / suffix_match fallbacks bind it to any same-named symbol anywhere in the project — including test-runner globals and library operators that have no relationship to the matched symbol. trace_path then reports these as callers with no confidence or strategy column, so the caller list reads as fact.
Minimal case: a Jest/Jasmine describe('...', () => {}) block in a .spec.ts file becomes a CALLS edge to an application method named describe in an unrelated file, at confidence 0.75.
At scale on a private Angular monorepo (11,788 files, 63,840 nodes / 120,805 edges), the entire top of the inbound-call ranking is fabricated:
| callee reported by the graph |
inbound CALLS |
what the call sites actually are |
ScheduleOpenShiftViewComponent.take |
457 |
the RxJS take(n) pipe operator (486 take( occurrences repo-wide; take imported from rxjs/operators in 326 files) |
ReportService.describe |
377 |
the Jest describe() global (794 spec files) |
ReportApi.describe |
275 |
same |
PersonalScheduleComponent.date |
264 |
see below |
PermissionDirective.permission |
207 |
unrelated permission references |
Filtering on confidence does not rescue it: with WHERE r.confidence >= 0.9, the top callee is still PersonalScheduleComponent.date with 250 inbound edges.
Two of those recorded "call sites" are not calls at all. I opened the source and verified both:
- An
@Input() set date(date: string | Date) { ... } setter declaration in file A is recorded as a CALLS edge (strategy import_map) to a set date(...) setter in unrelated file B. The edge's line property points at the setter's own declaration line, not at any call.
lazySelect(getTimesheet(this.timesheet.id)) — where this.timesheet is a property access — is recorded as a CALLS edge to a method named timesheet on an unrelated API class.
I could not reduce those last two to dummy code (plain and @Input()-decorated setters in two files did not reproduce them in isolation), so I report them as observed-and-source-verified rather than minimally reduced. The test-global case reduces cleanly and is in the repro repo.
Expected, in rough priority order:
- Prefer no edge over a guessed one when the callee is unresolvable — especially for known test-runner and library globals.
- Never emit a
CALLS edge for a setter declaration or a property access.
- Surface
strategy and confidence in trace_path output (a column, or a --min-confidence filter). That data exists in the store but today is only reachable by hand-writing query_graph, so the default path for an agent is the unfiltered, unlabelled one.
Reproduction
Public repro repo: https://github.com/artaommahe/codebase-memory-mcp-rc-repros — see Case B.
git clone https://github.com/artaommahe/codebase-memory-mcp-rc-repros
cd codebase-memory-mcp-rc-repros
codebase-memory-mcp cli index_repository --repo-path "$PWD" --mode full --name cbm-rc-repros
codebase-memory-mcp cli query_graph --project cbm-rc-repros \
--query "MATCH (a)-[r:CALLS]->(b) RETURN a.file_path AS caller, b.qualified_name AS callee, r.strategy AS s, r.confidence AS c, r.line AS line LIMIT 10"
src/app/report.spec.ts contains only Jest describe/it/expect globals. src/app/report.service.ts defines an unrelated method named describe. Observed (row 2 of 5):
src/app/report.spec.ts cbm-rc-repros.src.app.report.service.ReportService.describe unique_name "0.75" "9"
Line 9 is the describe('another suite', ...) block in the spec file. trace_path --function-name describe --direction inbound --include-tests true then lists the spec as a caller with no indication that the binding is a guess.
Project scale (if relevant)
Aggregate figures are from a private Angular monorepo: 11,788 files, 63,840 nodes / 120,805 edges, --mode full, 10,175 .ts files, 794 .spec.ts files. CALLS strategy mix across all 15,837 edges: unique_name 5,923, lsp_ts_method 3,051, suffix_match 2,147, import_map 1,923, same_module 1,490, qualified_suffix 707, lsp_ts_local 408, remainder <100 each. Roughly 5,500 edges carry confidence below 0.5. The linked repro is self-contained dummy code.
Confirmations
- I searched existing issues and this is not a duplicate.
- My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.
Posted by Claude Code on behalf of @artaommahe
Version
codebase-memory-mcp 0.9.1-rc.1
Platform
macOS (Apple Silicon)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
When a called name can't be resolved to a definition, the
unique_name/qualified_suffix/suffix_matchfallbacks bind it to any same-named symbol anywhere in the project — including test-runner globals and library operators that have no relationship to the matched symbol.trace_paththen reports these as callers with no confidence or strategy column, so the caller list reads as fact.Minimal case: a Jest/Jasmine
describe('...', () => {})block in a.spec.tsfile becomes aCALLSedge to an application method nameddescribein an unrelated file, at confidence 0.75.At scale on a private Angular monorepo (11,788 files, 63,840 nodes / 120,805 edges), the entire top of the inbound-call ranking is fabricated:
CALLSScheduleOpenShiftViewComponent.taketake(n)pipe operator (486take(occurrences repo-wide;takeimported fromrxjs/operatorsin 326 files)ReportService.describedescribe()global (794 spec files)ReportApi.describePersonalScheduleComponent.datePermissionDirective.permissionpermissionreferencesFiltering on confidence does not rescue it: with
WHERE r.confidence >= 0.9, the top callee is stillPersonalScheduleComponent.datewith 250 inbound edges.Two of those recorded "call sites" are not calls at all. I opened the source and verified both:
@Input() set date(date: string | Date) { ... }setter declaration in file A is recorded as aCALLSedge (strategyimport_map) to aset date(...)setter in unrelated file B. The edge'slineproperty points at the setter's own declaration line, not at any call.lazySelect(getTimesheet(this.timesheet.id))— wherethis.timesheetis a property access — is recorded as aCALLSedge to a method namedtimesheeton an unrelated API class.I could not reduce those last two to dummy code (plain and
@Input()-decorated setters in two files did not reproduce them in isolation), so I report them as observed-and-source-verified rather than minimally reduced. The test-global case reduces cleanly and is in the repro repo.Expected, in rough priority order:
CALLSedge for a setter declaration or a property access.strategyandconfidenceintrace_pathoutput (a column, or a--min-confidencefilter). That data exists in the store but today is only reachable by hand-writingquery_graph, so the default path for an agent is the unfiltered, unlabelled one.Reproduction
Public repro repo: https://github.com/artaommahe/codebase-memory-mcp-rc-repros — see Case B.
src/app/report.spec.tscontains only Jestdescribe/it/expectglobals.src/app/report.service.tsdefines an unrelated method nameddescribe. Observed (row 2 of 5):Line 9 is the
describe('another suite', ...)block in the spec file.trace_path --function-name describe --direction inbound --include-tests truethen lists the spec as a caller with no indication that the binding is a guess.Project scale (if relevant)
Aggregate figures are from a private Angular monorepo: 11,788 files, 63,840 nodes / 120,805 edges,
--mode full, 10,175.tsfiles, 794.spec.tsfiles.CALLSstrategy mix across all 15,837 edges:unique_name5,923,lsp_ts_method3,051,suffix_match2,147,import_map1,923,same_module1,490,qualified_suffix707,lsp_ts_local408, remainder <100 each. Roughly 5,500 edges carry confidence below 0.5. The linked repro is self-contained dummy code.Confirmations
Posted by Claude Code on behalf of @artaommahe