fix(config): trust APPS_SCHEMA float type over an int default in get_arg() (#4925) - #4938
Open
chalfontchubby wants to merge 1 commit into
Open
fix(config): trust APPS_SCHEMA float type over an int default in get_arg() (#4925)#4938chalfontchubby wants to merge 1 commit into
chalfontchubby wants to merge 1 commit into
Conversation
…arg() (#4925) get_arg() coerces its return value on the *type* of the default it was handed, not on the key's declared APPS_SCHEMA type, and applies that coercion to whatever value was resolved - real configured value or not. So get_arg("solcast_poll_hours", 8) ran a genuinely configured 4.8 through int(float(value)) and returned 4, shortening the Solcast poll TTL from 4.8h to 4h and pushing a two-site hobbyist account past its 10 poll/day quota into nightly HTTP 429s. Nothing warned: validate_config() checks the raw apps.yaml value against the float schema and passes it, so apps.yaml still reads 4.8 while the runtime behaves as 4. The issue's own suggested fix (normalise int defaults inside Components.initialize()) only covers the component-framework path. Auditing every float-declared APPS_SCHEMA key against its get_arg call sites found three more truncating reads that fix would miss - octopus_saving_session_rate and octopus_saving_session_min_octopoints_per_kwh are read directly from octopus.py, not through a component arg spec - plus a fifth affected component arg (alphaess_api_delay) the issue's table didn't list. Fixed at the source in get_arg() instead: promote an int default to float whenever APPS_SCHEMA declares the key float, before the coercion at the end of the function ever sees it. One normalisation point, mirroring where #4441 fixed the equivalent CONFIG_ITEMS-route bug in get_ha_config(), and no call site - present or future - can change a float-declared key's runtime type by writing 8 instead of 8.0. Test suite: a direct regression test for the reported 4.8 -> 288min case plus the money and non-component-path cases, and a sweep test that walks every COMPONENT_LIST arg spec whose APPS_SCHEMA type is float and confirms it resolves a fractional value intact - resolving each spec the way Components.initialize() does, so it stays correct for specs added later rather than asserting on today's literals. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Fixes #4925.
Problem
get_arg()coerces its return value on the type of the default it was handed, not on the key's declaredAPPS_SCHEMAtype, and applies that coercion to whatever value was resolved — real configured value or not. Soget_arg("solcast_poll_hours", 8)ran a genuinely configured4.8throughint(float(value))and returned4, shortening the Solcast poll TTL from 4.8h to 4h and pushing a two-site hobbyist account past its 10 poll/day quota into nightly HTTP 429s. Nothing warned:validate_config()checks the raw apps.yaml value against the float schema and passes it, so apps.yaml still reads4.8while the runtime behaves as4.Why not the issue's suggested fix
The issue proposes normalising int defaults inside
Components.initialize(). That only covers the component-framework path. Auditing every float-declaredAPPS_SCHEMAkey against itsget_argcall sites found three more truncating reads that fix would miss —octopus_saving_session_rateandoctopus_saving_session_min_octopoints_per_kwhare read directly fromoctopus.py, not through a component arg spec — plus a fifth affected component arg (alphaess_api_delay) the issue's table didn't list.Fix
Fixed at the source in
get_arg()(userinterface.py): promote an int default to float wheneverAPPS_SCHEMAdeclares the key float, before the coercion at the end of the function ever sees it. One normalisation point, mirroring where #4441 fixed the equivalentCONFIG_ITEMS-route bug inget_ha_config(), so no call site — present or future — can change a float-declared key's runtime type by writing8instead of8.0.Not included: the issue's second ask (a warning on lossy coercion). With the root cause fixed at the source, a remaining truncation means the schema genuinely declares the key an integer, so the warning would fire on intended behaviour every ~5 minutes on a routine sensor read.
Testing
test_get_arg_float_schema_int_default_not_truncated— the reported 4.8 → 288min case, anaxle_pence_per_kwhmoney case, a direct (non-component) call site, unset-fallback typing, and negative controls for integer-declared and boolean keys.test_component_arg_specs_resolve_float_declared_keys_as_float— sweeps everyCOMPONENT_LISTarg spec whoseAPPS_SCHEMAtype is float, resolving each the wayComponents.initialize()does (currently 9 keys), so it stays correct for specs added later rather than asserting on today's literals.userinterface.pyand pass with the fix../run_all --quickgreen,./run_pre_commitgreen.Written by Claude on behalf of @chalfontchubby.
🤖 Generated with Claude Code