Skip to content

spike: context.utterance_id — lifecycle identifier + converse round guard (PIPELINE-1 §9.1.1) - #859

Merged
JarbasAl merged 1 commit into
devfrom
feat/utterance-id
Aug 13, 2026
Merged

spike: context.utterance_id — lifecycle identifier + converse round guard (PIPELINE-1 §9.1.1)#859
JarbasAl merged 1 commit into
devfrom
feat/utterance-id

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Aug 13, 2026

Copy link
Copy Markdown
Member

🤖 Auto-generated by Claude Fable 5 (claude-fable-5) via Claude Code — NOT human-reviewed. Verify before acting.

Gives every utterance a lifecycle id, stamped once when the utterance enters the pipeline. It rides along in the message context through replies and forwards, so anything downstream can tell which utterance an event belongs to.

First consumer: the converse poll. Answers from a previous round (same session, older utterance) used to be able to sneak into the current round; now they're matched on session + utterance id and stale ones are dropped. Messages without the id behave exactly as before, so old clients lose nothing.

Unit suite green with new tests covering the stale-answer case and the no-id fallback.

Spike. The orchestrator names each utterance lifecycle once, at entry,
with an opaque uuid4 in context.utterance_id. Message.reply/forward
deep-copy context, so every derived Message carries it for free.

The transformer chain replaces message.context wholesale, so the entry
value is re-asserted after it runs (same value, not an overwrite).

One consumer ships: the converse ping-pong round guard discards a pong
whose utterance_id does not match the open round (CONVERSE-1 §4.2).
This closes the late-answer-wins-wrong-round bug, where a slow skill's
answer to round N-1 lands inside round N's window and decides it.

The guard stands down when the round has no utterance_id, so callers
that never entered through the orchestrator behave as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 54620a8a-6233-42cf-b192-ac673ea4d0db

📥 Commits

Reviewing files that changed from the base of the PR and between cb479ae and f68bebf.

📒 Files selected for processing (4)
  • ovos_core/intent_services/converse_service.py
  • ovos_core/intent_services/service.py
  • test/unittests/test_converse_service.py
  • test/unittests/test_intent_service_extended.py

📝 Walkthrough

Walkthrough

The change adds UUID-based utterance lifecycle tracking and preserves identifiers across transformations. Converse response collection now matches pong responses to the active utterance identifier while retaining legacy behavior for rounds without identifiers. Tests cover identifier propagation and stale-response filtering.

Changes

Utterance lifecycle and converse correlation

Layer / File(s) Summary
Utterance lifecycle identifier tracking
ovos_core/intent_services/service.py, test/unittests/test_intent_service_extended.py
handle_utterance creates or preserves context.utterance_id before transformation. It restores the identifier when a transformer replaces the message context. Tests cover uniqueness, preservation, and propagation.
Converse pong round correlation
ovos_core/intent_services/converse_service.py, test/unittests/test_converse_service.py
Converse collection ignores pongs with a different utterance_id. Matching pongs remain accepted, and unnamed rounds retain prior acceptance behavior. Tests cover all three cases.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

✨ 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 feat/utterance-id

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 Aug 13, 2026

Copy link
Copy Markdown

Elementary, my dear contributor! The checks are finished. 🕵️‍♂️

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

📋 Repo Health

Scanning for any signs of code rot or decay. 🍄

✅ All required files present.

Latest Version: 2.6.3a1

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)

Ensuring our security logs are being captured. 🪵

✅ No known vulnerabilities found (113 packages scanned).

🔎 Type Check

I've distilled the results into this summary. 🧪

mypy: 272 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/272)
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:3:1: error: Skipping analyzing "ovos_config": 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.intent_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.metadata_transformers": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/transformers.py:6: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.transformer_services": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/intent_services/manifest.py:15:1: error: Skipping analyzing "ovos_bus_client.message": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/intent_services/manifest.py:16:1: error: Skipping analyzing "ovos_spec_tools": module is installed, but missing library stubs or py.typed marker  [import-untyped]
ovos_core/intent_services/manifest.py:17:1: error: Skipping analyzing "ovos_utils.log": module is installed, but missing library stubs or py.typed marker  [import-untyped]

📚 Docs

Here's the report you've been waiting for. 📁

✅ All required documentation files present.

README.md

🏷️ Release Preview

Checking if we've included all the important changes. 📋

Current: 2.6.3a1Next: 2.6.3a2

Signal Value
Label (none)
PR title spike: context.utterance_id — lifecycle identifier + converse round guard (PIPELINE-1 §9.1.1)
Bump alpha

⚠️ No conventional commit prefix — alpha-only bump.
Suggested: fix: update the thing or feat: update the thing


🚀 Release Channel Compatibility

Predicted next version: 2.6.3a2

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

