diff --git a/CLAUDE.md b/CLAUDE.md index aaf08d4..3bfc536 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -357,6 +357,53 @@ Adding a rung to the ladder in `runTurn` means adding its name to `preRouteLadder` in `cmd/mavend/decisiontrace.go`, or that rung is silently missing from the record. +**A route now says where the answer lives, not only that the turn is a question** +(V-655, 07-08-2026). `query` was a shrug. The cascade sorted an utterance into one of +seven intents, with stage 0, the resident model and the classifier behind it. Then +`IntentQuery` handed the turn to `querySources` in the daemon. That is twenty-two branches +deciding by seed similarity in a fixed order. It has no fixture and no accuracy +number, no model arm and no floor. `Decision.Source` (`internal/router/source.go`) is +the second half of the route. Twelve destinations, not twenty-two. The three recall +passes plus `fact-by-key` are one destination from outside. So are search, Kiwix and +the URL reader. + +**`SourceUnknown` is a real value and it is the floor.** Nothing named a destination, +so the daemon walks the whole chain. That is byte-for-byte what shipped before the +field existed. The classifier arm names nothing, so a box whose model is down routes +queries exactly as it did. + +`queryWalk` in `cmd/mavend/actions_query.go` takes sources **out** and moves none. +That is the safety argument and it is not negotiable. The table's order is +load-bearing. Every comment on it argues a reason between two sources, and above all +it carries "the owner's data first, then the world". Naming `SourceWorld` does not +send the turn outside. His notes, his facts and the personal boundary still run first. + +What comes out is only the sources that **guess**. Those decide a turn is theirs by +cosine against frozen seeds, then answer whatever they claimed. They hold no table +that could come back empty. Weather is the pure case and has no local data at +all. It was measured on the box on 2026-08-07 +(`docs/evals/2026-08-07-week-of-usage.md` section 4). It answered both "что такое +TCP?" and "сколько будет 17 на 23?" with "для какого города?". The feed answered "какой у меня любимый язык?" with kernel headlines. +The personal boundary answered "кто такой Линус Торвальдс?" with "не нашла у тебя +такой записи". A source that guesses is marked `guesses: true` in the table. One that +looks is not, and it is always asked. + +Stage 0 fills the destination where a rule already knows it. `WorldQueryGrammars()` +(`internal/router/worldquery.go`) claims "что такое X" and "сколько будет 17 на 23". +It is wired after the agenda rules and **before** the feed and list rules. +"что такое лента" is a definition question, and the feed rule would take it on the +noun alone. +`calendar-query` and `event-time-query` name the calendar. The possessive agenda rules +deliberately do not. "что у меня в списке покупок" matches `agenda-query`, and naming +the calendar there would take the list source off the turn. + +Fixture unchanged at **69/91 classifier+ONNX**, measured both sides. That is the +expected result, because it scores intent and no case here changes intent. **The +destination has no fixture yet, so it has no accuracy number.** That and the model arm +are the follow-ups. The field is designed so a decider naming nothing costs nothing. +It lands on V-546. Intent, mood and BIO slot tags were already three heads on one +forward pass of the resident e5-small. Destination is a fourth head on the same pass. + ## LLM output contract All phrasing paths emit `{"response":"...","mood":"..."}`, with fallback to plain text when