a side query suspends the flow instead of ending it (V-561)

V-560 classified the side query correctly and then dropped the request behind
it, saying "Прошлую просьбу отпускаю." The owner rejected that on sight: he
asked about the weather in the middle of setting a reminder, and being told the
reminder was let go reports a loss he did not ask for. It had not been lost —
there was simply nowhere to put it.

There is now. ClarifyStore grew a bounded stack in V-559 and nothing called
Push; this is the caller it was built for. A side query leaves the question
parked exactly as it is, the words are answered as themselves, and the question
comes back on the end of the same reply — one utterance, two acts.

The resumed question is not the first one again. "Когда?" works in the same
breath as "напомни позвонить маме" and does not work after a turn about Rome, so
the deck has a second form per slot that names the request: "На какое время
поставить напоминание?". No attempt is spent, because he answered the side query
and not the parked question, and charging a retry for a turn that was never an
answer is the V-554 shape.

clarifyDropped stays for new_request and cancel, where something really does
die. Two things can now die at once, so TakeExpired reports a count instead of a
bool and the expiry notice has a plural wording — "прошлую просьбу" when two
were lost would be a lie about the number.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 01:23:19 +04:00
parent 70b32af8a7
commit c8a5b5416e
5 changed files with 236 additions and 32 deletions
+11
View File
@@ -31,6 +31,17 @@ type turnRoute struct {
// dropped — what she let go of this turn and must say out loud. A parked
// request that dies without a word leaves him thinking it landed.
dropped string
// resume — the parked question, re-worded, to put AFTER this turn's answer
// (Vikunja #561). A side query does not end the flow it interrupted, so the
// reply carries two acts: the answer he asked for, then the question he
// still owes her. Empty ⇒ nothing was suspended.
resume string
// suspended — a flow is parked underneath this turn. askClarify reads it to
// decide between Put (replace the top) and Push (keep the flow and stack the
// new question on it), because a side query that needs clarifying of its own
// must not overwrite the thing it interrupted.
suspended bool
}
type turnRouteKey struct{}