Vikunja #363. The follow-up session was a plain in-memory map, so any
mavend restart dropped the thread. It now mirrors to a small TTL-pruned
sqlite table and is loaded on startup; expired sessions are deleted on
load, not revived. Clarify's pending question is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
MaxAttempts was 1, justified as "not a nag". Wrong reading: "not a nag" is about
interrupting unprompted, and a clarifying question is part of a conversation he
started. Now three, configurable via voice.clarify_max_attempts (default 3).
Three, because after that the likely problem is she misheard the whole request,
not one slot.
Answer used to keep the parked value, so "в три" then "нет, в пять" threw the
five away. Now a value the answer carries wins for the slot she asked about.
Only for the clarify answer — a correction in a fresh turn is followUpMerge.
The eight-field chained assertion in the Answer test is one DeepEqual now, so a
new field in Slots is covered without touching the test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
PendingQuestion plus ClarifyStore: same shape, locking and expiry as SessionStore. Answer fills only the missing slots and never overwrites a filled one. No wiring yet — TODOs mark the daemon hooks.
Reviewer: MaxAttempts is 1 on purpose (Maven asks once, she is not a nag).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
router.Slots already carries the fact payload; the dialogue copy did not, so a clarifying answer had nowhere to put it. InheritSlots carries it like Key.
Reviewer: check the new inherit block does not overwrite a filled value.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
- session.go: add History []Turn + Turn type for multi-turn context
- slots.go: add AnaphoraResolver with Resolve() for RU pronoun detection
(это/он/она/оно/тот/мой and inflected forms)
- followup.go: extend followUpMerge with cross-intent inheritance:
Query/Fact/Reminder after a Fact with anaphora inherits the key.
Same-intent path unchanged. Anaphora detection from utterance.
- voice.go: add fact-by-key lookup path in applyAction for IntentQuery
when dialogue resolved an anaphoric reference (calls LatestFact,
formats with formatTime helper). History tracked in Session.History
capped at 4 most recent turns.
- followup_test.go: 7 new test cases: anaphora query-after-fact,
no-inheritance-without-anaphora, three-turn break, anaphora in
reminder, anaphora in fact, explicit key wins, time inheritance.
make test green (303+, -race, all 29 packages).
- Add CalendarEvents method to recordingAPI in auth_test.go
- Add CalendarEvents method to fakeCore in handlers_test.go
Co-Authored-By: opencode <opencode@anthropic.com>