FAILURE MAP
← Case archive

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.

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

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 fixtureActualExpectedOutcome
regression leap anniversary mapping 11.3369863011.334246575Failed
regression leap anniversary mapping 22.9205479452.917808219Failed
partial repair probe 18.0819672138.081967213Passed
partial repair probe 20.8060109290.806010929Passed
boundary control 11.01.0Passed
normal control 15.0109589045.010958904Passed
normal control 24.4931506854.493150685Passed
normal control 35.5232876715.523287671Passed

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 fixtureActualExpectedOutcome
regression leap anniversary mapping 11.3342465751.334246575Passed
regression leap anniversary mapping 22.9178082192.917808219Passed
partial repair probe 18.0794520558.081967213Failed
partial repair probe 20.8054794520.806010929Failed
boundary control 11.01.0Passed
normal control 15.0109589045.010958904Passed
normal control 24.4931506854.493150685Passed
normal control 35.5232876715.523287671Passed

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 fixtureActualExpectedOutcome
regression leap anniversary mapping 11.3342465751.334246575Passed
regression leap anniversary mapping 22.9178082192.917808219Passed
partial repair probe 18.0819672138.081967213Passed
partial repair probe 20.8060109290.806010929Passed
boundary control 11.01.0Passed
normal control 15.0109589045.010958904Passed
normal control 24.4931506854.493150685Passed
normal control 35.5232876715.523287671Passed

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