FAILURE MAP
← Case archive

FA-77096 / Calendar recurrence rules / Open access

Daily BYHOUR/BYMINUTE time-of-day expansion: default minute · case 01

A 09:30 series with BYHOUR=9,17 fires on the hour.

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

ROOT CAUSE

A missing BYMINUTE defaults to minute 0 instead of the dtstart minute.

VERIFIED REPAIR

At the default minute decision use `first.minute`, leaving the other decision sites of the model unchanged.

Unsuccessful approach: The partial repair `first.minute if not byhour else 0` only inherits the dtstart minute when BYHOUR is also missing.

Case contract

FREQ=DAILY. Each day produces the cartesian product of BYHOUR and BYMINUTE in chronological order; a missing BYHOUR defaults to the dtstart hour and a missing BYMINUTE to the dtstart minute. Duplicates in either list are ignored. Times before dtstart are dropped. Return the first count ISO date-times.

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, byhour, byminute, count):
    first = dt.datetime.fromisoformat(dtstart)
    hours = sorted(set(byhour)) if byhour else [first.hour]
    minutes = sorted(set(byminute)) if byminute else [0]
    out = []
    for k in range(400):
        day = first.date() + dt.timedelta(days=k)
        for h, mi in [(h, mi) for h in hours for mi in minutes]:
            t = dt.datetime.combine(day, dt.time(h, mi))
            if t < first:
                continue
            if len(out) >= count:
                return out
            out.append(t.isoformat(timespec='minutes'))
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
  ('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
  ('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05'])],
 [('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
  ('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'])],
 [('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15'])],
 [('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'])],
 [('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
  ('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09: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: default minute from dtstart['2024-01-01T17:00', '2024-01-02T09:00', '2024-01-02T17:00', '2024-01-03T09:00']['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']Failed
only byminute['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']Passed
unsorted duplicate hours['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']Passed
product of two lists['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']Passed
dtstart after some slots['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']Passed
dtstart between minutes['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']Passed
three by three['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05']['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05']Passed

SHA-256 / 8c89a6d3164f08240fe02ddbb5fdbd7ebfea3b593c603af7f23570eafc70476d

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, byhour, byminute, count):
    first = dt.datetime.fromisoformat(dtstart)
    hours = sorted(set(byhour)) if byhour else [first.hour]
    minutes = sorted(set(byminute)) if byminute else [first.minute if not byhour else 0]
    out = []
    for k in range(400):
        day = first.date() + dt.timedelta(days=k)
        for h, mi in [(h, mi) for h in hours for mi in minutes]:
            t = dt.datetime.combine(day, dt.time(h, mi))
            if t < first:
                continue
            if len(out) >= count:
                return out
            out.append(t.isoformat(timespec='minutes'))
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
  ('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
  ('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05'])],
 [('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
  ('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'])],
 [('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15'])],
 [('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'])],
 [('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
  ('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09: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: default minute from dtstart['2024-01-01T17:00', '2024-01-02T09:00', '2024-01-02T17:00', '2024-01-03T09:00']['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']Failed
only byminute['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']Passed
unsorted duplicate hours['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']Passed
product of two lists['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']Passed
dtstart after some slots['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']Passed
dtstart between minutes['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']Passed
three by three['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05']['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05']Passed

SHA-256 / d1322e5f1e7947d3e43f3c36d847195acd713b2361e4bc16c3cca13f9141206b

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, byhour, byminute, count):
    first = dt.datetime.fromisoformat(dtstart)
    hours = sorted(set(byhour)) if byhour else [first.hour]
    minutes = sorted(set(byminute)) if byminute else [first.minute]
    out = []
    for k in range(400):
        day = first.date() + dt.timedelta(days=k)
        for h, mi in [(h, mi) for h in hours for mi in minutes]:
            t = dt.datetime.combine(day, dt.time(h, mi))
            if t < first:
                continue
            if len(out) >= count:
                return out
            out.append(t.isoformat(timespec='minutes'))
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
  ('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
  ('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05'])],
 [('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']),
  ('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30'])],
 [('dtstart after some slots',
   ['2024-01-02T12:00', [8, 12, 18], [0], 4],
   ['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']),
  ('dtstart between minutes',
   ['2024-01-02T12:20', [12], [0, 20, 40], 4],
   ['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']),
  ('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15'])],
 [('three by three',
   ['2024-03-10T00:00', [6, 12, 18], [5, 10, 50], 7],
   ['2024-03-10T06:05',
    '2024-03-10T06:10',
    '2024-03-10T06:50',
    '2024-03-10T12:05',
    '2024-03-10T12:10',
    '2024-03-10T12:50',
    '2024-03-10T18:05']),
  ('count zero', ['2024-01-01T09:00', [9], [0], 0], []),
  ('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00'])],
 [('no lists', ['2024-02-28T23:45', [], [], 3], ['2024-02-28T23:45', '2024-02-29T23:45', '2024-03-01T23:45']),
  ('unsorted minutes',
   ['2024-02-28T07:00', [7, 8], [50, 10], 5],
   ['2024-02-28T07:10', '2024-02-28T07:50', '2024-02-28T08:10', '2024-02-28T08:50', '2024-02-29T07:10']),
  ('late hour only list',
   ['2024-05-05T22:15', [23, 1], [], 4],
   ['2024-05-05T23:15', '2024-05-06T01:15', '2024-05-06T23:15', '2024-05-07T01:15']),
  ('regression: default minute from dtstart',
   ['2024-01-01T09:30', [9, 17], [], 4],
   ['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']),
  ('only byminute',
   ['2024-01-01T14:10', [], [0, 30], 4],
   ['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']),
  ('unsorted duplicate hours',
   ['2024-01-01T08:00', [17, 9, 17], [15], 4],
   ['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']),
  ('product of two lists',
   ['2024-01-01T00:00', [9, 13], [0, 45], 5],
   ['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09: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: default minute from dtstart['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']['2024-01-01T09:30', '2024-01-01T17:30', '2024-01-02T09:30', '2024-01-02T17:30']Passed
only byminute['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']['2024-01-01T14:30', '2024-01-02T14:00', '2024-01-02T14:30', '2024-01-03T14:00']Passed
unsorted duplicate hours['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']['2024-01-01T09:15', '2024-01-01T17:15', '2024-01-02T09:15', '2024-01-02T17:15']Passed
product of two lists['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']['2024-01-01T09:00', '2024-01-01T09:45', '2024-01-01T13:00', '2024-01-01T13:45', '2024-01-02T09:00']Passed
dtstart after some slots['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']['2024-01-02T12:00', '2024-01-02T18:00', '2024-01-03T08:00', '2024-01-03T12:00']Passed
dtstart between minutes['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']['2024-01-02T12:20', '2024-01-02T12:40', '2024-01-03T12:00', '2024-01-03T12:20']Passed
three by three['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05']['2024-03-10T06:05', '2024-03-10T06:10', '2024-03-10T06:50', '2024-03-10T12:05', '2024-03-10T12:10', '2024-03-10T12:50', '2024-03-10T18:05']Passed

SHA-256 / 552f0115bf0ca085a219493cba88d84f860925f72a3dceae0daf25e5646f0136

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:22.410920+00:00.

Case digest / be5e8c4186b565f2a6fe3a11ce14f310e3074405abaa68bd371dbb673227552c