fix(daemon): close the resume-race that undoes manual-override handback - #10
Merged
Merged
Conversation
All three resume triggers (power-cycle, control-file, resume-trigger scene) flipped the controller out of SUSPENDED via a bare on_resume(), but never refreshed the settle-and-compare classifier's stale _cmd_brightness/_cmd_on reference (last set before the suspension) or granted the grace window _restore_after_security already uses for the identical race on the security-exit path. Since _tick_once always classifies before it drives, the very next settle judgment after a resume compared the freshly-resumed live brightness against that stale target and re-suspended within one tick, defeating the resume outright. Confirmed live 2026-08-08: motion-triggered brightness churn repeatedly power-cycled the zone overnight, and every single resume was undone by the next tick's stale comparison — 10 spurious suspends in one session, the zone stuck SUSPENDED at 100% by morning, and the user's own manual changes getting steamrolled in real time while working. Adds _resume_locked(), used by all three trigger sites: resets _obs_brightness/_obs_classified and opens _classify_grace_until for one fade + settle window, same as the security-restore path, so the daemon gets a real drive (or a clean drop to NIGHT_IDLE) before judging anything again. A genuine override after the grace still suspends normally (covered by a dedicated test). Regression tests for all three paths, verified to fail on the pre-fix code (reverted call sites, ran red, restored). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 8, 2026
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.
Re-landing 86f8d93 through a proper PR (originally direct-pushed to main,
reverted in #9).
All three resume triggers (power-cycle, control-file, resume-trigger scene)
flipped the controller out of SUSPENDED via a bare on_resume(), but never
refreshed the settle-and-compare classifier's stale
_cmd_brightness/_cmd_onreference (last set before the suspension) or granted the gracewindow
_restore_after_securityalready uses for the identical race on thesecurity-exit path. Since
_tick_oncealways classifies before it drives,the very next settle judgment after a resume compared the freshly-resumed
live brightness against that stale target and re-suspended within one tick,
defeating the resume outright.
Confirmed live 2026-08-08: motion-triggered brightness churn repeatedly
power-cycled the zone overnight, and every single resume was undone by the
next tick's stale comparison — 10 spurious suspends in one session, the zone
stuck SUSPENDED at 100% by morning.
Adds
_resume_locked(), used by all three trigger sites: resets_obs_brightness/_obs_classifiedand opens_classify_grace_untilfor onefade + settle window, same as the security-restore path. A genuine override
after the grace still suspends normally (covered by a dedicated test).
Regression tests for all three paths, verified to fail on the pre-fix code
(reverted call sites, ran red, restored).