FA-77181 / Calendar recurrence rules / Open access
Pending alarms for a recurring timed series: horizon cutoff · case 01
An alarm that fires inside the scheduling horizon is dropped because its occurrence starts after the horizon.
ROOT CAUSE
The horizon is compared with the occurrence start instead of the alarm fire time.
VERIFIED REPAIR
At the horizon cutoff decision use `fire > end`, leaving the other decision sites of the model unchanged.
Unsuccessful approach: The partial repair `fire >= end` makes the horizon end exclusive, dropping an alarm due exactly at the horizon.
Case contract
Occurrences start at dtstart + k*interval_hours for k < count. Each has one alarm at start + trigger_min minutes (negative means before the start). Occurrences whose start string (YYYY-MM-DDTHH:MM) is in acknowledged have no alarm. An alarm due at or before now is delivered at now if the occurrence has not started yet (start > now), otherwise dropped. Alarms due after now + horizon_hours are not scheduled. Return [occurrence_start, fire_time] pairs in series order.
Why this case matters
Recurring calendar series are expanded into concrete instances for display, reminders and conflict checks.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(dtstart, interval_hours, count, trigger_min, acknowledged, now, horizon_hours):
first = dt.datetime.fromisoformat(dtstart)
now_t = dt.datetime.fromisoformat(now)
acked = set(acknowledged)
end = now_t + dt.timedelta(hours=horizon_hours)
out = []
for k in range(count):
s = first + dt.timedelta(hours=k * interval_hours)
fire = s + dt.timedelta(minutes=trigger_min)
if s > end:
break
if s.isoformat(timespec='minutes') in acked:
continue
if fire <= now_t:
if s > now_t:
fire = now_t
else:
continue
out.append([s.isoformat(timespec='minutes'), fire.isoformat(timespec='minutes')])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']]),
('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']])],
[('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']]),
('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']])],
[('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']])],
[('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']])],
[('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: negative trigger | [['2024-01-01T09:00', '2024-01-01T08:45'], ['2024-01-02T09:00', '2024-01-02T08:45'], ['2024-01-03T09:00', '2024-01-03T08:45']] | [['2024-01-01T09:00', '2024-01-01T08:45'], ['2024-01-02T09:00', '2024-01-02T08:45'], ['2024-01-03T09:00', '2024-01-03T08:45']] | Passed |
| positive trigger | [['2024-01-01T09:00', '2024-01-01T09:10'], ['2024-01-02T09:00', '2024-01-02T09:10'], ['2024-01-03T09:00', '2024-01-03T09:10']] | [['2024-01-01T09:00', '2024-01-01T09:10'], ['2024-01-02T09:00', '2024-01-02T09:10'], ['2024-01-03T09:00', '2024-01-03T09:10']] | Passed |
| horizon edge with lead time | [['2024-01-01T10:00', '2024-01-01T09:00'], ['2024-01-01T11:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T11:00']] | [['2024-01-01T10:00', '2024-01-01T09:00'], ['2024-01-01T11:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T11:00'], ['2024-01-01T13:00', '2024-01-01T12:00']] | Failed |
| horizon exact | [['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']] | [['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']] | Passed |
| acknowledged occurrence | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-01T17:00', '2024-01-01T16:30'], ['2024-01-01T21:00', '2024-01-01T20:30']] | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-01T17:00', '2024-01-01T16:30'], ['2024-01-01T21:00', '2024-01-01T20:30']] | Passed |
| missed alarm catch-up | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']] | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']] | Passed |
| missed long before start | [['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']] | [['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']] | Passed |
SHA-256 / c9c8c62255bb2c025e602684fefb425a7d2df7d65b242db9c74531e3b9d39ad4
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(dtstart, interval_hours, count, trigger_min, acknowledged, now, horizon_hours):
first = dt.datetime.fromisoformat(dtstart)
now_t = dt.datetime.fromisoformat(now)
acked = set(acknowledged)
end = now_t + dt.timedelta(hours=horizon_hours)
out = []
for k in range(count):
s = first + dt.timedelta(hours=k * interval_hours)
fire = s + dt.timedelta(minutes=trigger_min)
if fire >= end:
break
if s.isoformat(timespec='minutes') in acked:
continue
if fire <= now_t:
if s > now_t:
fire = now_t
else:
continue
out.append([s.isoformat(timespec='minutes'), fire.isoformat(timespec='minutes')])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']]),
('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']])],
[('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']]),
('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']])],
[('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']])],
[('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']])],
[('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: negative trigger | [['2024-01-01T09:00', '2024-01-01T08:45'], ['2024-01-02T09:00', '2024-01-02T08:45'], ['2024-01-03T09:00', '2024-01-03T08:45']] | [['2024-01-01T09:00', '2024-01-01T08:45'], ['2024-01-02T09:00', '2024-01-02T08:45'], ['2024-01-03T09:00', '2024-01-03T08:45']] | Passed |
| positive trigger | [['2024-01-01T09:00', '2024-01-01T09:10'], ['2024-01-02T09:00', '2024-01-02T09:10'], ['2024-01-03T09:00', '2024-01-03T09:10']] | [['2024-01-01T09:00', '2024-01-01T09:10'], ['2024-01-02T09:00', '2024-01-02T09:10'], ['2024-01-03T09:00', '2024-01-03T09:10']] | Passed |
| horizon edge with lead time | [['2024-01-01T10:00', '2024-01-01T09:00'], ['2024-01-01T11:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T11:00']] | [['2024-01-01T10:00', '2024-01-01T09:00'], ['2024-01-01T11:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T11:00'], ['2024-01-01T13:00', '2024-01-01T12:00']] | Failed |
| horizon exact | [['2024-01-01T10:00', '2024-01-01T10:00']] | [['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']] | Failed |
| acknowledged occurrence | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-01T17:00', '2024-01-01T16:30'], ['2024-01-01T21:00', '2024-01-01T20:30']] | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-01T17:00', '2024-01-01T16:30'], ['2024-01-01T21:00', '2024-01-01T20:30']] | Passed |
| missed alarm catch-up | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']] | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']] | Passed |
| missed long before start | [['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']] | [['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']] | Passed |
SHA-256 / ab34143a9c67e85e4f8f8775c67bf6406a7f5866aafe53eb79e92fbcef3456f6
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(dtstart, interval_hours, count, trigger_min, acknowledged, now, horizon_hours):
first = dt.datetime.fromisoformat(dtstart)
now_t = dt.datetime.fromisoformat(now)
acked = set(acknowledged)
end = now_t + dt.timedelta(hours=horizon_hours)
out = []
for k in range(count):
s = first + dt.timedelta(hours=k * interval_hours)
fire = s + dt.timedelta(minutes=trigger_min)
if fire > end:
break
if s.isoformat(timespec='minutes') in acked:
continue
if fire <= now_t:
if s > now_t:
fire = now_t
else:
continue
out.append([s.isoformat(timespec='minutes'), fire.isoformat(timespec='minutes')])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']]),
('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']])],
[('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']]),
('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']])],
[('acknowledged occurrence',
['2024-01-01T09:00', 4, 4, -30, ['2024-01-01T13:00'], '2024-01-01T00:00', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'],
['2024-01-01T17:00', '2024-01-01T16:30'],
['2024-01-01T21:00', '2024-01-01T20:30']]),
('missed alarm catch-up',
['2024-01-01T09:00', 24, 2, -120, [], '2024-01-01T08:30', 48],
[['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']]),
('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']])],
[('missed long before start',
['2024-01-01T12:00', 24, 2, -1440, [], '2024-01-01T09:00', 48],
[['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']]),
('occurrence starting now',
['2024-01-01T09:00', 24, 2, -10, [], '2024-01-01T09:00', 48],
[['2024-01-02T09:00', '2024-01-02T08:50']]),
('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']])],
[('started occurrence dropped',
['2024-01-01T09:00', 1, 4, -5, [], '2024-01-01T10:30', 4],
[['2024-01-01T11:00', '2024-01-01T10:55'], ['2024-01-01T12:00', '2024-01-01T11:55']]),
('ack and catch-up mix',
['2024-02-01T09:00', 3, 4, -240, ['2024-02-01T12:00'], '2024-02-01T08:00', 12],
[['2024-02-01T09:00', '2024-02-01T08:00'],
['2024-02-01T15:00', '2024-02-01T11:00'],
['2024-02-01T18:00', '2024-02-01T14:00']]),
('zero trigger all future',
['2024-03-01T06:00', 6, 3, 0, ['2024-03-01T06:00'], '2024-03-01T00:00', 24],
[['2024-03-01T12:00', '2024-03-01T12:00'], ['2024-03-01T18:00', '2024-03-01T18:00']]),
('regression: negative trigger',
['2024-01-01T09:00', 24, 3, -15, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T08:45'],
['2024-01-02T09:00', '2024-01-02T08:45'],
['2024-01-03T09:00', '2024-01-03T08:45']]),
('positive trigger',
['2024-01-01T09:00', 24, 3, 10, [], '2024-01-01T00:00', 72],
[['2024-01-01T09:00', '2024-01-01T09:10'],
['2024-01-02T09:00', '2024-01-02T09:10'],
['2024-01-03T09:00', '2024-01-03T09:10']]),
('horizon edge with lead time',
['2024-01-01T10:00', 1, 6, -60, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T09:00'],
['2024-01-01T11:00', '2024-01-01T10:00'],
['2024-01-01T12:00', '2024-01-01T11:00'],
['2024-01-01T13:00', '2024-01-01T12:00']]),
('horizon exact',
['2024-01-01T10:00', 2, 5, 0, [], '2024-01-01T08:00', 4],
[['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: negative trigger | [['2024-01-01T09:00', '2024-01-01T08:45'], ['2024-01-02T09:00', '2024-01-02T08:45'], ['2024-01-03T09:00', '2024-01-03T08:45']] | [['2024-01-01T09:00', '2024-01-01T08:45'], ['2024-01-02T09:00', '2024-01-02T08:45'], ['2024-01-03T09:00', '2024-01-03T08:45']] | Passed |
| positive trigger | [['2024-01-01T09:00', '2024-01-01T09:10'], ['2024-01-02T09:00', '2024-01-02T09:10'], ['2024-01-03T09:00', '2024-01-03T09:10']] | [['2024-01-01T09:00', '2024-01-01T09:10'], ['2024-01-02T09:00', '2024-01-02T09:10'], ['2024-01-03T09:00', '2024-01-03T09:10']] | Passed |
| horizon edge with lead time | [['2024-01-01T10:00', '2024-01-01T09:00'], ['2024-01-01T11:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T11:00'], ['2024-01-01T13:00', '2024-01-01T12:00']] | [['2024-01-01T10:00', '2024-01-01T09:00'], ['2024-01-01T11:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T11:00'], ['2024-01-01T13:00', '2024-01-01T12:00']] | Passed |
| horizon exact | [['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']] | [['2024-01-01T10:00', '2024-01-01T10:00'], ['2024-01-01T12:00', '2024-01-01T12:00']] | Passed |
| acknowledged occurrence | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-01T17:00', '2024-01-01T16:30'], ['2024-01-01T21:00', '2024-01-01T20:30']] | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-01T17:00', '2024-01-01T16:30'], ['2024-01-01T21:00', '2024-01-01T20:30']] | Passed |
| missed alarm catch-up | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']] | [['2024-01-01T09:00', '2024-01-01T08:30'], ['2024-01-02T09:00', '2024-01-02T07:00']] | Passed |
| missed long before start | [['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']] | [['2024-01-01T12:00', '2024-01-01T09:00'], ['2024-01-02T12:00', '2024-01-01T12:00']] | Passed |
SHA-256 / d4963620f9fcdcfcc53dbda78dabbb588cfd28a6e90fb5ce3bc934e4cdea246a
Verification & scope
Stipulated, bounded recurrence-expansion model evaluated offline on explicit fixtures; it is not a complete iCalendar implementation and makes no claim of standards conformance. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:49:23.213389+00:00.
Case digest / f51c9500e6eec90e771e26f705113935e8ca3f421ff37afd91152f0ab278a1bc