fix(locale): refuse a months.voc that is not exactly twelve lines - #379
openvoiceos-bot wants to merge 1 commit into
Conversation
months.voc is read BY POSITION: line N is month N. The guard added on #366 refused only an index PAST the twelfth, so a file with too FEW lines never tripped it and every month after the gap answered as the month before it. Measured on an fr tree with mars deleted, 11 lines, before this change: la derniere semaine de avril -> 2018-03-26 la 1 semaine de avril -> 2018-03-05 le 31 jour de avril -> 2018-03-31 No warning and no exception. "avril" answered March. The fix sits in two places, because the two layers have different contracts and only one of them knows the locale. ScopedVocabulary has no locale field; load_scoped_vocabulary(lang, locale_dir) does. - The LOADER refuses the file and names the locale and the count. That is the loud half, and the same contract _positional_voc_reader already states for a malformed line. - The SCAN keeps its softer contract and gains a backstop for a table built in memory or by a caller that did not come through the loader. The guard is asymmetric on purpose. More than twelve entries: only the ones past the twelfth cannot be named, so a real month must still answer, which TestAMissizedFileDoesNotRaise and its control pin on a 13-entry table. Fewer than twelve: every entry at or after the gap is the wrong month and nothing says where the gap is, so no index is trustworthy and the table is refused whole. A flat `!= 12` would have broken that existing test. TestAShortMonthsVocIsRefused adds the 11-line fixture. Against dev 6bda4d9 with only the test file applied: 4 failed, 3 passed, the three passes being the controls (the untouched fixture still loads twelve, and the same utterances answer April on a full table), so the failures are the guard and not a phrase that never matched. Not fixed here: `le 31 jour de avril` raises ValueError "day is out of range for month" from ranges.get_date_ordinal on a CORRECT table, because April has 30 days and replace(day=) is unguarded. Reproduced on dev too, so it is pre-existing. It is why the reported symptom could answer "31 March" at all. Filed as T-6763 and excluded from the controls, with the exclusion stated in the test rather than left silent. T-4767, from reviewer-b's T-4673. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Tada! The results of the latest automation run are here. 🎉I've aggregated the results of the automated checks for this PR below. ⚖️ License CheckThe license check is now finished. 🏁 ✅ No license violations found. Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed. 📊 CoverageCalculating the test-to-code ratio. ➗ Files below 80% coverage (32 files)
Full report: download the 🔨 Build TestsEnsuring the code is correctly packaged and ready. 📦 ✅ All versions pass
Crafting a better voice assistant, one commit at a time 🎙️ |
months.vocis read by position: line N is month N. The guard added on#366refused only an index past the twelfth, so a file with too FEW linesnever tripped it, and every month after the gap answered as the month before
it.
Measured on an
frtree withmarsdeleted, 11 lines, before this change:No warning and no exception. "avril" answered March.
Two places, because the two layers have different contracts
This repository states one contract per layer: loading fails loud, scanning
fails soft. The task asked for a failure that names "the locale and the
count", and only one layer has the locale —
ScopedVocabularycarriesunits,months,seasons,ordinal,of,article,year_wordand nolocale;
load_scoped_vocabulary(lang, locale_dir)knows it.The loader refuses the file:
The scan keeps its softer contract and gains a backstop, for a table built
in memory or by a caller that did not come through the loader.
The guard is asymmetric, deliberately
A flat
len(vocab.months) != 12would have been wrong, because the two halvesof a wrong count do not mean the same thing.
Indices 0-11 are still the real months, so a real month must still answer.
TestAMissizedFileDoesNotRaiseand its control pin exactly that on a13-entry table, and a flat inequality would have broken them.
and nothing in the table says where the gap is. No index can be trusted, so
the table is refused whole.
So the guard is
index is None or index >= 12 or len(vocab.months) < 12.Evidence
TestAShortMonthsVocIsRefused, five cases. Againstdev6bda4d9with onlythe test file applied:
The three that pass on
devare the controls — the untouched fixture stillloads twelve, and the same utterances answer April on a full table — so the
failures are the guard and not a phrase that never matched.
With this change, the module is
15 passed, 532 subtests passed.The full local suite reached 93% with zero failures and was then stopped: the
box was at load average 52 and the process was starved at 0.0% CPU, competing
with other lanes. CI runs it here.
Not fixed here
le 31 jour de avrilagainst a correct table raisesValueError: day is out of range for monthfromranges.get_date_ordinal,which calls
ref_date.replace(day=ordinal)unguarded. April has 30 days.Reproduced on
origin/dev6bda4d9as well, so it is pre-existing and notintroduced here — and it is why the reported symptom could answer "31 March"
at all, since the shifted table landed the 31st on a month that has one.
Filed as T-6763 with the design question of whether an impossible day
answers
Noneor clamps. It is excluded from this branch's controls for thatreason, and the exclusion is stated in the test docstring rather than left
silent.
T-4767, from reviewer-b's T-4673.
🤖 Generated with Claude Code