Skip to content

fix: guard optional None blacklisted_skills/intents (SESSION-1 §3)#780

Merged
JarbasAl merged 1 commit into
devfrom
fix/guard-none-blacklists
Jun 27, 2026
Merged

fix: guard optional None blacklisted_skills/intents (SESSION-1 §3)#780
JarbasAl merged 1 commit into
devfrom
fix/guard-none-blacklists

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Jun 27, 2026

Copy link
Copy Markdown
Member

blacklisted_skills / blacklisted_intents are optional SESSION-1 §3 fields and are legally None when a Session doesn't carry an empty list. The stop / fallback / converse / intent services tested membership directly (x in sess.blacklisted_skills) → TypeError: 'NoneType' object is not iterable, aborting the stop ping/pong cascade, the fallback query cycle, and the converse round-trip before any bus traffic.

Guards every use with (... or []) (7 call sites across stop_service / fallback_service / converse_service / service.py).

How it was found: live integration testing in the OVOS spec-compliance harness (ovos-bus-client 2.x leaves these fields None); the harness conformance suite went green once both this and the padacioso lru_cache fix (OpenVoiceOS/padacioso#60) landed.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved blacklist handling across intent, fallback, converse, and stop flows.
    • The app now safely treats missing blacklist values as empty lists, preventing errors when filtering skills or intents.
    • Blacklisted skills and intents are now excluded more consistently during matching and command handling.

blacklisted_skills/blacklisted_intents are OPTIONAL SESSION-1 fields and are
legally absent (None) when a Session does not round-trip an empty list through
SessionManager. The stop, fallback, converse and intent services tested
membership/iteration directly (`x in sess.blacklisted_skills`), raising
TypeError: 'NoneType' object is not iterable and aborting the stop ping/pong
cascade, the fallback query cycle and the converse round-trip before any bus
traffic. Guard each use with `(... or [])`.

Surfaced by live integration testing in the OVOS spec-compliance harness
(ovos-bus-client 2.x leaves these fields None); validated end-to-end there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added the fix label Jun 27, 2026
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1cae913e-2794-438a-b162-0e181c1af16a

📥 Commits

Reviewing files that changed from the base of the PR and between ab2642c and b61036b.

📒 Files selected for processing (4)
  • ovos_core/intent_services/converse_service.py
  • ovos_core/intent_services/fallback_service.py
  • ovos_core/intent_services/service.py
  • ovos_core/intent_services/stop_service.py

📝 Walkthrough

Walkthrough

Blacklist membership checks in utterance matching, converse handling, fallback selection, and stop-skill collection now default missing blacklist lists to empty lists.

Changes

Intent-service blacklist checks

Layer / File(s) Summary
Utterance match and converse guards
ovos_core/intent_services/service.py, ovos_core/intent_services/converse_service.py
handle_utterance and converse skill matching now use empty-list defaults when checking blacklisted skills and intents.
Fallback and stop guards
ovos_core/intent_services/fallback_service.py, ovos_core/intent_services/stop_service.py
Fallback candidate filtering, fallback-range skipping, and stop-skill collection now use empty-list defaults for blacklisted skills.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

Hop hop, I checked the lists with care,
[] when none were there 🐰
No blacklisted skill could trip the air,
The bunny paths now filter fair,
Thump-thump, all safe and square!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: guarding optional None blacklisted_skills/intents in session handling.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/guard-none-blacklists

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 Jun 27, 2026

Copy link
Copy Markdown

I've completed my sweep! Here's the situation. 🧹

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

🌍 Locale Build

Just a quick heads-up on the latest check. 🛎️

✅ Locale properly configured (64 files, 17 languages)

Locale directories found:

  • ovos_core/intent_services/locale

Localization coverage:

  • ovos_core/intent_services/locale: 64 files in 17 languages (eu-ES, es-es, it-it, de-de, uk-ua...)

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

  • intent_services/locale/*/*.voc

Build manifest: ✅ 31 locale files included in package

📋 Repo Health

Ensuring the repo's immune system is strong (aka security checks). 🛡️

✅ All required files present.

Latest Version: 2.2.0a2

ovos_core/version.py — Version file
README.md — README
LICENSE — License file
pyproject.toml — pyproject.toml
⚠️ setup.py — setup.py
CHANGELOG.md — Changelog
ovos_core/version.py has valid version block markers

🔒 Security (pip-audit)

I've audited the access control lists. 📋

✅ No known vulnerabilities found (109 packages scanned).

🏷️ Release Preview

I've checked the release assets for completeness. 💾

Current: 2.2.0a2Next: 2.2.1a1

Signal Value
Label (none)
PR title fix: guard optional None blacklisted_skills/intents (SESSION-1 §3)
Bump build

✅ PR title follows conventional commit format.


🚀 Release Channel Compatibility

Predicted next version: 2.2.1a1

Channel Status Note Current Constraint
Stable Too new (must be <1.4.0) ovos-core>=1.3.1,<1.4.0
Testing Compatible ovos-core>=2.1.1,<3.0.0
Alpha Compatible ovos-core>=2.2.0a2

📊 Coverage

Ensuring every change is backed by a test. ✅

⚠️ 60.8% total coverage

Files below 80% coverage (8 files)
File Coverage Missing lines
ovos_core/__init__.py 0.0% 7
ovos_core/__main__.py 0.0% 26
ovos_core/intent_services/__init__.py 0.0% 1
ovos_core/version.py 0.0% 18
ovos_core/skill_installer.py 42.3% 139
ovos_core/intent_services/service.py 50.0% 163
ovos_core/skill_manager.py 58.8% 173
ovos_core/transformers.py 66.0% 49

Full report: download the coverage-report artifact.

🔨 Build Tests

Checking the blueprint against the actual construction. 📐

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

⚖️ License Check

The license report is filed and ready for review. 📁

✅ No license violations found.

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

🔌 Skill Tests (ovoscope)

Ensuring the skill's responses are natural and intuitive. 🗣️

2/36 passed

❌ **TestAdaptIntent** — 0/4
Test Result
test_adapt_match ❌ subtests passed
test_intent_blacklist ❌ subtests passed
test_skill_blacklist ❌ subtests passed
test_padatious_no_match ❌ subtests passed
❌ **TestCancelIntentMidSentence** — 0/1
Test Result
test_cancel_match ❌ subtests passed
❌ **TestConverse** — 0/1
Test Result
test_parrot_mode ❌ subtests passed
❌ **TestCountSkills** — 0/4
Test Result
test_count_infinity_global ❌ subtests passed
test_count ❌ subtests passed
test_count_infinity_active ❌ subtests passed
test_count_infinity_stop_low ❌ subtests passed
❌ **TestDeactivate** — 2/3
Test Result
test_deactivate ✅ passed
test_activate ✅ passed
test_deactivate_inside_converse ❌ subtests passed
❌ **TestFallback** — 0/1
Test Result
test_fallback_match ❌ subtests passed
❌ **TestGlobalStopVocWithActiveSkill** — 0/1
Test Result
test_global_stop_voc_with_active_skill ❌ subtests passed
❌ **TestGlobalStopVocabulary** — 0/2
Test Result
test_global_stop_voc_no_active_skills ❌ subtests passed
test_stop_voc_exact_still_works ❌ subtests passed
❌ **TestIntentPipelineRouting** — 0/4
Test Result
test_high_priority_stage_handles_before_low ❌ subtests passed
test_padatious_intent_matched ❌ subtests passed
test_no_match_produces_intent_failure ❌ subtests passed
test_blacklisted_skill_falls_through_to_failure ❌ subtests passed
❌ **TestLangDisambiguation** — 0/4
Test Result
test_lang_text_detection ❌ subtests passed
test_metadata_preferred_over_text_detection ❌ subtests passed
test_stt_lang ❌ subtests passed
test_invalid_lang_detection ❌ subtests passed
❌ **TestNoSkills** — 0/2
Test Result
test_routing ❌ subtests passed
test_complete_failure ❌ subtests passed
❌ **TestPadatiousIntent** — 0/4
Test Result
test_intent_blacklist ❌ subtests passed
test_padatious_match ❌ subtests passed
test_skill_blacklist ❌ subtests passed
test_adapt_no_match ❌ subtests passed
❌ **TestStopNoSkills** — 0/3
Test Result
test_not_exact_med ❌ subtests passed
test_exact ❌ subtests passed
test_not_exact_high ❌ subtests passed
❌ **TestStopServiceAsSkill** — 0/1
Test Result
test_stop_service_emits_activate_and_stop_response ❌ subtests passed
❌ **TestStopSkillCanHandleFalse** — 0/1
Test Result
test_stop_with_active_skill_ping_pong ❌ subtests passed

🚌 Bus Coverage

Checking the insulation of our event handlers. 🏠

🔴 Coverage Summary

Metric Status Coverage
Listeners ██░░░░░░░░ 27.7% 66/238 handlers
Emitters ██████████ 100% 60/60 observed
Assertions █████████░ 98% 59/60 asserted

📊 Per-Skill Breakdown

Skill Listeners Observed Asserted
AdaptPipeline 4/7 (57.1%) 0/0 0/0
ConverseService 3/4 (75.0%) 0/0 0/0
DomainAdaptPipeline 4/7 (57.1%) 0/0 0/0
FallbackService 2/2 (100.0%) 0/0 0/0
HierarchicalAdaptPipeline 4/7 (57.1%) 0/0 0/0
IntentService 3/4 (75.0%) 0/0 0/0
Model2VecIntentPipeline 3/5 (60.0%) 0/0 0/0
PadaciosoPipeline 2/4 (50.0%) 0/0 0/0
PadatiousPipeline 4/8 (50.0%) 0/0 0/0
SkillManager 0/4 (0.0%) 0/0 0/0
__core__ 7/36 (19.4%) 15/15 15/15
ovos-skill-count.openvoiceos 4/20 (20.0%) 8/8 7/8
ovos-skill-fallback-unknown.openvoiceos 3/21 (14.3%) 2/2 2/2
ovos-skill-hello-world.openvoiceos 3/24 (12.5%) 7/7 7/7
ovos-skill-parrot.openvoiceos 8/33 (24.2%) 10/10 10/10
stop.openvoiceos 3/21 (14.3%) 7/7 7/7
test_activation.openvoiceos 9/27 (33.3%) 11/11 11/11
type 0/4 (0.0%) 0/0 0/0
🔍 Detailed Message Type Breakdown

AdaptPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
    ✅ Covered Listeners:
  • detach_skill (4829x)
  • intent.service.adapt.manifest.get (7081x)
  • register_intent (676x)
  • register_vocab (138692x)

ConverseService

⚠️ Uncovered Listeners:

  • intent.service.active_skills.get
    ✅ Covered Listeners:
  • converse:skill (149x)
  • intent.service.skills.activate (57x)
  • intent.service.skills.deactivate (169x)

DomainAdaptPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
    ✅ Covered Listeners:
  • detach_skill (4829x)
  • intent.service.adapt.manifest.get (7081x)
  • register_intent (676x)
  • register_vocab (138692x)

FallbackService

✅ Covered Listeners:

  • ovos.skills.fallback.deregister (112x)
  • ovos.skills.fallback.register (59x)

HierarchicalAdaptPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
    ✅ Covered Listeners:
  • detach_skill (4829x)
  • intent.service.adapt.manifest.get (7081x)
  • register_intent (676x)
  • register_vocab (138692x)

IntentService

⚠️ Uncovered Listeners:

  • intent.service.intent.get (Intent)
    ✅ Covered Listeners:
  • intent.service.pipelines.reload (2660x)
  • intent.service.skills.deactivate (169x)
  • ovos.utterance.handle (1443x)

Model2VecIntentPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • mycroft.ready
    ✅ Covered Listeners:
  • detach_skill (4829x)
  • padatious:register_intent (1576x)
  • register_intent (676x)

PadaciosoPipeline

⚠️ Uncovered Listeners:

  • padatious:register_entity (Intent)
  • detach_intent
    ✅ Covered Listeners:
  • detach_skill (4829x)
  • padatious:register_intent (1576x)

PadatiousPipeline

⚠️ Uncovered Listeners:

  • padatious:register_entity (Intent)
  • detach_intent
  • intent.service.padatious.entities.manifest.get
  • intent.service.padatious.get
    ✅ Covered Listeners:
  • detach_skill (4829x)
  • intent.service.padatious.manifest.get (7081x)
  • mycroft.skills.train (2660x)
  • padatious:register_intent (1576x)

SkillManager

⚠️ Uncovered Listeners:

  • skillmanager.activate
  • skillmanager.deactivate
  • skillmanager.keep
  • skillmanager.list

__core__

⚠️ Uncovered Listeners:

  • add_context
  • clear_context
  • message
  • mycroft.ovos-skill-count.openvoiceos.all_loaded
  • mycroft.ovos-skill-count.openvoiceos.is_alive
  • mycroft.ovos-skill-count.openvoiceos.is_ready
  • mycroft.ovos-skill-fallback-unknown.openvoiceos.all_loaded
  • mycroft.ovos-skill-fallback-unknown.openvoiceos.is_alive
  • mycroft.ovos-skill-fallback-unknown.openvoiceos.is_ready
  • mycroft.ovos-skill-hello-world.openvoiceos.all_loaded
  • mycroft.ovos-skill-hello-world.openvoiceos.is_alive
  • mycroft.ovos-skill-hello-world.openvoiceos.is_ready
  • mycroft.ovos-skill-parrot.openvoiceos.all_loaded
  • mycroft.ovos-skill-parrot.openvoiceos.is_alive
  • mycroft.ovos-skill-parrot.openvoiceos.is_ready
  • mycroft.test_activation.openvoiceos.all_loaded
  • mycroft.test_activation.openvoiceos.is_alive
  • mycroft.test_activation.openvoiceos.is_ready
  • ovos-skill-count.openvoiceos.set
  • ovos-skill-fallback-unknown.openvoiceos.set
  • ovos-skill-hello-world.openvoiceos.set
  • ovos-skill-parrot.openvoiceos.set
  • ovos.session.sync
  • ovos.skills.fallback.force_timeout
  • ovos.skills.fallback.ovos-skill-fallback-unknown.openvoiceos
  • remove_context
  • skill.converse.get_response.disable
  • skill.converse.get_response.enable
  • test_activation.openvoiceos.set
    ✅ Covered Listeners:
  • ovos-skill-count.openvoiceos.stop.response (394x)
  • ovos.session.update_default (2942x)
  • ovos.skills.converse.force_timeout (200x)
  • ovos.skills.fallback.pong (58x)
  • ovos.utterance.handled (2622x)
  • skill.converse.pong (167x)
  • skill.stop.pong (216x)

📤 Emitters:

  • complete_intent_failure (Asserted ✅)
  • mycroft.audio.play_sound (Asserted ✅)
  • ovos-skill-count.openvoiceos.stop.ping (Asserted ✅)
  • ovos-skill-parrot.openvoiceos.converse.ping (Asserted ✅)
  • ovos.skills.fallback.ovos-skill-fallback-unknown.openvoiceos.request (Asserted ✅)
  • ovos.skills.fallback.ovos-skill-fallback-unknown.openvoiceos.response (Asserted ✅)
  • ovos.skills.fallback.ovos-skill-fallback-unknown.openvoiceos.start (Asserted ✅)
  • ovos.skills.fallback.ping (Asserted ✅)
  • ovos.utterance.cancelled (Asserted ✅)
  • ovos.utterance.handle (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • recognizer_loop:utterance (Asserted ✅)
  • test_activate (Asserted ✅)
  • test_activation.openvoiceos.converse.ping (Asserted ✅)
  • test_deactivate (Asserted ✅)

ovos-skill-count.openvoiceos

⚠️ Uncovered Listeners:

  • question:action (Intent)
  • question:action.ovos-skill-count.openvoiceos (Intent)
  • question:query (Intent)
  • homescreen.metadata.get
  • mycroft.ovos-skill-count.openvoiceos.all_loaded
  • mycroft.ovos-skill-count.openvoiceos.is_alive
  • mycroft.ovos-skill-count.openvoiceos.is_ready
  • mycroft.skill.disable_intent
  • mycroft.skill.enable_intent
  • mycroft.skill.remove_cross_context
  • mycroft.skill.set_cross_context
  • mycroft.skills.settings.changed
  • ovos-skill-count.openvoiceos.converse.get_response
  • ovos-skill-count.openvoiceos.set
  • ovos.common_query.ping
  • ovos.skills.settings_changed
    ✅ Covered Listeners:
  • mycroft.stop (627x)
  • ovos-skill-count.openvoiceos.stop (217x)
  • ovos-skill-count.openvoiceos.stop.ping (217x)
  • ovos-skill-count.openvoiceos:count_to_N.intent (501x)

📤 Emitters:

  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • ovos-skill-count.openvoiceos.activate (Asserted ✅)
  • ovos-skill-count.openvoiceos.stop.response (Asserted ✅)
  • ovos-skill-count.openvoiceos:count_to_N.intent (Asserted ✅)
  • ovos.skills.converse.force_timeout (Not Asserted ⚠️)
  • ovos.utterance.handled (Asserted ✅)
  • skill.stop.pong (Asserted ✅)

ovos-skill-fallback-unknown.openvoiceos

⚠️ Uncovered Listeners:

  • question:action (Intent)
  • question:action.ovos-skill-fallback-unknown.openvoiceos (Intent)
  • question:query (Intent)
  • homescreen.metadata.get
  • mycroft.ovos-skill-fallback-unknown.openvoiceos.all_loaded
  • mycroft.ovos-skill-fallback-unknown.openvoiceos.is_alive
  • mycroft.ovos-skill-fallback-unknown.openvoiceos.is_ready
  • mycroft.skill.disable_intent
  • mycroft.skill.enable_intent
  • mycroft.skill.remove_cross_context
  • mycroft.skill.set_cross_context
  • mycroft.skills.settings.changed
  • ovos-skill-fallback-unknown.openvoiceos.converse.get_response
  • ovos-skill-fallback-unknown.openvoiceos.set
  • ovos-skill-fallback-unknown.openvoiceos.stop
  • ovos-skill-fallback-unknown.openvoiceos.stop.ping
  • ovos.common_query.ping
  • ovos.skills.settings_changed
    ✅ Covered Listeners:
  • mycroft.stop (369x)
  • ovos.skills.fallback.ovos-skill-fallback-unknown.openvoiceos.request (59x)
  • ovos.skills.fallback.ping (59x)

📤 Emitters:

  • ovos.skills.fallback.pong (Asserted ✅)
  • ovos.utterance.speak (Asserted ✅)

ovos-skill-hello-world.openvoiceos

⚠️ Uncovered Listeners:

  • ovos-skill-hello-world.openvoiceos:HowAreYou.intent (Intent)
  • ovos-skill-hello-world.openvoiceos:ThankYouIntent (Intent)
  • question:action (Intent)
  • question:action.ovos-skill-hello-world.openvoiceos (Intent)
  • question:query (Intent)
  • hello.world
  • homescreen.metadata.get
  • mycroft.ovos-skill-hello-world.openvoiceos.all_loaded
  • mycroft.ovos-skill-hello-world.openvoiceos.is_alive
  • mycroft.ovos-skill-hello-world.openvoiceos.is_ready
  • mycroft.skill.disable_intent
  • mycroft.skill.enable_intent
  • mycroft.skill.remove_cross_context
  • mycroft.skill.set_cross_context
  • mycroft.skills.settings.changed
  • ovos-skill-hello-world.openvoiceos.converse.get_response
  • ovos-skill-hello-world.openvoiceos.set
  • ovos-skill-hello-world.openvoiceos.stop
  • ovos-skill-hello-world.openvoiceos.stop.ping
  • ovos.common_query.ping
  • ovos.skills.settings_changed
    ✅ Covered Listeners:
  • mycroft.stop (433x)
  • ovos-skill-hello-world.openvoiceos:Greetings.intent (11x)
  • ovos-skill-hello-world.openvoiceos:HelloWorldIntent (75x)

📤 Emitters:

  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • ovos-skill-hello-world.openvoiceos.activate (Asserted ✅)
  • ovos-skill-hello-world.openvoiceos:Greetings.intent (Asserted ✅)
  • ovos-skill-hello-world.openvoiceos:HelloWorldIntent (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • ovos.utterance.speak (Asserted ✅)

ovos-skill-parrot.openvoiceos

⚠️ Uncovered Listeners:

  • ovos-skill-parrot.openvoiceos:did.you.hear.me.intent (Intent)
  • ovos-skill-parrot.openvoiceos:repeat.stt.intent (Intent)
  • ovos-skill-parrot.openvoiceos:repeat.tts.intent (Intent)
  • ovos-skill-parrot.openvoiceos:speak.intent (Intent)
  • ovos-skill-parrot.openvoiceos:stop_parrot.intent (Intent)
  • question:action (Intent)
  • question:action.ovos-skill-parrot.openvoiceos (Intent)
  • question:query (Intent)
  • homescreen.metadata.get
  • mycroft.ovos-skill-parrot.openvoiceos.all_loaded
  • mycroft.ovos-skill-parrot.openvoiceos.is_alive
  • mycroft.ovos-skill-parrot.openvoiceos.is_ready
  • mycroft.skill.disable_intent
  • mycroft.skill.enable_intent
  • mycroft.skill.remove_cross_context
  • mycroft.skill.set_cross_context
  • mycroft.skills.settings.changed
  • ovos-skill-parrot.openvoiceos.converse.get_response
  • ovos-skill-parrot.openvoiceos.deactivate
  • ovos-skill-parrot.openvoiceos.set
  • ovos-skill-parrot.openvoiceos.stop
  • ovos-skill-parrot.openvoiceos.stop.ping
  • ovos.common_query.ping
  • ovos.skills.settings_changed
  • speak
    ✅ Covered Listeners:
  • intent.service.skills.activated (10x)
  • intent.service.skills.deactivated (30x)
  • mycroft.stop (140x)
  • ovos-skill-parrot.openvoiceos.activate (57x)
  • ovos-skill-parrot.openvoiceos.converse.ping (57x)
  • ovos-skill-parrot.openvoiceos.converse.request (38x)
  • ovos-skill-parrot.openvoiceos:start_parrot.intent (19x)
  • recognizer_loop:utterance (392x)

📤 Emitters:

  • converse:skill (Asserted ✅)
  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • ovos-skill-parrot.openvoiceos.activate (Asserted ✅)
  • ovos-skill-parrot.openvoiceos.converse.request (Asserted ✅)
  • ovos-skill-parrot.openvoiceos:start_parrot.intent (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • ovos.utterance.speak (Asserted ✅)
  • skill.converse.pong (Asserted ✅)
  • skill.converse.response (Asserted ✅)

stop.openvoiceos

⚠️ Uncovered Listeners:

  • question:action (Intent)
  • question:action.stop.openvoiceos (Intent)
  • question:query (Intent)
  • homescreen.metadata.get
  • mycroft.skill.disable_intent
  • mycroft.skill.enable_intent
  • mycroft.skill.remove_cross_context
  • mycroft.skill.set_cross_context
  • mycroft.skills.settings.changed
  • mycroft.stop.openvoiceos.all_loaded
  • mycroft.stop.openvoiceos.is_alive
  • mycroft.stop.openvoiceos.is_ready
  • ovos.common_query.ping
  • ovos.skills.settings_changed
  • stop.openvoiceos.converse.get_response
  • stop.openvoiceos.set
  • stop.openvoiceos.stop
  • stop.openvoiceos.stop.ping
    ✅ Covered Listeners:
  • mycroft.stop (637x)
  • stop:global (637x)
  • stop:skill (217x)

📤 Emitters:

  • mycroft.stop (Asserted ✅)
  • ovos-skill-count.openvoiceos.stop (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • stop.openvoiceos.activate (Asserted ✅)
  • stop.openvoiceos.stop.response (Asserted ✅)
  • stop:global (Asserted ✅)
  • stop:skill (Asserted ✅)

test_activation.openvoiceos

⚠️ Uncovered Listeners:

  • question:action (Intent)
  • question:action.test_activation.openvoiceos (Intent)
  • question:query (Intent)
  • homescreen.metadata.get
  • mycroft.skill.disable_intent
  • mycroft.skill.enable_intent
  • mycroft.skill.remove_cross_context
  • mycroft.skill.set_cross_context
  • mycroft.skills.settings.changed
  • mycroft.test_activation.openvoiceos.all_loaded
  • mycroft.test_activation.openvoiceos.is_alive
  • mycroft.test_activation.openvoiceos.is_ready
  • ovos.common_query.ping
  • ovos.skills.settings_changed
  • test_activation.openvoiceos.converse.get_response
  • test_activation.openvoiceos.set
  • test_activation.openvoiceos.stop
  • test_activation.openvoiceos.stop.ping
    ✅ Covered Listeners:
  • intent.service.skills.activated (57x)
  • intent.service.skills.deactivated (169x)
  • mycroft.stop (593x)
  • test_activate (57x)
  • test_activation.openvoiceos.activate (168x)
  • test_activation.openvoiceos.converse.ping (111x)
  • test_activation.openvoiceos.converse.request (111x)
  • test_activation.openvoiceos.deactivate (169x)
  • test_deactivate (58x)

📤 Emitters:

  • converse:skill (Asserted ✅)
  • intent.service.skills.activate (Asserted ✅)
  • intent.service.skills.activated (Asserted ✅)
  • intent.service.skills.deactivate (Asserted ✅)
  • intent.service.skills.deactivated (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • skill.converse.pong (Asserted ✅)
  • skill.converse.response (Asserted ✅)
  • test_activation.openvoiceos.activate (Asserted ✅)
  • test_activation.openvoiceos.converse.request (Asserted ✅)
  • test_activation.openvoiceos.deactivate (Asserted ✅)

type

⚠️ Uncovered Listeners:

  • recognizer_loop:audio_output_end (Intent)
  • recognizer_loop:audio_output_start (Intent)
  • recognizer_loop:record_begin (Intent)
  • recognizer_loop:record_end (Intent)


Coded with logic, delivered with care. 🧠

@github-actions github-actions Bot added fix and removed fix labels Jun 27, 2026
@JarbasAl JarbasAl merged commit f7e2fb9 into dev Jun 27, 2026
16 checks passed
@JarbasAl JarbasAl deleted the fix/guard-none-blacklists branch June 27, 2026 13:13
JarbasAl added a commit that referenced this pull request Jun 30, 2026
)

blacklisted_skills/blacklisted_intents are OPTIONAL SESSION-1 fields and are
legally absent (None) when a Session does not round-trip an empty list through
SessionManager. The stop, fallback, converse and intent services tested
membership/iteration directly (`x in sess.blacklisted_skills`), raising
TypeError: 'NoneType' object is not iterable and aborting the stop ping/pong
cascade, the fallback query cycle and the converse round-trip before any bus
traffic. Guard each use with `(... or [])`.

Surfaced by live integration testing in the OVOS spec-compliance harness
(ovos-bus-client 2.x leaves these fields None); validated end-to-end there.

Co-authored-by: Claude Opus 4.8 <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.

1 participant