11831c6ace
The e5 embedder puts every cosine in one narrow band (0.79-0.89), so the absolute query_min_score gate cannot tell a real hit from a made-up question: any value under the band answers everything, any value above it answers nothing. False recall was 5/5. New gate asks whether one note is clearly the best instead: top1 - top2 > delta. New query_min_margin config knob, default 0.008, read off the sweep in the recall harness. The absolute floor stays as a second check. On the recall fixture with e5: answered 72% -> 68%, false recall 5/5 -> 1/5. Vikunja #359 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
23 lines
925 B
Go
23 lines
925 B
Go
package main
|
|
|
|
import "github.com/kami/maven/internal/memory"
|
|
|
|
// bestRecall is the read side of the long-term memory store: the top hit's
|
|
// stored text when it clears the confidence gate. This recalls across BOTH
|
|
// notes and facts (facts aren't in the notes table, so this is the only path
|
|
// that can answer "when did I last …?" from a captured fact). A note hit here
|
|
// is redundant with the notes-RAG path — by design; the two indexes can diverge
|
|
// once the backend is swapped for a persistent/external store. ok=false when
|
|
// the hit fails the confidence gate (see memory.Confident: an absolute floor
|
|
// plus a margin over the runner-up) or carries no text.
|
|
func bestRecall(results []memory.Result, minScore, minMargin float64) (string, bool) {
|
|
if !memory.Confident(results, minScore, minMargin) {
|
|
return "", false
|
|
}
|
|
text := results[0].Meta["text"]
|
|
if text == "" {
|
|
return "", false
|
|
}
|
|
return text, true
|
|
}
|