Lexicons: the finite Russian sets move to one data file and get completed #164

Closed
claude wants to merge 1 commits from task/525-lexicons-the-finite-russian-sets-move-to into task/524-entity-reference-ask-nexus-about-every-l
Contributor

Closes Vikunja #525.

Opened during an unattended overnight run: the diff-budget block was off (task overnight). Read the diff, not only the tests.

Acceptance criteria and quality gate are in TASK.md on this branch.
Review the review, not the diff — leave comments and the agent will apply them via task start 525.

Closes Vikunja #525. Opened during an unattended overnight run: the diff-budget block was off (`task overnight`). Read the diff, not only the tests. Acceptance criteria and quality gate are in `TASK.md` on this branch. Review the review, not the diff — leave comments and the agent will apply them via `task start 525`.
claude added 1 commit 2026-08-04 16:34:14 +02:00
--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
Author
Contributor

Reviewed as part of a bottom-up pass over the whole open stack (#119 to #168). Merging: the data file is the right shape and make test is green at the top of the stack.

Four files still match Russian by hand. V-529 found that the sweep list named files that do not exist. These four were missed the same way. One is the duplication this data file exists to end.

internal/router/numwords.go holds ruNumerals, a second copy of the cardinals set. Both map spoken numbers to values and both stop around fifty. They disagree on the members: ruNumerals carries the oblique forms (семи, двух, трёх), the lexicon carries the English words and the gender variants. Months living in three files is the case named in CLAUDE.md, and this is the same case. A straight swap loses the case forms, so the fix is to add them to lexicon_ru_v1.json and read from it.

cmd/mavend/reminderbody.go strips reminder times with five hand-written regexes over через, часа|часов|минут[уы], завтра|послезавтра|сегодня|вечером. The day words are already day_offsets, and the hour words are already hours_spoken.

cmd/mavend/historyq.go matches on truncated prefixes: {"что я", "рассказ"}, {"что ты", "записал"}. That is the defect V-528 fixed in complaint.go, where лаг matched лагерь. Its output claims a query source, so a miss sends the turn to the next source.

internal/weather/openmeteo.go guesses declension by reversing endings, and internal/morph now answers that question. It also bails under four runes, so Уфе goes to the geocoder as spoken and finds nothing.

None of this is a regression against master, and none of it blocks the merge. Worth a follow-up task so the sweep can be called finished.

Reviewed as part of a bottom-up pass over the whole open stack (#119 to #168). Merging: the data file is the right shape and `make test` is green at the top of the stack. **Four files still match Russian by hand.** V-529 found that the sweep list named files that do not exist. These four were missed the same way. One is the duplication this data file exists to end. `internal/router/numwords.go` holds `ruNumerals`, a second copy of the `cardinals` set. Both map spoken numbers to values and both stop around fifty. They disagree on the members: `ruNumerals` carries the oblique forms (`семи`, `двух`, `трёх`), the lexicon carries the English words and the gender variants. Months living in three files is the case named in `CLAUDE.md`, and this is the same case. A straight swap loses the case forms, so the fix is to add them to `lexicon_ru_v1.json` and read from it. `cmd/mavend/reminderbody.go` strips reminder times with five hand-written regexes over `через`, `часа|часов|минут[уы]`, `завтра|послезавтра|сегодня|вечером`. The day words are already `day_offsets`, and the hour words are already `hours_spoken`. `cmd/mavend/historyq.go` matches on truncated prefixes: `{"что я", "рассказ"}`, `{"что ты", "записал"}`. That is the defect V-528 fixed in `complaint.go`, where `лаг` matched `лагерь`. Its output claims a query source, so a miss sends the turn to the next source. `internal/weather/openmeteo.go` guesses declension by reversing endings, and `internal/morph` now answers that question. It also bails under four runes, so `Уфе` goes to the geocoder as spoken and finds nothing. None of this is a regression against master, and none of it blocks the merge. Worth a follow-up task so the sweep can be called finished.
Author
Contributor

Landed transitively. This branch is already an ancestor of master, so there is nothing left to merge and Gitea did not close the pull request on its own.

Reviewed as part of a bottom-up pass over the open stack. The four open findings from that pass are worth a follow-up task, and none of them blocks anything here:

  • internal/router/stage0.go has two grammars named rest-of-day-query, and the second is dead.
  • internal/router/numwords.go holds ruNumerals, a second copy of the lexicon cardinals.
  • cmd/mavend/reminderbody.go and cmd/mavend/historyq.go still match Russian by hand.
  • internal/weather/openmeteo.go guesses declension by reversing endings, and bails under four runes.
Landed transitively. This branch is already an ancestor of `master`, so there is nothing left to merge and Gitea did not close the pull request on its own. Reviewed as part of a bottom-up pass over the open stack. The four open findings from that pass are worth a follow-up task, and none of them blocks anything here: - `internal/router/stage0.go` has two grammars named `rest-of-day-query`, and the second is dead. - `internal/router/numwords.go` holds `ruNumerals`, a second copy of the lexicon `cardinals`. - `cmd/mavend/reminderbody.go` and `cmd/mavend/historyq.go` still match Russian by hand. - `internal/weather/openmeteo.go` guesses declension by reversing endings, and bails under four runes.
claude closed this pull request 2026-08-04 18:35:25 +02:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kami/Maven#164