Skip to content

feat: rhythm engine stage 1 — observe-only day-phase inference#6

Merged
cnewkirk merged 15 commits into
mainfrom
rhythm-observe
Jul 5, 2026
Merged

feat: rhythm engine stage 1 — observe-only day-phase inference#6
cnewkirk merged 15 commits into
mainfrom
rhythm-observe

Conversation

@cnewkirk

@cnewkirk cnewkirk commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

Stage 1 of the Rhythm Engine: the daemon infers the occupant's day phase (dawn → morning → daylight → evening → wind_down → night → sleep), detects sleep onset and wake, learns wake/bed anchors — and drives nothing. Observe-only: zero bridge writes (enforced by a test client that asserts on any write), zero behavior change when rhythm: is absent from config.

  • rhythm: config block — bed target, weekend drift cap, presence tunables, signal-file paths, rollout stage (only "observe" starts; mornings/full refuse with a ConfigError until those stages ship).
  • presence.py — per-room activity judging with pet discounting (light change = human; room-to-room progression = human; motion near a light change = human; solo single-room motion = pet). Every judgment carries its rule name.
  • rhythm_control.py — learned-anchor store (bounded to 14 samples per weekday/weekend class, corrupt-file-safe JSON) + the phase engine (anchored, negotiated transitions; sleep-onset confidence vote; sustained-wake confirmation; night wakings explicitly rejected from the wake anchor; restart-safe seeding verified by a 24-hour sweep test).
  • Daemon plumbing — MotionAware SSE routing, .next-alarm/.phone-charging signal files (same control-file channel as TV bias), phase changes logged at INFO with the full evidence dict, atomic state persistence (tmp + rename), rhythm failures isolated from the drive loop, all rhythm state lock-guarded on both threads.
  • hueman rhythm — status command: phase, target vs learned anchors, weekly phase error in minutes, last decision's evidence. Degrades cleanly on malformed state files; needs no bridge access.
  • Docs: README section, CLAUDE.md pointer, example config block.

Process & verification

Built task-by-task with a fresh reviewer gating each task, then a whole-branch final review, which caught and drove fixes for two restart-path Criticals (morning restart stranding the engine in night; cold-start recording a fabricated sleep onset) and a design hole where nightly bathroom trips would poison the learned wake anchor. All fixes verified by direct simulation against the shipped head.

  • 356 tests passing (49 new), every behavior change RED-first
  • mypy --strict: clean
  • Homelab-identifier sweep over the full diff: clean

After merge (ops side)

Deploy with stage: "observe" and log_level: debug (night-waking rejections trace at DEBUG), let it run ≥5 days, compare hueman rhythm + the rhythm: log lines against reality before designing stage 2 (dawn ramp) on the observed data.

🤖 Generated with Claude Code

@cnewkirk
cnewkirk merged commit 2491c48 into main Jul 5, 2026
1 check passed
@cnewkirk
cnewkirk deleted the rhythm-observe branch July 5, 2026 12:13
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