topic seeds get a query vector to score (V-547)

turnIsAbout scored t.vec, and t.vec was set in one place: queryEmbed, the
source at actions_query.go:125. Every topic source sits above it — attention,
list, feeds, home, network, weather. So best was handed an empty slice on every
deployed turn, returned ok=false, and all six recognisers ran on their keyword
floors. The seeds have decided nothing outside the tests since the mechanism
landed.

TestONNXTopics passes because it embeds each utterance itself and calls best
directly. That is the shape that hid this for a month: it measures the scorer
and never the wiring. Found on the box instead — "что мне нужно купить" was
answered from an old note about a monitor, and the seeds place it as the list by
0.0841.

turnVector computes the vector on first ask and caches it on the turn;
queryEmbed returns early when it is already set. Chosen over moving the embed
source up the list, because the cost is then paid only by turns that ask a
topic source, and the order of querySources keeps meaning what its comments
argue for.

One scenario assertion moved, and it is a behaviour change rather than a bent
test. morning_missed step 5 pinned "не знаю" for "что я пропустил?" with an
unresolved Praxis item on the board. isAttentionQuery does not match that
phrasing and the topicAttend seeds carry "что важное я пропустил" almost
verbatim, so she reads the item back now. Reading a surfaced item aloud is not
inventing a morning summary, so the floor that step exists for still holds;
what moved is which source answers.
This commit is contained in:
2026-08-05 18:51:42 +04:00
parent de10d7664f
commit 982c25118a
3 changed files with 36 additions and 3 deletions
+4
View File
@@ -468,6 +468,10 @@ func (h *reactiveHandler) queryWeather(ctx context.Context, t *queryTurn) (strin
// sources below both need, run once, in the position it always ran in. It
// only claims the turn when the embedder fails.
func (h *reactiveHandler) queryEmbed(ctx context.Context, t *queryTurn) (string, bool) {
// A topic source above already paid for this one; see turnVector.
if len(t.vec) > 0 {
return "", false
}
vec, err := router.EmbedQuery(ctx, h.recall.embedder, t.dec.Utterance)
if err != nil {
log.Printf("voice: embed query: %v", err)