Skip to content

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

Draft
JarbasAl wants to merge 7 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 7 commits into
devfrom
feat/pipeline-1-conformance-wt

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Jun 26, 2026

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

Summary by CodeRabbit

  • New Features

    • Intent handling now reports matched and unmatched events through the standard message system, improving visibility into what the assistant is doing.
    • Added support for required-slot checks so incomplete matches are no longer treated as successful.
  • Bug Fixes

    • Prevents some intent pipelines from being downgraded unexpectedly during setup.
    • Improves behavior around reserved pipeline roles and no-match cases, reducing inconsistent intent handling.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

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: 632d0e93-7cd7-4670-bd23-415a11b7450d

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
📝 Walkthrough

Walkthrough

Adds OVOS-PIPELINE-1 orchestration to IntentService: a _missing_required_slots backstop skips matches with absent required slots, _produces_reserved_name suppresses active_handlers stamping for reserved pipelines, and _emit_match_message now accepts pipeline_id, stamps context, emits SpecMessage.INTENT_MATCHED, and returns the session. Cancel and failure terminals migrate to SpecMessage topics. All end-to-end and unit tests are updated to expect the new spec topics. Dependency minimums and CI workflow pinning are also bumped.

Changes

OVOS-PIPELINE-1 intent orchestration and spec topic migration

Layer / File(s) Summary
Reserved-name suppression, required-slots backstop, and _emit_match_message updates
ovos_core/intent_services/service.py
Adds _RESERVED_NAME_PIPELINES/_produces_reserved_name, _missing_required_slots backstop, pipeline_id parameter to _emit_match_message with active_handlers stamping and reserved-name suppression, emits SpecMessage.INTENT_MATCHED, and migrates send_cancel_event/send_complete_intent_failure to SpecMessage terminal topics.
Unit tests: active_handlers stamping and required-slots backstop
test/unittests/test_intent_service_extended.py
Updates send_complete_intent_failure assertion to spec topic; adds _emit_match_message active_handlers stamping rule tests; adds _missing_required_slots unit tests and a handle_utterance loop integration test.
End-to-end test updates for INTENT_MATCHED/INTENT_UNMATCHED
test/end2end/test_adapt.py, test/end2end/test_converse.py, test/end2end/test_activate.py, test/end2end/test_fallback.py, test/end2end/test_intent_pipeline.py, test/end2end/test_lang_detect.py, test/end2end/test_no_skills.py, test/end2end/test_padatious.py, test/end2end/test_stop.py, test/end2end/test_stop_refactor.py
Replaces hardcoded complete_intent_failure expectations with INTENT_UNMATCHED; inserts INTENT_MATCHED assertions in match paths; adds INTENT_MATCHED to ignore_messages filters where tests assert other flows.
Dependency version bumps and CI workflow pinning
pyproject.toml, .github/workflows/ovoscope.yml
Bumps ovos_bus_client, ovos-spec-tools, ovos-adapt-parser, and ovos_padatious minimum versions; pins spec stack git refs in CI via post_install_pip.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • OpenVoiceOS/ovos-core#775: Touches the same handle_utterance bus listener in service.py to migrate onto SpecMessage topics, directly preceding this PR's extension of that migration.
  • OpenVoiceOS/ovos-core#790: Also modifies pyproject.toml to update ovos-spec-tools[langcodes] constraints, overlapping with this PR's dependency bumps.

Suggested labels

fix

🐇 A rabbit hops through the pipeline with glee,
Reserved names suppressed, required slots set free,
INTENT_MATCHED rings out on the spec-aligned bus,
No more complete_intent_failure fuss!
The backstop holds firm, the session returns true—
Hop hop hooray for orchestration brand new! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main OVOS-PIPELINE-1 conformance changes, including matched/unmatched events, handled signaling, updated_session, and active_handlers.
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 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

Ensuring the repo is getting enough sleep (aka stable releases). 💤

✅ All required files present.

Latest Version: 2.4.0a1

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)

A detailed security audit of your contribution. 📝

✅ No known vulnerabilities found (110 packages scanned).

🏷️ Release Preview

Checking if we've met all our release criteria. ✅

Current: 2.4.0a1Next: 2.5.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.5.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.4a1

🌍 Locale Build

Here's the lowdown on the latest automated 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

📊 Coverage

Ensuring we've got all the bases covered! ⚾

⚠️ 64.6% total coverage