📊 Coverage

Peeking behind the curtain of your test suite. 🎭

⚠️ 65.1% 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/transformers.py 33.3% 18
ovos_core/skill_installer.py 45.3% 134
ovos_core/intent_services/service.py 55.7% 182
ovos_core/skill_manager.py 62.0% 156
ovos_core/intent_services/dispatcher.py 73.4% 29

Full report: download the coverage-report artifact.

🔌 Plugin Detection

Evaluating the overall quality of the plugin's implementation. ✨

Plugin Status: ERRORS (1)

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 ✅ 1542ms
ovos-fallback-pipeline-plugin pipeline ✅ 2ms
ovos-stop-pipeline-plugin pipeline ✅ 61ms

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

Issues:

  • ❌ Import time for ovos-converse-pipeline-plugin exceeds 500ms (1542ms)
  • ⚠️ No settingsmeta.json found
  • ⚠️ No settingsmeta.json found

🔨 Build Tests

I've laid the bricks for your new logic. 🧱

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

🔌 Skill Tests (ovoscope)

Testing the skill's 'offline' capabilities (if any). 🔌

4/40 passed

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

test_adapt_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

test_padatious_no_match 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:

[gw3] 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 ❌ subtests passed
test_count_infinity_stop_low ❌ subtests passed
test_count_infinity_global ❌ subtests passed
test_count_infinity_active ❌ subtests passed

test_count failure:

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

test_count_infinity_stop_low failure:

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

test_count_infinity_global failure:

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

test_deactivate_inside_converse failure:

[gw1] 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:

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

test_global_stop_voc_with_active_skill failure:

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

test_stop_voc_exact_still_works failure:

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

test_global_stop_voc_no_active_skills failure:

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

test_high_priority_stage_handles_before_low failure:

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

test_no_match_produces_intent_failure failure:

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

test_blacklisted_skill_falls_through_to_failure failure:

[gw0] 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:

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

test_lang_text_detection failure:

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

test_metadata_preferred_over_text_detection failure:

[gw3] linux -- Python 3.11.15 /opt/hostedtoolcache/Python/3.11.15/x64/bin/python
❌ **TestLegacyIntentIdBackCompat** — 0/2
Test Result
test_legacy_blacklist_id_suppresses ❌ subtests passed
test_legacy_dispatch_topic_fires_handler ❌ subtests passed

test_legacy_blacklist_id_suppresses failure:

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

test_legacy_dispatch_topic_fires_handler failure:

[gw2] 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:

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

test_complete_failure failure:

[gw2] 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_adapt_no_match ❌ subtests passed
test_padatious_match ❌ subtests passed
test_skill_blacklist ❌ subtests passed

test_intent_blacklist failure:

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

test_adapt_no_match failure:

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

test_padatious_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_exact ❌ subtests passed
test_not_exact_high ❌ subtests passed

test_not_exact_med failure:

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

test_exact failure:

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

test_not_exact_high failure:

[gw3] 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:

[gw2] 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

Measuring the reach of our bus handlers. 📏

🔴 Coverage Summary

Metric Status Coverage
Listeners █░░░░░░░░░ 12.9% 32/248 handlers
Emitters ██████████ 100% 59/59 observed
Assertions ██████████ 100% 59/59 asserted

📊 Per-Skill Breakdown

Skill Listeners Observed Asserted
AdaptPipeline 0/14 (0.0%) 0/0 0/0
ConverseService 3/4 (75.0%) 0/0 0/0
DomainAdaptPipeline 0/14 (0.0%) 0/0 0/0
FallbackService 0/2 (0.0%) 0/0 0/0
HierarchicalAdaptPipeline 0/14 (0.0%) 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
Model2VecPrototypePipeline 0/12 (0.0%) 0/0 0/0
PadaciosoPipeline 0/11 (0.0%) 0/0 0/0
PadatiousPipeline 0/15 (0.0%) 0/0 0/0
SkillManager 0/5 (0.0%) 0/0 0/0
StopService 1/2 (50.0%) 0/0 0/0
__core__ 4/24 (16.7%) 9/9 9/9
ovos-skill-count.openvoiceos 1/21 (4.8%) 8/8 8/8
ovos-skill-hello-world.openvoiceos 2/26 (7.7%) 9/9 9/9
ovos-skill-parrot.openvoiceos 8/39 (20.5%) 11/11 11/11
stop.openvoiceos 0/0 (0.0%) 6/6 6/6
test_activation.openvoiceos 8/27 (29.6%) 16/16 16/16
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
  • detach_skill
  • intent.service.adapt.get
  • intent.service.adapt.manifest.get
  • intent.service.adapt.vocab.manifest.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
  • register_intent
  • register_vocab

ConverseService

