Release 1.8.8a1 - #206
Closed
github-actions[bot] wants to merge 158 commits into
Closed
Release 1.8.8a1#206github-actions[bot] wants to merge 158 commits into
github-actions[bot] wants to merge 158 commits into
Conversation
Added AI disclosure section to README.md outlining the use of AI tools in project development and the maintenance of public records.
Add a self-contained probe that drives a real HotWordEngine over a single clip the way the listening loop does: a few seconds of leading silence to warm the engine's rolling feature window (openWakeWord et al. only emit once it is full, ~2.5 s — too little lead silently drops short positives and biases false rejects), then the clip streamed frame by frame, returning a detection decision plus latency and frames-to-detection. Unlike MiniVoiceLoop it needs no bus or [listener] extra — just the [bench] extra (numpy). Tolerates the HotWordEngine(lang) signature and the vestigial found_wake_word(frame) arg. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: per-clip WakeWordProbe for benchmark/test harnesses
…us-on-stop fix: restore SessionManager.bus when MiniCroft stops
End2EndTest.execute() and from_message() only stopped the MiniCroft on the success path, so a failing assertion left SessionManager.bus, default_session and Configuration patched for every later test. Both now run stop() from a finally block. MiniCroft snapshots the whole default Session at boot and restores it in stop(), so inject_active activations and wire-folded session values no longer outlive the test that made them. Mock-TTS unduck timers are tracked, made daemon and cancelled in stop(). An orphaned timer could otherwise emit onto a closed bus and fold a stale session onto the global SessionManager during a later test. CaptureSession resets its eof state atomically, records a timed_out flag, and returns a copy from finish(). A capture timeout now fails with a clear message instead of surfacing as a message-count mismatch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BusCoverageTracker snapshotted the session-cumulative global collector and added it into per-test counts, so every later test inherited the invocations of every earlier one. The snapshot is now a baseline and the report uses the delta over the tracker's own lifetime, frozen at start_tracking() so the tracking window is not counted twice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cmd_run booted a MiniCroft but never assigned it to the test, so execute() booted a second managed one and both patched the same globals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
match() treated mycroft.skill.handler.start as a failure signal, but it fires on a SUCCESSFUL match — so a successful match returned None. It also checked the failure flag before the captured message and spun a watcher thread that polled at 20Hz forever after a timeout. match_result() now returns a discriminated matched/no-match/timeout outcome and waits on the events directly. assert_no_match() fails on a timeout instead of passing vacuously; match() keeps its old signature. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The docstring told callers to emit after calling the helper, which is impossible single-threaded because the helper blocks. It now takes an optional emit= message and sends it once the handlers are in place. A match that raced an intent failure could also be dropped; appends are guarded by a lock and re-read once before giving up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The side effect inspected `mock.url` on a MagicMock, so no configured URL
ever matched and json() always returned {}. It now lives on the patched
GET, which receives the URL.
OCPTest also waits for ovos.common_play.query.response instead of sleeping
half the timeout, and stops the MiniCroft from a finally block.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AudioServiceHarness.__exit__ skipped bus.close() when shutdown() raised. ListenerHarness and MiniListener left their wildcard "message" capture handler on the bus, so a shared bus kept feeding a dead harness. PlaybackServiceHarness now restores the TTS.queue object it replaced and refuses a second concurrent harness, because TTS.queue is process-wide class state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A load failure was warned about and skipped, then resurfaced much later as an unrelated assert_emitted timeout. Loading now raises by default; pass tolerate_load_errors=True to keep going, in which case the errors are kept in load_errors and quoted in assert_emitted failures. MiniPHAL.__exit__ also detaches its capture handler and closes the bus. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cached MiniCrofts were never stopped and two could be live at once, each clobbering the same globals. At most one stays live now, and an atexit hook stops the rest. _wait_for_m2v_sync removes its three listeners in a finally block and only pays the 3.5s pad when no m2v activity was observed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feed_file ignored the join() result, so a listener thread that outlived its stop() kept appending to _messages during the next run. A still-alive thread is now logged and replaced with a fresh listener object. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`except (ImportError, Exception): pass` turned a malformed pyproject.toml into an understated coverage number. TOMLDecodeError and OSError are now caught explicitly and recorded in EcosystemCoverageReport.parse_errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The client was left in place on a ConnectionError, so its reconnect thread lived for the rest of the process. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One test per defect, each written to fail against the pre-fix code: teardown on the failure path, default-session isolation, TTS timer lifecycle, bus-coverage deltas, CaptureSession races, pipeline match verdicts, wait_for_match subscription order, the OCP HTTP mock, harness teardown, PHAL load errors, coverage parse errors and the RemoteRecorder connect leak. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
raise-by-default made the old warn-and-skip expectation wrong; cover both the default raise and the tolerate_load_errors opt-out. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CI showed two gaps: the session restore bailed out when boot replaced the default-session singleton, leaking exactly the state it exists to scrub — restore now targets whatever object holds the role at stop() time. And on Python 3.10 there is no stdlib tomllib, so a malformed pyproject.toml was silently ignored — depend on the tomli backport there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ovos-bus-client 1.x has serialize/deserialize, 2.x to_dict/from_dict; the snapshot silently became None on 1.x and the restore no-opped. Support both and warn instead of failing silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix: Han audit round 1 — teardown safety, session isolation, harness lifecycle
…n available cmd_validate always ran _basic_validate, contradicting docs/cli.md which documented it as preferring pydantic_helpers.validate_fixture when the pydantic extra is importable. Match the code to the documented behaviour instead of weakening the docs, and add tests covering both the pydantic-available and fallback paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
E2EPipelineHarness.setUp() (via detach_skill), register_padatious_intent,
register_padatious_entity, register_adapt_vocab, register_adapt_intent, and
detach_intent all emitted registration/deregistration/detach messages with
no context["skill_id"]. OVOS-INTENT-4 §3.1 requires every Message a skill
originates to carry context["skill_id"], and §3.2 requires it to equal the
payload skill_id for registration/deregistration traffic; a conformant
plugin (padatious#146, adapt#70, m2v#122, core#956) that enforces this drops
the harness's context-less messages, breaking test isolation between cases.
detach_skill already receives skill_id as an argument and now stamps it on
context unconditionally. The other five helpers gained a new *required*
keyword-only skill_id argument that is always stamped on context — there is
no derivation fallback from the name/entity_type/builder argument, because
Adapt vocab and intent names are conventionally unscoped ("Fruit",
"greeting", "R2TestIntent"): guessing a skill_id from a colon that may not
be there would silently register vocab under the wrong owner (or no owner),
which is the leak this fix exists to close. Every call site in ovoscope's
own tests and in docs/e2e-pipeline-harness.md now passes skill_id=
explicitly. Payload ("data") shapes are unchanged.
BREAKING CHANGE: register_padatious_intent, register_padatious_entity,
register_adapt_vocab, register_adapt_intent, and detach_intent now require
a skill_id keyword-only argument; calls omitting it raise TypeError.
Fail-before: reverting the ovoscope/e2e.py hunk while keeping the new tests
made all "requires_skill_id" assertions fail (no TypeError was raised, or
context["skill_id"] was absent); restoring the hunk turned them green.
Full suite: 698 passed, 25 skipped, 0 failed.
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…#190) The e2e registration helpers took skill_id as a keyword-only argument with no default, which broke every existing caller the moment it shipped. Eight repositories are red on that alone, found one CI job at a time. The argument stays required in every new call, and every shim still stamps Message.context['skill_id'] so a conformant plugin accepts the registration. A caller that omits it now gets the unattributed message it asked for, plus one warning naming the release the argument becomes required in, instead of a TypeError out of setUpClass.
… say (#189) `mycroft.skills.trained` is emitted before the container it reports has finished compiling: padatious never trains on the calling thread, so the event fires while `needs_compile` is still true. A consumer that waits on the event and then matches an utterance races the compile, and loses under load. The wait now reads the trainer. A plugin offering `wait_until_trained` is asked directly, and `container.needs_compile` decides whether work is outstanding, so the deadline is pushed forward while a trainer still has work rather than expiring on a quiet bus. The wait is skipped when it cannot be needed: no skill registered an intent, or nothing on the bus trains one. The first of those is not merely an optimisation. A fresh container reports `needs_compile` before anything is registered in it, so a boot with no skills at all would otherwise wait for a compile nobody asked for -- measured at 4.08s against dev's 0.59s on this host, and the whole of ovoscope's own suite at 117s against dev's 113s once the skip is in place. `docs/minicroft.md` stated a 300-second pytest-timeout, which is below the wait's own worst case. That ceiling is `OVOSCOPE_TRAINED_MAX` plus `OVOSCOPE_TRAINED_TIMEOUT`, 780 seconds at the shipped defaults, and a framework timeout below it kills setup mid-wait and reads as a boot failure -- exactly the misdiagnosis that section exists to prevent. It now names the sum and asks for 900. Co-authored-by: Claude Opus 5 (claude-opus-5) <noreply@anthropic.com>
DEFAULT_KEEP_SRC named only the legacy fallback ping, so under the canonical spelling the membership test missed and source/destination fell through to the rolling comparison. The assertion still ran and still passed, against a different rule. both_spellings() expands any topic to its migration counterpart and is applied to caller-supplied lists too, which had the same silent flip.
ovos-padatious dropped libfann and is now pure Apache; it moved from the [lgpl] extra to [plugins] in ovos-core 3.0.1a1. Bump the floor to 3.0.1a1 and remove the lgpl extra pin to reflect the current upstream split, matching ovoscope's prerelease-always policy. Verified: ovos-core 3.0.1a1 requires_dist lists - ovos_padatious<3.0.0,>=2.0.1a1; extra == "plugins" - ovos_padatious<3.0.0,>=2.0.1a1; extra == "test" All three matchers (Adapt, Padatious, Padacioso) are reachable through the single [plugins] extra, and the resolver no longer warns that ovos-core has no extra named lgpl. No lgpl reference survives in the tree. pyproject.toml's engines-extra comment and docs/multi-engine-golden.md both said padatious and padacioso ship with ovos-core[lgpl,plugins], and pyproject.toml, docs/minicroft.md and docs/prerelease-quirks.md told readers on older cores to add [lgpl] themselves — an extra that no longer exists, below a floor those cores cannot satisfy. All now name ovos-core[plugins]. Also clarifies timeout-blame semantics: the trained event carries no skill_id, so only the intent-registering set can be blamed. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…tent (#201) pyee guards its handler map with a plain Lock. _call_handlers holds that lock while it copies the handler list. The copy can start the cyclic garbage collector. When the collector ran CaptureSession.__del__ on that thread, __del__ called finish(). finish() called bus.remove(), and remove_listener waited for the lock that its own thread held. The thread deadlocked. This hung ovos-skill-weather#263 on Python 3.10 and 3.12. __del__ now only disarms the session and sets done. It takes no lock and does not call the bus. While the handlers are registered, the bus holds a reference to the session, so __del__ has nothing to remove. finish() records that it ran. A second call returns the snapshot and does not touch the bus. No signature changes. Co-authored-by: JarbasAi <jarbasai@mailfence.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The release-workflow.yml build_tests job was using install_extras: "audio,pydantic", which is narrower than the extras needed by the test suite. test_golden.py requires the engines extra (nebulento, ovos-m2v-pipeline), and test_listener_stream.py requires the listener extra (ovos-dinkum-listener). Align with build-tests.yml by installing the full test extra, which is the superset that covers all test dependencies. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…hem (#200) test_pipeline_config_none_does_not_patch allowed pipeline and blacklisted_intents. The default boot also sets blacklisted_pipelines, deliberately: intents.pipeline alone does not stop IntentService loading every other installed pipeline plugin, and only the blacklist does. The key belongs with the other two, and the allow-list had not followed the code. The docstring claimed the config must not be modified while the body already allowed two keys of modification; it now says what the test guards. Nothing asserted that stop() puts the config back. The fields tracking the original values work, but a key surviving stop() leaks into every later test in the same process and surfaces as an unrelated failure elsewhere. test_stop_restores_the_intents_config pins the key set and every value. Co-authored-by: JarbasAi <jarbasai@mailfence.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
§3.3 gives destination one form, a string, with no multi-address form. Every value here was a one-item list. Co-authored-by: JarbasAi <jarbasai@mailfence.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human review requested! This supersedes any earlier open release proposal for this repository.