# Praxis reach at stage 0, 2026-08-05 Vikunja #516. Measured with `make eval-reach` on the held-out ecosystem fixture (`internal/router/eval/ru_ecosystem_v1.json`, 30 cases), classifier + ONNX embedder, no llama-server in the run. The LLM arm was not measured, so judge a cascade number again before quoting one. ## Result | | before | after | |---|---|---| | overall | 16/30 (53.3%) | 27/30 (90.0%) | | by want: praxis | 0/12 | 11/12 | | by want: hexis | 9/10 | 9/10 | | by want: none | 7/8 | 7/8 | | by tag: lifecycle | 0/5 | 5/5 | | by tag: attention | 0/7 | 6/7 | | by tag: reading | 0/7 | 6/7 | | wrong praxis arm | 0 | 0 | | p50 latency | 20.6ms | 16.5ms | ## Why it was zero Not a tuning gap. `handlePraxisAct` dispatches on exact equality between `Slots.Fn` and a capability alias, and the fn slot is filled by `DefaultActMatcher` from the deployment's enabled tool names. No Praxis alias is on that list, so no utterance could put one in the slot. The Russian aliases in `praxisCapabilities` read as if they matched speech. They are compared against a fn slot and never against an utterance. `PraxisGrammars()` (`internal/router/praxis.go`) fills the slot at stage 0, wired in `buildRouter` before the capture marker because "отметь" is a capture verb. ## The three misses that remain - `eco-ru-006` "запусти бэкап на нексусе", a Hexis case, routed note. Pre-existing. - `eco-ru-028` "выключи", reached Hexis, should have asked. Pre-existing. - `eco-ru-021` "что там с нексусом" wants scoped attention. Deliberately not claimed. "что там с X" also opens "что там с погодой". Routing a weather question to Nexus is worse than one missed fixture case. ## Two judgement calls worth re-arguing **A lifecycle word alone does not transition an item.** "готово" is what he says about the thing he just finished. So the rules split lifecycle words by mood. An imperative he says to her ("закрывай") claims the turn bare, and the capability asks which пункт. A stative ("готово", "принято") needs an item named beside it. The bare-imperative arm also requires that nothing else in the sentence is being acted on. "закрой шторы в комнате" is an imperative too. Without that guard it took a house command to Praxis, measured at hexis 8/10 mid-change. **A demonstrative resolves only against a one-item digest.** "отметь это как сделанное" points at what she just read. `resolveSurfacedPosition` maps it to an id only when exactly one item was spoken. With two or more it gives the turn back to the cascade rather than transitioning one of them at random. With no digest at all it gives the turn back too, because "я это сделал" was never about a пункт. ## Routing fixture `make eval-router`, same run: classifier + ONNX 60/84 (71.4% full and intent-only), 0 false clarifies, 6 missed clarifies (the known `amb-*` set). No failure in that list comes from a stage-0 decision. Every one carries a classifier confidence score.