⚠️ Uncovered Listeners:

  • intent.service.active_skills.get
    ✅ Covered Listeners:
  • converse:skill (6x)
  • intent.service.skills.activate (1x)
  • intent.service.skills.deactivate (3x)

DomainAdaptPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.keyword (Intent)
  • detach_intent
  • detach_skill
  • intent.service.adapt.get
  • intent.service.adapt.manifest.get
  • intent.service.adapt.vocab.manifest.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
  • register_intent
  • register_vocab

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
  • detach_skill
  • intent.service.adapt.get
  • intent.service.adapt.manifest.get
  • intent.service.adapt.vocab.manifest.get
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
  • register_intent
  • register_vocab

IntentDispatcher

⚠️ Uncovered Listeners:

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

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.pipelines.reload
    ✅ Covered Listeners:
  • intent.service.skills.deactivate (3x)
  • ovos.utterance.handle (12x)

Model2VecPrototypePipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • padatious:register_intent (Intent)
  • detach_intent
  • detach_skill
  • mycroft.ready
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister
  • register_intent

PadaciosoPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • padatious:register_entity (Intent)
  • padatious:register_intent (Intent)
  • detach_intent
  • detach_skill
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister

PadatiousPipeline

⚠️ Uncovered Listeners:

  • ovos.intent.deregister (Intent)
  • ovos.intent.disable (Intent)
  • ovos.intent.enable (Intent)
  • ovos.intent.register.template (Intent)
  • padatious:register_entity (Intent)
  • padatious:register_intent (Intent)
  • detach_intent
  • detach_skill
  • intent.service.padatious.entities.manifest.get
  • intent.service.padatious.get
  • intent.service.padatious.manifest.get
  • mycroft.skills.train
  • ovos.entity.deregister
  • ovos.entity.register
  • ovos.skill.deregister

SkillManager

⚠️ Uncovered Listeners:

  • skill.converse.get_response.disable
  • skillmanager.activate
  • skillmanager.deactivate
  • skillmanager.keep
  • skillmanager.list

StopService

⚠️ Uncovered Listeners:

  • stop:skill (Intent)
    ✅ Covered Listeners:
  • stop:global (2x)

__core__

⚠️ Uncovered Listeners:

  • add_context
  • clear_context
  • message
  • 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-hello-world.openvoiceos.set
  • ovos-skill-parrot.openvoiceos.set
  • ovos.session.sync
  • ovos.session.update_default
  • ovos.skills.converse.force_timeout
  • remove_context
  • skill.converse.get_response.enable
  • test_activation.openvoiceos.set
    ✅ Covered Listeners:
  • ovos.utterance.handled (23x)
  • ovos.utterance.speak (20x)
  • skill.converse.pong (5x)
  • skill.converse.response (4x)

