Status: fix open — PR #1907 (extractor is_method flag for Go selector calls + Go-gated cbm_go_suppress_weak_method_match). Full post-fix census inline below.
Version
codebase-memory-mcp 0.10.8 (also reproduced on a source build @ d706c33)
Platform
macOS (Apple Silicon)
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
A Go selector call whose receiver the Go LSP cannot type falls through to the generic registry, which binds it by bare short name to an arbitrary same-named project symbol (suffix_match / unique_name). Stdlib/third-party calls are the worst case: the real callee is not in the tree, so every candidate is wrong by construction. Go never sets is_method, so the receiver-aware guard TS/JS got in #592/#606 (and Perl in #476) never fires.
Measured (private Go monorepo, ~19.6k CALLS): suffix_match 3817 @ avg 0.30, unique_name 3162 @ avg 0.53 — 36% of all CALLS from name guesses. One 14-line checksum helper touching only os/io/crypto/sha256 got 3/3 false outbound edges: f.Close() → a project Close (conf 0.11, 15 candidates), sha256.New() → an unrelated New, io.Copy → the sole project Copy (unique_name 0.375). trace_path surfaces all of it unfiltered, so Close/New/Run accumulate dozens of phantom callers.
Expected: no CALLS edge for a call the resolver cannot place; typed, local, and import-qualified calls keep resolving.
Reproduction
Dummy fixture: go.mod (module example.com/myapp) + storage/storage.go (the lone project Close method + a typed same-package Boot caller) + hash/hash.go:
package hash
import (
"os"
"example.com/myapp/util"
)
func FileLen(path string) int64 {
f, err := os.Open(path)
if err != nil {
return 0
}
defer f.Close() // ← false CALLS edge: hash.FileLen -> storage.Close
st, err := f.Stat()
if err != nil {
return 0
}
return st.Size()
}
func UsesUtil() string { return util.Tag() } // import-qualified: must keep resolving
Actual: FileLen | Close | {"strategy":"unique_name","confidence":0.75,…} (with ≥2 candidates: suffix_match @ 0.1–0.4). Expected: no FileLen → Close; Boot → Close, bare local calls, and UsesUtil → Tag all survive.
Two Go-specific constraints (why the TS/JS drop-list can't be reused as-is)
Post-fix strategy census (same tree indexed with v0.10.8 vs Stack A = #1907+#1913+#1915)
| strategy |
v0.10.8 |
with the fixes |
Δ |
lsp_strategy_cross_file |
5273 |
6468 |
+23% |
lsp_direct |
3033 |
3372 |
+11% |
lsp_type_dispatch |
137 |
687 |
+401% |
lsp_interface_dispatch |
17 |
79 |
+365% |
lsp_embed_dispatch |
— |
42 |
new |
import_map |
284 |
88 |
−69% |
field_type_hint |
493 |
1484 |
+201% — see #1927/#1936 |
unique_name |
3162 (avg 0.53) |
1573 (avg 0.68) |
−50% |
suffix_match |
3817 (avg 0.30) |
113 |
−97% |
same_module |
3267 |
224 |
−93% |
| CALLS total |
19653 |
14316 |
−27% |
Weak short-name share (suffix_match+unique_name+callee_suffix): 36.0% → 12.4%, with lsp_* rising 8481 → 10672 in absolute terms — the edges were re-resolved, not merely deleted. The field_type_hint growth is the direct consequence tracked as #1927 (guesses moved from a visibly-weak 0.30 bucket into a 0.85 one); fixed by #1936.
Related: #592/#606 (TS/JS), #476 (Perl), #1893 (Swift), #1276 (Python), #1114; tracked in #1932.
Confirmations
Status: fix open — PR #1907 (extractor
is_methodflag for Go selector calls + Go-gatedcbm_go_suppress_weak_method_match). Full post-fix census inline below.Version
codebase-memory-mcp 0.10.8 (also reproduced on a source build @ d706c33)
Platform
macOS (Apple Silicon)
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
A Go selector call whose receiver the Go LSP cannot type falls through to the generic registry, which binds it by bare short name to an arbitrary same-named project symbol (
suffix_match/unique_name). Stdlib/third-party calls are the worst case: the real callee is not in the tree, so every candidate is wrong by construction. Go never setsis_method, so the receiver-aware guard TS/JS got in #592/#606 (and Perl in #476) never fires.Measured (private Go monorepo, ~19.6k CALLS):
suffix_match3817 @ avg 0.30,unique_name3162 @ avg 0.53 — 36% of all CALLS from name guesses. One 14-line checksum helper touching onlyos/io/crypto/sha256got 3/3 false outbound edges:f.Close()→ a projectClose(conf 0.11, 15 candidates),sha256.New()→ an unrelatedNew,io.Copy→ the sole projectCopy(unique_name0.375).trace_pathsurfaces all of it unfiltered, soClose/New/Runaccumulate dozens of phantom callers.Expected: no CALLS edge for a call the resolver cannot place; typed, local, and import-qualified calls keep resolving.
Reproduction
Dummy fixture:
go.mod(module example.com/myapp) +storage/storage.go(the lone projectClosemethod + a typed same-packageBootcaller) +hash/hash.go:Actual:
FileLen | Close | {"strategy":"unique_name","confidence":0.75,…}(with ≥2 candidates:suffix_match@ 0.1–0.4). Expected: noFileLen → Close;Boot → Close, bare local calls, andUsesUtil → Tagall survive.Two Go-specific constraints (why the TS/JS drop-list can't be reused as-is)
field_type_hintis kept for Go — but see fix(pipeline): field_type_hint binds by receiver variable-name substring, not declared type — 1484 edges at conf 0.85 on one Go repo #1927: its receiver-awareness premise did not hold and is fixed separately (fix(pipeline): bind field_type_hint by owning QN segment, not substring #1936).unique_namedrops only when penalized (CONF_UNIQUE_NAMEscaled 0.75 → 0.375 when the lone candidate is outside the caller's import closure — the stdlib-hijack shape). Unpenalized lone candidates are genuinely typed and must keep resolving.Post-fix strategy census (same tree indexed with v0.10.8 vs Stack A = #1907+#1913+#1915)
lsp_strategy_cross_filelsp_directlsp_type_dispatchlsp_interface_dispatchlsp_embed_dispatchimport_mapfield_type_hintunique_namesuffix_matchsame_moduleWeak short-name share (
suffix_match+unique_name+callee_suffix): 36.0% → 12.4%, withlsp_*rising 8481 → 10672 in absolute terms — the edges were re-resolved, not merely deleted. Thefield_type_hintgrowth is the direct consequence tracked as #1927 (guesses moved from a visibly-weak 0.30 bucket into a 0.85 one); fixed by #1936.Related: #592/#606 (TS/JS), #476 (Perl), #1893 (Swift), #1276 (Python), #1114; tracked in #1932.
Confirmations