wake-alarm/wake_alarm
Krzysztof kuhy Rudnicki 03392e7ea5 Discover alarm device directories instead of reading a fixed phone path
The PC read one hardcoded path, wake-alarm-sync/devices/phone/alarm.json,
and never parsed the HLC. The phone's device id is migrating from the fixed
constant "phone" to a per-install uuid (a role constant collides as soon as
a second install takes the same role, and a reinstall inherits the previous
install's CRDT identity). A reader pinned to the old path would have stopped
seeing the alarm the moment the phone migrated, fallen through to the cache
and then to FALLBACK_ALARM_HOUR -- i.e. woken at the wrong time, silently.

So the PC half ships first, and this commit is that half plus the phone
change it makes safe:

- _fetch_firebase_alarm() lists SYNC_DEVICES_PREFIX, reads every device's
  alarm.json, and picks the newest by the hour field's HLC rather than by
  listing order. device_id breaks an exact tie so two devices stamped in the
  same millisecond don't alternate between ticks; a device whose payload
  doesn't parse is skipped rather than allowed to win with a bad value.
- SYNC_ALARM_PATH stays as a last-resort read for a backend that lists
  nothing, so an un-migrated install keeps working. The GitHub mirror still
  reads the single fixed path.
- The phone persists a uuid under SharedPreferences 'crdt.nodeId' (the key
  todo and home_inventory already use) and pushes under it. deviceId is now
  an instance field, injectable so tests don't touch real prefs.

Parsing and ranking moved to _alarm_payload.py: _sync.py was over the repo's
500-line cap, and the wire format deserves testing without network or disk --
a misparse here doesn't raise, it just resolves to the wrong wake-up time.

Verified against the live RTDB, not just mocks: seeded a uuid-named device
directory and confirmed the reader discovered it, read it and ranked it --
losing to the phone with an old stamp, winning with a new one (03:15 vs the
real 07:45). Test device deleted; --show returns 07:45 and the cache is
intact.

354 tests, 100% branch coverage. Phone app: 10 tests, analyzer clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZH89WEqAjuJT8WZdqc7AP
2026-08-09 17:06:43 +02:00
..
tests Discover alarm device directories instead of reading a fixed phone path 2026-08-09 17:06:43 +02:00
__init__.py Add tests and fix pre-commit issues across all projects 2026-04-12 20:45:24 +02:00
_alarm_display.py feat: split oversized modules for 500-line limit, fix kasa coverage gap 2026-06-14 07:19:37 +02:00
_alarm_payload.py Discover alarm device directories instead of reading a fixed phone path 2026-08-09 17:06:43 +02:00
_alarm_view.py Size the alarm's type in pixels, and gate every screen on fitting 768px 2026-08-03 16:04:27 +02:00
_alarm.py Size the alarm's type in pixels, and gate every screen on fitting 768px 2026-08-03 16:04:27 +02:00
_audio.py Play alarm audio on every sink, not one hardcoded output 2026-07-11 18:12:39 +02:00
_challenges.py Fire alarm daily, harden dismissal challenge; ignore wake_state.json 2026-07-10 23:14:40 +02:00
_constants.py Discover alarm device directories instead of reading a fixed phone path 2026-08-09 17:06:43 +02:00
_escape_flow.py Size the alarm's type in pixels, and gate every screen on fitting 768px 2026-08-03 16:04:27 +02:00
_logging_setup.py Extract wake_alarm from testsAndMisc as a standalone repo 2026-06-22 12:31:40 +02:00
_sinks.py Replace sleep-and-hope audio waits with per-cycle presence checks 2026-07-11 18:51:03 +02:00
_smart_plug.py Extract wake_alarm from testsAndMisc as a standalone repo 2026-06-22 12:31:40 +02:00
_state.py Extract wake_alarm from testsAndMisc as a standalone repo 2026-06-22 12:31:40 +02:00
_sync.py Discover alarm device directories instead of reading a fixed phone path 2026-08-09 17:06:43 +02:00
_trigger.py Fire the alarm at the phone's time via a per-minute timer 2026-07-19 20:21:17 +02:00