fix(alarms): spend a skip at its occurrence again

Keeping a skip armed through its fire grace let the editor's switch or another dismissal inside those two minutes ring the skipped alarm late, or be absorbed. The resolver goes back to spending the skip at its occurrence and recording it as handled, and the upcoming check wakes at an armed skip's occurrence so the list stops saying "skipping next" on time.

Fixes #16
This commit is contained in:
makiolaj committed 2026-10-22 08:07:52 +02:00
1 parent a88e696d52
commit fdb725e64c
6 files changed
+25 -72

No files matched your search

+9 -11
View File
@@ -250,12 +250,10 @@ so the skip eats a second alarm. With the watermark:
one after;
- watermark still in the future ⇒ fire the first candidate after it; write
nothing;
- watermark and its fire grace both behind now ⇒ consumed: clear the flag and
the watermark, record the skipped occurrence as the handled one, and *still*
return the first candidate after it, so the skipped occurrence cannot ring on
this pass or the next. Not spent during the grace itself (#16): a late fire
for the skipped occurrence can still be accepted until then, and `onFire`
refuses it by the armed watermark.
- watermark at or before now ⇒ consumed: clear the flag and the watermark,
record the skipped occurrence as the handled one, and *still* return the
first candidate after it, so the skipped occurrence cannot ring on its way
out through the grace window, on this pass or the next (#16).
Arming is deferred while a snooze is pending, and a **non-repeating** alarm with
the flag set is *disabled* rather than skipped: a one-shot has exactly one
@@ -1241,11 +1239,11 @@ the alarm's row for whoever opens the app instead.
`rescheduleLocked`, so that is where the notices are synced and the third
slot is armed for the earliest window still to open, *after* the real
registration. The check also wakes once a noticed occurrence's fire grace has
run out (so a notice cannot outlive a fire that came late) and once an armed
skip's has (so a skip dismissed in advance is spent on time, and the list
stops saying "skipping next" about an occurrence already gone). Both wait out
the grace rather than land on the alarm's own instant, so they never race its
fire. The sync is wrapped so a notification failure costs nothing,
run out (so a notice cannot outlive a fire that came late; waiting out the
grace keeps it from racing that fire) and at an armed skip's occurrence (so a
skip dismissed in advance is spent on time, and the list stops saying
"skipping next" about an occurrence already gone; nothing is registered to
fire then, so there is nothing to race). The sync is wrapped so a notification failure costs nothing,
and on the fire path it is deferred until the ring has started, so its binder
calls never stand between the fire and the sound. The check's receiver just
calls `onUpcomingWindow()`, which is `reschedule()`.