diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/memory/L3RepoKnowledgeRetriever.kt b/apps/server/src/main/kotlin/com/correx/apps/server/memory/L3RepoKnowledgeRetriever.kt index 3e50044a..5ee22283 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/memory/L3RepoKnowledgeRetriever.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/memory/L3RepoKnowledgeRetriever.kt @@ -24,7 +24,15 @@ private const val RETRIEVAL_OVERSAMPLE_FACTOR = 4 // live grounding); below this floor a hit is just the nearest thing in a small corpus, not // actually related to the query — rendering it as "relevant" is the same poisoning failure // mode as the markdown-in-L3 bug, just via low-signal cosine similarity instead of topic drift. -private const val MIN_SIMILARITY_SCORE = 0.5f +// +// ponytail: 0.5 was too low. Docs embed a terse *symbol-list* descriptor ("path: module X; +// symbols: a,b") while queries embed *prose* intent — an asymmetric prose↔symbols comparison +// that collapses ALL scores into a ~0.5 noise band (2026-07-21 session 459: top junk hits at +// 0.54/0.53, real relevance never reached). At 0.5 those noise-winners cleared the bar and +// SUPPRESSED the deterministic repo-map floor (repoEntriesOrMapFloor). 0.6 sits above the +// observed noise ceiling (~0.55) and below the real-signal floor (0.68): noise → empty → +// fall back to the repo map. Calibration knob — retune if the embedder model changes. +private const val MIN_SIMILARITY_SCORE = 0.6f class L3RepoKnowledgeRetriever( private val embedder: Embedder,