FA-60691 / Loyalty points ledgers / Open access
Birthday bonus window: leap-day fallback date · case 01
Members born on Feb 29 get their bonus window centred on March 1 in common years.
ROOT CAUSE
The non-leap fallback moves the birthday to March 1 instead of February 28.
VERIFIED REPAIR
Fall back to February 28 in non-leap years.
Unsuccessful approach: Moving the birthday to February 28 in every year also shifts it in leap years when Feb 29 exists.
Case contract
Input {bmonth, bday, window, bonus, purchases:[[y,m,d]] chronological}. The birthday of year Y is (Y,bmonth,bday), with Feb 29 falling back to Feb 28 in non-leap years (Gregorian rule). A purchase within window days (inclusive, either side) of the birthday of year Y-1, Y or Y+1 earns the bonus once per birthday year. Return per-purchase bonus list.
Why this case matters
Member point balances, statements and the program liability depend on this ledger rule.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(x):
def bday(y):
m, d = x['bmonth'], x['bday']
if m == 2 and d == 29 and not (y % 4 == 0 and (y % 100 != 0 or y % 400 == 0)):
m, d = 3, 1
return datetime.date(y, m, d)
got = set()
out = []
for y, m, d in x['purchases']:
p = datetime.date(y, m, d)
award = 0
for yy in (y - 1, y, y + 1):
if abs((p - bday(yy)).days) <= x['window'] and yy not in got:
got.add(yy)
award = x['bonus']
break
out.append(award)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 11], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 8]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 29], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 801, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [801, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 21], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 12], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 9]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 30], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 2], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 802, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [802, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 22], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 13], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 10]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 28], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 803, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [803, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 23], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 14], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 11]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 29], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 2], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 804, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [804, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 24], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 15], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 12]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 30], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 805, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [805, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 25], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]]]
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 |
|---|---|---|---|
| inside window | [500, 0] | [500, 0] | Passed |
| window edge | [500, 0] | [500, 0] | Passed |
| year crossing | [300, 0] | [300, 0] | Passed |
| late december birthday | [250, 250] | [250, 250] | Passed |
| leap day | [0, 800, 800] | [800, 800, 0] | Failed |
| century year | [0, 801] | [801, 0] | Failed |
| before birthday only | [0, 100, 0] | [0, 100, 0] | Passed |
SHA-256 / 38b34b5e78ee8e9ffda682d9506e727e050077524b69c13b9b3b6c87ab4815c6
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(x):
def bday(y):
m, d = x['bmonth'], x['bday']
if m == 2 and d == 29:
d = 28
return datetime.date(y, m, d)
got = set()
out = []
for y, m, d in x['purchases']:
p = datetime.date(y, m, d)
award = 0
for yy in (y - 1, y, y + 1):
if abs((p - bday(yy)).days) <= x['window'] and yy not in got:
got.add(yy)
award = x['bonus']
break
out.append(award)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 11], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 8]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 29], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 801, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [801, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 21], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 12], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 9]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 30], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 2], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 802, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [802, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 22], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 13], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 10]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 28], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 803, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [803, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 23], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 14], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 11]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 29], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 2], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 804, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [804, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 24], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 15], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 12]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 30], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 805, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [805, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 25], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]]]
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 |
|---|---|---|---|
| inside window | [500, 0] | [500, 0] | Passed |
| window edge | [500, 0] | [500, 0] | Passed |
| year crossing | [300, 0] | [300, 0] | Passed |
| late december birthday | [250, 250] | [250, 250] | Passed |
| leap day | [800, 0, 0] | [800, 800, 0] | Failed |
| century year | [801, 0] | [801, 0] | Passed |
| before birthday only | [0, 100, 0] | [0, 100, 0] | Passed |
SHA-256 / f948b57ae89e69a02fa5166dc10fb200e3533e7b42995ee5e065dc6ac2a2873d
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(x):
def bday(y):
m, d = x['bmonth'], x['bday']
if m == 2 and d == 29 and not (y % 4 == 0 and (y % 100 != 0 or y % 400 == 0)):
d = 28
return datetime.date(y, m, d)
got = set()
out = []
for y, m, d in x['purchases']:
p = datetime.date(y, m, d)
award = 0
for yy in (y - 1, y, y + 1):
if abs((p - bday(yy)).days) <= x['window'] and yy not in got:
got.add(yy)
award = x['bonus']
break
out.append(award)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 11], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 8]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 29], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 801, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [801, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 21], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 12], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 9]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 30], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 2], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 802, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [802, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 22], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 13], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 10]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 28], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 803, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [803, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 23], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 14], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 11]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 29], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 2], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 804, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [804, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 24], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]], [['inside window', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2024, 6, 15], [2024, 6, 20]]}, [500, 0]], ['window edge', {'bmonth': 6, 'bday': 15, 'window': 7, 'bonus': 500, 'purchases': [[2023, 6, 22], [2023, 6, 12]]}, [500, 0]], ['year crossing', {'bmonth': 1, 'bday': 3, 'window': 7, 'bonus': 300, 'purchases': [[2023, 12, 30], [2024, 1, 5]]}, [300, 0]], ['late december birthday', {'bmonth': 12, 'bday': 30, 'window': 5, 'bonus': 250, 'purchases': [[2025, 1, 3], [2025, 12, 29]]}, [250, 250]], ['leap day', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 800, 'purchases': [[2023, 2, 28], [2024, 2, 29], [2023, 3, 1]]}, [800, 800, 0]], ['century year', {'bmonth': 2, 'bday': 29, 'window': 0, 'bonus': 805, 'purchases': [[2100, 2, 28], [2100, 3, 1]]}, [805, 0]], ['before birthday only', {'bmonth': 9, 'bday': 1, 'window': 3, 'bonus': 100, 'purchases': [[2024, 8, 25], [2024, 8, 30], [2024, 9, 3]]}, [0, 100, 0]]]]
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 |
|---|---|---|---|
| inside window | [500, 0] | [500, 0] | Passed |
| window edge | [500, 0] | [500, 0] | Passed |
| year crossing | [300, 0] | [300, 0] | Passed |
| late december birthday | [250, 250] | [250, 250] | Passed |
| leap day | [800, 800, 0] | [800, 800, 0] | Passed |
| century year | [801, 0] | [801, 0] | Passed |
| before birthday only | [0, 100, 0] | [0, 100, 0] | Passed |
SHA-256 / c842cb4d7438dad16e02581497d87b36082a2eb5bd805aa8a6cdaa102ec8be39
Verification & scope
Stipulated bounded loyalty-program model with explicit toy rules; not any real program terms. 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:46:47.971862+00:00.
Case digest / 1567aa97127cf5a526abea33126ce711759c63a2bdec7c9e12367d579ec60b64