FAILURE MAP
← Case archive

FA-77081 / Calendar recurrence rules / Open access

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

After the final occurrence the lookup invents one more occurrence.

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

ROOT CAUSE

The series-exhausted test is off by one.

VERIFIED REPAIR

At the exhausted series decision use `idx >= count`, leaving the other decision sites of the model unchanged.

Unsuccessful approach: The partial repair `idx >= count - 1` declares the series exhausted one occurrence early.

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 + 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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3])],
 [('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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3])],
 [('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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None])],
 [('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]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None])]]
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, '2024-02-16', 3][True, None, None]Failed
far before anchor[False, '2024-01-05', 0][False, '2024-01-05', 0]Passed
penultimate occurrence[True, '2024-07-19', 3][True, '2024-07-19', 3]Passed

SHA-256 / 01e57c21512d72bf9c53ad89c61584317e3387e226d97a46c699ef7eac44513a

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 // period + 1
    if idx >= count - 1:
        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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3])],
 [('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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3])],
 [('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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None])],
 [('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]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None])]]
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
penultimate occurrence[True, None, None][True, '2024-07-19', 3]Failed

SHA-256 / 71f82d897f606dea2398b58d2e4057fa3166cd55a5cfe80f4037eaefa3ac444b

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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3])],
 [('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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3])],
 [('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]),
  ('penultimate occurrence', ['2024-06-07', 2, 4, '2024-07-05'], [True, '2024-07-19', 3]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None])],
 [('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]),
  ('query on last occurrence', ['2024-01-05', 2, 3, '2024-02-02'], [True, None, None])]]
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
penultimate occurrence[True, '2024-07-19', 3][True, '2024-07-19', 3]Passed

SHA-256 / 1372313a02f93a8a372fa0a45fbd12a2373c9a54fd134260e0d7535168e8e982

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

Case digest / 1616c4101daa5cec6036aadb155ff9f16437a42405700379ed034490c28b2913