Skip to content

fix: a holiday named after a weekday answers with the holiday - #374

Draft
openvoiceos-bot wants to merge 1 commit into
devfrom
fix/holiday-shadowing-and-partial-match
Draft

openvoiceos-bot wants to merge 1 commit into
devfrom
fix/holiday-shadowing-and-partial-match

Conversation

@openvoiceos-bot

Copy link
Copy Markdown
Contributor

What this changes

Finding 5 of reviewer-c's review of #369: a holiday whose own name carries the
calendar vocabulary of its language answers with a weekday instead of the
holiday.

extract_datetime runs the per-language engine first and asks the holiday layer
only when the engine read nothing. "good friday" therefore reaches the engine,
which reads "friday" and answers with the coming Friday, and the holiday layer —
which knows the date — is never asked.

The engine-first order is right everywhere else and is not reversed.
holiday_overrides_engine asks one narrow question: are the words the engine
consumed all words the holiday phrase itself covers?

  • "good friday" — the engine consumed "friday" and left "good", a word of the
    phrase. The holiday layer answers.
  • "play christmas music on friday" — the engine read a Friday that the phrase
    "christmas" does not cover. The engine's answer stands.

A text that names no holiday of its language never reaches chronologia:
_names_a_holiday is a table lookup and answers first.

Measured, anchor 25 September 2026 (a Friday)

Every expected date is reckoned independently of the parser. Western Easter 2027
is 28 March by the Gregorian computus, and the movable feasts are counted from
it: Palm Sunday −7, Maundy Thursday −3, Good Friday −2, Holy Saturday −1, Easter
Monday +1, Whit Monday +50, Shrove Tuesday −47, Ash Wednesday −46.

utterance origin/dev this branch holiday layer asked directly
good friday 2026-09-25 2027-03-26 2027-03-26
easter monday 2026-09-28 2027-03-29 2027-03-29
whit monday 2026-09-28 2027-05-17 2027-05-17
shrove tuesday 2026-09-29 2027-02-09 2027-02-09
ash wednesday 2026-09-30 2027-02-10 2027-02-10
maundy thursday 2026-10-01 2027-03-25 2027-03-25
holy saturday 2026-09-26 2027-03-27 2027-03-27
palm sunday 2026-09-27 2027-03-21 2027-03-21

Unchanged: "may day", "boxing day" and "earth day" already agreed; "labour day"
is declined by both sides.

Controls

  • "sunday" still answers 2026-09-27, the coming Sunday. A weekday that names no
    holiday is untouched.
  • "play christmas music on friday" still answers the Friday, not 25 December.
  • "boxing day", which the engine cannot read at all, still answers 2026-12-26
    through the unchanged None path.

Cost

The extra question runs only when the text names a holiday of its language.
Measured in one process after the language spec is loaded: "good friday" 7.2 ms,
"play christmas music on friday" 3.9 ms, "remind me on friday" 9.5 ms (no
holiday word, so no chronologia call), "what is the weather" 0.7 ms.
extract_datetime_spans on "play some christmas music" is 54 ms, so finding 1's
29.9 seconds stays fixed.

Failing-first

16 new assertions were written before the fix and all 16 failed on origin/dev
at a9c7ff4 — eight dates and eight remainders. The four controls passed before
and after. Whole suite after: 2892 passed, 3 skipped, 14 xfailed, 1797 subtests.

The other three findings of that review are chronologia's

Measured on this same tree and settled by chronologia's own tables, not by
opinion. They are filed as separate tasks and are not touched here.

  • Finding 3, "the hebrew new year" answering 1 January: chronologia's
    hebrew_new_year construction has one order,
    article? hebrew new year_word YEAR, which requires a year slot. With no
    year, nothing matches it, and new_year_ref takes the "new year" substring.
    new_year_ref's own docstring says it is kept a separate construction so that
    it "would [not] shadow _resolve_hebrew_new_year", so the grammar contradicts
    its stated design. A year-less order is the fix.
  • Finding 4, "when was easter" answering the next Easter: chronologia reads
    no verb tense. The docstring half is already corrected on dev; whether a
    date library should read a verb at all is a design question and is filed as a
    panel decision.
  • Finding 6, en-CA "thanksgiving" answering the United States date:
    CONFIRMED, where the review had it plausible.
    chronologia.extract_timespan("thanksgiving", lang="en", anchor=REF, jurisdiction=j) returns 2026-11-26 for US, CA, GB, DE and None alike. The
    well-known table's own comment says the surface is offered "only under the
    documented U.S. reading" and that a Canadian reference is "NOT silently
    resolved to the U.S. date" — which is what happens. ca.tab already carries
    the Canadian rule as nth_weekday | Thanksgiving Day | 10 2 0.

Evidence:
knowledge/wiki/audits/chronologia/t5128-date-parser-369-findings.md

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the fix label Sep 26, 2026
@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Synchronizing... Check results have been successfully retrieved. 📡

