diff --git a/cmd/mavend/continuation.go b/cmd/mavend/continuation.go index 83a1896..bbe0b1a 100644 --- a/cmd/mavend/continuation.go +++ b/cmd/mavend/continuation.go @@ -34,18 +34,24 @@ var continuationParticles = map[string]bool{ // continuableIntents — which intents an ellipsis may inherit. // // query and system are questions: asking the same question about a different -// day is exactly what "а завтра?" means. reminder is an instruction that names -// a time, so re-aiming it at another day is a coherent second instruction. +// day is exactly what "а завтра?" means, and re-aiming the Time slot answers it +// completely. // // The rest are excluded on purpose. fact and note would write something he did // not say — "поужинал" then "а вчера?" is a question about yesterday, not a // claim about it. chat has no slot to re-aim. act is the dangerous one: an // allowlisted fn inherited by a two-word utterance is a way to run a // destructive command nobody typed, and no follow-up is worth that. +// +// reminder was in this list and came out after a live check on 01-08-2026. A +// reminder's payload is its Text, and the Text embeds the day word it was +// created with: continuing "напомни сегодня о событиях" with "а завтра?" fires +// tomorrow with the text still reading "сегодня". Re-aiming Time is not enough +// when the day is also written into the payload, and rewriting the payload +// needs the date's span in the string, which ParseCalendarDate does not report. var continuableIntents = map[dialogue.Intent]bool{ - dialogue.IntentQuery: true, - dialogue.IntentSystem: true, - dialogue.IntentReminder: true, + dialogue.IntentQuery: true, + dialogue.IntentSystem: true, } // continuationDecision reads an utterance as "the previous question, but for diff --git a/cmd/mavend/continuation_test.go b/cmd/mavend/continuation_test.go index 674dc03..931bcff 100644 --- a/cmd/mavend/continuation_test.go +++ b/cmd/mavend/continuation_test.go @@ -67,8 +67,11 @@ func TestContinuationDeclinesWhatIsNotAnEllipsis(t *testing.T) { func TestContinuationDeclinesUncontinuableIntents(t *testing.T) { // act is the one that matters: inheriting an allowlisted fn from a // two-word utterance would be a way to run a destructive command. + // reminder is here because its payload is its Text, and the Text embeds + // the day word it was created with — see continuableIntents. for _, in := range []dialogue.Intent{ - dialogue.IntentAct, dialogue.IntentFact, dialogue.IntentNote, dialogue.IntentChat, + dialogue.IntentAct, dialogue.IntentFact, dialogue.IntentNote, + dialogue.IntentChat, dialogue.IntentReminder, } { if _, ok := continuationDecision(contSession(in, "water"), "а завтра?", contNow); ok { t.Errorf("continuationDecision inherited intent %q, want refusal", in)