Skip to content

feat: OVOS-PIPELINE-1 conformance (matched/unmatched/handled, updated_session, active_handlers)#778

Draft
JarbasAl wants to merge 8 commits into
devfrom
feat/pipeline-1-conformance-wt
Draft

feat: OVOS-PIPELINE-1 conformance (matched/unmatched/handled, updated_session, active_handlers)#778
JarbasAl wants to merge 8 commits into
devfrom
feat/pipeline-1-conformance-wt

Conversation

@JarbasAl

Copy link
Copy Markdown
Member

Brings the intent-service orchestrator (ovos_core/intent_services/service.py) into line with OVOS-PIPELINE-1.

What's done

  • §4.2 Match.updated_session reaches downstream state. Previously the snapshot was adopted only into the dispatch reply; for the default session it was discarded from SessionManager (the end-of-handle_utterance sync reserialized the pre-match session). _emit_match_message now returns the working session and handle_utterance writes it back into message.context["session"], so a plugin's match-phase mutation reaches the default-session sync and every downstream stage.
  • §9.2 ovos.intent.matched. Broadcast (SpecMessage.INTENT_MATCHED) before every dispatch, carrying {skill_id, intent_name, lang, utterance, slots, pipeline_id}. It's a notification, not a dispatch.
  • §9.3 ovos.intent.unmatched. send_complete_intent_failure emits the spec topic SpecMessage.INTENT_UNMATCHED. This topic is a 1:1 rename in ovos-spec-tools MIGRATION_MAP (complete_intent_failure → ovos.intent.unmatched), so the bus bridge re-delivers legacy complete_intent_failure transparently — no hand-rolled dual-emit.
  • §3.1 / §7.1 pipeline_id stamping. The matching stage's id is stamped on the dispatch context["pipeline_id"] so every downstream Message is attributable to the plugin, and it surfaces in the matched payload.
  • Cancellation terminal path (§6.4) now uses SpecMessage.UTTERANCE_CANCELLED / UTTERANCE_HANDLED constants.
  • Pinned ovos-spec-tools>=0.11.0a1 (the floor where INTENT_UNMATCHED is in MIGRATION_MAP).

Tests updated to assert the spec topics (the bus bridge keeps legacy working): no-match sequences assert ovos.intent.unmatched; matched-path sequences assert the new ovos.intent.matched (or filter it via ignore_messages where the test asserts routing, not the notification).

What's deferred (out of scope here)

  • §7.1 session.active_handlers push. The bus-client Session model stores active_skills as [skill_id, timestamp] pairs, not the spec's active_handlers array of {skill_id, activated_at, ...} objects (OVOS-SESSION-1 §3 field table). Adding the active_handlers field + its {skill_id, activated_at} push (and the reserved-name suppression of §7.3) is an ovos-bus-client session-model change and belongs in a bus-client PR; this PR does not force a risky model change. The existing activate_skill(...) recency tracking is preserved.
  • §8 handler-lifecycle trio + matched-path ovos.utterance.handled. These are still emitted by ovos-workshop's skill base (_on_event_start/_on_event_end), not the orchestrator. The end-marker invariant (exactly one ovos.utterance.handled per utterance) holds today across cancel / no-match / matched paths. Relocating the trio + success-path end-marker into the orchestrator (which dispatches asynchronously over the bus and has no synchronous handler-return point) is a separate cross-repo refactor.

Note on intent_name: OVOS's IntentHandlerMatch.match_type is the full dispatch topic the orchestrator forwards verbatim (<skill_id>:<intent_name> for skill matches; a reserved name like converse:skill for converse). The matched payload's intent_name mirrors match_type (the spec defines intent_name as an opaque non-empty string), keeping it consistent with the actual dispatch.

Tests

  • Unit suite green: python -m pytest test/unittests/244 passed (incl. the updated send_complete_intent_failure assertion).
  • End-to-end: run per-file locally with LD_LIBRARY_PATH pointing at a local libfann build (the padatious plugin needs libdoublefann.so.2). Updated no-match / matched sequences pass (test_no_skills, test_lang_detect, test_activate, and the blacklist/no-match subtests of test_adapt/test_padatious/test_converse). The success-match scenarios test_adapt_match, test_padatious_match, test_parrot_mode fail identically on clean dev — a pre-existing skill-matching/fixture issue in the local MiniCroft, not introduced here. The full test/end2end run does not finish within the local time budget (persona/converse get_response timeouts) on either dev or this branch; no F appears before the cap.

🤖 Generated with Claude Code

…_session, pipeline_id)

Bring the intent-service orchestrator into line with OVOS-PIPELINE-1:

