FA-77301 / Calendar recurrence rules / Open access
Re-keying instance overrides after a series start or interval change: index map · case 01
After changing weekly to every-two-weeks, exceptions attach to the wrong occurrences.
ROOT CAUSE
The occurrence index is computed with the new interval.
VERIFIED REPAIR
At the index map decision use `diff // interval`, leaving the other decision sites of the model unchanged.
Unsuccessful approach: The partial repair `diff // max(interval, new_interval)` uses the larger interval, which is still wrong when the interval shrinks.
Case contract
An all-day series (old_start, interval, count) is edited to start at new_start with new_interval. Each override [original, target] (target None = cancelled) is keyed by occurrence index i, where original = old_start + i*interval; overrides not on an old instance (before the series, misaligned or at i >= count) are dropped. The override is re-keyed to new_start + i*new_interval; moved targets are absolute and kept unchanged; an override whose target equals its new key is dropped as a no-op; the last override for a key wins. Return [[new_key, target]] sorted by new key.
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(old_start, interval, count, new_start, new_interval, overrides):
old = dt.date.fromisoformat(old_start)
new = dt.date.fromisoformat(new_start)
out = {}
for orig, target in overrides:
o = dt.date.fromisoformat(orig)
diff = (o - old).days
if diff < 0 or diff % interval != 0 or diff // interval >= count:
continue
i = diff // new_interval
key = new + dt.timedelta(days=i * new_interval)
if target == key.isoformat():
continue
out[key.isoformat()] = target
return [[k, out[k]] for k in sorted(out)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']]),
('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], []),
('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]])],
[('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], []),
('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']]),
('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], [])]]
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: override before series start | [['2024-01-17', '2024-01-20']] | [['2024-01-17', '2024-01-20']] | Passed |
| interval change | [['2024-01-15', '2024-01-16']] | [['2024-01-29', '2024-01-16']] | Failed |
| beyond count | [['2024-01-03', '2024-01-10']] | [['2024-01-03', '2024-01-10']] | Passed |
| target becomes new key | [] | [] | Passed |
| former no-op now moves | [['2024-01-10', '2024-01-08']] | [['2024-01-10', '2024-01-08']] | Passed |
| reverse edit order | [['2024-03-06', None], ['2024-03-11', '2024-03-30']] | [['2024-03-06', None], ['2024-03-11', '2024-03-30']] | Passed |
| shrinking interval | [['2024-03-15', '2024-03-16'], ['2024-03-29', None]] | [['2024-03-08', '2024-03-16'], ['2024-03-15', None]] | Failed |
SHA-256 / bbed9377415d35846d5af96df7cc0ca7450536bd45b4740dcb7836d1e270bcdc
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(old_start, interval, count, new_start, new_interval, overrides):
old = dt.date.fromisoformat(old_start)
new = dt.date.fromisoformat(new_start)
out = {}
for orig, target in overrides:
o = dt.date.fromisoformat(orig)
diff = (o - old).days
if diff < 0 or diff % interval != 0 or diff // interval >= count:
continue
i = diff // max(interval, new_interval)
key = new + dt.timedelta(days=i * new_interval)
if target == key.isoformat():
continue
out[key.isoformat()] = target
return [[k, out[k]] for k in sorted(out)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']]),
('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], []),
('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]])],
[('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], []),
('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']]),
('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], [])]]
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: override before series start | [['2024-01-17', '2024-01-20']] | [['2024-01-17', '2024-01-20']] | Passed |
| interval change | [['2024-01-15', '2024-01-16']] | [['2024-01-29', '2024-01-16']] | Failed |
| beyond count | [['2024-01-03', '2024-01-10']] | [['2024-01-03', '2024-01-10']] | Passed |
| target becomes new key | [] | [] | Passed |
| former no-op now moves | [['2024-01-10', '2024-01-08']] | [['2024-01-10', '2024-01-08']] | Passed |
| reverse edit order | [['2024-03-06', None], ['2024-03-11', '2024-03-30']] | [['2024-03-06', None], ['2024-03-11', '2024-03-30']] | Passed |
| shrinking interval | [['2024-03-08', '2024-03-16'], ['2024-03-15', None]] | [['2024-03-08', '2024-03-16'], ['2024-03-15', None]] | Passed |
SHA-256 / 7ce8c1e798abbd2b4c80651d21efcb255598abfc428f634a241ac1c31cea3f24
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(old_start, interval, count, new_start, new_interval, overrides):
old = dt.date.fromisoformat(old_start)
new = dt.date.fromisoformat(new_start)
out = {}
for orig, target in overrides:
o = dt.date.fromisoformat(orig)
diff = (o - old).days
if diff < 0 or diff % interval != 0 or diff // interval >= count:
continue
i = diff // interval
key = new + dt.timedelta(days=i * new_interval)
if target == key.isoformat():
continue
out[key.isoformat()] = target
return [[k, out[k]] for k in sorted(out)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']]),
('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], []),
('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]])],
[('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], []),
('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('former no-op now moves',
['2024-01-01', 7, 4, '2024-01-03', 7, [['2024-01-08', '2024-01-08']]],
[['2024-01-10', '2024-01-08']]),
('reverse edit order',
['2024-03-01', 1, 10, '2024-03-05', 1, [['2024-03-07', '2024-03-30'], ['2024-03-02', None]]],
[['2024-03-06', None], ['2024-03-11', '2024-03-30']]),
('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('shrinking interval',
['2024-03-01', 14, 5, '2024-03-01', 7, [['2024-03-29', None], ['2024-03-15', '2024-03-16']]],
[['2024-03-08', '2024-03-16'], ['2024-03-15', None]]),
('misaligned override',
['2024-04-01', 3, 5, '2024-04-02', 3, [['2024-04-02', None], ['2024-04-04', '2024-04-30']]],
[['2024-04-05', '2024-04-30']]),
('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']])],
[('last wins',
['2024-05-01', 2, 4, '2024-05-02', 2, [['2024-05-03', '2024-05-20'], ['2024-05-03', '2024-05-21']]],
[['2024-05-04', '2024-05-21']]),
('moved forward past neighbour',
['2024-06-01',
1,
5,
'2024-06-11',
1,
[['2024-06-01', '2024-06-30'], ['2024-06-03', None], ['2024-06-04', '2024-06-12']]],
[['2024-06-11', '2024-06-30'], ['2024-06-13', None], ['2024-06-14', '2024-06-12']]),
('earlier-moved target',
['2024-07-10', 7, 3, '2024-07-12', 7, [['2024-07-17', '2024-07-01']]],
[['2024-07-19', '2024-07-01']]),
('regression: override before series start',
['2024-01-08', 7, 5, '2024-01-10', 7, [['2024-01-01', None], ['2024-01-15', '2024-01-20']]],
[['2024-01-17', '2024-01-20']]),
('interval change',
['2024-01-01', 7, 6, '2024-01-01', 14, [['2024-01-15', '2024-01-16']]],
[['2024-01-29', '2024-01-16']]),
('beyond count',
['2024-01-01', 1, 3, '2024-01-02', 1, [['2024-01-05', None], ['2024-01-02', '2024-01-10']]],
[['2024-01-03', '2024-01-10']]),
('target becomes new key', ['2024-01-01', 7, 4, '2024-01-02', 7, [['2024-01-08', '2024-01-09']]], [])]]
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: override before series start | [['2024-01-17', '2024-01-20']] | [['2024-01-17', '2024-01-20']] | Passed |
| interval change | [['2024-01-29', '2024-01-16']] | [['2024-01-29', '2024-01-16']] | Passed |
| beyond count | [['2024-01-03', '2024-01-10']] | [['2024-01-03', '2024-01-10']] | Passed |
| target becomes new key | [] | [] | Passed |
| former no-op now moves | [['2024-01-10', '2024-01-08']] | [['2024-01-10', '2024-01-08']] | Passed |
| reverse edit order | [['2024-03-06', None], ['2024-03-11', '2024-03-30']] | [['2024-03-06', None], ['2024-03-11', '2024-03-30']] | Passed |
| shrinking interval | [['2024-03-08', '2024-03-16'], ['2024-03-15', None]] | [['2024-03-08', '2024-03-16'], ['2024-03-15', None]] | Passed |
SHA-256 / 3c47ef2a595d6203b8fd69040797e04c2074a5f02429a69a91280da6d3f4af18
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:24.411204+00:00.
Case digest / 499974f2a7dbadf1d5e369685cc6253bd7cbfcf46b6edbd581c099db2023d3c6