fix: honour the contract that justifies a silent swallow, and log state removal on change (#308, #312) - #313
Merged
Merged
Conversation
…te removal on change (#308, #312) **#308 — the silence was fine; the contract behind it was not implemented.** I filed #308 saying `SurveyLog._persist`'s silent swallow was the wrong shape. Reading the code properly says otherwise: the silence is deliberate and its comment gives the reason — "the caller supplies the save hook and logs there if it wants to", and a failed save costs one repeated INFO rather than an exception escaping `create_devices`. `NodeDeviceTombstones._persist` warns instead because ITS failure resurrects a deliberately-deleted device, which is not cosmetic. The asymmetry is reasoned and stands. The actual defect: `DiagnosticsMenuMixin._save_survey_log` — the hook that comment points at — had no try/except and no logging, so a raising `savePluginPrefs()` reached `_persist`, was swallowed, and nobody logged anything. The comment described a contract nothing honoured. The hook now catches and warns, naming the failure and its consequence. `_persist` stays silent and its comment now states a fact. **#312 — log on change, not on evaluation.** `getDeviceStateList`'s state-removal INFO reprinted on every rebuild with the same answer: ~3 lines per plugin start, every start, measured across a week of jarvis logs. The filtering is correct — Indigo calls it on each rebuild, so re-applying it every time is right. Only the cadence was wrong. The comment justifying INFO ("a state disappearing silently breaks any trigger bound to it") holds the first time a device loses a set of states, not the fortieth reprint of an unchanged answer. `device_settings.RemovedStateLog` records device id → fingerprint of the removed set, so a device that later loses a DIFFERENT state still logs. It persists, because an in-memory latch would have suppressed almost nothing: the jarvis data shows the repeats are per-restart, not within-session. `deviceDeleted` forgets the entry for every device type, so a deleted device cannot leak one forever. `getDeviceStateList` fails open to logging every time if the store is somehow unwired. 3882 passing on 3.11 and 3.13 (3873 + 9 new). pylint 9.48, unchanged. No existing test was changed or deleted — the two touched test files are additions only. Closes #308 Closes #312 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 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.
Closes #308. Closes #312.
#308 — the silence was fine; the contract behind it was not implemented
I filed #308 claiming
SurveyLog._persist's silent swallow was the wrong shape. Reading the code properly says otherwise — the silence is deliberate and documented:And
NodeDeviceTombstones._persistwarns instead because its failure resurrects a deliberately-deleted device, which is not cosmetic. The asymmetry is reasoned and stands.The actual defect is that
DiagnosticsMenuMixin._save_survey_log— the hook that comment points at — had notry/exceptand no logging:So a raising
savePluginPrefs()reached_persist, was swallowed, and nobody logged anything. The comment described a contract nothing honoured.The hook now catches and warns, naming the failure and its consequence.
_persiststays silent, and its comment now states a fact rather than an intention.#312 — log on change, not on evaluation
The state-removal INFO reprinted on every rebuild with the same answer — ~3 lines per plugin start, every start, measured across a week of jarvis logs.
The filtering is correct and unchanged: Indigo calls
getDeviceStateListon each rebuild, so re-applying it every time is right. Only the cadence was wrong. The comment justifying INFO — "a state disappearing silently breaks any trigger or control page bound to it" — holds the first time a device loses a set of states, not the fortieth reprint of an unchanged answer.device_settings.RemovedStateLogrecords device id → fingerprint of the removed set, so a device that later loses a different state still logs.deviceDeletedforgets the entry for every device type.getDeviceStateListfails open to logging every time if the store is somehow unwired.Why persisted rather than an in-memory latch: the jarvis data shows the repeats are per-restart, not within-session — an in-memory dict would have suppressed almost nothing.
Worth flagging
This makes three stores of the same "RLock + JSON blob in
pluginPrefs" shape (NodeDeviceTombstones,SurveyLog,RemovedStateLog). A shared base was assessed and rejected at two during the refactor arc; the skeleton is still only ~20-25 lines each and the domain logic genuinely differs (a set, a fingerprint map, a different persist-failure policy per store).If a third store to suppress a log line reads as too much machinery for the problem, the cheaper alternative is to demote the message to DEBUG and drop the store entirely. Say the word and I'll swap it.
Numbers
3882 passing on both 3.11 and 3.13 (3873 + 9 new). pylint 9.48, unchanged. No existing test changed or deleted — both touched test files are additions only.
Version 2026.28.9. No
[release]marker.🤖 Generated with Claude Code