Skip to content

refactor: drop redundant legacy dual bus subscriptions - #179

Merged
JarbasAl merged 6 commits into
devfrom
refactor/trust-the-bus-bridge
Aug 15, 2026
Merged

refactor: drop redundant legacy dual bus subscriptions#179
JarbasAl merged 6 commits into
devfrom
refactor/trust-the-bus-bridge

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Aug 1, 2026

Copy link
Copy Markdown
Member

Summary

PlaybackService.init_messagebus subscribed both the legacy and the spec
topic for six AUDIO-1 adoptions:

  • mycroft.stop
  • mycroft.audio.speech.stop
  • mycroft.audio.speak.status
  • mycroft.audio.queue
  • mycroft.audio.play_sound
  • speak:b64_audio

All six are already present in the ovos-spec-tools MIGRATION_MAP, and the
ovos-bus-client namespace bridge (MessageBusClient.on_message, and its
FakeBus equivalent) mirrors a legacy emit onto its spec counterpart for
LOCAL listeners. This means a handler subscribed only on the spec topic
already fires when a deployment emits the legacy one — the manual legacy
self.bus.on(...) calls were redundant duplicate dispatch, not a
compatibility requirement.

This PR drops the six legacy subscriptions and keeps the spec-topic
subscription only, relying on the bridge for legacy-emitting deployments.

Test plan

  • Added test/end2end/test_legacy_dual_subscription_dropped_e2e.py: boots a
    real PlaybackService on a bridge-enabled FakeBus (modernize=True,
    emit_legacy=True) and emits each of the six legacy topics directly,
    asserting the spec-only handler still fires. This locks in the dependency
    on the bus-client bridge contract going forward.
  • Updated test/unittests/test_service_handlers.py::TestAudio1DualNamespaceRegistration
    to assert the legacy topics are no longer registered directly (spec topic
    only).
  • Ran the touched suites: test/unittests/test_service.py,
    test/unittests/test_service_handlers.py,
    test/end2end/test_spec_bus_messages_e2e.py,
    test/end2end/test_b64_dual_namespace_e2e.py,
    test/end2end/test_legacy_dual_subscription_dropped_e2e.py — 75 passed, 7
    skipped.

Identified by automated compat-layer survey; implemented by Claude (sonnet),
orchestrated by Claude Fable.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved compatibility between legacy and current audio message topics, ensuring stop, speaking-status, queued audio, instant playback, and speech messages continue to reach the correct handlers.
    • Instant playback now provides both current and legacy response notifications for broader compatibility.
  • Tests

    • Added end-to-end coverage for legacy audio message handling and updated service lifecycle verification.