Files below 80% coverage (9 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 55.9% 165
ovos_core/skill_manager.py 58.8% 173
ovos_core/transformers.py 66.0% 49
ovos_core/intent_services/dispatcher.py 73.4% 29

Full report: download the coverage-report artifact.

🔨 Build Tests

I've fired up the furnaces and forged your changes. ⚒️

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

⚖️ License Check

Double-checking the fine print for any surprises. 🔍

✅ No license violations found.

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

🔌 Skill Tests (ovoscope)

Testing the skill's 'personality' for warmth and helpfulness. 😊

2/36 passed

❌ **TestAdaptIntent** — 0/4
Test Result
test_intent_blacklist ❌ subtests passed
test_padatious_no_match ❌ subtests passed
test_skill_blacklist ❌ subtests passed
test_adapt_match ❌ subtests passed

test_intent_blacklist failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_padatious_no_match failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_skill_blacklist failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestCancelIntentMidSentence** — 0/1
Test Result
test_cancel_match ❌ subtests passed

test_cancel_match failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestConverse** — 0/1
Test Result
test_parrot_mode ❌ subtests passed

test_parrot_mode failure:

[gw1] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestCountSkills** — 0/4
Test Result
test_count_infinity_active ❌ subtests passed
test_count_infinity_global ❌ subtests passed
test_count ❌ subtests passed
test_count_infinity_stop_low ❌ subtests passed

test_count_infinity_active failure:

[gw3] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_count_infinity_global failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_count failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestDeactivate** — 2/3
Test Result
test_activate ✅ passed
test_deactivate ✅ passed
test_deactivate_inside_converse ❌ subtests passed

test_deactivate_inside_converse failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestFallback** — 0/1
Test Result
test_fallback_match ❌ subtests passed

test_fallback_match failure:

[gw1] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestGlobalStopVocWithActiveSkill** — 0/1
Test Result
test_global_stop_voc_with_active_skill ❌ subtests passed

test_global_stop_voc_with_active_skill failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestGlobalStopVocabulary** — 0/2
Test Result
test_global_stop_voc_no_active_skills ❌ subtests passed
test_stop_voc_exact_still_works ❌ subtests passed

test_global_stop_voc_no_active_skills failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_stop_voc_exact_still_works failure:

[gw1] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestIntentPipelineRouting** — 0/4
Test Result
test_blacklisted_skill_falls_through_to_failure ❌ subtests passed
test_high_priority_stage_handles_before_low ❌ subtests passed
test_no_match_produces_intent_failure ❌ subtests passed
test_padatious_intent_matched ❌ subtests passed

test_blacklisted_skill_falls_through_to_failure failure:

[gw3] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_high_priority_stage_handles_before_low failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_no_match_produces_intent_failure failure:

[gw1] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestLangDisambiguation** — 0/4
Test Result
test_stt_lang ❌ subtests passed
test_lang_text_detection ❌ subtests passed
test_metadata_preferred_over_text_detection ❌ subtests passed
test_invalid_lang_detection ❌ subtests passed

test_stt_lang failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_lang_text_detection failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_metadata_preferred_over_text_detection failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestNoSkills** — 0/2
Test Result
test_routing ❌ subtests passed
test_complete_failure ❌ subtests passed

test_routing failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_complete_failure failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestPadatiousIntent** — 0/4
Test Result
test_intent_blacklist ❌ subtests passed
test_skill_blacklist ❌ subtests passed
test_adapt_no_match ❌ subtests passed
test_padatious_match ❌ subtests passed

test_intent_blacklist failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_skill_blacklist failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_adapt_no_match failure:

[gw1] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestStopNoSkills** — 0/3
Test Result
test_not_exact_med ❌ subtests passed
test_not_exact_high ❌ subtests passed
test_exact ❌ subtests passed

test_not_exact_med failure:

[gw3] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_not_exact_high failure:

[gw2] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

test_exact failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestStopServiceNotASkill** — 0/1
Test Result
test_stop_service_is_not_a_skill ❌ subtests passed

test_stop_service_is_not_a_skill failure:

[gw0] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestStopSkillCanHandleFalse** — 0/1
Test Result
test_stop_with_active_skill_ping_pong ❌ subtests passed

test_stop_with_active_skill_ping_pong failure:

[gw3] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python

🚌 Bus Coverage

Is every event handler pullin' its weight? Let's check! 🏋️‍♂️

🔴 Coverage Summary

Metric Status Coverage
Listeners ██░░░░░░░░ 23.1% 42/182 handlers
Emitters ██████████ 100% 30/30 observed
Assertions ██████████ 100% 30/30 asserted

📊 Per-Skill Breakdown

Skill Listeners Observed Asserted
AdaptPipeline 4/14 (28.6%) 0/0 0/0
ConverseService 0/4 (0.0%) 0/0 0/0
DomainAdaptPipeline 4/14 (28.6%) 0/0 0/0
FallbackService 0/2 (0.0%) 0/0 0/0
HierarchicalAdaptPipeline 4/14 (28.6%) 0/0 0/0
IntentDispatcher 1/2 (50.0%) 0/0 0/0
IntentManifest 0/8 (0.0%) 0/0 0/0
IntentService 2/4 (50.0%) 0/0 0/0
Model2VecIntentPipeline 3/12 (25.0%) 0/0 0/0
Model2VecPrototypePipeline 3/12 (25.0%) 0/0 0/0
PadaciosoPipeline 2/11 (18.2%) 0/0 0/0
PadatiousPipeline 4/15 (26.7%) 0/0 0/0
SkillManager 0/4 (0.0%) 0/0 0/0
StopService 2/2 (100.0%) 0/0 0/0
__core__ 5/16 (31.2%) 5/5 5/5
ovos-skill-count.openvoiceos 4/20 (20.0%) 8/8 8/8
ovos-skill-hello-world.openvoiceos 2/24 (8.3%) 9/9 9/9
stop.openvoiceos 0/0 (0.0%) 8/8 8/8
type 2/4 (50.0%) 0/0 0/0
🔍 Detailed Message Type Breakdown

AdaptPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.keyword (Intent)
  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • intent.service.adapt.manifest.get (337x)
  • register_intent (6x)
  • register_vocab (1008x)

ConverseService

⚠️ Uncovered Listeners:

  • converse:skill (Intent)
  • intent.service.active_skills.get
  • intent.service.skills.activate
  • intent.service.skills.deactivate

DomainAdaptPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.keyword (Intent)
  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • intent.service.adapt.manifest.get (337x)
  • register_intent (6x)
  • register_vocab (1008x)

FallbackService

⚠️ Uncovered Listeners:

  • ovos.skills.fallback.deregister
  • ovos.skills.fallback.register

HierarchicalAdaptPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.keyword (Intent)
  • detach_intent
  • intent.service.adapt.get
  • intent.service.adapt.vocab.manifest.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • intent.service.adapt.manifest.get (337x)
  • register_intent (6x)
  • register_vocab (1008x)

IntentDispatcher

⚠️ Uncovered Listeners:

  • mycroft.skill.handler.error
    ✅ Covered Listeners:
  • mycroft.skill.handler.complete (111x)

IntentManifest

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.describe (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.list (Intent)
  • ovos.intent.register.keyword (Intent)
  • ovos.intent.register.template (Intent)
  • ovos.skill.deregister

IntentService

⚠️ Uncovered Listeners:

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

Model2VecIntentPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • detach_intent
  • mycroft.ready
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • padatious:register_intent (89x)
  • register_intent (6x)

Model2VecPrototypePipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • detach_intent
  • mycroft.ready
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • padatious:register_intent (89x)
  • register_intent (6x)

PadaciosoPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • padatious:register_entity (Intent)
  • detach_intent
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • padatious:register_intent (89x)

PadatiousPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • padatious:register_entity (Intent)
  • detach_intent
  • intent.service.padatious.entities.manifest.get
  • intent.service.padatious.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
    ✅ Covered Listeners:
  • detach_skill (137x)
  • intent.service.padatious.manifest.get (337x)
  • mycroft.skills.train (105x)
  • padatious:register_intent (89x)

SkillManager

⚠️ Uncovered Listeners:

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

StopService

✅ Covered Listeners:

  • stop:global (19x)
  • stop:skill (33x)

__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
  • ovos-skill-count.openvoiceos.set
  • ovos.session.sync
  • remove_context
  • skill.converse.get_response.disable
  • skill.converse.get_response.enable
    ✅ Covered Listeners:
  • ovos-skill-count.openvoiceos.stop.response (32x)
  • ovos.session.update_default (105x)
  • ovos.utterance.handled (137x)
  • ovos.utterance.speak (112x)
  • skill.stop.pong (32x)

📤 Emitters:

  • mycroft.audio.play_sound (Asserted ✅)
  • ovos.intent.unmatched (Asserted ✅)
  • ovos.utterance.handle (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • recognizer_loop:utterance (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 (19x)
  • ovos-skill-count.openvoiceos.stop (33x)
  • ovos-skill-count.openvoiceos.stop.ping (33x)
  • ovos-skill-count.openvoiceos:count_to_N.intent (56x)

📤 Emitters:

  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • ovos-skill-count.openvoiceos.activate (Asserted ✅)
  • ovos-skill-count.openvoiceos:count_to_N.intent (Asserted ✅)
  • ovos.intent.handler.complete (Asserted ✅)
  • ovos.intent.handler.start (Asserted ✅)
  • ovos.intent.matched (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)

ovos-skill-hello-world.openvoiceos

⚠️ Uncovered Listeners:

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

📤 Emitters:

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

stop.openvoiceos

📤 Emitters:

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

type

⚠️ Uncovered Listeners:

  • recognizer_loop:record_begin (Intent)
  • recognizer_loop:record_end (Intent)
    ✅ Covered Listeners:
  • recognizer_loop:audio_output_end (112x)
  • recognizer_loop:audio_output_start (112x)

📚 Docs

I've got some results for you! 📝

✅ All required documentation files present.

README.md

🔎 Type Check

I've checked the pulse of your pull request. 💓

mypy: 268 error(s) found

ovos_core/main.py:24:1: error: Skipping analyzing "ovos_utils.log": module is installed, but missing library stubs or py.typed marker [import-untyped]

Errors (showing first 10/268)
test/unittests/test_skill/__init__.py:15:1: error: Skipping analyzing "ovos_workshop.skills.ovos": module is installed, but missing library stubs or py.typed marker  [import-untyped]
test/end2end/conftest.py:10:1: error: Cannot find implementation or library stub for module named "pytest"  [import-not-found]
ovos_core/transformers.py:2:1: error: Skipping analyzing "ovos_config": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:3:1: error: Skipping analyzing "ovos_plugin_manager.intent_transformers": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:4:1: error: Skipping analyzing "ovos_plugin_manager.metadata_transformers": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:5:1: error: Skipping analyzing "ovos_plugin_manager.text_transformers": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:7:1: error: Skipping analyzing "ovos_plugin_manager.templates.pipeline": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:8:1: error: Skipping analyzing "ovos_utils.json_helper": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:9:1: error: Skipping analyzing "ovos_utils.log": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:16:9: error: Need type annotation for "loaded_plugins" (hint: "loaded_plugins: dict[<type>, <type>] = ...")  [var-annotated]

🔌 Plugin Detection

I've checked the plugin's 'maintainer' info. 👤

⚠️ Plugin Status: WARNINGS (2)

Plugin Info:

  • Name: ovos-core
  • Description: The spiritual successor to Mycroft AI, OVOS is flexible voice assistant software that can be run almost anywhere!

OPM Detection:

Plugin Type Wheel Editable
pipeline

Entry Point Validation:

Entry Point Type Import Interface
ovos-converse-pipeline-plugin pipeline ✅ 17ms
ovos-fallback-pipeline-plugin pipeline ✅ 2ms
ovos-stop-pipeline-plugin pipeline ✅ 56ms

⊘ No settingsmeta.json
requires-python >=3.10 — running Python 3.11

Issues:

  • ⚠️ No settingsmeta.json found
  • ⚠️ No settingsmeta.json found

Standard Automated Signature v2.0 🏷️

@JarbasAl JarbasAl force-pushed the feat/pipeline-1-conformance-wt branch from 97f5751 to 215121b Compare June 27, 2026 14:46
@JarbasAl JarbasAl marked this pull request as ready for review June 27, 2026 15:00
@JarbasAl JarbasAl force-pushed the feat/pipeline-1-conformance-wt branch from 4f519cc to 279b183 Compare June 27, 2026 15:30
@github-actions github-actions Bot added feature and removed feature labels Jun 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
test/unittests/test_intent_service_extended.py (1)

466-546: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert pipeline_id propagation explicitly.

These tests already pass pipeline_id, but they never check the new attribution fields on the emitted dispatch or ovos.intent.matched notification. A regression that drops pipeline_id would still pass this PR's new coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unittests/test_intent_service_extended.py` around lines 466 - 546, The
active_handler tests cover session stamping but do not verify that pipeline
attribution is preserved on emitted events. Update the _emit_match_message test
cases to explicitly assert that the passed pipeline_id is propagated into the
emitted dispatch and the ovos.intent.matched notification payload/context, so a
regression that drops pipeline_id will fail. Use the existing
_emit_match_message, svc.bus.emit, and pipeline_id values in these tests to
locate and verify the new assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ovoscope.yml:
- Around line 22-28: The `post_install_pip` setting in the `ovoscope` workflow
is using floating Git refs like `@dev` and `@feat/intent-4-producer`, which
makes the install set non-reproducible. Update the pinned package list to use
immutable commit SHAs or tags for each repository referenced there, keeping the
same package order and coverage while replacing the mutable refs so the workflow
resolves consistently.

In `@ovos_core/intent_services/service.py`:
- Around line 343-347: The required-slot check in the match filtering logic is
treating falsy values as missing, so valid slots like 0 or False get rejected.
Update the required-slot validation in the function that reads
match_data/__required_slots__ to test whether each required slot key is absent
from match_data rather than whether its value is truthy, so only truly missing
slots are filtered out.
- Around line 445-451: The updated session is being attached to reply.context
after self.bus.emit(reply.forward(f"{match.skill_id}.activate")), so the first
forwarded .activate event can still carry a stale session snapshot. In the
intent service flow around the match handling in service.py, update
reply.context["session"] from sess.serialize() before emitting the activation
event, and keep the session mutation tied to the same reply object so downstream
handlers always receive the latest session state.

In `@pyproject.toml`:
- Around line 19-24: The dependency constraint for ovos-workshop is still too
low and can resolve to an incompatible release. Update the version range in
pyproject.toml where ovos-workshop is listed so the minimum required version
matches the newer INTENT-4 producer branch, and keep the upper bound unchanged
unless the codebase requires otherwise.

In `@test/end2end/test_adapt.py`:
- Around line 76-81: The `test_adapt.py` intent-matched broadcast assertion is
too loose and can miss regressions in the `IntentService` payload. Update the
`Message(INTENT_MATCHED, ...)` expectation in this test to assert the full
payload, including `slots={}` and
`pipeline_id="ovos-adapt-pipeline-plugin-high"` alongside the existing
`skill_id`, `intent_name`, `utterance`, and `lang` fields.

In `@test/end2end/test_padatious.py`:
- Around line 76-81: The INTENT_MATCHED expectation in the padatious end-to-end
test is missing required payload fields, so update the Message(INTENT_MATCHED)
assertion to include the new slots and pipeline_id data alongside skill_id,
intent_name, utterance, and lang. Use the existing test case in
test_padatious.py to assert slots={} and
pipeline_id="ovos-padatious-pipeline-plugin-high" so the payload check matches
the spec and catches regressions.

In `@test/end2end/test_stop.py`:
- Around line 49-51: The INTENT_MATCHED filter is currently applied too broadly
in the stop test helpers, which can hide accidental matched broadcasts on the
no-match path. Update the stop scenario message filtering so INTENT_MATCHED is
only excluded for the dispatching exact/medium cases, and remove it from
_run_not_exact_high while keeping the IGNORE_MESSAGES behavior there. Use the
helper names _run_not_exact_high and the dispatching stop scenario setup to
locate the filter list.

---

Nitpick comments:
In `@test/unittests/test_intent_service_extended.py`:
- Around line 466-546: The active_handler tests cover session stamping but do
not verify that pipeline attribution is preserved on emitted events. Update the
_emit_match_message test cases to explicitly assert that the passed pipeline_id
is propagated into the emitted dispatch and the ovos.intent.matched notification
payload/context, so a regression that drops pipeline_id will fail. Use the
existing _emit_match_message, svc.bus.emit, and pipeline_id values in these
tests to locate and verify the new assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7a528f8a-451c-4749-94a9-9daa5cd65a2c

📥 Commits

Reviewing files that changed from the base of the PR and between 723c9c0 and be8864c.

📒 Files selected for processing (14)
  • .github/workflows/ovoscope.yml
  • ovos_core/intent_services/service.py
  • pyproject.toml
  • test/end2end/test_activate.py
  • test/end2end/test_adapt.py
  • test/end2end/test_converse.py
  • test/end2end/test_fallback.py
  • test/end2end/test_intent_pipeline.py
  • test/end2end/test_lang_detect.py
  • test/end2end/test_no_skills.py
  • test/end2end/test_padatious.py
  • test/end2end/test_stop.py
  • test/end2end/test_stop_refactor.py
  • test/unittests/test_intent_service_extended.py

Comment thread .github/workflows/ovoscope.yml Outdated
Comment on lines +22 to +28
# Pin the integrated spec stack AFTER `.[test]` so the resolver cannot
# downgrade ovos-workshop below the 9.x INTENT-4 producer (the published
# fixture skills + plugins cap it lower). Mirrors the proven pin-set from
# OpenVoiceOS/ovos-test-harness@dev requirements.txt. Runs with
# --force-reinstall --no-deps; this PR's own core source still wins via the
# workflow's final local reinstall. Flip refs to @dev as each branch lands.
post_install_pip: "git+https://github.com/OpenVoiceOS/ovos-workshop@feat/intent-4-producer git+https://github.com/OpenVoiceOS/ovos-adapt-pipeline-plugin@dev git+https://github.com/OpenVoiceOS/ovos-padatious-pipeline-plugin@dev git+https://github.com/OpenVoiceOS/padacioso@dev git+https://github.com/OpenVoiceOS/ovoscope@dev git+https://github.com/OpenVoiceOS/ovos-skill-parrot@dev git+https://github.com/OpenVoiceOS/ovos-skill-fallback-unknown@dev git+https://github.com/OpenVoiceOS/ovos-skill-count@dev git+https://github.com/OpenVoiceOS/ovos-skill-hello-world@dev"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python - <<'PY'
import pathlib, re

text = pathlib.Path(".github/workflows/ovoscope.yml").read_text()
m = re.search(r'post_install_pip:\s*"([^"]+)"', text)
for dep in m.group(1).split():
    ref = dep.rsplit("@", 1)[-1]
    immutable = bool(re.fullmatch(r"[0-9a-fA-F]{7,40}", ref))
    print(f"{dep}\t{'immutable' if immutable else 'moving-ref'}")
PY

Repository: OpenVoiceOS/ovos-core

Length of output: 805


Use immutable refs for post_install_pip

@dev and @feat/intent-4-producer still drift, so this job isn’t actually pinned and can change behavior between runs. Use commit SHAs or tags here instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ovoscope.yml around lines 22 - 28, The `post_install_pip`
setting in the `ovoscope` workflow is using floating Git refs like `@dev` and
`@feat/intent-4-producer`, which makes the install set non-reproducible. Update
the pinned package list to use immutable commit SHAs or tags for each repository
referenced there, keeping the same package order and coverage while replacing
the mutable refs so the workflow resolves consistently.

Comment thread ovos_core/intent_services/service.py Outdated
Comment on lines +343 to +347
match_data = match.match_data or {}
required_slots = match_data.get("__required_slots__")
if not required_slots:
return []
return [slot for slot in required_slots if not match_data.get(slot)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don't treat every falsy slot value as missing.

Line 347 currently declines matches when a required slot is present but holds a falsy value like 0 or False. That widens the backstop from “slot absent” to “slot falsy” and can skip valid matches.

Suggested fix
-        return [slot for slot in required_slots if not match_data.get(slot)]
+        return [
+            slot for slot in required_slots
+            if slot not in match_data or match_data[slot] in (None, "")
+        ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
match_data = match.match_data or {}
required_slots = match_data.get("__required_slots__")
if not required_slots:
return []
return [slot for slot in required_slots if not match_data.get(slot)]
match_data = match.match_data or {}
required_slots = match_data.get("__required_slots__")
if not required_slots:
return []
return [
slot for slot in required_slots
if slot not in match_data or match_data[slot] in (None, "")
]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ovos_core/intent_services/service.py` around lines 343 - 347, The
required-slot check in the match filtering logic is treating falsy values as
missing, so valid slots like 0 or False get rejected. Update the required-slot
validation in the function that reads match_data/__required_slots__ to test
whether each required slot key is absent from match_data rather than whether its
value is truthy, so only truly missing slots are filtered out.

Comment thread ovos_core/intent_services/service.py Outdated
Comment on lines 445 to 451
if not _produces_reserved_name(pipeline_id):
sess.add_active_handler(match.skill_id)
# emit event for skills callback -> self.handle_activate
self.bus.emit(reply.forward(f"{match.skill_id}.activate"))

# update Session if modified by pipeline
reply.context["session"] = sess.serialize()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Propagate the updated session before emitting .activate.

Line 448 forwards <skill_id>.activate before Line 451 overwrites reply.context["session"]. When Match.updated_session is a different snapshot, that first downstream event still carries the pre-match session, so the new propagation contract is already broken on the first bus hop.

Suggested fix
                 if not was_deactivated:
                     if not _produces_reserved_name(pipeline_id):
                         sess.add_active_handler(match.skill_id)
+                    reply.context["session"] = sess.serialize()
                     # emit event for skills callback -> self.handle_activate
                     self.bus.emit(reply.forward(f"{match.skill_id}.activate"))

             # update Session if modified by pipeline
             reply.context["session"] = sess.serialize()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not _produces_reserved_name(pipeline_id):
sess.add_active_handler(match.skill_id)
# emit event for skills callback -> self.handle_activate
self.bus.emit(reply.forward(f"{match.skill_id}.activate"))
# update Session if modified by pipeline
reply.context["session"] = sess.serialize()
if not _produces_reserved_name(pipeline_id):
sess.add_active_handler(match.skill_id)
reply.context["session"] = sess.serialize()
# emit event for skills callback -> self.handle_activate
self.bus.emit(reply.forward(f"{match.skill_id}.activate"))
# update Session if modified by pipeline
reply.context["session"] = sess.serialize()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ovos_core/intent_services/service.py` around lines 445 - 451, The updated
session is being attached to reply.context after
self.bus.emit(reply.forward(f"{match.skill_id}.activate")), so the first
forwarded .activate event can still carry a stale session snapshot. In the
intent service flow around the match handling in service.py, update
reply.context["session"] from sess.serialize() before emitting the activation
event, and keep the session mutation tied to the same reply object so downstream
handlers always receive the latest session state.

Comment thread pyproject.toml Outdated
Comment on lines +19 to +24
"ovos_bus_client>=2.6.1a1,<3.0.0",
"ovos-plugin-manager>=2.5.0a1,<3.0.0",
"ovos-config>=0.0.13,<3.0.0",
"ovos-workshop>=8.3.0a1,<10.0.0",
"rapidfuzz>=3.6,<4.0",
"ovos-spec-tools[langcodes]>=0.9.0a1",
"ovos-spec-tools[langcodes]>=0.11.0a1,<1.0.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "pyproject.toml:"
sed -n '19,24p' pyproject.toml

echo
echo ".github/workflows/ovoscope.yml:"
sed -n '22,28p' .github/workflows/ovoscope.yml

Repository: OpenVoiceOS/ovos-core

Length of output: 1483


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "All ovos-workshop constraints in the repo:"
rg -n --hidden --no-ignore-vcs 'ovos-workshop' .

echo
echo "pyproject.toml dependency section:"
sed -n '1,120p' pyproject.toml

Repository: OpenVoiceOS/ovos-core

Length of output: 8974


Raise the ovos-workshop floor in pyproject.toml.
This dependency range still allows ovos-workshop>=8.3.0a1, while the workflow now requires the newer INTENT-4 producer branch. That leaves published/local installs able to resolve an incompatible workshop version.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyproject.toml` around lines 19 - 24, The dependency constraint for
ovos-workshop is still too low and can resolve to an incompatible release.
Update the version range in pyproject.toml where ovos-workshop is listed so the
minimum required version matches the newer INTENT-4 producer branch, and keep
the upper bound unchanged unless the codebase requires otherwise.

Comment thread test/end2end/test_adapt.py Outdated
Comment on lines +76 to +81
# OVOS-PIPELINE-1 §9.2: matched broadcast precedes the dispatch
Message(INTENT_MATCHED,
data={"skill_id": self.skill_id,
"intent_name": f"{self.skill_id}:HelloWorldIntent",
"utterance": "hello world", "lang": session.lang},
context={"skill_id": self.skill_id}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Assert the full ovos.intent.matched payload.

IntentService now includes both slots and pipeline_id in this broadcast, so this test would still pass if either contract regressed. Please assert slots={} and pipeline_id="ovos-adapt-pipeline-plugin-high" here as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/end2end/test_adapt.py` around lines 76 - 81, The `test_adapt.py`
intent-matched broadcast assertion is too loose and can miss regressions in the
`IntentService` payload. Update the `Message(INTENT_MATCHED, ...)` expectation
in this test to assert the full payload, including `slots={}` and
`pipeline_id="ovos-adapt-pipeline-plugin-high"` alongside the existing
`skill_id`, `intent_name`, `utterance`, and `lang` fields.

Comment thread test/end2end/test_padatious.py Outdated
Comment on lines +76 to +81
# OVOS-PIPELINE-1 §9.2: matched broadcast precedes the dispatch
Message(INTENT_MATCHED,
data={"skill_id": self.skill_id,
"intent_name": f"{self.skill_id}:Greetings.intent",
"utterance": "good morning", "lang": session.lang},
context={"skill_id": self.skill_id}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Assert the full ovos.intent.matched payload.

This matched-event expectation omits the new slots and pipeline_id fields, so it won't catch regressions in the spec payload the PR is adding. Please assert slots={} and pipeline_id="ovos-padatious-pipeline-plugin-high" here too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/end2end/test_padatious.py` around lines 76 - 81, The INTENT_MATCHED
expectation in the padatious end-to-end test is missing required payload fields,
so update the Message(INTENT_MATCHED) assertion to include the new slots and
pipeline_id data alongside skill_id, intent_name, utterance, and lang. Use the
existing test case in test_padatious.py to assert slots={} and
pipeline_id="ovos-padatious-pipeline-plugin-high" so the payload check matches
the spec and catches regressions.

Comment thread test/end2end/test_stop.py Outdated
Comment on lines +49 to +51
# ovos.intent.matched (§9.2) precedes every dispatch; these scenarios assert
# stop routing/activation, not the matched broadcast, so it is filtered here.
INTENT_MATCHED,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Scope this INTENT_MATCHED filter to the dispatching stop scenarios.

_run_not_exact_high also reuses IGNORE_MESSAGES, so an accidental ovos.intent.matched emission on that no-match path would be hidden and the test would still pass. Keep this filter for the exact/medium dispatch cases, but not for the unmatched one.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/end2end/test_stop.py` around lines 49 - 51, The INTENT_MATCHED filter is
currently applied too broadly in the stop test helpers, which can hide
accidental matched broadcasts on the no-match path. Update the stop scenario
message filtering so INTENT_MATCHED is only excluded for the dispatching
exact/medium cases, and remove it from _run_not_exact_high while keeping the
IGNORE_MESSAGES behavior there. Use the helper names _run_not_exact_high and the
dispatching stop scenario setup to locate the filter list.

@JarbasAl JarbasAl marked this pull request as draft June 30, 2026 16:49
@JarbasAl JarbasAl force-pushed the feat/pipeline-1-conformance-wt branch from be8864c to 43825c8 Compare June 30, 2026 17:09
JarbasAl added 2 commits July 1, 2026 12:37
…, active_handlers push, updated_session adoption

Rebases the conformance work cleanly onto dev (which already landed §8 trio +
§9 utterance-terminal events via #788, the spec-tools 1.x cap via #790, and the
workshop 9.x floor via #779). The previous branch bumped bus-client to 2.6.1a1
and re-added a stale spec-tools pin, producing an unsatisfiable resolver
(ovos-core==2.2.4a3 cannot be used) — dropped; dev's deps already satisfy the
stack. The PR's revert of #788's IntentDispatcher is also dropped — dev's
dispatcher-based §7/§8 path is kept and the new clauses are layered onto it.

OVOS-PIPELINE-1 conformance added:

- §4.2 ``updated_session`` adoption: ``_dispatch_match`` now returns the working
  session (``Match.updated_session or inbound``) and ``handle_utterance`` adopts
  it for the remainder of the lifecycle, so a plugin's match-phase session
  mutation reaches downstream stages and the default-session sync.

- §6.2 required_slots orchestrator backstop: after the §5.3/§5.4 denylist
  checks, the orchestrator verifies the match's slot map contains every slot in
  ``match_data['__required_slots__']``; if any is *absent* it treats the match as
  if the plugin declined and continues iteration (no bus event, observable only
  as a non-match). A present slot carrying a falsy value (0/False/'') is a
  legitimate, present slot — only a missing key is missing (CodeRabbit fix; the
  prior truthiness check wrongly rejected valid slots). Sourced from the Match
  itself today (no INTENT-4 §10 manifest is plumbed yet); TODO notes the upgrade
  path.

- §7.1 ``session.active_handlers`` push + §7.3 reserved-name suppression: a
  claiming non-reserved dispatch pushes
  ``{skill_id, activated_at}`` head-first via the spec ``Session.add_active_handler``
  helper (dedup-promoting prior entries), applied after ``Match.updated_session``
  is committed so a plugin's wipe (e.g. STOP-1 global stop) sees the stamp land
  on top. The push is SUPPRESSED for reserved intent_names
  (converse/response/stop/fallback/common_query) per §7.1 — keyed *strictly off
  the reserved-name registry (the Match's intent_name)*, not off the producing
  pipeline_id (the prior pipeline_id-based keying was non-conformant; a reserved
  name produced by any pipeline suppresses).

- Ordering fix (CodeRabbit): the working session is serialized into
  ``reply.context['session']`` *before* the ``{skill_id}.activate`` forward is
  emitted, so subscribers receive the latest session snapshot instead of a stale
  one.

Tests:
- test_intent_service_extended: new ``TestActiveHandlersPush`` (push, dedup,
  reserved-name suppression keyed off intent_name, deactivated, pipeline_id
  propagation into §9.2 matched + dispatch context, session-serialize-before-
  activate ordering, §4.2 return) and ``TestRequiredSlotsBackstop`` (unit +
  match-loop behaviour; falsy-present-value coverage).
- test_adapt / test_padatious e2e: assert the §3.1/§9.2 ``pipeline_id`` is
  propagated into the ``ovos.intent.matched`` payload and dispatch context (a
  regression that drops it now fails).
… __required_slots__

The orchestrator backstop for required_slots (PIPELINE-1 §6.2) was
reading from a made-up match_data.__required_slots__ convention that
no plugin implements. Per spec, required_slots is an optional field
in ovos.intent.register.template broadcasts (INTENT-4 §6.1), stored
in the orchestrator's manifest (INTENT-4 §10) as part of the full
registration payload.

- Remove __required_slots__ convention entirely
- _missing_required_slots now reads from IntentManifest.definition
  via _manifest_required_slots()
- Converted from staticmethod to instance method to access
  self.intent_manifest
- Tests rewritten to register template intents on the manifest
  rather than injecting __required_slots__ into match_data
@JarbasAl JarbasAl force-pushed the feat/pipeline-1-conformance-wt branch from 43825c8 to 01d7ea1 Compare July 1, 2026 12:09
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