FAILURE MAP
← Case archive

FA-77076 / Calendar recurrence rules / Open access

Occurrence test and next-occurrence lookup for an anchored N-weekly series: next index · case 01

Querying on an occurrence date returns that same date as the next occurrence.

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

ROOT CAUSE

The next index uses a ceiling division, giving at-or-after instead of strictly-after semantics.

VERIFIED REPAIR

At the next index decision use `diff // period + 1`, leaving the other decision sites of the model unchanged.

Unsuccessful approach: The partial repair `(diff + 1) // period + 1` rounds the day before an occurrence up into the following period.

Case contract

A series occurs every interval_weeks weeks starting at anchor, for count occurrences. For a query date return [is_occurrence, next occurrence strictly after the query or None, 0-based index of that next occurrence or None]. Dates before the anchor are never occurrences; the next occurrence after a query before the anchor is the anchor itself.

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(anchor, interval_weeks, count, query):
    a = dt.date.fromisoformat(anchor)
    q = dt.date.fromisoformat(query)
    period = 7 * interval_weeks
    diff = (q - a).days
    is_occ = diff >= 0 and diff % period == 0 and diff // period < count
    if diff < 0:
        idx = 0
    else:
        idx = -(-diff // period)
    if idx >= count:
        return [is_occ, None, None]
    return [is_occ, (a + dt.timedelta(days=idx * period)).isoformat(), idx]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: aligned date before anchor', ['2024-01-05', 2, 10, '2023-12-22'], [False, '2024-01-05', 0]),
  ('query on anchor', ['2024-01-05', 2, 10, '2024-01-05'], [True, '2024-01-19', 1]),
  ('query on later occurrence', ['2024-01-05', 2, 10, '2024-02-02'], [True, '2024-02-16', 3]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1]),
  ('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0])],
 [('query on later occurrence', ['2024-01-05', 2, 10, '2024-02-02'], [True, '2024-02-16', 3]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1]),
  ('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3])],
 [('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])],
 [('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('three periods before anchor weekly', ['2024-03-04', 1, 5, '2024-02-12'], [False, '2024-03-04', 0]),
  ('beyond series end', ['2024-03-04', 1, 2, '2024-04-30'], [False, None, None]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])],
 [('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('three periods before anchor weekly', ['2024-03-04', 1, 5, '2024-02-12'], [False, '2024-03-04', 0]),
  ('beyond series end', ['2024-03-04', 1, 2, '2024-04-30'], [False, None, None]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3]),
  ('regression: aligned date before anchor', ['2024-01-05', 2, 10, '2023-12-22'], [False, '2024-01-05', 0]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])]]
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: aligned date before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed
query on anchor[True, '2024-01-05', 0][True, '2024-01-19', 1]Failed
query on later occurrence[True, '2024-02-02', 2][True, '2024-02-16', 3]Failed
day before occurrence[False, '2024-01-19', 1][False, '2024-01-19', 1]Passed
one period after last[False, None, None][False, None, None]Passed
query on last occurrence[True, '2024-02-02', 2][True, None, None]Failed
far before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed

SHA-256 / 2b18200399d0bb3f5f3e2f59318ede537b07227069b4063e16bc47e262010d18

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(anchor, interval_weeks, count, query):
    a = dt.date.fromisoformat(anchor)
    q = dt.date.fromisoformat(query)
    period = 7 * interval_weeks
    diff = (q - a).days
    is_occ = diff >= 0 and diff % period == 0 and diff // period < count
    if diff < 0:
        idx = 0
    else:
        idx = (diff + 1) // period + 1
    if idx >= count:
        return [is_occ, None, None]
    return [is_occ, (a + dt.timedelta(days=idx * period)).isoformat(), idx]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: aligned date before anchor', ['2024-01-05', 2, 10, '2023-12-22'], [False, '2024-01-05', 0]),
  ('query on anchor', ['2024-01-05', 2, 10, '2024-01-05'], [True, '2024-01-19', 1]),
  ('query on later occurrence', ['2024-01-05', 2, 10, '2024-02-02'], [True, '2024-02-16', 3]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1]),
  ('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0])],
 [('query on later occurrence', ['2024-01-05', 2, 10, '2024-02-02'], [True, '2024-02-16', 3]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1]),
  ('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3])],
 [('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])],
 [('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('three periods before anchor weekly', ['2024-03-04', 1, 5, '2024-02-12'], [False, '2024-03-04', 0]),
  ('beyond series end', ['2024-03-04', 1, 2, '2024-04-30'], [False, None, None]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])],
 [('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('three periods before anchor weekly', ['2024-03-04', 1, 5, '2024-02-12'], [False, '2024-03-04', 0]),
  ('beyond series end', ['2024-03-04', 1, 2, '2024-04-30'], [False, None, None]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3]),
  ('regression: aligned date before anchor', ['2024-01-05', 2, 10, '2023-12-22'], [False, '2024-01-05', 0]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])]]
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: aligned date before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed
query on anchor[True, '2024-01-19', 1][True, '2024-01-19', 1]Passed
query on later occurrence[True, '2024-02-16', 3][True, '2024-02-16', 3]Passed
day before occurrence[False, '2024-02-02', 2][False, '2024-01-19', 1]Failed
one period after last[False, None, None][False, None, None]Passed
query on last occurrence[True, None, None][True, None, None]Passed
far before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed

SHA-256 / aea43bafe222c96ddf625bf1abc4a56fc9b8572b8f23973a8b0a4a45becf9c18

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(anchor, interval_weeks, count, query):
    a = dt.date.fromisoformat(anchor)
    q = dt.date.fromisoformat(query)
    period = 7 * interval_weeks
    diff = (q - a).days
    is_occ = diff >= 0 and diff % period == 0 and diff // period < count
    if diff < 0:
        idx = 0
    else:
        idx = diff // period + 1
    if idx >= count:
        return [is_occ, None, None]
    return [is_occ, (a + dt.timedelta(days=idx * period)).isoformat(), idx]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: aligned date before anchor', ['2024-01-05', 2, 10, '2023-12-22'], [False, '2024-01-05', 0]),
  ('query on anchor', ['2024-01-05', 2, 10, '2024-01-05'], [True, '2024-01-19', 1]),
  ('query on later occurrence', ['2024-01-05', 2, 10, '2024-02-02'], [True, '2024-02-16', 3]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1]),
  ('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0])],
 [('query on later occurrence', ['2024-01-05', 2, 10, '2024-02-02'], [True, '2024-02-16', 3]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1]),
  ('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3])],
 [('one period after last', ['2024-01-05', 2, 3, '2024-02-16'], [False, None, None]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None]),
  ('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])],
 [('far before anchor', ['2024-01-05', 3, 4, '2023-11-01'], [False, '2024-01-05', 0]),
  ('weekly mid week', ['2024-03-04', 1, 5, '2024-03-13'], [False, '2024-03-18', 2]),
  ('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('three periods before anchor weekly', ['2024-03-04', 1, 5, '2024-02-12'], [False, '2024-03-04', 0]),
  ('beyond series end', ['2024-03-04', 1, 2, '2024-04-30'], [False, None, None]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])],
 [('four-weekly aligned', ['2024-03-04', 4, 6, '2024-04-29'], [True, '2024-05-27', 3]),
  ('aligned before anchor weekly', ['2024-03-04', 1, 5, '2024-02-26'], [False, '2024-03-04', 0]),
  ('two periods before anchor', ['2024-01-05', 2, 10, '2023-12-08'], [False, '2024-01-05', 0]),
  ('three periods before anchor weekly', ['2024-03-04', 1, 5, '2024-02-12'], [False, '2024-03-04', 0]),
  ('beyond series end', ['2024-03-04', 1, 2, '2024-04-30'], [False, None, None]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3]),
  ('regression: aligned date before anchor', ['2024-01-05', 2, 10, '2023-12-22'], [False, '2024-01-05', 0]),
  ('day before occurrence', ['2024-01-05', 2, 10, '2024-01-18'], [False, '2024-01-19', 1])]]
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: aligned date before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed
query on anchor[True, '2024-01-19', 1][True, '2024-01-19', 1]Passed
query on later occurrence[True, '2024-02-16', 3][True, '2024-02-16', 3]Passed
day before occurrence[False, '2024-01-19', 1][False, '2024-01-19', 1]Passed
one period after last[False, None, None][False, None, None]Passed
query on last occurrence[True, None, None][True, None, None]Passed
far before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed

SHA-256 / 91c8d4c896d50a4803cf45ec1c03be8c55ebd470705209f0e168cbf97cd1a151

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

Case digest / 53d34b0668f33ca14474b7046d2b38f0b08a3b62b1f71fecc7b9f3605f1a2b00