FA-61311 / Bond day-count conventions / Open access
Act/Act AFB whole-year decomposition: the leap-day search looks at the whole period instead of the stub · case 01
Stubs in periods of more than a year use 366 because of leap days in the whole years.
ROOT CAUSE
The 29 February search runs up to the final end date instead of the stub end.
VERIFIED REPAIR
Search for 29 February only inside (start, stub end].
Unsuccessful approach: OR-ing the correct search with the stub end year leap status still overcounts.
Case contract
Inputs start < end [y,m,d]. Count whole years n stepping back from the end date (an end of 29 February maps to 28 February in non-leap years) while the stepped date is not before start. The stub runs from start to the end stepped back n years; its denominator is 366 if a 29 February lies in (start, stub end], else 365. Return n + stub days/denominator rounded to 9 decimals.
Why this case matters
Bond accrual and pricing systems depend on exact day-count arithmetic; a single-day error changes settlement cash.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(a, b):
A = datetime.date(*a)
B = datetime.date(*b)
def leap(y):
return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
def back_years(n):
y = B.year - n
if B.month == 2 and B.day == 29 and not leap(y):
return datetime.date(y, 2, 28)
return datetime.date(y, B.month, B.day)
n = 0
while back_years(n + 1) >= A:
n += 1
stub_end = back_years(n)
has29 = any(leap(y) and A < datetime.date(y, 2, 29) <= B for y in range(A.year, B.year + 1))
den = 366 if has29 else 365
return round(n + (stub_end - A).days / den, 9)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression stub leap window 1', [[2059, 3, 3], [2062, 3, 16]], 3.035616438], ['regression stub leap window 2', [[2022, 6, 12], [2030, 6, 23]], 8.030136986], ['partial repair probe 1', [[2016, 3, 31], [2019, 7, 2]], 3.254794521], ['partial repair probe 2', [[2088, 7, 31], [2088, 10, 23]], 0.230136986], ['boundary control 1', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[1991, 10, 30], [1995, 7, 29]], 3.745901639], ['normal control 2', [[2097, 11, 30], [2098, 2, 21]], 0.22739726]], [['regression stub leap window 1', [[2067, 4, 30], [2072, 9, 7]], 5.356164384], ['regression stub leap window 2', [[2053, 2, 8], [2057, 12, 7]], 4.82739726], ['partial repair probe 1', [[2068, 8, 18], [2070, 8, 23]], 2.01369863], ['partial repair probe 2', [[2040, 5, 31], [2042, 11, 14]], 2.457534247], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2017, 12, 31], [2018, 5, 3]], 0.336986301], ['normal control 2', [[2052, 2, 28], [2059, 11, 6]], 7.68852459]], [['regression stub leap window 1', [[2030, 1, 31], [2034, 12, 4]], 4.84109589], ['regression stub leap window 2', [[1993, 2, 28], [2000, 11, 9]], 7.695890411], ['partial repair probe 1', [[2068, 3, 23], [2069, 12, 20]], 1.745205479], ['partial repair probe 2', [[2076, 7, 3], [2077, 8, 10]], 1.104109589], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2036, 9, 30], [2038, 9, 29]], 1.997260274], ['normal control 2', [[2019, 7, 18], [2024, 2, 29]], 4.617486339]], [['regression stub leap window 1', [[2004, 5, 26], [2008, 2, 29]], 3.761643836], ['regression stub leap window 2', [[2010, 12, 22], [2012, 2, 29]], 1.18630137], ['partial repair probe 1', [[2084, 8, 12], [2087, 8, 15]], 3.008219178], ['partial repair probe 2', [[2092, 4, 30], [2092, 10, 27]], 0.493150685], ['boundary control 1', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2011, 3, 11], [2012, 2, 29]], 0.969945355], ['normal control 2', [[2012, 8, 30], [2015, 5, 30]], 2.747945205]], [['regression stub leap window 1', [[2001, 5, 31], [2009, 1, 23]], 7.649315068], ['regression stub leap window 2', [[2015, 2, 28], [2021, 8, 1]], 6.421917808], ['partial repair probe 1', [[2056, 2, 29], [2059, 9, 9]], 3.528767123], ['partial repair probe 2', [[2068, 3, 28], [2071, 10, 31]], 3.594520548], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2046, 3, 23], [2046, 7, 28]], 0.347945205], ['normal control 2', [[2080, 6, 2], [2082, 2, 16]], 1.709589041]]]
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 stub leap window 1 | 3.035519126 | 3.035616438 | Failed |
| regression stub leap window 2 | 8.030054645 | 8.030136986 | Failed |
| partial repair probe 1 | 3.254794521 | 3.254794521 | Passed |
| partial repair probe 2 | 0.230136986 | 0.230136986 | Passed |
| boundary control 1 | 4.99726776 | 4.99726776 | Passed |
| boundary control 2 | 1.0 | 1.0 | Passed |
| normal control 1 | 3.745901639 | 3.745901639 | Passed |
| normal control 2 | 0.22739726 | 0.22739726 | Passed |
SHA-256 / 734b982bced0397fbddf0df5463f9981abbfcbe47be014f5348757da17775b41
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(a, b):
A = datetime.date(*a)
B = datetime.date(*b)
def leap(y):
return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
def back_years(n):
y = B.year - n
if B.month == 2 and B.day == 29 and not leap(y):
return datetime.date(y, 2, 28)
return datetime.date(y, B.month, B.day)
n = 0
while back_years(n + 1) >= A:
n += 1
stub_end = back_years(n)
has29 = any(leap(y) and A < datetime.date(y, 2, 29) <= stub_end for y in range(A.year, stub_end.year + 1))
den = 366 if has29 or leap(stub_end.year) else 365
return round(n + (stub_end - A).days / den, 9)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression stub leap window 1', [[2059, 3, 3], [2062, 3, 16]], 3.035616438], ['regression stub leap window 2', [[2022, 6, 12], [2030, 6, 23]], 8.030136986], ['partial repair probe 1', [[2016, 3, 31], [2019, 7, 2]], 3.254794521], ['partial repair probe 2', [[2088, 7, 31], [2088, 10, 23]], 0.230136986], ['boundary control 1', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[1991, 10, 30], [1995, 7, 29]], 3.745901639], ['normal control 2', [[2097, 11, 30], [2098, 2, 21]], 0.22739726]], [['regression stub leap window 1', [[2067, 4, 30], [2072, 9, 7]], 5.356164384], ['regression stub leap window 2', [[2053, 2, 8], [2057, 12, 7]], 4.82739726], ['partial repair probe 1', [[2068, 8, 18], [2070, 8, 23]], 2.01369863], ['partial repair probe 2', [[2040, 5, 31], [2042, 11, 14]], 2.457534247], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2017, 12, 31], [2018, 5, 3]], 0.336986301], ['normal control 2', [[2052, 2, 28], [2059, 11, 6]], 7.68852459]], [['regression stub leap window 1', [[2030, 1, 31], [2034, 12, 4]], 4.84109589], ['regression stub leap window 2', [[1993, 2, 28], [2000, 11, 9]], 7.695890411], ['partial repair probe 1', [[2068, 3, 23], [2069, 12, 20]], 1.745205479], ['partial repair probe 2', [[2076, 7, 3], [2077, 8, 10]], 1.104109589], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2036, 9, 30], [2038, 9, 29]], 1.997260274], ['normal control 2', [[2019, 7, 18], [2024, 2, 29]], 4.617486339]], [['regression stub leap window 1', [[2004, 5, 26], [2008, 2, 29]], 3.761643836], ['regression stub leap window 2', [[2010, 12, 22], [2012, 2, 29]], 1.18630137], ['partial repair probe 1', [[2084, 8, 12], [2087, 8, 15]], 3.008219178], ['partial repair probe 2', [[2092, 4, 30], [2092, 10, 27]], 0.493150685], ['boundary control 1', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2011, 3, 11], [2012, 2, 29]], 0.969945355], ['normal control 2', [[2012, 8, 30], [2015, 5, 30]], 2.747945205]], [['regression stub leap window 1', [[2001, 5, 31], [2009, 1, 23]], 7.649315068], ['regression stub leap window 2', [[2015, 2, 28], [2021, 8, 1]], 6.421917808], ['partial repair probe 1', [[2056, 2, 29], [2059, 9, 9]], 3.528767123], ['partial repair probe 2', [[2068, 3, 28], [2071, 10, 31]], 3.594520548], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2046, 3, 23], [2046, 7, 28]], 0.347945205], ['normal control 2', [[2080, 6, 2], [2082, 2, 16]], 1.709589041]]]
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 stub leap window 1 | 3.035616438 | 3.035616438 | Passed |
| regression stub leap window 2 | 8.030136986 | 8.030136986 | Passed |
| partial repair probe 1 | 3.254098361 | 3.254794521 | Failed |
| partial repair probe 2 | 0.229508197 | 0.230136986 | Failed |
| boundary control 1 | 4.99726776 | 4.99726776 | Passed |
| boundary control 2 | 1.0 | 1.0 | Passed |
| normal control 1 | 3.745901639 | 3.745901639 | Passed |
| normal control 2 | 0.22739726 | 0.22739726 | Passed |
SHA-256 / ee19ab500d8ff0d65fa2ca3fdafffd4e2e0bab291e7fb2ebc89f028695e3c8d1
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(a, b):
A = datetime.date(*a)
B = datetime.date(*b)
def leap(y):
return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
def back_years(n):
y = B.year - n
if B.month == 2 and B.day == 29 and not leap(y):
return datetime.date(y, 2, 28)
return datetime.date(y, B.month, B.day)
n = 0
while back_years(n + 1) >= A:
n += 1
stub_end = back_years(n)
has29 = any(leap(y) and A < datetime.date(y, 2, 29) <= stub_end for y in range(A.year, stub_end.year + 1))
den = 366 if has29 else 365
return round(n + (stub_end - A).days / den, 9)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression stub leap window 1', [[2059, 3, 3], [2062, 3, 16]], 3.035616438], ['regression stub leap window 2', [[2022, 6, 12], [2030, 6, 23]], 8.030136986], ['partial repair probe 1', [[2016, 3, 31], [2019, 7, 2]], 3.254794521], ['partial repair probe 2', [[2088, 7, 31], [2088, 10, 23]], 0.230136986], ['boundary control 1', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[1991, 10, 30], [1995, 7, 29]], 3.745901639], ['normal control 2', [[2097, 11, 30], [2098, 2, 21]], 0.22739726]], [['regression stub leap window 1', [[2067, 4, 30], [2072, 9, 7]], 5.356164384], ['regression stub leap window 2', [[2053, 2, 8], [2057, 12, 7]], 4.82739726], ['partial repair probe 1', [[2068, 8, 18], [2070, 8, 23]], 2.01369863], ['partial repair probe 2', [[2040, 5, 31], [2042, 11, 14]], 2.457534247], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2017, 12, 31], [2018, 5, 3]], 0.336986301], ['normal control 2', [[2052, 2, 28], [2059, 11, 6]], 7.68852459]], [['regression stub leap window 1', [[2030, 1, 31], [2034, 12, 4]], 4.84109589], ['regression stub leap window 2', [[1993, 2, 28], [2000, 11, 9]], 7.695890411], ['partial repair probe 1', [[2068, 3, 23], [2069, 12, 20]], 1.745205479], ['partial repair probe 2', [[2076, 7, 3], [2077, 8, 10]], 1.104109589], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2036, 9, 30], [2038, 9, 29]], 1.997260274], ['normal control 2', [[2019, 7, 18], [2024, 2, 29]], 4.617486339]], [['regression stub leap window 1', [[2004, 5, 26], [2008, 2, 29]], 3.761643836], ['regression stub leap window 2', [[2010, 12, 22], [2012, 2, 29]], 1.18630137], ['partial repair probe 1', [[2084, 8, 12], [2087, 8, 15]], 3.008219178], ['partial repair probe 2', [[2092, 4, 30], [2092, 10, 27]], 0.493150685], ['boundary control 1', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['boundary control 2', [[2019, 3, 1], [2024, 2, 29]], 4.99726776], ['normal control 1', [[2011, 3, 11], [2012, 2, 29]], 0.969945355], ['normal control 2', [[2012, 8, 30], [2015, 5, 30]], 2.747945205]], [['regression stub leap window 1', [[2001, 5, 31], [2009, 1, 23]], 7.649315068], ['regression stub leap window 2', [[2015, 2, 28], [2021, 8, 1]], 6.421917808], ['partial repair probe 1', [[2056, 2, 29], [2059, 9, 9]], 3.528767123], ['partial repair probe 2', [[2068, 3, 28], [2071, 10, 31]], 3.594520548], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2046, 3, 23], [2046, 7, 28]], 0.347945205], ['normal control 2', [[2080, 6, 2], [2082, 2, 16]], 1.709589041]]]
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 stub leap window 1 | 3.035616438 | 3.035616438 | Passed |
| regression stub leap window 2 | 8.030136986 | 8.030136986 | Passed |
| partial repair probe 1 | 3.254794521 | 3.254794521 | Passed |
| partial repair probe 2 | 0.230136986 | 0.230136986 | Passed |
| boundary control 1 | 4.99726776 | 4.99726776 | Passed |
| boundary control 2 | 1.0 | 1.0 | Passed |
| normal control 1 | 3.745901639 | 3.745901639 | Passed |
| normal control 2 | 0.22739726 | 0.22739726 | Passed |
SHA-256 / 26de7292414bf5fb5b2c4d0ad11e595a34e858457d12eccb6301694b96364d2e
Verification & scope
A deterministic toy contract stated explicitly in the contract field; no claim of conformance to any published convention text. 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:54.176905+00:00.
Case digest / 585fd63352f1a2ebf89d81f285cb97319f6b9609c2ae32e1ec0c0bfd49bf758a