FA-77011 / Calendar recurrence rules / Open access
Splitting a series for a this-and-following edit: tail start · case 01
The new tail series begins on a date that was never an occurrence.
ROOT CAUSE
The split occurrence is located using the new interval instead of the original one.
THE FAILURE
The split occurrence is located using the new interval instead of the original one.
Unsuccessful approach: The partial repair `start + dt.timedelta(days=k)` ignores the interval entirely.
Case contract
A daily-interval series (dtstart, interval, and either count or until). Editing from 0-based occurrence k splits it: the head keeps occurrences 0..k-1 (count k, or until = its last retained occurrence date) and the tail starts at the original date of occurrence k with new_interval and the remaining count (or the original until). k <= 0 makes the head None; a split at or past the end makes the tail None. Return {"head": [dtstart, count, until] or None, "tail": [start, interval, count, until] or None}.
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, until, k, new_interval):
start = dt.date.fromisoformat(dtstart)
until_d = dt.date.fromisoformat(until) if until else None
tail_start = start + dt.timedelta(days=k * new_interval)
if (count is not None and k >= count) or (until_d is not None and tail_start > until_d):
tail = None
else:
tail = [tail_start.isoformat(), new_interval, count - k if count is not None else None, until]
if k <= 0:
head = None
elif count is not None:
head = [dtstart, k, None]
else:
head = [dtstart, None, (start + dt.timedelta(days=(k - 1) * interval)).isoformat()]
return {'head': head, 'tail': tail}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: count series split at 3',
['2024-01-01', 2, 10, None, 3, 7],
{'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]}),
('until series split at 2',
['2024-01-01', 3, None, '2024-02-01', 2, 1],
{'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']}),
('split at first occurrence',
['2024-01-01', 1, 5, None, 0, 2],
{'head': None, 'tail': ['2024-01-01', 2, 5, None]}),
('until split at first',
['2024-03-01', 7, None, '2024-06-01', 0, 14],
{'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']}),
('split exactly at count',
['2024-01-01', 1, 4, None, 4, 2],
{'head': ['2024-01-01', 4, None], 'tail': None}),
('split past until',
['2024-01-01', 5, None, '2024-01-20', 5, 2],
{'head': ['2024-01-01', None, '2024-01-21'], 'tail': None}),
('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']})],
[('split at first occurrence',
['2024-01-01', 1, 5, None, 0, 2],
{'head': None, 'tail': ['2024-01-01', 2, 5, None]}),
('until split at first',
['2024-03-01', 7, None, '2024-06-01', 0, 14],
{'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']}),
('split exactly at count',
['2024-01-01', 1, 4, None, 4, 2],
{'head': ['2024-01-01', 4, None], 'tail': None}),
('split past until',
['2024-01-01', 5, None, '2024-01-20', 5, 2],
{'head': ['2024-01-01', None, '2024-01-21'], 'tail': None}),
('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']}),
('count split near end',
['2024-05-10', 1, 6, None, 5, 3],
{'head': ['2024-05-10', 5, None], 'tail': ['2024-05-15', 3, 1, None]}),
('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']})],
[('split exactly at count',
['2024-01-01', 1, 4, None, 4, 2],
{'head': ['2024-01-01', 4, None], 'tail': None}),
('split past until',
['2024-01-01', 5, None, '2024-01-20', 5, 2],
{'head': ['2024-01-01', None, '2024-01-21'], 'tail': None}),
('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']}),
('count split near end',
['2024-05-10', 1, 6, None, 5, 3],
{'head': ['2024-05-10', 5, None], 'tail': ['2024-05-15', 3, 1, None]}),
('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']}),
('interval 1 count split',
['2024-12-30', 1, 8, None, 2, 1],
{'head': ['2024-12-30', 2, None], 'tail': ['2025-01-01', 1, 6, None]}),
('split beyond count', ['2024-01-01', 1, 3, None, 7, 2], {'head': ['2024-01-01', 7, None], 'tail': None})],
[('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']}),
('count split near end',
['2024-05-10', 1, 6, None, 5, 3],
{'head': ['2024-05-10', 5, None], 'tail': ['2024-05-15', 3, 1, None]}),
('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']}),
('interval 1 count split',
['2024-12-30', 1, 8, None, 2, 1],
{'head': ['2024-12-30', 2, None], 'tail': ['2025-01-01', 1, 6, None]}),
('split beyond count', ['2024-01-01', 1, 3, None, 7, 2], {'head': ['2024-01-01', 7, None], 'tail': None}),
('regression: count series split at 3',
['2024-01-01', 2, 10, None, 3, 7],
{'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]}),
('until series split at 2',
['2024-01-01', 3, None, '2024-02-01', 2, 1],
{'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']})],
[('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']}),
('interval 1 count split',
['2024-12-30', 1, 8, None, 2, 1],
{'head': ['2024-12-30', 2, None], 'tail': ['2025-01-01', 1, 6, None]}),
('split beyond count', ['2024-01-01', 1, 3, None, 7, 2], {'head': ['2024-01-01', 7, None], 'tail': None}),
('regression: count series split at 3',
['2024-01-01', 2, 10, None, 3, 7],
{'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]}),
('until series split at 2',
['2024-01-01', 3, None, '2024-02-01', 2, 1],
{'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']}),
('split at first occurrence',
['2024-01-01', 1, 5, None, 0, 2],
{'head': None, 'tail': ['2024-01-01', 2, 5, None]}),
('until split at first',
['2024-03-01', 7, None, '2024-06-01', 0, 14],
{'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']})]]
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: count series split at 3 | {'head': ['2024-01-01', 3, None], 'tail': ['2024-01-22', 7, 7, None]} | {'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]} | Failed |
| until series split at 2 | {'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-03', 1, None, '2024-02-01']} | {'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']} | Failed |
| split at first occurrence | {'head': None, 'tail': ['2024-01-01', 2, 5, None]} | {'head': None, 'tail': ['2024-01-01', 2, 5, None]} | Passed |
| until split at first | {'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']} | {'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']} | Passed |
| split exactly at count | {'head': ['2024-01-01', 4, None], 'tail': None} | {'head': ['2024-01-01', 4, None], 'tail': None} | Passed |
| split past until | {'head': ['2024-01-01', None, '2024-01-21'], 'tail': ['2024-01-11', 2, None, '2024-01-20']} | {'head': ['2024-01-01', None, '2024-01-21'], 'tail': None} | Failed |
| split at last until occurrence | {'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-05', 1, None, '2024-01-21']} | {'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']} | Failed |
SHA-256 / 9dd3162bbd3fc46715d6791652d099301f7b257a7eaca606631d04dcc1682e2f
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, until, k, new_interval):
start = dt.date.fromisoformat(dtstart)
until_d = dt.date.fromisoformat(until) if until else None
tail_start = start + dt.timedelta(days=k)
if (count is not None and k >= count) or (until_d is not None and tail_start > until_d):
tail = None
else:
tail = [tail_start.isoformat(), new_interval, count - k if count is not None else None, until]
if k <= 0:
head = None
elif count is not None:
head = [dtstart, k, None]
else:
head = [dtstart, None, (start + dt.timedelta(days=(k - 1) * interval)).isoformat()]
return {'head': head, 'tail': tail}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: count series split at 3',
['2024-01-01', 2, 10, None, 3, 7],
{'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]}),
('until series split at 2',
['2024-01-01', 3, None, '2024-02-01', 2, 1],
{'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']}),
('split at first occurrence',
['2024-01-01', 1, 5, None, 0, 2],
{'head': None, 'tail': ['2024-01-01', 2, 5, None]}),
('until split at first',
['2024-03-01', 7, None, '2024-06-01', 0, 14],
{'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']}),
('split exactly at count',
['2024-01-01', 1, 4, None, 4, 2],
{'head': ['2024-01-01', 4, None], 'tail': None}),
('split past until',
['2024-01-01', 5, None, '2024-01-20', 5, 2],
{'head': ['2024-01-01', None, '2024-01-21'], 'tail': None}),
('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']})],
[('split at first occurrence',
['2024-01-01', 1, 5, None, 0, 2],
{'head': None, 'tail': ['2024-01-01', 2, 5, None]}),
('until split at first',
['2024-03-01', 7, None, '2024-06-01', 0, 14],
{'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']}),
('split exactly at count',
['2024-01-01', 1, 4, None, 4, 2],
{'head': ['2024-01-01', 4, None], 'tail': None}),
('split past until',
['2024-01-01', 5, None, '2024-01-20', 5, 2],
{'head': ['2024-01-01', None, '2024-01-21'], 'tail': None}),
('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']}),
('count split near end',
['2024-05-10', 1, 6, None, 5, 3],
{'head': ['2024-05-10', 5, None], 'tail': ['2024-05-15', 3, 1, None]}),
('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']})],
[('split exactly at count',
['2024-01-01', 1, 4, None, 4, 2],
{'head': ['2024-01-01', 4, None], 'tail': None}),
('split past until',
['2024-01-01', 5, None, '2024-01-20', 5, 2],
{'head': ['2024-01-01', None, '2024-01-21'], 'tail': None}),
('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']}),
('count split near end',
['2024-05-10', 1, 6, None, 5, 3],
{'head': ['2024-05-10', 5, None], 'tail': ['2024-05-15', 3, 1, None]}),
('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']}),
('interval 1 count split',
['2024-12-30', 1, 8, None, 2, 1],
{'head': ['2024-12-30', 2, None], 'tail': ['2025-01-01', 1, 6, None]}),
('split beyond count', ['2024-01-01', 1, 3, None, 7, 2], {'head': ['2024-01-01', 7, None], 'tail': None})],
[('split at last until occurrence',
['2024-01-01', 5, None, '2024-01-21', 4, 1],
{'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']}),
('count split near end',
['2024-05-10', 1, 6, None, 5, 3],
{'head': ['2024-05-10', 5, None], 'tail': ['2024-05-15', 3, 1, None]}),
('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']}),
('interval 1 count split',
['2024-12-30', 1, 8, None, 2, 1],
{'head': ['2024-12-30', 2, None], 'tail': ['2025-01-01', 1, 6, None]}),
('split beyond count', ['2024-01-01', 1, 3, None, 7, 2], {'head': ['2024-01-01', 7, None], 'tail': None}),
('regression: count series split at 3',
['2024-01-01', 2, 10, None, 3, 7],
{'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]}),
('until series split at 2',
['2024-01-01', 3, None, '2024-02-01', 2, 1],
{'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']})],
[('until split mid',
['2024-05-10', 4, None, '2024-07-01', 6, 2],
{'head': ['2024-05-10', None, '2024-05-30'], 'tail': ['2024-06-03', 2, None, '2024-07-01']}),
('interval 1 count split',
['2024-12-30', 1, 8, None, 2, 1],
{'head': ['2024-12-30', 2, None], 'tail': ['2025-01-01', 1, 6, None]}),
('split beyond count', ['2024-01-01', 1, 3, None, 7, 2], {'head': ['2024-01-01', 7, None], 'tail': None}),
('regression: count series split at 3',
['2024-01-01', 2, 10, None, 3, 7],
{'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]}),
('until series split at 2',
['2024-01-01', 3, None, '2024-02-01', 2, 1],
{'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']}),
('split at first occurrence',
['2024-01-01', 1, 5, None, 0, 2],
{'head': None, 'tail': ['2024-01-01', 2, 5, None]}),
('until split at first',
['2024-03-01', 7, None, '2024-06-01', 0, 14],
{'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']})]]
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: count series split at 3 | {'head': ['2024-01-01', 3, None], 'tail': ['2024-01-04', 7, 7, None]} | {'head': ['2024-01-01', 3, None], 'tail': ['2024-01-07', 7, 7, None]} | Failed |
| until series split at 2 | {'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-03', 1, None, '2024-02-01']} | {'head': ['2024-01-01', None, '2024-01-04'], 'tail': ['2024-01-07', 1, None, '2024-02-01']} | Failed |
| split at first occurrence | {'head': None, 'tail': ['2024-01-01', 2, 5, None]} | {'head': None, 'tail': ['2024-01-01', 2, 5, None]} | Passed |
| until split at first | {'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']} | {'head': None, 'tail': ['2024-03-01', 14, None, '2024-06-01']} | Passed |
| split exactly at count | {'head': ['2024-01-01', 4, None], 'tail': None} | {'head': ['2024-01-01', 4, None], 'tail': None} | Passed |
| split past until | {'head': ['2024-01-01', None, '2024-01-21'], 'tail': ['2024-01-06', 2, None, '2024-01-20']} | {'head': ['2024-01-01', None, '2024-01-21'], 'tail': None} | Failed |
| split at last until occurrence | {'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-05', 1, None, '2024-01-21']} | {'head': ['2024-01-01', None, '2024-01-16'], 'tail': ['2024-01-21', 1, None, '2024-01-21']} | Failed |
SHA-256 / 65f4a6a6f7754917b2e5c4f9496b629e8edb0fb3e8d9adb103cc0802ab6c28e6
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗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.809009+00:00.
Case digest / d21d1582e3caf5bace8d621ecee1aea60ea8a400c8433984a5177d1a3ab79fe4