Skip to content

feat(injector): exclude smart_icons attrs from recorder persistence - #15

Merged
jpettitt merged 1 commit into
mainfrom
feat/recorder-unrecorded-attrs-v2
Jun 14, 2026
Merged

jpettitt merged 1 commit into
mainfrom
feat/recorder-unrecorded-attrs-v2

Conversation

@jpettitt

Copy link
Copy Markdown
Owner

Summary

Tell HA's recorder to strip smart_icons_color and smart_icons_background from the JSON it persists to the state_attributes table. The state_changed event still fires (the painter needs it for live updates) — only the database-side payload changes:

  • Stored state_attributes rows shrink (our 2 attrs gone from the JSON)
  • Adjacent rows deduplicate much better, since the "real" entity attributes change less often than our decoration writes do
  • No effect on RAM / in-memory event bus / frontend behaviour

Motivated by a question that came up during a separate memory-leak investigation: even though the leak turned out not to be Smart Icons, recorder-side noise reduction is a real ongoing concern for installs with broad glob rules (e.g. sensor.* mapping rules that re-evaluate on every sensor change).

This supersedes #13, which was opened against an older injector.py and conflicts after the _apply_target refactor in 0332f4a. This branch re-applies the same change cleanly onto current main, plus the API was re-verified against HA 2026.2.3 (StateInfo, State.state_info, and the state_info= kwarg on async_set all present).

Mechanism

HA's recorder reads state.state_info["unrecorded_attributes"] (a frozenset[str]) and strips matching attribute keys before writing the row. The set is per-State, populated via the optional state_info parameter to hass.states.async_set.

Two implementation points worth noting:

  1. ATTR_ICON is NOT excluded. It's HA's standard glyph attribute — other integrations, templates, and user automations legitimately change it. Recording the history of icon changes is correct; only our two namespaced extensions are recorder noise.
  2. The merge with existing unrecorded_attributes is load-bearing. Some integrations declare their own (e.g. a sensor that excludes last_reset from history). A naïve state_info= override would clobber the entity author's declaration. _state_info_excluding_smart_icons merges both sets.

What this is NOT

Not a memory fix. The reporter's HA install was leaking memory; investigation confirmed it's not Smart Icons (memory continued climbing with the integration uninstalled). This PR addresses a related-but-separate concern: recorder DB growth from our writes.

Test plan

  • 3 new tests in tests/test_injector.py:
    • Smart-icons attrs marked unrecorded on apply
    • Entity owner's existing unrecorded_attrs preserved on merge
    • state_info still travels with release writes
  • Full backend suite: 131 pass (128 previous + 3 new)
  • Backend-only change — no frontend files or static/ bundles touched
  • CI on this PR

🤖 Generated with Claude Code

Pass `state_info` with `unrecorded_attributes` on every async_set
call so HA's recorder strips `smart_icons_color` and
`smart_icons_background` before persisting state-changed events to
the state_attributes table. The state_changed event still fires —
the painter needs it for live updates — but the database-side
payload shrinks, and adjacent state_attributes rows deduplicate
better since the "real" entity attributes change less often than
our decoration writes.

Implementation notes:

- `_SMART_ICONS_UNRECORDED_ATTRS` declares the keys to exclude.
  `ATTR_ICON` is intentionally NOT included — it's HA's standard
  glyph attribute that other integrations and templates may
  legitimately change, so recording its history is correct.
- `_state_info_excluding_smart_icons` merges our exclusion set
  with the target's existing `unrecorded_attributes` (if any).
  Some integrations declare their own (e.g. a sensor that
  excludes `last_reset` from history); a bare override would
  re-enable recording of attrs the integration author chose to
  exclude. The merge preserves both.
- Both write paths (`_apply_target` and `_release_target`) carry
  the same state_info — uniform contract; the recorder hint
  travels with every write the injector produces.

This is a recorder-disk optimization, not a memory fix — it does
not affect in-memory event bus traffic, only the persisted row
payload size and deduplication.

Re-applies #13 cleanly onto main (the original branch conflicted
after the _apply_target refactor in 0332f4a). Verified against HA
2026.2.3: StateInfo, State.state_info, and the state_info= kwarg
on async_set all present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jpettitt
jpettitt merged commit 43af79b into main Jun 14, 2026
2 checks passed
@jpettitt
jpettitt deleted the feat/recorder-unrecorded-attrs-v2 branch June 14, 2026 05:25
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