a re-ask names what the answer before it gave her (V-593)

After "на 9" and then "на завтра" she asked "Сейчас 02:34. Это утра или
вечера?" twice, byte for byte. Asking again is right — the half of the
day is still unsaid — but a reply with no trace of his turn in it is
indistinguishable from not having been heard, which is the failure mode
the V-558 family exists to remove.

whenKnownOf reads the three things he has to say about the time off the
same predicates whenGapOf reads. When his answer moved any of them
forward, the ask carries an acknowledgement of what it took, in his own
words and never a restatement: a 1.7B asked to say a Russian sentence
back is exactly where V-592 came from. When it moved nothing, there is
nothing to acknowledge and the question repeats honestly.

The clock still opens every time question, per the owner's ruling. The
acknowledgement goes between it and the question. Whether she should
state the clock on every ask of one flow is his call, not mine.

Also folds a fact's raw answer into the parked utterance (V-592): a fact
fills no Text slot, so "запиши" + "пил воду" confirmed as "запиши".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 02:58:49 +04:00
parent 5187f3bd14
commit fec572c997
4 changed files with 147 additions and 22 deletions
+4 -4
View File
@@ -169,11 +169,11 @@ func TestClarifyAsksThreeTimesThenSaysSo(t *testing.T) {
}
// The wording changes with the attempt (Vikunja #457): repeating a
// question he already failed to answer is the worst way to ask it.
want, _ := whenQuestion(whenNoHour, i, h.now())
want, _ := whenQuestion(whenNoHour, i, h.now(), "")
if reply != want {
t.Fatalf("attempt %d should ask again as %q, got %q", i, want, reply)
}
if first, _ := whenQuestion(whenNoHour, 1, h.now()); reply == first {
if first, _ := whenQuestion(whenNoHour, 1, h.now(), ""); reply == first {
t.Fatalf("attempt %d repeated the first wording: %q", i, reply)
}
if h.clarifyStore.Get(voiceDialogueID, h.now()) == nil {
@@ -368,7 +368,7 @@ func TestClarifyAsksAboutTheSecondGapToo(t *testing.T) {
}
// Second gap, second attempt, so it is the second wording of the time
// question — the attempt budget is shared between the two paths.
want, _ := whenQuestion(whenNoHour, 2, h.now())
want, _ := whenQuestion(whenNoHour, 2, h.now(), "")
if reply != want {
t.Fatalf("a filled subject with no time must ask about the time as %q, got %q", want, reply)
}
@@ -685,7 +685,7 @@ func TestIncompleteReminderAsksInsteadOfFailing(t *testing.T) {
h, st := newRoutingClarifyHandler(t)
reply := h.handleText(ctx, "web", "напомни позвонить маме")
want, _ := whenQuestion(whenNoHour, 1, h.now())
want, _ := whenQuestion(whenNoHour, 1, h.now(), "")
if reply != want {
t.Fatalf("reply = %q, want the time question %q", reply, want)
}