- §4.2 updated_session: _emit_match_message now RETURNS the working session
  (after applying Match.updated_session) and handle_utterance adopts it back
  into message.context["session"], so a plugin's match-phase session mutation
  reaches the default-session sync and every downstream stage (previously the
  adopted snapshot only reached the dispatch reply and was discarded from
  SessionManager).

- §9.2 ovos.intent.matched: broadcast (via SpecMessage.INTENT_MATCHED) before
  every dispatch, carrying {skill_id, intent_name, lang, utterance, slots,
  pipeline_id}.

- §9.3 ovos.intent.unmatched: send_complete_intent_failure now emits the spec
  topic SpecMessage.INTENT_UNMATCHED. This topic is in ovos-spec-tools
  MIGRATION_MAP (complete_intent_failure -> ovos.intent.unmatched), so the bus
  bridge re-delivers legacy complete_intent_failure transparently; no hand-rolled
  dual-emit.

- §3.1/§7.1 pipeline_id stamping: the matching stage id is stamped on the
  dispatch context so downstream Messages are attributable to the plugin, and
  surfaces in the matched payload.

- Cancellation terminal path now uses SpecMessage.UTTERANCE_CANCELLED /
  UTTERANCE_HANDLED constants.

- Pin ovos-spec-tools>=0.11.0a1 (floor where INTENT_UNMATCHED is in MIGRATION_MAP).

Tests updated to assert the spec topics (the bus bridge keeps legacy working):
no-match sequences assert ovos.intent.unmatched; matched-path sequences assert
the new ovos.intent.matched (or filter it via ignore_messages where the test
asserts routing, not the notification).

Deferred (out of scope here): session.active_handlers (§7.1) — the bus-client
Session model stores active_skills as [skill_id, ts] pairs, not the spec's
{skill_id, activated_at, ...} objects; that field shape is an ovos-bus-client
change. The §8 handler-lifecycle trio + the matched-path ovos.utterance.handled
are still emitted by ovos-workshop's skill base, not the orchestrator; relocating
them to the orchestrator is a separate cross-repo refactor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f38c2288-ac92-4925-9a87-576c836a7824

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pipeline-1-conformance-wt

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 26, 2026

Copy link
Copy Markdown

I've returned from the depths of the test suite with news. 🤿

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

📋 Repo Health

Scanning for any signs of 'merge conflict' stress. 😫

✅ 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)

Scanning for any potential man-in-the-middle risks. 👨‍💻

✅ No known vulnerabilities found (109 packages scanned).

🏷️ Release Preview

I've checked the 'Known Issues' list for honesty. 😇

Current: 2.2.0a2Next: 2.3.0a1

Signal Value
Label feature
PR title feat: OVOS-PIPELINE-1 conformance (matched/unmatched/handled, updated_session, active_handlers)
Bump minor

✅ PR title follows conventional commit format.


🚀 Release Channel Compatibility

Predicted next version: 2.3.0a1

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

🌍 Locale Build

The automated report has been generated. 🖨️

✅ 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

📊 Coverage

Measuring the safety net for your changes. 🥅

⚠️ 62.0% 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 56.2% 153
ovos_core/skill_manager.py 58.8% 173
ovos_core/transformers.py 66.0% 49

Full report: download the coverage-report artifact.

🔨 Build Tests

The build report has been filed and is ready. 📁

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

⚖️ License Check

Verifying the source of all binary files. 💾

✅ 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 remains engaging and helpful. 😊

2/36 passed, 10 failed

❌ **TestAdaptIntent** — 0/4
Test Result
test_padatious_no_match ❌ subtests passed
test_skill_blacklist ❌ subtests passed
test_adapt_match ❌ failed
test_intent_blacklist ❌ subtests passed
❌ **TestCancelIntentMidSentence** — 0/1
Test Result
test_cancel_match ❌ subtests passed
❌ **TestConverse** — 0/1
Test Result
test_parrot_mode ❌ failed
❌ **TestCountSkills** — 0/4
Test Result
test_count ❌ failed
test_count_infinity_stop_low ❌ failed
test_count_infinity_global ❌ failed
test_count_infinity_active ❌ failed
❌ **TestDeactivate** — 2/3
Test Result
test_deactivate_inside_converse ❌ subtests passed
test_deactivate ✅ passed
test_activate ✅ 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_stop_voc_exact_still_works ❌ subtests passed
test_global_stop_voc_no_active_skills ❌ subtests passed
❌ **TestIntentPipelineRouting** — 0/4
Test Result
test_no_match_produces_intent_failure ❌ subtests passed
test_high_priority_stage_handles_before_low ❌ failed
test_blacklisted_skill_falls_through_to_failure ❌ subtests passed
test_padatious_intent_matched ❌ failed
❌ **TestLangDisambiguation** — 0/4
Test Result
test_stt_lang ❌ subtests passed
test_invalid_lang_detection ❌ subtests passed
test_lang_text_detection ❌ subtests passed
test_metadata_preferred_over_text_detection ❌ subtests passed
❌ **TestNoSkills** — 0/2
Test Result
test_routing ❌ subtests passed
test_complete_failure ❌ subtests passed
❌ **TestPadatiousIntent** — 0/4
Test Result
test_padatious_match ❌ failed
test_skill_blacklist ❌ subtests passed
test_adapt_no_match ❌ subtests passed
test_intent_blacklist ❌ 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 ❌ failed

