feat(daemon): night-guide — motion-triggered path lighting with a clean hand-back - #11
Merged
Conversation
…an hand-back Adds circadian_daemon.night_guide (optional): while the driven zone is out of the circadian window (parked at night_look, or off), motion on a configured MotionAware area briefly raises it to a soft guide look (e.g. dim red, for a night trip to the bathroom/kitchen), then hands control back once `timeout` elapses with no further motion. Repeated motion extends the episode from the latest event, not the first. This closes the actual product gap behind the 2026-08-08 incident: the daemon's resume-race fix (86f8d93) stopped the daemon from fighting itself, but neither the bridge's native convenience-motion feature nor hueman's own (bridge-native) night_motion automation has any concept of "restore whatever was there before" — both only know a fixed configured fallback, which is what made native motion recalls fight manual overrides and the daemon's resume logic in the first place. Built daemon-native instead, sharing the same recompute-when-possible hand-back shape _restore_after_security already established: - A real manual override showing when the guide engages (SUSPENDED) is snapshotted (a raw grouped_light GET) before the guide look overwrites it, and restored verbatim on hand-back -- a manual look is arbitrary, not derivable from anything else. - Otherwise (ordinary circadian/night_look was showing) hand-back recomputes the current authoritative target fresh instead of replaying a snapshot: the curve if the window reopened mid-episode, otherwise the normal resting state. Hold alone would leave the guide look showing forever, since Hold assumes nothing changed underneath it -- false here, the guide write is what changed it. Consumes the same MotionAware SSE events `rhythm` already reads (independent consumers of one event, _handle_event restructured so neither requires the other to be configured) -- no new sensor plumbing. Never fights the operator (an override suspends and stays suspended straight through a guide episode) or the curve (circadian reclaims the zone the instant its window opens). New: nightguide_control.py (pure IDLE/GUIDING timing, 7 tests), NightGuideSpec (config.py), full daemon wiring + 10 integration tests covering: gating to out-of-window only, snapshot-vs-recompute on hand-back both ways, mid-episode window reopen, repeated-motion extension, unrelated-area/motion-false rejection, and rhythm coexistence. Spot-verified the snapshot-restore test fails without the restore branch (temporarily disabled, ran red, restored). Full suite (393 tests) + mypy clean. Co-Authored-By: Claude Sonnet 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.
Re-landing 6ca92b6 through a proper PR (originally direct-pushed to main,
reverted in #9).
Adds
circadian_daemon.night_guide(optional): while the driven zone is outof the circadian window (parked at night_look, or off), motion on a
configured MotionAware area briefly raises it to a soft guide look, then
hands control back once
timeoutelapses with no further motion. Repeatedmotion extends the episode from the latest event, not the first.
Closes the actual product gap behind the 2026-08-08 incident: the resume-race
fix (#10) stopped the daemon from fighting itself, but neither the bridge's
native convenience-motion feature nor hueman's own (bridge-native)
night_motion automation has any concept of "restore whatever was there
before" — both only know a fixed configured fallback. Built daemon-native
instead, sharing the recompute-when-possible hand-back shape
_restore_after_securityalready established:snapshotted (a raw grouped_light GET) before the guide look overwrites it,
and restored verbatim on hand-back.
curve if the window reopened mid-episode, otherwise the normal resting
state.
New: nightguide_control.py (pure IDLE/GUIDING timing, 7 tests),
NightGuideSpec, full daemon wiring + 10 integration tests. Spot-verified the
snapshot-restore test fails without the restore branch (temporarily
disabled, ran red, restored).