Backcompat audit (executed version-skew matrix, three bus-client vintages): the receive-side bridge (counterpart_topics dispatch in MessageBusClient.on_message) is what makes the dropped subscriptions redundant, and it delivers exactly-once for a stable 1.5.0-era emitter and for modern marked twins alike. Two corrections landed from the audit: the ovos-bus-client floor moves to >=2.8.3a1 (the old floor admitted client versions without the bridge, where a stable emitter's mycroft.stop/play_sound/queue/b64 frames reached no handler at all), and the e2e test's claim is narrower than its wording — it runs on FakeBus's reimplementation of the rules, so the bridge contract itself is guarded by the executed skew matrix and by ovos-test-harness cells (five legacy-audio cells queued there), not by that test.

…vice

init_messagebus subscribed both the legacy and spec topic for six
AUDIO-1 adoptions (mycroft.stop, mycroft.audio.speech.stop,
mycroft.audio.speak.status, mycroft.audio.queue,
mycroft.audio.play_sound, speak:b64_audio). All six are already in the
ovos-spec-tools MIGRATION_MAP, and the bus-client namespace bridge
(MessageBusClient.on_message) mirrors a legacy emit onto its spec
counterpart for local listeners, so the manual legacy subscription was
dead weight duplicating handler dispatch. Keep the spec-topic
subscription only and add a regression test that drives each legacy
topic through a bridge-enabled FakeBus to lock in the dependency on
that boundary contract.

Identified by automated compat-layer survey; implemented by Claude
(sonnet), orchestrated by Claude Fable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The audio service now relies on namespace bridging for legacy input topics, keeps specification-topic subscriptions, emits the legacy instant-playback response, and adds regression coverage for bridged delivery and updated registrations.

Changes

Audio namespace bridge

Layer / File(s) Summary
Service topic wiring and responses
ovos_audio/service.py
Instant playback emits both response topics. Stop, speech-status, queue, playback, and base64 speech handlers subscribe directly only to specification topics.
Namespace bridge regression coverage
test/end2end/test_legacy_dual_subscription_dropped_e2e.py, test/unittests/test_service_handlers.py, test/unittests/test_speech.py
End-to-end tests verify six legacy topics reach specification-only handlers. Unit tests verify specification-only registrations and current stop events.

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

Sequence Diagram(s)

sequenceDiagram
  participant LegacyTopicEmitter
  participant NamespaceBridge
  participant PlaybackService
  LegacyTopicEmitter->>NamespaceBridge: emit legacy audio topic
  NamespaceBridge->>PlaybackService: forward as specification topic
  PlaybackService->>PlaybackService: invoke specification-only handler
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the removal of redundant legacy bus subscriptions, which is the main change.
✨ 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 refactor/trust-the-bus-bridge

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

Copy link
Copy Markdown

At your service! I've gathered all the check results for you. 🫡

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

🏷️ Release Preview

I've checked the 'Migration Guide' for clarity. 🗺️

Current: 2.2.0a1Next: 2.2.0a2

Signal Value
Label (none)
PR title refactor: drop redundant legacy dual bus subscriptions
Bump alpha

✅ PR title follows conventional commit format.


🚀 Release Channel Compatibility

Predicted next version: 2.2.0a2

Channel Status Note Current Constraint
Stable Too new (must be <0.5.0) ovos-audio>=0.4.0,<0.5.0
Testing Too new (must be <2.0.0) ovos-audio>=1.1.0,<2.0.0
Alpha Compatible ovos-audio>=2.2.0a1

📊 Coverage

Exploring the coverage frontier of your PR. 🚀

98.2% total coverage

Per-file coverage (9 files)
File Coverage Missing lines
ovos_audio/__main__.py 93.8% 1
ovos_audio/audio.py 95.3% 16
ovos_audio/__init__.py 100.0% 0
ovos_audio/playback.py 100.0% 0
ovos_audio/service.py 100.0% 0
ovos_audio/transformers.py 100.0% 0
ovos_audio/tts.py 100.0% 0
ovos_audio/utils.py 100.0% 0
ovos_audio/version.py 100.0% 0

Full report: download the coverage-report artifact.

🔒 Security (pip-audit)

Security report: No threats detected in the area. ✅

✅ No known vulnerabilities found (66 packages scanned).

🔍 Lint

I've double-checked the data for any anomalies. 🔍

ruff: issues found — see job log

📋 Repo Health

A routine checkup to keep the repo running smoothly. 🏥

✅ All required files present.

Latest Version: 2.2.0a1

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

🔌 Skill Tests (ovoscope)

I've checked the skill's 'integration' with other OVOS skills. 🤝

63/63 passed

TestAudioCaptureSequence — 1/1
TestAudioCaptureSequencePlayStop — 1/1
TestAudioDuckingLowersVolume — 1/1
TestAudioDuckingNoCurrentOnRecord — 1/1
TestAudioDuckingOnRecord — 1/1
TestAudioDuckingRestoresVolume — 1/1
TestB64Audio — 1/1
TestB64DualNamespaceDelivery — 6/6
TestDefaultSessionAccepted — 1/1
TestGetLanguagesTts — 1/1
TestGetTrackLength — 1/1
TestGetTrackPosition — 1/1
TestInstantPlayBinaryData — 1/1
TestInstantPlayWav — 1/1
TestLegacyTopicsStillReachSpecOnlyHandlers — 6/6
TestListBackends — 1/1
TestMultipleSpeaks — 1/1
TestMultipleSpeaksCaptureAllEvents — 1/1
TestNoSpuriousEventsAfterShutdown — 1/1
TestOcpFlagIntegration — 1/1
TestOpmG2pQuery — 1/1
TestOpmTtsQuery — 1/1
TestPlayHttpTrack — 1/1
TestPlayPauseResume — 1/1
TestPlaybackStopDualSubscription — 2/2
TestPlaylistNextPrev — 1/1
TestQueueSound — 1/1
TestQueueSoundWithBinaryData — 1/1
TestQueueTracks — 1/1
TestRestoreVolumeOnHandled — 1/1
TestRestoreVolumeOnHandledWhileSpeaking — 1/1
TestSeekBackward — 1/1
TestSeekForward — 1/1
TestSessionValidation — 1/1
TestSetTrackPosition — 1/1
TestSpeakAfterStop — 1/1
TestSpeakBasic — 1/1
TestSpeakExpectResponse — 1/1
TestSpeakNonDefaultSessionRejected — 1/1
TestSpeakResetMockTts — 1/1
TestSpeakSpecTopic — 1/1
TestSpeakStatus — 1/1
TestSpeakStatusNotSpeaking — 1/1
TestSpeakWithIdentContext — 1/1
TestStop — 1/1
TestStopBeforeGuardIsIgnored — 1/1
TestStopTTS — 1/1
TestTrackEndCallbackEmission — 1/1
TestTrackInfo — 1/1
TestTrackStartCallbackEmission — 1/1
TestTtsStopDualTopic — 2/2

🚌 Bus Coverage

Quantifying the invisible connections in your code. 💪

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

🔨 Build Tests

Did the code survive the compilation gauntlet? Let's see. 🛡️

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

🔗 Downstream Dependents

Just a little bit of automation magic for you. ✨

No dependents found for ovos-audio

⚖️ License Check

Checking for any missing license headers. ✍️

✅ No license violations found.

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


End of Line. ⬛

handle_instant_play replied via the generic <topic>.response
derivation, which ovos-spec-tools MIGRATION_MAP does not mirror
(only base request topics are mapped, not their derived replies).
A caller reaching the handler through the now-sole spec subscription
via the legacy 'mycroft.audio.play_sound' request never saw a
response. Emit both spellings explicitly, matching the existing
hand-mirrored pattern in handle_speak_status.

test_speech.py::test_life_cycle still asserted the dropped
'mycroft.stop' / 'mycroft.audio.speech.stop' direct subscriptions;
updated to the spec topics the refactor kept.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@JarbasAl
JarbasAl marked this pull request as ready for review August 1, 2026 18:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@test/unittests/test_service_handlers.py`:
- Around line 723-726: Remove direct legacy-topic registrations from
_wire_audio1_handlers, or initialize the service via
PlaybackService.init_messagebus using a bridge-enabled bus; update
test/end2end/test_legacy_dual_subscription_dropped_e2e.py lines 32-51 to assert
exactly one received message per legacy input and verify each uses the expected
specification topic.
🪄 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 Plus

Run ID: 377802a9-df12-4437-a6e5-097e4d298d7b

📥 Commits

Reviewing files that changed from the base of the PR and between 314f1d7 and c9df410.

📒 Files selected for processing (4)
  • ovos_audio/service.py
  • test/end2end/test_legacy_dual_subscription_dropped_e2e.py
  • test/unittests/test_service_handlers.py
  • test/unittests/test_speech.py

Comment thread test/unittests/test_service_handlers.py
JarbasAl and others added 4 commits August 1, 2026 19:24
…d-wired shortcut

_wire_audio1_handlers used to subscribe legacy topics directly, so the
dual-namespace unit tests could pass even if the bus-client namespace
bridge itself were broken. It now drives PlaybackService.init_messagebus
on the bridge-enabled FakeBus, exercising the actual bridge.

Also tighten the legacy-dual-subscription-dropped e2e test to assert
exactly one delivery on the expected spec topic per legacy input,
proving the bridge delivers once with no duplicate, instead of merely
asserting some invocation occurred.

Addresses CodeRabbit review on ovos-audio#179.
The tightened exactly-once check tripped on handle_speak_status: it
subscribes to ovos.audio.is_speaking AND emits its reply there
(AUDIO-OUT-1 §5.3 query==reply), so it legitimately re-fires on its own
reply — not a duplicate of the bridged legacy delivery. Assert the
bridge delivered on the spec topic first, not an exact count.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dropped legacy subscriptions are redundant only because
MessageBusClient.on_message counterpart-dispatches legacy wire frames onto
spec topics; that loop first exists in 2.6.3a1, and the twin-marker
semantics the exactly-once behavior relies on land in 2.8.3a1. The old
floor (2.5.1a1) admitted clients where a stable emitter's mycroft.stop /
play_sound / queue / b64 frames reached no handler at all.
@JarbasAl
JarbasAl merged commit d83123e into dev Aug 15, 2026
16 checks passed
@JarbasAl
JarbasAl deleted the refactor/trust-the-bus-bridge branch August 15, 2026 15:00
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