FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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