Files
claude ea0eb167fd a missing slot asks, whatever the confidence (V-557)
The clarify path was gated on dec.Clarify, so a turn the cascade routed
confidently but incompletely skipped it. "напомни позвонить" reached applyAction,
failed on the missing time and parked nothing, and the "в семь вечера" that
followed was routed as a world question and web-searched.

The gate now also fires when missingFor names a required slot. A bare capture
verb gets a stage-0 rule of its own: it was reaching the resident model as chat,
which answered by agreeing to a wording change nobody asked for.
2026-08-06 00:08:43 +04:00

52 lines
1.9 KiB
Go

package router
import (
"regexp"
"strings"
)
// BareCaptureGrammar — a capture verb with nothing after it is a fact she has
// yet to hear, not a conversation (Vikunja #557).
//
// A bare "запиши" reached the resident model as chat, and the model answered by
// agreeing to something nobody asked for: "Я поняла, теперь я буду говорить
// «записала» или «записала заметку»." It read its own instruction block as the
// subject of the turn. Whatever the routing, that reply is invented.
//
// The route this rule asks for is a fact with no key, which is a gap the clarify
// path already has copy for ("Что записать?"). So the rule does not answer the
// turn — it hands it to the one mechanism that asks.
//
// Wired before TaskCaptureGrammar, whose pattern needs an object, so it can
// never claim this shape. There is nothing to disambiguate: the whole utterance
// is one verb from a closed lexicon.
func BareCaptureGrammar() []Grammar {
return []Grammar{{
Name: "bare-capture",
Pattern: bareCapturePattern,
Build: bareCaptureBuild,
}}
}
// Anchored at both ends, so only the verb and punctuation are in the utterance.
// Trailing "-ка" and "пожалуйста" are the same request said politely.
var bareCapturePattern = regexp.MustCompile(`(?i)^\s*([\p{L}]+)(?:-ка)?[,\s]*(?:пожалуйста)?[\s.!?]*$`)
func bareCaptureBuild(m []string) (Decision, bool) {
word := strings.ToLower(strings.TrimSpace(m[1]))
for _, v := range captureVerbs {
if word != v {
continue
}
// No key, no text: she was told to record and not what. Confidence is
// 1.0 about the shape, which is all stage 0 ever claims — the gap is
// carried by the empty slots, not by a doubt.
return Decision{
Stage: 0,
Intent: IntentFact,
Confidence: 1.0,
}, true
}
return Decision{}, false
}