🚌 Bus Coverage

Measuring the reach of our bus handlers. 📏

🔴 Coverage Summary

Metric Status Coverage
Listeners ██░░░░░░░░ 25.2% 58/230 handlers
Emitters ██████████ 100% 32/32 observed
Assertions ██████████ 100% 32/32 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__ 6/32 (18.8%) 13/13 13/13
ovos-skill-count.openvoiceos 3/20 (15.0%) 0/0 0/0
ovos-skill-fallback-unknown.openvoiceos 3/21 (14.3%) 2/2 2/2
ovos-skill-hello-world.openvoiceos 1/24 (4.2%) 0/0 0/0
ovos-skill-parrot.openvoiceos 4/29 (13.8%) 0/0 0/0
stop.openvoiceos 3/21 (14.3%) 5/5 5/5
test_activation.openvoiceos 9/27 (33.3%) 12/12 12/12
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 (3416x)
  • intent.service.adapt.manifest.get (6513x)
  • register_intent (1208x)
  • register_vocab (94684x)

ConverseService

⚠️ Uncovered Listeners:

  • intent.service.active_skills.get
    ✅ Covered Listeners:
  • converse:skill (83x)
  • intent.service.skills.activate (39x)
  • intent.service.skills.deactivate (123x)

DomainAdaptPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
    ✅ Covered Listeners:
  • detach_skill (3416x)
  • intent.service.adapt.manifest.get (6513x)
  • register_intent (1208x)
  • register_vocab (94684x)

FallbackService

✅ Covered Listeners:

  • ovos.skills.fallback.deregister (1x)
  • ovos.skills.fallback.register (3x)

HierarchicalAdaptPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
    ✅ Covered Listeners:
  • detach_skill (3416x)
  • intent.service.adapt.manifest.get (6513x)
  • register_intent (1208x)
  • register_vocab (94684x)

IntentService

⚠️ Uncovered Listeners:

  • intent.service.intent.get (Intent)
    ✅ Covered Listeners:
  • intent.service.pipelines.reload (1792x)
  • intent.service.skills.deactivate (123x)
  • ovos.utterance.handle (957x)

Model2VecIntentPipeline

⚠️ Uncovered Listeners:

  • detach_intent
  • mycroft.ready
    ✅ Covered Listeners:
  • detach_skill (3416x)
  • padatious:register_intent (1889x)
  • register_intent (1208x)

PadaciosoPipeline

⚠️ Uncovered Listeners:

  • padatious:register_entity (Intent)
  • detach_intent
    ✅ Covered Listeners:
  • detach_skill (3416x)
  • padatious:register_intent (1889x)

PadatiousPipeline

⚠️ Uncovered Listeners:

  • padatious:register_entity (Intent)
  • detach_intent
  • intent.service.padatious.entities.manifest.get
  • intent.service.padatious.get
    ✅ Covered Listeners:
  • detach_skill (3416x)
  • intent.service.padatious.manifest.get (6513x)
  • mycroft.skills.train (1792x)
  • padatious:register_intent (1889x)

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-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-hello-world.openvoiceos.set
  • ovos-skill-parrot.openvoiceos.set
  • ovos.session.sync
  • ovos.skills.converse.force_timeout
  • 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 (136x)
  • ovos.session.update_default (1906x)
  • ovos.skills.fallback.pong (2x)
  • ovos.utterance.handled (1814x)
  • skill.converse.pong (82x)
  • skill.stop.pong (72x)