📤 Emitters:

  • mycroft.audio.play_sound (Asserted ✅)
  • ovos-skill-parrot.openvoiceos.converse.ping (Asserted ✅)
  • ovos.intent.unmatched (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
  • mycroft.stop
  • ovos-skill-count.openvoiceos.converse.get_response
  • ovos-skill-count.openvoiceos.set
  • ovos-skill-count.openvoiceos.stop
  • ovos-skill-count.openvoiceos.stop.ping
  • ovos.common_query.ping
  • ovos.skills.settings_changed
    ✅ Covered Listeners:
  • ovos-skill-count.openvoiceos:count_to_n (4x)

📤 Emitters:

  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • ovos-skill-count.openvoiceos.activate (Asserted ✅)
  • ovos-skill-count.openvoiceos:count_to_n (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:HelloWorldIntent (Intent)
  • ovos-skill-hello-world.openvoiceos:HowAreYou (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 (2x)
  • ovos-skill-hello-world.openvoiceos:Greetings (2x)

📤 Emitters:

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

ovos-skill-parrot.openvoiceos

⚠️ Uncovered Listeners:

  • ovos-skill-parrot.openvoiceos:did_you_hear_me (Intent)
  • ovos-skill-parrot.openvoiceos:did_you_hear_me.intent (Intent)
  • ovos-skill-parrot.openvoiceos:repeat_stt (Intent)
  • ovos-skill-parrot.openvoiceos:repeat_stt.intent (Intent)
  • ovos-skill-parrot.openvoiceos:repeat_tts (Intent)
  • ovos-skill-parrot.openvoiceos:repeat_tts.intent (Intent)
  • ovos-skill-parrot.openvoiceos:speak (Intent)
  • ovos-skill-parrot.openvoiceos:speak.intent (Intent)
  • ovos-skill-parrot.openvoiceos:start_parrot.intent (Intent)
  • ovos-skill-parrot.openvoiceos:stop_parrot (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 (1x)
  • intent.service.skills.deactivated (3x)
  • mycroft.stop (2x)
  • ovos-skill-parrot.openvoiceos.activate (6x)
  • ovos-skill-parrot.openvoiceos.converse.ping (6x)
  • ovos-skill-parrot.openvoiceos.converse.request (4x)
  • ovos-skill-parrot.openvoiceos:start_parrot (2x)
  • recognizer_loop:utterance (8x)

📤 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 (Asserted ✅)
  • ovos.intent.matched (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • ovos.utterance.speak (Asserted ✅)
  • skill.converse.pong (Asserted ✅)
  • skill.converse.response (Asserted ✅)

stop.openvoiceos

📤 Emitters:

  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • mycroft.stop (Asserted ✅)
  • ovos.utterance.handled (Asserted ✅)
  • stop.openvoiceos.activate (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.stop
  • 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 (1x)
  • intent.service.skills.deactivated (3x)
  • test_activate (1x)
  • test_activation.openvoiceos.activate (3x)
  • test_activation.openvoiceos.converse.ping (2x)
  • test_activation.openvoiceos.converse.request (2x)
  • test_activation.openvoiceos.deactivate (3x)
  • test_deactivate (1x)

📤 Emitters:

  • converse:skill (Asserted ✅)
  • intent.service.skills.activate (Asserted ✅)
  • intent.service.skills.activated (Asserted ✅)
  • intent.service.skills.deactivate (Asserted ✅)
  • intent.service.skills.deactivated (Asserted ✅)
  • mycroft.skill.handler.complete (Asserted ✅)
  • mycroft.skill.handler.start (Asserted ✅)
  • ovos.intent.handler.complete (Asserted ✅)
  • ovos.intent.handler.start (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:record_begin (Intent)
  • recognizer_loop:record_end (Intent)
    ✅ Covered Listeners:
  • recognizer_loop:audio_output_end (18x)
  • recognizer_loop:audio_output_start (20x)

⚖️ License Check

Verifying that everything is above board legally. ⚓

✅ No license violations found.

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


Providing clarity through automated analysis 🔍

@JarbasAl
JarbasAl marked this pull request as ready for review August 13, 2026 18:58
@JarbasAl
JarbasAl merged commit 140f088 into dev Aug 13, 2026
20 checks passed
@JarbasAl
JarbasAl deleted the feat/utterance-id branch August 13, 2026 18:58
JarbasAl added a commit that referenced this pull request Aug 14, 2026
…p ping/pong (PIPELINE-1 §9.1.1)

Applies the same round-correlation guard added to converse_service's
handle_ack in #859 to the remaining poll rounds: fallback_service's
ovos.skills.fallback.pong collector and stop_service's skill.stop.pong
collector now discard pongs whose utterance_id or session mismatches
the open round, standing down when the round carries no utterance_id
(V0 back-compat). This closes the same late-answer-wins-wrong-round
class of bug for fallback and stop, mirroring converse's fix.

Note: common_query.py's phrase-string correlation (also flagged in the
originating task) does not live in ovos-core -- that logic is in the
separate ovos-common-query-pipeline-plugin repo and is out of scope
here; left untouched.

> 🤖 Auto-generated by Claude Sonnet 5 (claude-sonnet-5) via Claude Code — NOT human-reviewed. Verify before acting.
Verified: new tests exercise the actual FallbackService/StopService
ping-pong collectors against a FakeBus; red-before confirmed by
reverting the source guard (test files kept) and re-running the new
test classes, which failed exactly as expected; green after
reapplying. Full unit suite (350 tests) passes on top of the fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JarbasAl added a commit that referenced this pull request Aug 14, 2026
…p ping/pong (PIPELINE-1 §9.1.1) (#862)

Applies the same round-correlation guard added to converse_service's
handle_ack in #859 to the remaining poll rounds: fallback_service's
ovos.skills.fallback.pong collector and stop_service's skill.stop.pong
collector now discard pongs whose utterance_id or session mismatches
the open round, standing down when the round carries no utterance_id
(V0 back-compat). This closes the same late-answer-wins-wrong-round
class of bug for fallback and stop, mirroring converse's fix.

Note: common_query.py's phrase-string correlation (also flagged in the
originating task) does not live in ovos-core -- that logic is in the
separate ovos-common-query-pipeline-plugin repo and is out of scope
here; left untouched.

> 🤖 Auto-generated by Claude Sonnet 5 (claude-sonnet-5) via Claude Code — NOT human-reviewed. Verify before acting.
Verified: new tests exercise the actual FallbackService/StopService
ping-pong collectors against a FakeBus; red-before confirmed by
reverting the source guard (test files kept) and re-running the new
test classes, which failed exactly as expected; green after
reapplying. Full unit suite (350 tests) passes on top of the fix.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant