AUTO-FIX: a pause never lasts past midnight

2026-10-22 10:14 a tap paused NA's auto-fix 'through the next hours', which were all of Sunday's services,
and nothing fixed itself on 10/25. The user: alarms on means auto-fix on. A pause now holds through the
hours it is in (or ones starting later that day) and ends at midnight at the latest. Deployed to NA,
and patched into WS and SC's copies (they still run 51a1414 otherwise).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 06:49:46 -04:00
co-authored by Claude Opus 5.5
parent 49acb08157
commit 0f3471bf51
2 changed files with 19 additions and 9 deletions
+9 -5
View File
@@ -36,7 +36,7 @@ import time
import urllib.parse import urllib.parse
import urllib.request import urllib.request
from collections import deque from collections import deque
from datetime import datetime from datetime import datetime, timedelta
HERE = os.path.dirname(os.path.abspath(__file__)) HERE = os.path.dirname(os.path.abspath(__file__))
log = logging.getLogger("status-panel") log = logging.getLogger("status-panel")
@@ -1203,12 +1203,15 @@ class ServiceMode:
self._save() self._save()
def pause(self, now): def pause(self, now):
"""AUTO-FIX paused: through the hours it is in now, or, pressed outside them, through the next ones """AUTO-FIX paused: through the hours it is in now (or the next ones, if they start today), but never
(2026-10-21: a press on Saturday night used to do nothing for Sunday).""" past midnight. The user: alarms on means auto-fix on. A tap on Thursday 2026-10-22 had paused it through
all of Sunday's services; now every day starts with auto-fix back on its hours."""
sched = self.scheduled(now) sched = self.scheduled(now)
start = now if sched else self.next_change(now) start = now if sched else self.next_change(now)
d = datetime.fromtimestamp(now)
midnight = time.mktime((datetime(d.year, d.month, d.day) + timedelta(days=1)).timetuple())
self.override, self.hold, self.test, self.last_sched = False, True, False, sched self.override, self.hold, self.test, self.last_sched = False, True, False, sched
self.edge = self.next_change(start) if start else None self.edge = min(self.next_change(start) or midnight, midnight) if start and start < midnight else midnight
self._save() self._save()
def resume(self, now): def resume(self, now):
@@ -2391,7 +2394,8 @@ def render(engine, service_on):
when = "" when = ""
if until: if until:
same_day = datetime.fromtimestamp(until).date() == datetime.fromtimestamp(engine.now).date() same_day = datetime.fromtimestamp(until).date() == datetime.fromtimestamp(engine.now).date()
when = ("" if same_day else datetime.fromtimestamp(until).strftime("%a ").upper()) + clock12(until) tonight = datetime.fromtimestamp(until - 1).date() == datetime.fromtimestamp(engine.now).date() # a pause's midnight
when = ("" if same_day or tonight else datetime.fromtimestamp(until).strftime("%a ").upper()) + clock12(until)
if engine.autofix.paused: if engine.autofix.paused:
text = "%s\nPAUSED" % tile["label"] + ("\nTIL " + when if when else "") text = "%s\nPAUSED" % tile["label"] + ("\nTIL " + when if when else "")
elif engine.autofix.test and on: elif engine.autofix.test and on:
+10 -4
View File
@@ -2519,14 +2519,20 @@ class TestSwitches(unittest.TestCase):
self.assertTrue(self.new_engine().autofix.paused) # survives a restart self.assertTrue(self.new_engine().autofix.paused) # survives a restart
self.assertTrue(self.engine.autofix.on(datetime(2026, 10, 14, 16, 30).timestamp())) # Wednesday's hours: back by itself self.assertTrue(self.engine.autofix.on(datetime(2026, 10, 14, 16, 30).timestamp())) # Wednesday's hours: back by itself
self.assertFalse(self.engine.autofix.paused) self.assertFalse(self.engine.autofix.paused)
# Pressed outside the hours (Thursday): the key said OFF / ON SUN 6:30AM; the pause holds through Sunday's hours. # Pressed outside the hours (Thursday): never past midnight, so Sunday's services always start with auto-fix on
# (2026-10-25: a Thursday tap had paused it through all of Sunday; the user: alarms on means auto-fix on).
thursday = SUNDAY - 3 * 86400 thursday = SUNDAY - 3 * 86400
tiles = self.engine.step(self.snap, thursday) tiles = self.engine.step(self.snap, thursday)
self.assertEqual(tiles["autofix"]["x"], "AUTO-FIX\nOFF\nON SUN 6:30AM") self.assertEqual(tiles["autofix"]["x"], "AUTO-FIX\nOFF\nON SUN 6:30AM")
self.engine.autofix.pause(thursday) self.engine.autofix.pause(thursday)
self.assertEqual(self.engine.step(self.snap, thursday + 1)["autofix"]["x"], "AUTO-FIX\nPAUSED\nTIL SUN 1:30PM") self.assertEqual(self.engine.step(self.snap, thursday + 1)["autofix"]["x"], "AUTO-FIX\nPAUSED\nTIL 12AM")
self.assertFalse(self.engine.autofix.on(SUNDAY)) # Sunday 8:00, inside the hours: still paused self.assertTrue(self.engine.autofix.on(SUNDAY)) # Sunday 8:00: on, as its hours say
self.assertTrue(self.engine.autofix.on(datetime(2026, 10, 14, 16, 30).timestamp())) # and over after them self.assertFalse(self.engine.autofix.paused)
saturday_night = SUNDAY - 10 * 3600 # Saturday 22:00
self.engine.autofix.pause(saturday_night)
self.assertTrue(self.engine.autofix.on(SUNDAY)) # a Saturday-night tap is over by Sunday too
self.engine.autofix.pause(SUNDAY)
self.assertFalse(self.engine.autofix.on(SUNDAY + 3600)) # tapped on Sunday morning: paused till 1:30PM
self.engine.autofix.pause(thursday) self.engine.autofix.pause(thursday)
self.engine.autofix.resume(thursday + 60) # pressed again: back to the hours self.engine.autofix.resume(thursday + 60) # pressed again: back to the hours
self.assertTrue(self.engine.autofix.on(SUNDAY)) self.assertTrue(self.engine.autofix.on(SUNDAY))