Skip to content

fix: handle absent number/date without False sentinel or crash - #85

Draft
JarbasAl wants to merge 1 commit into
devfrom
fix/number-facts-handler-bugs
Draft

fix: handle absent number/date without False sentinel or crash#85
JarbasAl wants to merge 1 commit into
devfrom
fix/number-facts-handler-bugs

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Sep 4, 2026

Copy link
Copy Markdown
Member

🤖 Auto-generated by Claude Sonnet 5 via Claude Code — NOT human-reviewed. Verify before acting.

This fixes two handler bugs surfaced by skills-QA leads.

handle_numbers guarded on if number is not None, but extract_number returns False (not None) when nothing is found. Since False is not None is true, an unparsed number was forwarded straight into number_trivia(False), producing a spoken sentinel like a "False" fact instead of falling back to random trivia. The fix switches the guard to plain truthiness, matching how the sibling handle_math and handle_year handlers already treat this case.

handle_date unconditionally indexed the result of extract_datetime(...), but that call returns None when no date can be extracted from the utterance. A bare request such as "tell me a date fact" would then raise TypeError: 'NoneType' object is not subscriptable and surface as a skill error instead of degrading gracefully to a random date fact.

Both bugs have regression tests in test/unittests/test_random_fallback_handlers.py. I confirmed each test fails against the pre-fix code (a NUMBER_FACT_False sentinel leaks through in one case, a TypeError is raised in the other) and passes after the fix, using a patch-revert-run-restore cycle rather than trusting the test in isolation. The full suite (43 tests, unit + end-to-end) passes after the fix.

handle_numbers guarded with `if number is not None`, which is truthy
for extract_number's False sentinel, so an unparsed number leaked into
number_trivia() and spoke a NUMBER_FACT_False dialog instead of falling
back to random trivia. Guard on truthiness like the sibling handlers
already do.

handle_date unconditionally indexed extract_datetime()'s result, which
raises TypeError when nothing is extractable (e.g. "tell me a date
fact"), surfacing as skill.error instead of degrading to a random date
fact.

Fail-before: both new regression tests in
test/unittests/test_random_fallback_handlers.py fail against the
pre-fix code (NUMBER_FACT_False leaks through; handle_date raises
TypeError: 'NoneType' object is not subscriptable) and pass after the
fix. Full suite: 43 passed.
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

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 commented Sep 4, 2026

Copy link
Copy Markdown

Tada! The results of the latest automation run are here. 🎉

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

📋 Repo Health

I've checked the repo's hydration (aka documentation density). 💧

✅ All required files present.

Latest Version: 0.1.15a1

version.py — Version file
README.md — README
LICENSE — License file
pyproject.toml — pyproject.toml
⚠️ setup.py — setup.py
🗑️ MANIFEST.in — legacy: pyproject.toml is present; this file is no longer needed
CHANGELOG.md — Changelog
version.py has valid version block markers

🌍 Locale Build

Processing complete! Details follow. 📬

✅ Locale properly configured (114 files, 10 languages)

Locale directories found:

  • locale

Localization coverage:

  • locale: 114 files in 10 languages (ca-ES, pt-PT, de-DE, fr-FR, da-DK...)

pyproject.toml:[tool.setuptools.package-data.ovos_skill_number_facts] includes locale

  • locale/**/*

Build manifest: ✅ 228 locale files included in package

🔍 Lint

I've tidied up the results for you. 🧹

ruff: issues found — see job log

🎙️ Skill

Is it a bird? Is it a plane? No, it's a skill check result! 🦸

ℹ️ Not an OVOS skill repo — check skipped.

🏷️ Release Preview

The release train is fueling up! 🚂

Current: 0.1.15a1Next: 0.1.16a1

Signal Value
Label (none)
PR title fix: handle absent number/date without False sentinel or crash
Bump build

✅ PR title follows conventional commit format.


🚀 Release Channel Compatibility

Predicted next version: 0.1.16a1

Channel Status Note Current Constraint
Stable Compatible ovos-skill-number-facts>=0.1.12,<0.2.0
Testing Compatible ovos-skill-number-facts>=0.1.12,<1.0.0
Alpha Compatible ovos-skill-number-facts>=0.1.15a1

🧪 Spec Lint

Checking if there's anything else we need to do. 📋

12 error(s), 10 warning(s)

locale/ca-ES/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/ca-ES/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/da-DK/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/da-DK/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/de-DE/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/de-DE/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/de-DE/api.voc: error: single-branch group (Pi): a group must offer a choice between at least two branches  [in: '(Zahl) (Pi)']
locale/en-US/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/en-US/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/en-US/no.number.found.dialog: error: base name 'no.number.found' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/es-ES/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/es-ES/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/eu-ES/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/eu-ES/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/fr-FR/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/fr-FR/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/gl-ES/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/gl-ES/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/kab/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)
locale/kab/Numbers.voc: warning: file name should be lowercase (OVOS-INTENT-2 §2)
locale/pt-PT/Numbers.voc: error: base name 'Numbers' must be lowercase ASCII letters, digits and underscores only (OVOS-INTENT-2 §2)

