# Language: what the model emits, and how Russian is matched *Last verified: 2026-08-09 @ a9b480a* Two contracts live here. What a model call is allowed to return, and which mechanism is allowed to recognise a Russian word. ## The LLM output contract All phrasing paths emit `{"response":"...","mood":"..."}`. They fall back to plain text when the model skips the JSON. **One parser, `parseResponseMood` in `internal/phraser/parse.go`.** Every path reaches it: the six `LLMPhraser` methods, `PhraseWorld`, and `Replier.PhraseReply`. `cmd/mavend/replier_llm.go` wraps the last of those, holds the stub fallback, and parses nothing itself. Mood is a fixed enum. The router prompt is a separate contract: ```text [{"intent":, key?, value?, text?, verb?}, ...] ``` over 7 intents: `fact, reminder, note, query, act, chat, system`. `llm/check_prompt_parity.py` in the training workspace enforces that the Go prompt and the relabelling prompt stay identical. They diverged once, and the relabelled set then taught a head the Go router never asks for. ## Russian patterns: three mechanisms, no fourth Hand-written Russian stem patterns were swept out on 2026-08-04 by the owner's call. A regex whose output is a fact or a route is the defect. A regex over structured input, such as HTML, MIME, JSON, a URL or an argv list, is not. Before writing a Russian word list, pick one of these. ### `internal/lexicon`, for closed classes `lexicon_ru_v1.json` holds interrogatives, capture verbs, reminder verbs, cardinals, day offsets, parts of day, weekdays, months and spoken hours. Editing a word is a data change and there is exactly one copy. Months used to live in three files and drifted between them. Cardinals carry the oblique forms, because a spoken time declines. `в семь` and `к семи` are one hour. ### `internal/morph`, for grammar From the vendored golem Russian dictionary. `IsVerbForm` and `SameWord`. Lemma matching is BROADER than stem-plus-one-ending. A verb slot that means the imperative must be matched exactly. `говори` and `говорил` share a lemma and only one of them is a command (`cmd/mavend/quiet_toggle.go`). ### `cmd/mavend/topics.go` and the embedder, for open sets Use these when the question is what a turn is ABOUT. Frozen seeds per subject plus a real `other` class, scored against the turn's own query vector. Same shape as the personal boundary in `personalboundary.go`, with one difference. A topic must clear the runner-up by `topicMargin`, because a false claim here spends a network scan rather than one honest "не знаю". The old keyword tests stay as the offline floor. ### The ecosystem trio Use it when the answer is not in the utterance at all. Identity is Nexus's, never a local pattern. ## Seeds are scoring data Editing one moves a recogniser. Re-measure against the `TestONNX*` tests rather than eyeballing the change.