Status: fix open — PR #1913 (receiver-qualified Go method QNs, mirroring the C++ out-of-line block; stacked on #1907). Post-fix: Close methods 15 → 86 nodes, Process 12 → 47, Task 1 → 8; one generated dir recovered 1 → 63 Close methods (source 66; the residual 3 are #1911's twins). Generic receivers verified on real code: 45 methods across 8 generic receivers carry clean receiver-qualified QNs (pkg.Cache.Add for func (c *Cache[K, V]) Add) and zero node QNs contain a [. Changes extracted QNs for Go methods → reindex needed (flagged per CONTRIBUTING).
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?
Go concrete methods get a flat, package-scoped QN (proj.pkg.method — receiver ignored), so every same-name method in a package collides on one QN; cbm_gbuf_upsert_node keeps exactly one node and the losers vanish silently (parse coverage stays clean, so check_index_coverage cannot see it).
Measured (private Go repo): 20 Process/Name declarations across 15 files kept 2 nodes; 9 distinct Task() methods fused into one chimera node carrying all 9 bodies' CALLS edges (26 with line numbers outside the surviving body); 19 structs point DEFINES_METHOD at the same single Process; a _test.go mock Close won the smallest-file-path tie-break over the production Close, so callers of the "production" symbol got filtered as test noise.
Interface members already get proj.pkg.Iface.method; C++ out-of-line methods already get proj.file.Class.method; the extractor already computes the receiver type for parent_class — it just doesn't put it in the QN.
Expected: func (s *Storage) Close() → proj.pkg.Storage.Close, one node per receiver.
Reproduction
// x.go
package m
type Storage struct{}
type Cache struct{}
func (s *Storage) Close() {}
func (c Cache) Close() {}
Actual: one Method node m.Close, both types' DEFINES_METHOD pointing at it. Expected: m.Storage.Close + m.Cache.Close.
Secondary effect this also fixes
resolve_same_module (conf 0.90) is an exact module.name lookup. Flat method QNs occupy that key, so pipeline.Process(event) binds whatever unrelated Process merged into the caller's package — a high-confidence false edge no filter can remove. Receiver-qualified QNs delete the flat key; those calls fall through to the typed/guarded paths.
Fix notes (all consumers already agree)
pxc_build_lsp_def passes def QNs verbatim (LSP registries follow automatically); check_go_class_implements already supports class-qualified method QNs; the call-scope side (compute_func_qn) mirrors the def formula via one shared receiver-type helper.
Related: #1906 (the merge made weak edges land on high-traffic symbols), #1114; tracked in #1932.
Confirmations
Status: fix open — PR #1913 (receiver-qualified Go method QNs, mirroring the C++ out-of-line block; stacked on #1907). Post-fix:
Closemethods 15 → 86 nodes,Process12 → 47,Task1 → 8; one generated dir recovered 1 → 63Closemethods (source 66; the residual 3 are #1911's twins). Generic receivers verified on real code: 45 methods across 8 generic receivers carry clean receiver-qualified QNs (pkg.Cache.Addforfunc (c *Cache[K, V]) Add) and zero node QNs contain a[. Changes extracted QNs for Go methods → reindex needed (flagged per CONTRIBUTING).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?
Go concrete methods get a flat, package-scoped QN (
proj.pkg.method— receiver ignored), so every same-name method in a package collides on one QN;cbm_gbuf_upsert_nodekeeps exactly one node and the losers vanish silently (parse coverage stays clean, socheck_index_coveragecannot see it).Measured (private Go repo): 20
Process/Namedeclarations across 15 files kept 2 nodes; 9 distinctTask()methods fused into one chimera node carrying all 9 bodies' CALLS edges (26 with line numbers outside the surviving body); 19 structs pointDEFINES_METHODat the same singleProcess; a_test.gomockClosewon the smallest-file-path tie-break over the productionClose, so callers of the "production" symbol got filtered as test noise.Interface members already get
proj.pkg.Iface.method; C++ out-of-line methods already getproj.file.Class.method; the extractor already computes the receiver type forparent_class— it just doesn't put it in the QN.Expected:
func (s *Storage) Close()→proj.pkg.Storage.Close, one node per receiver.Reproduction
Actual: one Method node
m.Close, both types'DEFINES_METHODpointing at it. Expected:m.Storage.Close+m.Cache.Close.Secondary effect this also fixes
resolve_same_module(conf 0.90) is an exactmodule.namelookup. Flat method QNs occupy that key, sopipeline.Process(event)binds whatever unrelatedProcessmerged into the caller's package — a high-confidence false edge no filter can remove. Receiver-qualified QNs delete the flat key; those calls fall through to the typed/guarded paths.Fix notes (all consumers already agree)
pxc_build_lsp_defpasses def QNs verbatim (LSP registries follow automatically);check_go_class_implementsalready supports class-qualified method QNs; the call-scope side (compute_func_qn) mirrors the def formula via one shared receiver-type helper.Related: #1906 (the merge made weak edges land on high-traffic symbols), #1114; tracked in #1932.
Confirmations