Files
Maven/internal/router/source.go
claude b5500a5be8 Say where the answer lives, not just that it is a question (V-655)
A question was sorted twice. The cascade picked one of seven intents with
stage 0 rules, the resident model and the classifier behind it, a 91-case
fixture measuring it and the decision trace recording it. Then IntentQuery
handed the turn to a second dispatch in the daemon, twenty-two branches
deciding by seed similarity in a fixed order, with none of that. The careful
sorter did the easy half.

Decision grows a Source: twelve destinations, not twenty-two, because the
recall passes are one destination from the outside and so are the three world
sources. Empty is a real value and it is the floor — nothing names one, the
daemon walks its whole chain, and that is exactly what shipped before.

Stage 0 fills it where a deterministic rule already knows. Two new world rules
for the shapes measured failing on the box on 2026-08-07: "что такое TCP?" and
"кто такой Линус Торвальдс?" were answered by weather and by the personal
boundary, and "сколько будет 17 на 23?" was answered "для какого города?".
The calendar noun rule and the closed event-noun rule name the calendar. The
possessive agenda rules deliberately do not: "что у меня в списке покупок"
matches agenda-query, and naming the calendar there would take the list off
the turn.

Fixture unchanged at 69/91, which is the point — it scores intent, and none of
these cases changes intent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 13:01:59 +04:00

79 lines
3.5 KiB
Go

package router
// Source — where the answer to a query lives. It is the second half of a
// routing decision and it used to be made outside the router entirely (V-655).
//
// The cascade sorted an utterance into one of seven intents with stage 0 rules,
// the resident model and the classifier behind it, a fixture measuring it and
// the decision trace recording it. Then IntentQuery handed the turn to
// querySources in the daemon, a chain of twenty-two branches deciding by seed
// similarity in a fixed order, with none of that. So the careful sorter did the
// easy half and the sloppy one did the hard half: on 2026-08-07 weather claimed
// "что такое TCP?" and answered "для какого города?", because weather read one
// percent closer to the turn than the pile of leftover seeds did, and one
// percent was enough. Search would have answered it and search was never asked.
//
// "query" is not a destination. It is a shrug. This is the field that says
// where to look.
//
// # Why twelve and not twenty-two
//
// A destination is what a decider can plausibly name from the utterance alone,
// not one entry per source. Three of the daemon's sources are successive passes
// over his own words and a fourth reads the facts by key: which of them lands
// the hit is an ordering detail inside the chain, and no utterance says. They
// are SourceRecall together. The same goes for the metasearch, the offline
// encyclopedia and a page he named by URL, which are SourceWorld.
//
// # Empty is a real value and it is the floor
//
// SourceUnknown means nobody decided. The daemon then walks the whole chain in
// its original order, which is the behaviour that shipped before this field
// existed. So the classifier arm sets nothing and costs nothing, and a box
// whose model is down routes queries exactly as it did.
type Source string
const (
// SourceUnknown — no decider named a destination. Walk the chain.
SourceUnknown Source = ""
// His own data.
SourceRecall Source = "recall" // notes, facts and what he has said before
SourceCalendar Source = "calendar" // events, and the only date-aware destination
SourceTasks Source = "tasks" // the task list
SourceList Source = "list" // the shopping and other named lists
SourceMoney Source = "money" // the spending facts the poller writes
// The surroundings.
SourceWeather Source = "weather" // the forecast for a place
SourceHome Source = "home" // lights, devices, the house
SourceNetwork Source = "network" // the LAN and what is on it
SourceFeeds Source = "feeds" // the RSS she reads
SourceAttention Source = "attention" // what Praxis says needs looking at
// Everything else.
SourceSelf Source = "self" // a question about Maven herself
SourceWorld Source = "world" // search, the ZIMs, a page he named
)
// Sources — every destination a decider may name, in a fixed order so a prompt,
// a grammar table and a test all read the same list. SourceUnknown is not a
// member: it is the absence of a choice, not one of the choices.
var Sources = []Source{
SourceRecall, SourceCalendar, SourceTasks, SourceList, SourceMoney,
SourceWeather, SourceHome, SourceNetwork, SourceFeeds, SourceAttention,
SourceSelf, SourceWorld,
}
// ValidSource reports whether s is one a decider may name. Anything else,
// including a destination invented by a model, is dropped back to
// SourceUnknown by the caller rather than trusted.
func ValidSource(s Source) bool {
for _, known := range Sources {
if s == known {
return true
}
}
return false
}