FAILURE MAP
← Case archive

FA-76981 / Calendar recurrence rules / Open access

Merging RRULE instances with RDATE and EXDATE: exdate scope · case 01

An EXDATE matching an RDATE leaves the RDATE on the calendar.

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

ROOT CAUSE

EXDATE is applied to the rule instances only.

VERIFIED REPAIR

At the exdate scope decision use `[d for d in rule + extra if d not in excluded]`, leaving the other decision sites of the model unchanged.

Unsuccessful approach: The partial repair `[d for d in rule if d not in excluded] + [d for d in extra if d not in rule]` avoids RDATE duplicates of rule dates but still does not exclude RDATEs.

Case contract

All-day series: the rule yields exactly count instances dtstart + k*interval days (COUNT counts rule instances before exclusions; RDATEs never consume COUNT). The instance set is rule plus RDATE minus EXDATE; EXDATE also removes RDATEs. EXDATE values may carry a time part (YYYY-MM-DDTHH:MM:SS) and then exclude their calendar date. Return the unique dates sorted ascending.

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, count, rdates, exdates):
    start = dt.date.fromisoformat(dtstart)
    excluded = {dt.date.fromisoformat(x[:10]) for x in exdates}
    rule = [start + dt.timedelta(days=k * interval) for k in range(count)]
    extra = [dt.date.fromisoformat(x) for x in rdates]
    rule = rule
    merged = [d for d in rule if d not in excluded] + extra
    result = sorted(set(merged))
    return [d.isoformat() for d in result]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07'])],
 [('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03'])],
 [('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], [])],
 [('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], []),
  ('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03'])],
 [('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], []),
  ('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03'])]]
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: exdate does not extend count['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']Passed
timed exdate['2024-03-01', '2024-03-03', '2024-03-07']['2024-03-01', '2024-03-03', '2024-03-07']Passed
midnight exdate['2024-03-01', '2024-03-03']['2024-03-01', '2024-03-03']Passed
rdate equal to rule date['2024-01-01', '2024-01-08', '2024-01-15']['2024-01-01', '2024-01-08', '2024-01-15']Passed
rdate before dtstart['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']Passed
exdate removes rdate['2024-01-01', '2024-01-02', '2024-01-03', '2024-02-01']['2024-01-01', '2024-01-02', '2024-01-03']Failed
exdate outside rule['2024-01-01', '2024-01-04', '2024-01-07']['2024-01-01', '2024-01-04', '2024-01-07']Passed

SHA-256 / 203b9e66b748b79f5491912a4d62c7be3d1fe6ffedfabaea08f37ac153326c81

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, count, rdates, exdates):
    start = dt.date.fromisoformat(dtstart)
    excluded = {dt.date.fromisoformat(x[:10]) for x in exdates}
    rule = [start + dt.timedelta(days=k * interval) for k in range(count)]
    extra = [dt.date.fromisoformat(x) for x in rdates]
    rule = rule
    merged = [d for d in rule if d not in excluded] + [d for d in extra if d not in rule]
    result = sorted(set(merged))
    return [d.isoformat() for d in result]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07'])],
 [('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03'])],
 [('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], [])],
 [('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], []),
  ('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03'])],
 [('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], []),
  ('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03'])]]
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: exdate does not extend count['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']Passed
timed exdate['2024-03-01', '2024-03-03', '2024-03-07']['2024-03-01', '2024-03-03', '2024-03-07']Passed
midnight exdate['2024-03-01', '2024-03-03']['2024-03-01', '2024-03-03']Passed
rdate equal to rule date['2024-01-01', '2024-01-08', '2024-01-15']['2024-01-01', '2024-01-08', '2024-01-15']Passed
rdate before dtstart['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']Passed
exdate removes rdate['2024-01-01', '2024-01-02', '2024-01-03', '2024-02-01']['2024-01-01', '2024-01-02', '2024-01-03']Failed
exdate outside rule['2024-01-01', '2024-01-04', '2024-01-07']['2024-01-01', '2024-01-04', '2024-01-07']Passed

SHA-256 / 8775dd54d4371ca43fb60aef70c1490be30c21518e273bd96803d017d9fdd9c1

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, count, rdates, exdates):
    start = dt.date.fromisoformat(dtstart)
    excluded = {dt.date.fromisoformat(x[:10]) for x in exdates}
    rule = [start + dt.timedelta(days=k * interval) for k in range(count)]
    extra = [dt.date.fromisoformat(x) for x in rdates]
    rule = rule
    merged = [d for d in rule + extra if d not in excluded]
    result = sorted(set(merged))
    return [d.isoformat() for d in result]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07'])],
 [('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03'])],
 [('rdate before dtstart',
   ['2024-01-10', 1, 3, ['2024-01-02'], []],
   ['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03']),
  ('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], [])],
 [('exdate outside rule',
   ['2024-01-01', 3, 3, [], ['2024-01-02']],
   ['2024-01-01', '2024-01-04', '2024-01-07']),
  ('rdate between instances',
   ['2024-05-01', 10, 3, ['2024-05-05', '2024-05-30'], ['2024-05-11']],
   ['2024-05-01', '2024-05-05', '2024-05-21', '2024-05-30']),
  ('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], []),
  ('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03'])],
 [('count zero with rdate', ['2024-01-01', 1, 0, ['2024-01-03'], []], ['2024-01-03']),
  ('duplicate rdates and timed exdate',
   ['2024-02-27', 1, 4, ['2024-03-05', '2024-03-05'], ['2024-02-28T12:00:00']],
   ['2024-02-27', '2024-02-29', '2024-03-01', '2024-03-05']),
  ('all excluded', ['2024-07-01', 1, 2, [], ['2024-07-01', '2024-07-02']], []),
  ('regression: exdate does not extend count',
   ['2024-03-01', 1, 5, [], ['2024-03-03']],
   ['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']),
  ('timed exdate',
   ['2024-03-01', 2, 4, [], ['2024-03-05T09:30:00']],
   ['2024-03-01', '2024-03-03', '2024-03-07']),
  ('midnight exdate', ['2024-03-01', 1, 3, [], ['2024-03-02T00:00:00']], ['2024-03-01', '2024-03-03']),
  ('rdate equal to rule date',
   ['2024-01-01', 7, 3, ['2024-01-08'], []],
   ['2024-01-01', '2024-01-08', '2024-01-15']),
  ('exdate removes rdate',
   ['2024-01-01', 1, 3, ['2024-02-01'], ['2024-02-01']],
   ['2024-01-01', '2024-01-02', '2024-01-03'])]]
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: exdate does not extend count['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']['2024-03-01', '2024-03-02', '2024-03-04', '2024-03-05']Passed
timed exdate['2024-03-01', '2024-03-03', '2024-03-07']['2024-03-01', '2024-03-03', '2024-03-07']Passed
midnight exdate['2024-03-01', '2024-03-03']['2024-03-01', '2024-03-03']Passed
rdate equal to rule date['2024-01-01', '2024-01-08', '2024-01-15']['2024-01-01', '2024-01-08', '2024-01-15']Passed
rdate before dtstart['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']['2024-01-02', '2024-01-10', '2024-01-11', '2024-01-12']Passed
exdate removes rdate['2024-01-01', '2024-01-02', '2024-01-03']['2024-01-01', '2024-01-02', '2024-01-03']Passed
exdate outside rule['2024-01-01', '2024-01-04', '2024-01-07']['2024-01-01', '2024-01-04', '2024-01-07']Passed

SHA-256 / 8ccb0df371148241cc9cb68cf8bb6d6396d8e3b76aa9111ecceacbc76e5f4cee

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

Case digest / 6ec06cb4823e7cd0a66466fe4ecf11c7450f6ecb6d6a667a3281ecd6b02dd9d5