Summary
When a file containing a callee is modified, incremental indexing purges every inbound CALLS edge pointing at symbols in that file, then only re-parses the changed file itself. The call sites living in other (unchanged) files are never re-parsed, so those edges are lost permanently. trace_path(direction="inbound") then silently returns an incomplete — often empty — caller list.
force: true does not help; only deleting the .db and re-indexing restores the edges.
Environment
codebase-memory-mcp 0.8.1, macOS (darwin/arm64)
- Language: Go (also expected to affect other languages, not verified)
Minimal reproduction
/tmp/cbm-repro
├── go.mod module example.com/repro
├── main.go func main() { _ = pkg.Target("from main") }
└── pkg
├── target.go func Target(s string) string { return s + "!" }
├── caller_a.go func CallerA() string { return Target("a") }
├── caller_b.go func CallerB() string { return Target("b") }
│ func CallerC() string { return Target("c") }
└── caller_d.go func CallerD() string { return Target("d") }
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-repro"}'
codebase-memory-mcp cli trace_path '{"project":"private-tmp-cbm-repro","function_name":"Target","direction":"inbound","depth":1}'
→ correct: CallerA, CallerB, CallerC, CallerD, main (5 callers)
- Edit only
pkg/target.go (e.g. change the function body / a comment — signature unchanged). Do not touch any caller file.
- Re-run
index_repository (incremental path), then repeat the trace_path from step 2.
Actual: {"function":"Target","direction":"inbound","callers":[]} — all 5 callers gone.
Expected: the same 5 callers.
Adding a new caller file works fine (that file is re-parsed), so the bug is specific to inbound edges of a changed callee file.
Relevant log lines from step 4
incremental.classify changed=1 unchanged=5 deleted=0 mode_skipped=0
incremental.reparse files=1
incremental.purge elapsed_ms=0
pass.done pass=definitions defs=2 calls=0 imports=0 errors=0
pass.done pass=calls total=0 resolved=0 unresolved=0 errors=0
incremental.done elapsed_ms=18
purge removes the edges; pass=calls total=0 shows nothing is rebuilt, because the only re-parsed file contains no calls to Target.
Impact on a real repository
On a ~3.6k-node Go repo that had been incrementally indexed for a few weeks:
| query |
stale index |
after deleting the .db and re-indexing |
grep ground truth |
trace_path(SendBotMessage, inbound) |
2 callers |
9 callers |
13 call sites across exactly those 9 functions |
trace_path(chatKey, inbound) |
2 callers |
6 callers |
14 call sites across exactly those 6 functions |
Edge count went from 9,401 to 10,446 on a full rebuild with essentially the same node count (3,605 → 3,603), i.e. ~10% of edges had been silently dropped over time.
The dangerous part is that it fails silently: impact analysis looks like it succeeded and simply reports fewer callers, so a caller can easily be missed during a refactor.
Suggested fix
When purging inbound edges for symbols in a changed file, also re-parse (or at least re-resolve calls for) the files that previously had edges into it — the pre-purge edge set already identifies exactly which files those are.
Workaround
rm ~/.cache/codebase-memory-mcp/<project-slug>.db
codebase-memory-mcp cli index_repository '{"repo_path":"<repo>"}'
Summary
When a file containing a callee is modified, incremental indexing purges every inbound
CALLSedge pointing at symbols in that file, then only re-parses the changed file itself. The call sites living in other (unchanged) files are never re-parsed, so those edges are lost permanently.trace_path(direction="inbound")then silently returns an incomplete — often empty — caller list.force: truedoes not help; only deleting the.dband re-indexing restores the edges.Environment
codebase-memory-mcp 0.8.1, macOS (darwin/arm64)Minimal reproduction
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-repro"}'codebase-memory-mcp cli trace_path '{"project":"private-tmp-cbm-repro","function_name":"Target","direction":"inbound","depth":1}'→ correct:
CallerA, CallerB, CallerC, CallerD, main(5 callers)pkg/target.go(e.g. change the function body / a comment — signature unchanged). Do not touch any caller file.index_repository(incremental path), then repeat thetrace_pathfrom step 2.Actual:
{"function":"Target","direction":"inbound","callers":[]}— all 5 callers gone.Expected: the same 5 callers.
Adding a new caller file works fine (that file is re-parsed), so the bug is specific to inbound edges of a changed callee file.
Relevant log lines from step 4
purgeremoves the edges;pass=calls total=0shows nothing is rebuilt, because the only re-parsed file contains no calls toTarget.Impact on a real repository
On a ~3.6k-node Go repo that had been incrementally indexed for a few weeks:
.dband re-indexingtrace_path(SendBotMessage, inbound)trace_path(chatKey, inbound)Edge count went from 9,401 to 10,446 on a full rebuild with essentially the same node count (3,605 → 3,603), i.e. ~10% of edges had been silently dropped over time.
The dangerous part is that it fails silently: impact analysis looks like it succeeded and simply reports fewer callers, so a caller can easily be missed during a refactor.
Suggested fix
When purging inbound edges for symbols in a changed file, also re-parse (or at least re-resolve calls for) the files that previously had edges into it — the pre-purge edge set already identifies exactly which files those are.
Workaround