wake-alarm/DOCS-ramp.md

1.8 KiB
Raw Blame History

The wake-time ramp ("cooking the frog")

The alarm starts at 08:00 and moves one earned minute earlier at a time, down to a permanent 07:00. Owned entirely by the phone (phone_app/lib/services/alarm_ramp.dart, ramp_progress.dart).

The rule

  • A Monday, Friday, Saturday or Sunday whose alarm rang and was dismissed that same day earns one minute (RampProgress.recordDismiss, called from the ring screen's dismiss before it re-arms).
  • Tuesday–Thursday (freedays.WORKDAYS) earn nothing and ring at the time of the most recent non-workday: a minute earned on Monday first shows on Friday.
  • A free day never rings, so it earns nothing. A missed alarm (rang, never dismissed) earns nothing.
  • Ring time for day D = 08:00 − |earned dates before the latest non-workday ≤ D|, floored at 07:00.

Why a set of dates, not a counter

The earned dates are a grow-only set: each date counts once, so a re-run, a duplicate sync or a double dismiss cannot move the alarm twice, and nothing can run it away. It rides the synced alarm.json record (settings_sync.dart, field ramp_earned_dates) as a union, so a reinstall gets every minute back. rampSeedDates holds the three mornings earned before dates were recorded (2026-09-25/26/27).

Where it is not

The PC no longer computes a ramp: it trusts the time the phone publishes, clamped to ≤ 08:00, and falls back to 08:00. The Kotlin side has no ramp either: the alarm only moves when a Dart dismiss earns a minute and re-arms, so the native re-arm after a free day, a missed ring, a boot or the watchdog is already the right time by re-using the stored one.

workdays in alarm_ramp.dart and STICK_DAYS in WorkdayStick.kt are literal copies of freedays.WORKDAYS; wake_alarm/tests/test_workday_mirrors.py fails when either drifts.