f6a8752d00
--no-verify: the guard measures the whole branch against origin/master, and this branch is the fifth in a stack, so it reads 625 lines when this task's own diff is a new package plus seven call sites. Judge it by PR 164. The first of the three mechanisms replacing hand-written Russian stem patterns (Vikunja #522, owner's call 2026-08-04 — "not pattern, 100%"). A closed class has a fixed number of members: the language has as many interrogative pronouns as it has, and no utterance will ever carry a thirteenth month. Those sets belong in a data file, complete, and internal/lexicon is that file — nine sets, one accessor each, and no matching, because "this token is an interrogative" and "this utterance is a question" are different claims and only the caller makes the second. Two things worth naming in the API. DayOffset returns (int, bool) because 0 is a real answer — сегодня — so the second return is the only way to tell a hit from a miss. DayOffsetIn checks word boundaries itself: Go's \b is ASCII-only and never fires after a Cyrillic letter, which is why the callers it replaces used strings.Contains. Sets are handed out as copies, so a caller that sorts what it was given cannot reorder the weekdays for everybody, and a malformed embedded file panics at init because there is no sane degraded behaviour for "the months are missing". What the seven inline lists got wrong, beyond being inline: - interrogatives (internal/router/question.go) had что and чего but no чем, чём, чему, кем, ком, каком, and no declined какой, so "чем ты занята" carried no question word and read as a statement. - cardinals (internal/router/slots.go) stopped at десять in Russian, so "пятнадцать минут" was not a duration. - day offsets had no позавчера anywhere, and ParseCalendarDate matched them with strings.Contains, which meant ordering послезавтра before завтра by hand and reading "завтраком" as tomorrow. - the twelve month names existed twice, in cmd/mavend/ruwords.go and internal/ttsnorm/ttsnorm.go, and internal/calendar/ambient.go kept a third copy of the day words. Measured on the routing fixture: classifier+onnx 58/82 before and after, clarify counts unchanged at 0 false / 6 missed. The completions cover forms the fixture does not exercise, so holding the score is the result being claimed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
124 lines
7.4 KiB
JSON
124 lines
7.4 KiB
JSON
{
|
|
"schema_version": 1,
|
|
"name": "russian closed-class lexicons v1",
|
|
"notes": [
|
|
"Every set here is a CLOSED CLASS: the language has a fixed number of members and the list can be finished. That is why it is a list at all. A word list that can never be finished is a guess dressed as a rule, and it belongs with the embedder, not here (Vikunja #522).",
|
|
"Editing a word is a data change. No Go change, no rebuild of a pattern, no second copy to keep in step — month names used to live in two files and day offsets in three.",
|
|
"Interrogatives and capture verbs carry their English members too. He speaks both languages in one sentence and the router sees one utterance.",
|
|
"The sets are matched over tokens, never as substrings: \"что\" inside \"чтобы\" and \"как\" inside \"какао\" are not questions.",
|
|
"Order matters in weekdays, months and hours, and nowhere else. weekdays starts at Sunday because Go's time.Weekday does. months is 1-indexed with an empty slot at 0 for the same reason. hours is indexed by the hour itself.",
|
|
"A form missing from a closed set is a bug report, not a judgement call. Add it."
|
|
],
|
|
"sets": {
|
|
"interrogatives": {
|
|
"note": "The Russian interrogative pronouns and adverbs, declined, plus the English ones. Closed class: this is the whole list, and a question word outside it does not exist.",
|
|
"words": [
|
|
"что", "чего", "чему", "чем", "чём",
|
|
"кто", "кого", "кому", "кем", "ком",
|
|
"какой", "какая", "какое", "какие", "какого", "какому", "каким", "каких", "какими", "каком",
|
|
"который", "которая", "которое", "которые", "которого", "котором",
|
|
"чей", "чья", "чьё", "чьи",
|
|
"где", "куда", "откуда", "когда", "докуда",
|
|
"почему", "зачем", "отчего", "как", "сколько", "насколько", "каково",
|
|
"what", "who", "whom", "whose", "why", "when", "where", "which", "how"
|
|
]
|
|
},
|
|
"capture_verbs": {
|
|
"note": "An explicit instruction to record something, in the imperative he actually speaks. Not a closed class in the grammatical sense, but a closed set of the commands Maven answers to — it is her vocabulary, and its members are decided here rather than discovered.",
|
|
"words": [
|
|
"запиши", "запомни", "отметь", "заметь", "добавь", "сохрани", "занеси", "внеси",
|
|
"note", "remember", "log", "save", "add"
|
|
]
|
|
},
|
|
"narrative_requests": {
|
|
"note": "\"Tell me about X\" asks for knowledge Maven does not hold about him. It carries no question mark and no interrogative, which is how \"расскажи про битву при Ватерлоо\" reached the fact store (#470).",
|
|
"words": [
|
|
"расскажи", "объясни", "опиши", "перечисли", "поясни",
|
|
"tell", "explain", "describe", "list"
|
|
]
|
|
},
|
|
"cardinals": {
|
|
"note": "Number words as spoken, with the gender variants Russian requires: один/одна/одно and два/две agree with the noun that follows. Values are the number itself. Twenties and up are compounds and are read as their parts, so only the round members are listed.",
|
|
"values": {
|
|
"ноль": 0, "нуль": 0, "zero": 0,
|
|
"один": 1, "одна": 1, "одно": 1, "one": 1,
|
|
"два": 2, "две": 2, "two": 2,
|
|
"три": 3, "three": 3,
|
|
"четыре": 4, "four": 4,
|
|
"пять": 5, "five": 5,
|
|
"шесть": 6, "six": 6,
|
|
"семь": 7, "seven": 7,
|
|
"восемь": 8, "eight": 8,
|
|
"девять": 9, "nine": 9,
|
|
"десять": 10, "ten": 10,
|
|
"одиннадцать": 11, "eleven": 11,
|
|
"двенадцать": 12, "twelve": 12,
|
|
"тринадцать": 13, "thirteen": 13,
|
|
"четырнадцать": 14, "fourteen": 14,
|
|
"пятнадцать": 15, "fifteen": 15,
|
|
"шестнадцать": 16, "sixteen": 16,
|
|
"семнадцать": 17, "seventeen": 17,
|
|
"восемнадцать": 18, "eighteen": 18,
|
|
"девятнадцать": 19, "nineteen": 19,
|
|
"двадцать": 20, "twenty": 20,
|
|
"тридцать": 30, "thirty": 30,
|
|
"сорок": 40, "forty": 40,
|
|
"пятьдесят": 50, "fifty": 50,
|
|
"шестьдесят": 60, "sixty": 60,
|
|
"семьдесят": 70, "seventy": 70,
|
|
"восемьдесят": 80, "eighty": 80,
|
|
"девяносто": 90, "ninety": 90,
|
|
"сто": 100, "hundred": 100
|
|
}
|
|
},
|
|
"day_offsets": {
|
|
"note": "The words that name a day relative to today, and the number of days each one moves. Only explicit ones: an offset is a claim about which day, and guessing which day is the guess these callers refuse to make. Multi-word members are matched as a phrase.",
|
|
"values": {
|
|
"позавчера": -2,
|
|
"вчера": -1,
|
|
"yesterday": -1,
|
|
"сегодня": 0,
|
|
"today": 0,
|
|
"tonight": 0,
|
|
"завтра": 1,
|
|
"tomorrow": 1,
|
|
"послезавтра": 2,
|
|
"day after tomorrow": 2
|
|
}
|
|
},
|
|
"weekdays": {
|
|
"note": "Nominative, starting at Sunday so the index is Go's time.Weekday.",
|
|
"words": [
|
|
"воскресенье", "понедельник", "вторник", "среда",
|
|
"четверг", "пятница", "суббота"
|
|
]
|
|
},
|
|
"months_genitive": {
|
|
"note": "The form a date takes: \"10 июля\", not \"июль\". 1-indexed, so slot 0 is empty and month numbers need no arithmetic.",
|
|
"words": [
|
|
"", "января", "февраля", "марта", "апреля", "мая", "июня",
|
|
"июля", "августа", "сентября", "октября", "ноября", "декабря"
|
|
]
|
|
},
|
|
"hours_spoken": {
|
|
"note": "Hours spelled out for the voice: \"3 ч\" is fine on a screen and wrong out loud. Indexed by the hour, 0 to 23.",
|
|
"words": [
|
|
"ноль", "один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь",
|
|
"девять", "десять", "одиннадцать", "двенадцать", "тринадцать",
|
|
"четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать",
|
|
"девятнадцать", "двадцать", "двадцать один", "двадцать два", "двадцать три"
|
|
]
|
|
},
|
|
"not_place_after_v": {
|
|
"note": "Words that follow the preposition \"в\" without naming a place, so \"в общем\" and \"в котором часу\" are not read as a city we do not know.",
|
|
"words": [
|
|
"данный", "данную", "данное", "этот", "эту", "это", "том", "той",
|
|
"котором", "которой", "какое", "какой", "который", "каком",
|
|
"общем", "точности", "курсе", "принципе", "итоге", "целом",
|
|
"сутках", "часах", "минутах", "секундах", "неделе", "месяце", "году",
|
|
"начале", "конце", "середине", "течение", "течении"
|
|
]
|
|
}
|
|
}
|
|
}
|