FA-61301 / Bond day-count conventions / Open access
Act/Act AFB whole-year decomposition: a 29 February end steps back to 1 March in common years · case 01
Periods ending on a leap day count one fewer stub day or one fewer whole year.
ROOT CAUSE
The anniversary of 29 February in a common year is taken as 1 March.
VERIFIED REPAIR
Map 29 February to 28 February in years without a leap day.
Unsuccessful approach: Mapping to 28 February even in leap years shortens anniversaries that do exist.
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, 3, 1)
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 leap anniversary mapping 1', [[2010, 10, 29], [2012, 2, 29]], 1.334246575], ['regression leap anniversary mapping 2', [[2005, 3, 30], [2008, 2, 29]], 2.917808219], ['partial repair probe 1', [[1996, 1, 30], [2004, 2, 29]], 8.081967213], ['partial repair probe 2', [[2003, 5, 10], [2004, 2, 29]], 0.806010929], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2069, 7, 30], [2074, 8, 3]], 5.010958904], ['normal control 2', [[2005, 4, 25], [2009, 10, 22]], 4.493150685], ['normal control 3', [[2020, 6, 30], [2026, 1, 7]], 5.523287671]], [['regression leap anniversary mapping 1', [[1998, 10, 13], [2004, 2, 29]], 5.378082192], ['regression leap anniversary mapping 2', [[1999, 2, 28], [2004, 2, 29]], 5.0], ['partial repair probe 1', [[2011, 3, 31], [2024, 2, 29]], 12.915300546], ['partial repair probe 2', [[2011, 7, 23], [2012, 2, 29]], 0.603825137], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2093, 8, 31], [2093, 10, 22]], 0.142465753], ['normal control 2', [[2069, 11, 30], [2073, 8, 25]], 3.734246575], ['normal control 3', [[2075, 1, 27], [2081, 10, 22]], 6.734246575]], [['regression leap anniversary mapping 1', [[2010, 8, 29], [2016, 2, 29]], 5.501369863], ['regression leap anniversary mapping 2', [[2013, 7, 23], [2016, 2, 29]], 2.602739726], ['partial repair probe 1', [[2003, 8, 6], [2008, 2, 29]], 4.56557377], ['partial repair probe 2', [[2003, 12, 4], [2004, 2, 29]], 0.237704918], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2084, 7, 30], [2092, 7, 14]], 7.956164384], ['normal control 2', [[2054, 8, 16], [2056, 3, 16]], 1.580821918], ['normal control 3', [[2062, 9, 23], [2066, 12, 16]], 4.230136986]], [['regression leap anniversary mapping 1', [[2029, 12, 24], [2032, 2, 29]], 2.180821918], ['regression leap anniversary mapping 2', [[2018, 4, 22], [2020, 2, 29]], 1.854794521], ['partial repair probe 1', [[2015, 3, 5], [2020, 2, 29]], 4.986338798], ['partial repair probe 2', [[2007, 7, 27], [2032, 2, 29]], 24.592896175], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2024, 4, 6], [2031, 2, 24]], 6.887671233], ['normal control 2', [[2033, 6, 29], [2040, 5, 23]], 6.898630137], ['normal control 3', [[2051, 1, 7], [2058, 2, 25]], 7.134246575]], [['regression leap anniversary mapping 1', [[2006, 11, 30], [2008, 2, 29]], 1.246575342], ['regression leap anniversary mapping 2', [[2004, 5, 31], [2020, 2, 29]], 15.747945205], ['partial repair probe 1', [[2023, 4, 11], [2028, 2, 29]], 4.885245902], ['partial repair probe 2', [[1999, 6, 29], [2020, 2, 29]], 20.669398907], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2087, 6, 12], [2090, 7, 1]], 3.052054795], ['normal control 2', [[2082, 4, 17], [2085, 1, 14]], 2.745205479], ['normal control 3', [[2067, 10, 30], [2069, 5, 28]], 1.576502732]]]
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 leap anniversary mapping 1 | 1.336986301 | 1.334246575 | Failed |
| regression leap anniversary mapping 2 | 2.920547945 | 2.917808219 | Failed |
| partial repair probe 1 | 8.081967213 | 8.081967213 | Passed |
| partial repair probe 2 | 0.806010929 | 0.806010929 | Passed |
| boundary control 1 | 1.0 | 1.0 | Passed |
| normal control 1 | 5.010958904 | 5.010958904 | Passed |
| normal control 2 | 4.493150685 | 4.493150685 | Passed |
| normal control 3 | 5.523287671 | 5.523287671 | Passed |
SHA-256 / 7c5fa1768671ec8c5e0b1bd9e8d88c0a1a34a444549101957724417c9a1eccd9
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:
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 leap anniversary mapping 1', [[2010, 10, 29], [2012, 2, 29]], 1.334246575], ['regression leap anniversary mapping 2', [[2005, 3, 30], [2008, 2, 29]], 2.917808219], ['partial repair probe 1', [[1996, 1, 30], [2004, 2, 29]], 8.081967213], ['partial repair probe 2', [[2003, 5, 10], [2004, 2, 29]], 0.806010929], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2069, 7, 30], [2074, 8, 3]], 5.010958904], ['normal control 2', [[2005, 4, 25], [2009, 10, 22]], 4.493150685], ['normal control 3', [[2020, 6, 30], [2026, 1, 7]], 5.523287671]], [['regression leap anniversary mapping 1', [[1998, 10, 13], [2004, 2, 29]], 5.378082192], ['regression leap anniversary mapping 2', [[1999, 2, 28], [2004, 2, 29]], 5.0], ['partial repair probe 1', [[2011, 3, 31], [2024, 2, 29]], 12.915300546], ['partial repair probe 2', [[2011, 7, 23], [2012, 2, 29]], 0.603825137], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2093, 8, 31], [2093, 10, 22]], 0.142465753], ['normal control 2', [[2069, 11, 30], [2073, 8, 25]], 3.734246575], ['normal control 3', [[2075, 1, 27], [2081, 10, 22]], 6.734246575]], [['regression leap anniversary mapping 1', [[2010, 8, 29], [2016, 2, 29]], 5.501369863], ['regression leap anniversary mapping 2', [[2013, 7, 23], [2016, 2, 29]], 2.602739726], ['partial repair probe 1', [[2003, 8, 6], [2008, 2, 29]], 4.56557377], ['partial repair probe 2', [[2003, 12, 4], [2004, 2, 29]], 0.237704918], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2084, 7, 30], [2092, 7, 14]], 7.956164384], ['normal control 2', [[2054, 8, 16], [2056, 3, 16]], 1.580821918], ['normal control 3', [[2062, 9, 23], [2066, 12, 16]], 4.230136986]], [['regression leap anniversary mapping 1', [[2029, 12, 24], [2032, 2, 29]], 2.180821918], ['regression leap anniversary mapping 2', [[2018, 4, 22], [2020, 2, 29]], 1.854794521], ['partial repair probe 1', [[2015, 3, 5], [2020, 2, 29]], 4.986338798], ['partial repair probe 2', [[2007, 7, 27], [2032, 2, 29]], 24.592896175], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2024, 4, 6], [2031, 2, 24]], 6.887671233], ['normal control 2', [[2033, 6, 29], [2040, 5, 23]], 6.898630137], ['normal control 3', [[2051, 1, 7], [2058, 2, 25]], 7.134246575]], [['regression leap anniversary mapping 1', [[2006, 11, 30], [2008, 2, 29]], 1.246575342], ['regression leap anniversary mapping 2', [[2004, 5, 31], [2020, 2, 29]], 15.747945205], ['partial repair probe 1', [[2023, 4, 11], [2028, 2, 29]], 4.885245902], ['partial repair probe 2', [[1999, 6, 29], [2020, 2, 29]], 20.669398907], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2087, 6, 12], [2090, 7, 1]], 3.052054795], ['normal control 2', [[2082, 4, 17], [2085, 1, 14]], 2.745205479], ['normal control 3', [[2067, 10, 30], [2069, 5, 28]], 1.576502732]]]
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 leap anniversary mapping 1 | 1.334246575 | 1.334246575 | Passed |
| regression leap anniversary mapping 2 | 2.917808219 | 2.917808219 | Passed |
| partial repair probe 1 | 8.079452055 | 8.081967213 | Failed |
| partial repair probe 2 | 0.805479452 | 0.806010929 | Failed |
| boundary control 1 | 1.0 | 1.0 | Passed |
| normal control 1 | 5.010958904 | 5.010958904 | Passed |
| normal control 2 | 4.493150685 | 4.493150685 | Passed |
| normal control 3 | 5.523287671 | 5.523287671 | Passed |
SHA-256 / 4d186cde445586c3aa2f9cfcc2fd530681957b74e6ef3a844b8d0f4c86870024
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 leap anniversary mapping 1', [[2010, 10, 29], [2012, 2, 29]], 1.334246575], ['regression leap anniversary mapping 2', [[2005, 3, 30], [2008, 2, 29]], 2.917808219], ['partial repair probe 1', [[1996, 1, 30], [2004, 2, 29]], 8.081967213], ['partial repair probe 2', [[2003, 5, 10], [2004, 2, 29]], 0.806010929], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2069, 7, 30], [2074, 8, 3]], 5.010958904], ['normal control 2', [[2005, 4, 25], [2009, 10, 22]], 4.493150685], ['normal control 3', [[2020, 6, 30], [2026, 1, 7]], 5.523287671]], [['regression leap anniversary mapping 1', [[1998, 10, 13], [2004, 2, 29]], 5.378082192], ['regression leap anniversary mapping 2', [[1999, 2, 28], [2004, 2, 29]], 5.0], ['partial repair probe 1', [[2011, 3, 31], [2024, 2, 29]], 12.915300546], ['partial repair probe 2', [[2011, 7, 23], [2012, 2, 29]], 0.603825137], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2093, 8, 31], [2093, 10, 22]], 0.142465753], ['normal control 2', [[2069, 11, 30], [2073, 8, 25]], 3.734246575], ['normal control 3', [[2075, 1, 27], [2081, 10, 22]], 6.734246575]], [['regression leap anniversary mapping 1', [[2010, 8, 29], [2016, 2, 29]], 5.501369863], ['regression leap anniversary mapping 2', [[2013, 7, 23], [2016, 2, 29]], 2.602739726], ['partial repair probe 1', [[2003, 8, 6], [2008, 2, 29]], 4.56557377], ['partial repair probe 2', [[2003, 12, 4], [2004, 2, 29]], 0.237704918], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2084, 7, 30], [2092, 7, 14]], 7.956164384], ['normal control 2', [[2054, 8, 16], [2056, 3, 16]], 1.580821918], ['normal control 3', [[2062, 9, 23], [2066, 12, 16]], 4.230136986]], [['regression leap anniversary mapping 1', [[2029, 12, 24], [2032, 2, 29]], 2.180821918], ['regression leap anniversary mapping 2', [[2018, 4, 22], [2020, 2, 29]], 1.854794521], ['partial repair probe 1', [[2015, 3, 5], [2020, 2, 29]], 4.986338798], ['partial repair probe 2', [[2007, 7, 27], [2032, 2, 29]], 24.592896175], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2024, 4, 6], [2031, 2, 24]], 6.887671233], ['normal control 2', [[2033, 6, 29], [2040, 5, 23]], 6.898630137], ['normal control 3', [[2051, 1, 7], [2058, 2, 25]], 7.134246575]], [['regression leap anniversary mapping 1', [[2006, 11, 30], [2008, 2, 29]], 1.246575342], ['regression leap anniversary mapping 2', [[2004, 5, 31], [2020, 2, 29]], 15.747945205], ['partial repair probe 1', [[2023, 4, 11], [2028, 2, 29]], 4.885245902], ['partial repair probe 2', [[1999, 6, 29], [2020, 2, 29]], 20.669398907], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2087, 6, 12], [2090, 7, 1]], 3.052054795], ['normal control 2', [[2082, 4, 17], [2085, 1, 14]], 2.745205479], ['normal control 3', [[2067, 10, 30], [2069, 5, 28]], 1.576502732]]]
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 leap anniversary mapping 1 | 1.334246575 | 1.334246575 | Passed |
| regression leap anniversary mapping 2 | 2.917808219 | 2.917808219 | Passed |
| partial repair probe 1 | 8.081967213 | 8.081967213 | Passed |
| partial repair probe 2 | 0.806010929 | 0.806010929 | Passed |
| boundary control 1 | 1.0 | 1.0 | Passed |
| normal control 1 | 5.010958904 | 5.010958904 | Passed |
| normal control 2 | 4.493150685 | 4.493150685 | Passed |
| normal control 3 | 5.523287671 | 5.523287671 | Passed |
SHA-256 / 5caaa375fd773631549225adb4a0a6f1082dc8af65de5a9d035ce445ac19d051
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:53.967892+00:00.
Case digest / df08932c9da878a8cb097a90ead3c7884530b8f50e19ddf7244c464596413d64