📊 Coverage

Exploring the coverage frontier of your PR. 🚀

48.2% total coverage

Per-file coverage (2 files)
File Coverage Missing lines
version.py 0.0% 5
__init__.py 51.3% 38

Full report: download the coverage-report artifact.

🔒 Security (pip-audit)

Checking the vault for any security leaks. 🔓

✅ No known vulnerabilities found (78 packages scanned).

⚖️ License Check

I've audited the 'About' files for accuracy. 📄

✅ No license violations found.

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

🔨 Build Tests

The build bots have finished their assembly. 🤖

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

🔌 Skill Tests (ovoscope)

I've performed a deep-tissue massage on your skill's logic. 💆‍♂️

0/29 passed, 29 errors

❌ **TestDateTrivia** — 0/1
Test Result
test_date_fact ❌ error
❌ **TestMathTrivia** — 0/1
Test Result
test_math_fact ❌ error
❌ **TestNumberTrivia** — 0/3
Test Result
test_number_fact ❌ error
test_random_number_fact ❌ error
test_give_me_a_fact_about_numbers ❌ error
❌ **TestTriviaRoutingWithoutAdapt** — 0/4
Test Result
test_math_fact ❌ error
test_date_fact ❌ error
test_number_fact ❌ error
test_year_fact ❌ error
❌ **TestYearTrivia** — 0/1
Test Result
test_year_fact ❌ error
❌ **test_golden_utterance[fact about december 3]** — 0/1
Test Result
test_golden_utterance[fact about december 3] ❌ error
❌ **test_golden_utterance[fact about the date 5]** — 0/1
Test Result
test_golden_utterance[fact about the date 5] ❌ error
❌ **test_golden_utterance[fact about the year 1992]** — 0/1
Test Result
test_golden_utterance[fact about the year 1992] ❌ error
❌ **test_golden_utterance[fact about today]** — 0/1
Test Result
test_golden_utterance[fact about today] ❌ error
❌ **test_golden_utterance[give me a fact about the number 42]** — 0/1
Test Result
test_golden_utterance[give me a fact about the number 42] ❌ error
❌ **test_golden_utterance[give me a math fact]** — 0/1
Test Result
test_golden_utterance[give me a math fact] ❌ error
❌ **test_golden_utterance[give me a mathematical trivia]** — 0/1
Test Result
test_golden_utterance[give me a mathematical trivia] ❌ error
❌ **test_golden_utterance[give me a trivia about the year 1999]** — 0/1
Test Result
test_golden_utterance[give me a trivia about the year 1999] ❌ error
❌ **test_golden_utterance[number fact 7]** — 0/1
Test Result
test_golden_utterance[number fact 7] ❌ error
❌ **test_golden_utterance[tell me a fact about mathematics]** — 0/1
Test Result
test_golden_utterance[tell me a fact about mathematics] ❌ error
❌ **test_golden_utterance[tell me a random number fact]** — 0/1
Test Result
test_golden_utterance[tell me a random number fact] ❌ error
❌ **test_golden_utterance[year fact 2001]** — 0/1
Test Result
test_golden_utterance[year fact 2001] ❌ error
❌ **test_negative_confusable_not_claimed[play a random song]** — 0/1
Test Result
test_negative_confusable_not_claimed[play a random song] ❌ error
❌ **test_negative_confusable_not_claimed[play some music]** — 0/1
Test Result
test_negative_confusable_not_claimed[play some music] ❌ error
❌ **test_negative_confusable_not_claimed[set a timer for 5 minutes]** — 0/1
Test Result
test_negative_confusable_not_claimed[set a timer for 5 minutes] ❌ error
❌ **test_negative_confusable_not_claimed[tell me a random joke]** — 0/1
Test Result
test_negative_confusable_not_claimed[tell me a random joke] ❌ error
❌ **test_negative_confusable_not_claimed[what year is it]** — 0/1
Test Result
test_negative_confusable_not_claimed[what year is it] ❌ error
❌ **test_negative_confusable_not_claimed[what's the weather]** — 0/1
Test Result
test_negative_confusable_not_claimed[what's the weather] ❌ error
❌ **test_negative_confusable_not_claimed[what's today's date]** — 0/1
Test Result
test_negative_confusable_not_claimed[what's today's date] ❌ error

🚌 Bus Coverage

Ensuring the bus logic is battle-tested. ⚔️

⚠️ Bus coverage report unavailable — check the job log.


Transmitted from the OVOS mothership. 🛸

@github-actions github-actions Bot added the fix label Sep 4, 2026
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.

1 participant