b705a786ef
The note body was already the utterance. Two other holes were not. The LLM router filled Slots.Text for a note from the model's own text field, and that slot is what the replier reads out. So the confirmation he heard named things he never said, twice over, differently each time. The note payload is now the utterance and the model cannot touch it. A correction with no referent is also not a note. 'нет, не маме, а папе' names no intent, so parseRepair declines it and it routed as a fresh note. actionNote now declines it and asks instead of filing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
59 lines
1.7 KiB
Go
59 lines
1.7 KiB
Go
package main
|
||
|
||
import (
|
||
"strings"
|
||
|
||
"github.com/kami/maven/internal/lexicon"
|
||
"github.com/kami/maven/internal/morph"
|
||
)
|
||
|
||
// correctionFragment reports that an utterance replaces a referent and states
|
||
// nothing of its own: "нет, не маме, а папе" (V-576).
|
||
//
|
||
// Measured on the box 2026-08-06, that fragment routed to note and was filed.
|
||
// It is not a repair either, because it names no intent, so parseRepair
|
||
// declines it and repair.go is the wrong place to catch it. This is the note
|
||
// path saying it has nothing to store.
|
||
//
|
||
// Three offline tests, all of them narrow on purpose. The sentence opens with a
|
||
// refusal word from the lexicon, it carries the contrastive "а" that names the
|
||
// replacement, and no token in it is a verb form. The verb test is what keeps
|
||
// the rule off real notes: "нет, я не поеду, а останусь" says something, and a
|
||
// Russian verb carries its own subject and tense.
|
||
func correctionFragment(utterance string) bool {
|
||
toks := repairTokens(strings.ToLower(strings.TrimSpace(utterance)))
|
||
if len(toks) < 3 {
|
||
return false
|
||
}
|
||
if !refusalWord(toks[0]) {
|
||
return false
|
||
}
|
||
var negated, contrasted bool
|
||
for _, tok := range toks[1:] {
|
||
switch tok {
|
||
case "не", "not":
|
||
negated = true
|
||
case "а", "but":
|
||
contrasted = true
|
||
}
|
||
if morph.IsVerbForm(tok) {
|
||
return false
|
||
}
|
||
}
|
||
return negated && contrasted
|
||
}
|
||
|
||
// refusalWord reports that a token is a one-word refusal. The lexicon set holds
|
||
// phrases too ("не надо"), and those are not what opens a correction.
|
||
func refusalWord(tok string) bool {
|
||
for _, w := range lexicon.ConfirmNo() {
|
||
if strings.ContainsRune(w, ' ') {
|
||
continue
|
||
}
|
||
if w == tok {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|