Skip to content

fix: enable_intent rebinds the handler after disable_intent - #508

Draft
JarbasAl wants to merge 1 commit into
devfrom
fix/enable-intent-rebind
Draft

fix: enable_intent rebinds the handler after disable_intent#508
JarbasAl wants to merge 1 commit into
devfrom
fix/enable-intent-rebind

Conversation

@JarbasAl

@JarbasAl JarbasAl commented Aug 1, 2026

Copy link
Copy Markdown
Member

Root cause

disable_intent() followed by enable_intent() never actually rebound the handler. Two separate bugs combine:

  1. ovos_workshop/skills/ovos.py enable_intent() called register_intent_file(intent_name, None) for padatious intents and register_intent(intent, None) for adapt intents. Both register_intent_file and _register_adapt_intent only call add_event(...) if handler: — passing None silently skips rebinding, so the intent was "enabled" bus-side but no callback was ever attached again.
  2. ovos_workshop/intents.py IntentServiceInterface.remove_intent() was invoked by disable_intent() with the skill_id-prefixed name, but registered_intents/detached_intents are keyed by the bare name (register_intent/register_template strip the <skill_id>: prefix before storing). The prefixed lookup never matched, so the intent was never actually moved into detached_intents — the internal disable bookkeeping was already broken before enable_intent even ran.
  3. While fixing the above and building the regression tests, found that register_template() (used by register_intent_file) never dropped a re-registered intent from detached_intents on re-registration — register_intent() (adapt path) already did this. Without it, intent_is_detached() kept reporting True forever after a padatious .intent file was re-enabled.

Fix

  • OVOSSkill now remembers each intent's handler in self._intent_handlers at registration time (register_intent_file / _register_adapt_intent), and enable_intent() passes that handler back into register_intent_file/register_intent instead of None.
  • IntentServiceInterface.remove_intent() normalizes away the <skill_id>: prefix before matching against the bare-keyed registry.
  • IntentServiceInterface.register_template() now clears the matching detached_intents entry on re-registration, mirroring register_intent().

Public API signatures are unchanged.

Reproduced on origin/dev (pre-fix). Found during adversarial review of #500.

Test plan

  • test/unittests/skills/test_base.py: implemented the previously-empty test_enable_intent, test_disable_intent, test_handle_enable_intent, test_handle_disable_intent stubs as real disable→enable round-trip regression tests, covering both padatious (.intent file) and adapt intents — asserting the handler actually fires again after re-enabling.
  • Verified all 4 new/filled tests fail on unfixed origin/dev code (checked out the pre-fix ovos_workshop/intents.py and ovos_workshop/skills/ovos.py against the new tests): 4 failed, 1 passed.
  • With the fix applied: pytest test/unittests/skills/test_base.py -q → 72 passed.
  • pytest test/unittests/skills/test_base.py test/unittests/skills/test_ovos.py test/unittests/test_intent4_producer.py test/unittests/skills/test_intent_provider.py test/end2end/test_intent4_producer_e2e.py -q → 129 passed.

🤖 Implemented by Claude (Sonnet), orchestrated by Claude Fable.

🤖 Generated with Claude Code

disable_intent()/enable_intent() never actually restored a handler:

- OVOSSkill.enable_intent() called register_intent_file(name, None) /
  register_intent(intent, None); both register_* paths skip add_event()
  whenever handler is falsy, so nothing was ever rebound.
- IntentServiceInterface.remove_intent() was called with the
  skill_id-prefixed name, but registered_intents/detached_intents are
  keyed by the bare name (register_intent/register_template strip the
  prefix before storing), so the detach bookkeeping never matched and
  disable_intent's internal state was already wrong going in.
- register_template() also never dropped a re-registered intent from
  detached_intents (register_intent already did), so intent_is_detached()
  kept reporting True forever after a padatious intent was re-enabled.

Fix: OVOSSkill now remembers each intent's handler in
self._intent_handlers at registration time and passes it back into
register_intent_file/register_intent on enable_intent(), instead of
None. remove_intent() normalizes the skill_id prefix before matching
against the bare-keyed registry, and register_template() clears the
matching detached_intents entry on re-registration.

Reproduced on origin/dev; found during adversarial review of #500.
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

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 Plus

Run ID: 99ee9065-bc94-46f6-a69b-f0f5afcc419e

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

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 added the fix label Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Checking back in with the latest test results. 📡

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

📋 Repo Health

Health report: The repository is thriving! 🌟

✅ All required files present.

Latest Version: 9.3.3a1

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

🔒 Security (pip-audit)

Ensuring our encryption is top-notch. 🔐

✅ No known vulnerabilities found (74 packages scanned).

🔍 Lint

I've got some results for you! 📝

ruff: issues found — see job log

⚖️ License Check

I've checked for any conflicting terms of service. 📜

✅ No license violations found.

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

🔨 Build Tests

Ensuring the foundation is solid for these changes. 🏛️

✅ All versions pass

Python Build Install Tests
3.10
3.11
3.12
3.13
3.14

Automating the path to a better future 🌈

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