feed questions ask the seeds, not a stem list (V-522)

Whether a turn is about the feeds is a question about meaning, and
internal/router/feeds.go was deciding it with three word lists. Their own
comments admit the shape: vagueNouns exists because "что нового?" is the most
common opener in the language and it matched a feed noun, so a daemon with no
feeds block answered a greeting with a configuration status.

So topicFeed joins the four subjects in cmd/mavend/topics.go and queryFeeds
calls turnIsAbout. The word lists stay as the offline floor, reached through
feedFloor, and they are allowed to stay narrow now that they are not the only
answer. The category is not a recogniser — a topic is marked by a preposition —
so it comes out of the utterance either way, through the new
router.FeedCategoryOf.

The greeting is handled by the shape rather than by a bail-out list. "что
нового" is a topicOther seed, close enough to the feed seeds that a bare
"что нового?" cannot clear topicMargin, and a thin call goes to
ParseFeedQuery, which declines a vague noun with no topic beside it.

Measured on TestONNXTopics, four held-out cases added: 23/23, and no case that
passed before it regressed. One seed pair was added during the measurement,
because "какие сегодня заголовки" first read as weather — "какая сегодня
погода" was the nearest thing in the whole set carrying "сегодня".
This commit is contained in:
2026-08-05 18:37:38 +04:00
parent 8e3b288858
commit 47128bb1ca
4 changed files with 69 additions and 9 deletions
+17 -4
View File
@@ -5,10 +5,16 @@ import "strings"
// Feed queries — "что нового в лентах?", "что нового по технологиям?"
// (Vikunja #258).
//
// Deterministic matching, like the calendar, plan and habit matchers above it:
// the LLM router says this is a query, and this decides whether it is a question
// about the feeds. A model deciding that would occasionally answer "что нового?"
// out of world knowledge, which is the one thing a feed reader exists to avoid.
// This file is the OFFLINE FLOOR as of 05-08-2026 (V-522). Whether a turn is
// about the feeds is a question about meaning, so the frozen seeds decide it —
// topicFeed in cmd/mavend/topics.go, through turnIsAbout. The word lists below
// stay because they always answer: a box with no embedder, a turn whose vector
// never got computed, and any call that does not clear topicMargin. They are
// allowed to stay narrow now that they are not the only answer.
//
// What has not changed is that no generative model decides this. One would
// occasionally answer "что нового?" out of world knowledge, which is the one
// thing a feed reader exists to avoid.
// FeedQuery — a parsed "what's new" question. Category is the topic he named
// ("технологии"), empty when he asked about the feeds in general.
@@ -95,6 +101,13 @@ func ParseFeedQuery(text string) (FeedQuery, bool) {
// cannot be mistaken for anything else.
var categoryPreps = map[string]bool{"по": true, "об": true, "про": true, "about": true, "on": true}
// FeedCategoryOf reads the topic out of an utterance without deciding whether the
// turn is a feed question at all. The seeds answer that now (topicFeed in
// cmd/mavend/topics.go, V-522), and they answer it for phrasings the word lists
// here never held — but a claimed turn still needs its category, and a category
// is marked by a preposition rather than recognised.
func FeedCategoryOf(text string) string { return feedCategory(planTokens(text)) }
func feedCategory(toks []string) string {
for i, t := range toks {
if categoryPreps[t] && i+1 < len(toks) {