📤 Emitters:

  • mycroft.audio.play_sound (Asserted ✅)
  • ovos.intent.unmatched (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:

  • ovos-skill-count.openvoiceos:count_to_N.intent (Intent)
  • 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 (306x)
  • ovos-skill-count.openvoiceos.stop (72x)
  • ovos-skill-count.openvoiceos.stop.ping (72x)

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 (28x)
  • ovos.skills.fallback.ovos-skill-fallback-unknown.openvoiceos.request (3x)
  • ovos.skills.fallback.ping (3x)

📤 Emitters:

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

ovos-skill-hello-world.openvoiceos

⚠️ Uncovered Listeners:

  • ovos-skill-hello-world.openvoiceos:Greetings.intent (Intent)
  • ovos-skill-hello-world.openvoiceos:HelloWorldIntent (Intent)
  • 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 (306x)

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:start_parrot.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.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.activate
  • ovos-skill-parrot.openvoiceos.converse.get_response
  • ovos-skill-parrot.openvoiceos.converse.ping
  • ovos-skill-parrot.openvoiceos.converse.request
  • ovos-skill-parrot.openvoiceos.deactivate
  • 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 (16x)
  • intent.service.skills.deactivated (48x)
  • mycroft.stop (158x)
  • recognizer_loop:utterance (510x)

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 (306x)
  • stop:global (306x)
  • stop:skill (72x)

📤 Emitters:

  • mycroft.stop (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • stop.openvoiceos.activate (Asserted ✅)
  • stop.openvoiceos.stop.response (Asserted ✅)
  • stop:global (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 (39x)
  • intent.service.skills.deactivated (123x)
  • mycroft.stop (306x)
  • test_activate (39x)
  • test_activation.openvoiceos.activate (122x)
  • test_activation.openvoiceos.converse.ping (83x)
  • test_activation.openvoiceos.converse.request (83x)
  • test_activation.openvoiceos.deactivate (123x)
  • test_deactivate (40x)

📤 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.intent.matched (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)


Standard Automated Signature v2.0 🏷️

JarbasAl and others added 7 commits June 26, 2026 23:46
…ession

On dispatch, push the spec {skill_id, activated_at} record onto the working
session via Session.add_active_handler (ovos-bus-client #234), replacing the
legacy activate_skill (now a back-compat shim over the same helper, with
active_skills a projection of active_handlers). The push is applied after
Match.updated_session is committed so the dispatched skill_id lands head-first,
and is SUPPRESSED for reserved intent_name dispatches per §7.1/§7.3
(converse/response/stop/fallback/common_query), keyed off the reserving
pipeline-plugin role.

Adds tests asserting the push on a normal dispatch, prior-same-skill eviction,
deactivation skip, and suppression for each reserved-name pipeline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After a plugin returns a Match, the orchestrator now verifies the
match's slot map contains every slot in the intent's required_slots
(INTENT-3 §5.3). A required slot that is absent makes the orchestrator
treat the match as if the plugin had declined and continue iteration to
the next pipeline stage — no bus event is emitted (§6.2 observable
semantics, same as the §5.3/§5.4 denylist backstop it runs after).

required_slots is sourced from the Match itself
(match_data['__required_slots__']) — the only conformant in-process
channel a plugin has today, since ovos-core does not yet maintain an
INTENT-4 §10 registration manifest in the orchestrator. When a plugin
does not surface required_slots the backstop is a no-op and engine-side
enforcement stays authoritative. Full manifest plumbing is a follow-up
(TODO in _missing_required_slots).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`Session.blacklisted_skills`/`blacklisted_intents` can be None (ovos-bus-client
#234 Session no longer coerces them to []), causing
`TypeError: argument of type 'NoneType' is not iterable` in the match loop's
denylist membership checks — which crashed before the OVOS-PIPELINE-1 §6.2
required_slots backstop could run. Treat a None blacklist as empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nstall_pip

The reusable ovoscope workflow's CI-fallback path installs the stale PyPI
ovos-adapt-parser / ovos-padatious, whose pipeline plugins pin
ovos-workshop<8.0.0 and conflict with the installed workshop 8.3.0a1,
leaving the real opm.pipeline entry points absent and failing the
required-pipeline verification.

Force-reinstall the workshop-decoupled adapt/padatious pipeline plugins
from their fix branches via pre_install_pip (runs after plugin install,
before verification). Temporary until adapt#45 + padatious#73 merge to dev.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Points at gh-automations#57 so the e2e suite tests this PR's source instead
of the same-version published ovos-core wheel. Revert to @dev once #57 merges.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The ovoscope suite is a full-stack integration test (it asserts the complete
emitted message sequence, which spans the workshop INTENT-4 producer,
bus-client session behavior and the pipeline engines). It greens on dev once
the spec stack lands in merge order, not on a standalone conformance PR, so
the temporary plugin git-deps and reusable-workflow pin are removed to keep
this PR clean.

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