FAILURE MAP
← Case archive

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.

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

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 fixtureActualExpectedOutcome
regression stub leap window 13.0355191263.035616438Failed
regression stub leap window 28.0300546458.030136986Failed
partial repair probe 13.2547945213.254794521Passed
partial repair probe 20.2301369860.230136986Passed
boundary control 14.997267764.99726776Passed
boundary control 21.01.0Passed
normal control 13.7459016393.745901639Passed
normal control 20.227397260.22739726Passed

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 fixtureActualExpectedOutcome
regression stub leap window 13.0356164383.035616438Passed
regression stub leap window 28.0301369868.030136986Passed
partial repair probe 13.2540983613.254794521Failed
partial repair probe 20.2295081970.230136986Failed
boundary control 14.997267764.99726776Passed
boundary control 21.01.0Passed
normal control 13.7459016393.745901639Passed
normal control 20.227397260.22739726Passed

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 fixtureActualExpectedOutcome
regression stub leap window 13.0356164383.035616438Passed
regression stub leap window 28.0301369868.030136986Passed
partial repair probe 13.2547945213.254794521Passed
partial repair probe 20.2301369860.230136986Passed
boundary control 14.997267764.99726776Passed
boundary control 21.01.0Passed
normal control 13.7459016393.745901639Passed
normal control 20.227397260.22739726Passed

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