I've aggregated the results of the automated checks for this PR below.

⚖️ License Check

I've checked for any conflicting terms of service. 📜

✅ No license violations found.

Policy: Apache 2.0 (universal donor). StrongCopyleft / NetworkCopyleft / WeakCopyleft / Other / Error categories fail. MPL allowed.

🔨 Build Tests

I've checked the welds on your new features. 👨‍🏭

✅ All versions pass

Python Build Install Tests pytest
3.10 ✅ ✅ ✅ 2913 passed, 3 skipped, 14 xfailed, 58366 warnings, 2294 subtests passed in 160.88s (0:02:40)
3.11 ✅ ✅ ✅ 2913 passed, 3 skipped, 14 xfailed, 58366 warnings, 2294 subtests passed in 138.52s (0:02:18)
3.12 ✅ ✅ ✅ 2913 passed, 3 skipped, 14 xfailed, 58366 warnings, 2294 subtests passed in 161.67s (0:02:41)

📊 Coverage

Quantifying the quality of our test suite. 🧪

⚠️ 73.9% total coverage

Files below 80% coverage (32 files)
File Coverage Missing lines
ovos_date_parser/calendars.py 0.0% 2
ovos_date_parser/cycles.py 0.0% 2
ovos_date_parser/regnal.py 0.0% 2
ovos_date_parser/roman.py 0.0% 2
ovos_date_parser/dates_cs.py 53.3% 359
ovos_date_parser/dates_da.py 59.0% 246
ovos_date_parser/dates_uk.py 63.1% 343
ovos_date_parser/dates_nb.py 63.5% 179
ovos_date_parser/dates_nn.py 63.5% 179
ovos_date_parser/dates_ru.py 64.1% 299
ovos_date_parser/dates_it.py 64.5% 223
ovos_date_parser/dates_ca.py 64.8% 357
ovos_date_parser/dates_gl.py 66.1% 242
ovos_date_parser/dates_pl.py 66.3% 208
ovos_date_parser/dates_eu.py 66.6% 222
ovos_date_parser/dates_nl.py 66.7% 219
ovos_date_parser/dates_es.py 68.2% 229
ovos_date_parser/dates_ast.py 70.4% 219
ovos_date_parser/dates_en.py 71.0% 266
ovos_date_parser/dates_ro.py 71.5% 199
ovos_date_parser/dates_pt.py 71.7% 210
ovos_date_parser/dates_an.py 72.5% 172
ovos_date_parser/dates_bg.py 73.8% 106
ovos_date_parser/dates_hr.py 73.8% 107
ovos_date_parser/dates_fy.py 74.1% 158
ovos_date_parser/dates_sv.py 75.6% 144
ovos_date_parser/dates_oc.py 77.0% 161
ovos_date_parser/dates_el.py 77.2% 141
ovos_date_parser/dates_az.py 77.6% 127
ovos_date_parser/dates_sl.py 78.0% 86
ovos_date_parser/common.py 78.3% 20
ovos_date_parser/dates_de.py 78.4% 132

Full report: download the coverage-report artifact.


Automating the boring stuff so you don't have to! 🚀

@JarbasAl
JarbasAl force-pushed the fix/holiday-shadowing-and-partial-match branch from 50b8699 to 351ad89 Compare September 29, 2026 01:12
`extract_datetime` runs the per-language engine first and asks the holiday
layer only when the engine read nothing. A holiday whose own name is
written with the calendar vocabulary of its language — "good friday",
"palm sunday", "ash wednesday" — is therefore read as that weekday, and
the layer that knows the date is never asked. Eight of the twelve
weekday- and month-named English holidays answered with the coming
weekday: at an anchor of 25 September 2026, "good friday" answered
25 September, the anchor day, which is a Friday.

The engine-first order is right everywhere else, so it is not reversed.
`holiday_overrides_engine` asks one narrow question instead: are the words
the engine consumed all words the holiday phrase itself covers? They are
for "good friday", where the engine consumed "friday" and left "good".
They are not for "play christmas music on friday", where the engine read a
Friday the phrase "christmas" does not cover, and that answer stands.

The question costs nothing on a text that names no holiday of its
language: `_names_a_holiday` is a table lookup and answers first.

Measured at the same anchor: eight of eight now answer with the holiday,
"sunday" still answers with the coming Sunday, and "boxing day", which the
engine cannot read at all, is unchanged.

The review of this head asked for two things. The extent test compares a set
of folded words, so a weekday word written both inside the holiday name and
outside it cannot be told from one inside the name alone: the docstring now
says so, and two known-answer cells hold the answers the library gives for
"the friday before good friday" and "monday after easter monday" so the day
the extent becomes positional the cells report the change. A leftover
`if holiday is None: return None` below the line that returns `found` was
unreachable and said the opposite of it; it is deleted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants