fix: Correct the supported Home Assistant floor and three cost defects - #18
Merged
Merged
Conversation
hacs.json declared 2025.2.0, but every platform module imports AddConfigEntryEntitiesCallback, which Home Assistant only gained in 2025.3.0. HACS gates installation on that declared floor, so anyone on the 2025.2 line was allowed to install and then had every platform fail to import, including the event entities, leaving a traceback instead of the clean "needs a newer Home Assistant" message HACS exists to give. The floor was established by resolving every homeassistant import in the package against 2025.2.5 and 2025.3.0 wheels, not by taking the review at its word: that one symbol is the only thing missing at 2025.2.5, and nothing in the import surface pushes it higher. Two CI jobs now keep that honest. One installs the declared minimum and imports every module, so the claim cannot drift again. One runs the suite against the newest Home Assistant, which is what the weekly schedule was documented to do and could not, because the test requirements pin a single version, so every scheduled run re-tested exactly what the last push had. Both are scheduled or manual only, so neither can block a pull request for something a contributor did not do. Setup no longer blocks for twenty seconds on an unreachable device. Provisioning moves off the setup path, so platforms stop queueing behind it, and a device whose shape is already remembered gets a shorter first deadline because that poll is only fetching values the next one will bring anyway. A device nothing is known about deliberately keeps the full deadline: there, the poll is the only thing that can create its entities at all. The slow refresh cadence counted refreshes rather than seconds, so every requested refresh advanced it and metadata was polled more often than its own docstring claimed. It is now measured in elapsed time and named for it. Automatic-mode healing retried forever, one error line and one extra request a minute for as long as the entry existed. It now backs off on repeated failure, keyed on what the attempt would do rather than on the error, so freeing a slot in the wBox app is acted on at the next cycle instead of at the end of the backoff, and a genuinely new problem is never delayed by an old one. CONTRIBUTING no longer claims lint blocks the build, since branch protection decides that and does not currently require it.
sdebasek
force-pushed
the
fix/review-install-and-perf
branch
from
August 21, 2026 11:50
6204de7 to
5980103
Compare
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.
Second of three PRs from the multi-agent review: installation, CI and runtime cost. Merge after #17.
1. The declared Home Assistant floor was wrong, and shipped a broken install
hacs.jsondeclared2025.2.0. All eight platform modules importAddConfigEntryEntitiesCallbackat module top level, and that name only exists from 2025.3.0. HACS gates installation on the declared floor, so a user on the 2025.2 line was allowed to install and update, and then every platform raised ImportError duringasync_forward_entry_setups. Nothing survived, not even the pushed event entities, sinceevent.pyimports the same name. They got a traceback instead of the clean "requires a newer Home Assistant" message HACS exists to produce.The floor was established rather than assumed. Every
from homeassistant...import across all 17 modules was AST-extracted and each symbol resolved against unpacked 2025.2.5 and 2025.3.0 wheels, checking top-level bindings, class members, function signatures and keyword arguments:AddConfigEntryEntitiesCallbackis the only symbol missing at 2025.2.5, and the entire import surface is satisfied at 2025.3.0. PyPI confirms 2025.2.5 is the last 2025.2 patch, so the floor is exactly 2025.3.0.ConfigEntry[_DataT]withruntime_data(so both the attribute and thetypealias work),DataUpdateCoordinator(config_entry=...),async_schedule_reload,ir.async_create_issuekwargs,er.RegistryEntryDisabler,dr.async_get_device(identifiers=...),get_url's five kwargs, all eight selectors,EventEntity,UpdateEntityFeature.INSTALL,ColorMode.RGB,ZeroconfServiceInfo.host,DhcpServiceInfo.Fixed in
hacs.jsonandREADME.md.2. The weekly CI run could not do the job it was added for
The workflow's weekly
schedule:exists, per its own comment and CONTRIBUTING, so that a Home Assistant release breaking the integration is caught without anyone pushing. It could not:requirements-test.txtpinspytest-homeassistant-custom-component, so every scheduled run installed the same Home Assistant and re-tested exactly what the last push tested.Two new jobs, both scheduled or manual only, so neither can block a pull request for something a contributor did not cause:
latest HAinstallspytest-homeassistant-custom-componentunpinned and runs the suite. Chosen overcontinue-on-erroron the pinned job, because that would hide a genuine break behind a green run.minimum HAreads the floor back out ofhacs.json, installs that Home Assistant, and imports every module, so point 1 cannot silently drift again. It installshomeassistantdirectly rather than adding a second pin that could drift from the claim it guards, and it imports rather than running the suite, since the tests target a core 18 months newer.Both steps were dry-run locally: the floor step resolves to
homeassistant==2025.3.0and the import step imports all 17 modules and exits 0.3. Setup blocked for about 20 seconds on an unreachable device
Two sequential 10 second timeouts, addressed separately:
Offline restart of a known device: roughly 20s becomes 3s. First-ever setup of an offline device stays at 10s on purpose, since there the poll is the only thing that can ever create its polled entities. That asymmetry has its own test so it cannot be tidied away later.
Rejected: forwarding platforms before the refresh completes.
last_update_successstartsTrue, so entities built from the seeded cache would briefly publish remembered values as live state and pollute history.4. The slow cadence counted refreshes, not seconds
SLOW_REFRESH_EVERY = 12was documented as "5s x 12 = 1min" but counted refresh cycles, so every requested refresh (each settings write triggers one) advanced it and metadata was polled more often than claimed, at a rate that varied with user activity. NowSLOW_REFRESH_SECONDS = 60, compared against elapsed time._force_fullstill short-circuits it, so writes are unaffected.5. Healing retried forever
A device that can never accept provisioning, for example one whose slots are full of foreign actions, produced one ERROR line and one extra request every minute indefinitely. Backoff is now 1, 2, 4, 8 ... slow cycles up to about an hour, keyed on what the attempt would do (the missing callbacks plus the slot layout) rather than on the error type. So freeing a slot in the wBox app resets it and is acted on at the next cycle instead of at the end of a long wait, and a genuinely new problem is never delayed by an old failure. A repeated identical failure now logs at DEBUG, taking the documented case from about 1440 ERROR lines a day to one.
Not the approach the review suggested. Keying on
InsufficientSlotsErroralone would have left every other repeated failure retrying forever.6. CONTRIBUTING claimed lint blocks the build
It does not, because branch protection decides and does not currently require it. The doc now says so plainly.
Action for you: mark
ruffas a required status check onmain. The full set should behassfest,HACS,ruff,tests.minimum HAis deliberately not recommended as required yet: it installs an old release from PyPI, so an upstream packaging problem could block merges for an unrelated reason.Testing
205 passing, 98% coverage counting branches,
ruffclean, all YAML parses.Seven new tests, five of them proven to fail against pre-fix code with the failure recorded. One backoff test was additionally checked against a wrong fix (backoff ignoring the slot layout) to confirm it catches that too. Two tests are flagged as behaviour-preservation guards rather than presented as regressions.
Not tested on hardware.