FAILURE MAP
← Case archive

FA-60841 / Bond day-count conventions / Open access

30/360 US bond basis: end day 31 is clamped regardless of the start day · case 01

Periods ending on the 31st lose a day even when the start day is early in the month.

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

ROOT CAUSE

The D2 adjustment ignores the requirement that the adjusted D1 is already 30 or 31.

VERIFIED REPAIR

Clamp D2=31 to 30 only when the adjusted D1 is 30 or more.

Unsuccessful approach: Requiring D1 to be exactly 31 misses starts on the 30th and February-end starts promoted to 30.

Case contract

Inputs are two [year, month, day] dates. Apply, in order: if both dates are the last day of February, D2 becomes 30; if D1 is the last day of February, D1 becomes 30; if D2 is 31 and (adjusted) D1 is 30 or 31, D2 becomes 30; if D1 is 31, D1 becomes 30. Return 360*(Y2-Y1)+30*(M2-M1)+(D2-D1) as an integer day count.

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

N = 1
observations = []
def solve(a, b):
    y1, m1, d1 = a
    y2, m2, d2 = b
    def feb_end(y, m, d):
        leap = (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
        return m == 2 and d == (29 if leap else 28)
    e1 = feb_end(y1, m1, d1)
    e2 = feb_end(y2, m2, d2)
    if e1 and e2:
        d2 = 30
    if e1:
        d1 = 30
    if d2 == 31:
        d2 = 30
    if d1 == 31:
        d1 = 30
    return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression d2 thirty-one condition 1', [[2003, 3, 4], [2004, 7, 31]], 507], ['regression d2 thirty-one condition 2', [[2054, 5, 29], [2055, 7, 31]], 422], ['partial repair probe 1', [[2065, 12, 30], [2067, 5, 31]], 510], ['partial repair probe 2', [[2004, 2, 29], [2004, 1, 31]], -30], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 2, 29], [2025, 2, 28]], 360], ['normal control 1', [[2015, 9, 30], [2015, 11, 1]], 31], ['normal control 2', [[2016, 2, 28], [2016, 6, 23]], 115]], [['regression d2 thirty-one condition 1', [[2010, 12, 29], [2011, 12, 31]], 362], ['regression d2 thirty-one condition 2', [[2016, 2, 28], [2017, 3, 31]], 393], ['partial repair probe 1', [[2082, 11, 30], [2084, 3, 31]], 480], ['partial repair probe 2', [[2004, 2, 29], [2005, 5, 31]], 450], ['boundary control 1', [[2024, 3, 15], [2024, 9, 15]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2001, 11, 21], [2003, 11, 23]], 722], ['normal control 2', [[2032, 7, 29], [2033, 2, 28]], 209]], [['regression d2 thirty-one condition 1', [[2077, 11, 25], [2077, 12, 31]], 36], ['regression d2 thirty-one condition 2', [[2030, 1, 14], [2033, 7, 31]], 1277], ['partial repair probe 1', [[2074, 1, 30], [2077, 12, 31]], 1410], ['partial repair probe 2', [[2047, 6, 30], [2050, 1, 31]], 930], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[2007, 3, 31], [2009, 2, 28]], 688], ['normal control 2', [[2065, 5, 31], [2068, 7, 31]], 1140]], [['regression d2 thirty-one condition 1', [[2065, 12, 23], [2069, 1, 31]], 1118], ['regression d2 thirty-one condition 2', [[2058, 1, 18], [2060, 1, 31]], 733], ['partial repair probe 1', [[2016, 2, 29], [2018, 12, 31]], 1020], ['partial repair probe 2', [[2096, 2, 29], [2097, 12, 31]], 660], ['boundary control 1', [[2024, 2, 29], [2025, 2, 28]], 360], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[1999, 12, 31], [1999, 3, 31]], -270], ['normal control 2', [[2066, 7, 31], [2069, 12, 30]], 1230]], [['regression d2 thirty-one condition 1', [[2080, 3, 21], [2080, 10, 31]], 220], ['regression d2 thirty-one condition 2', [[2038, 8, 15], [2039, 10, 31]], 436], ['partial repair probe 1', [[2030, 11, 30], [2033, 8, 31]], 990], ['partial repair probe 2', [[2051, 9, 30], [2053, 5, 31]], 600], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2091, 11, 20], [2092, 2, 29]], 99], ['normal control 2', [[2000, 2, 28], [2002, 2, 9]], 701]]]
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 d2 thirty-one condition 1506507Failed
regression d2 thirty-one condition 2421422Failed
partial repair probe 1510510Passed
partial repair probe 2-30-30Passed
boundary control 16060Passed
boundary control 2360360Passed
normal control 13131Passed
normal control 2115115Passed

SHA-256 / 038c99700188bc86910da21fc772cd7d24fe3ffbe8cf3876ea2bf5f1e605aeac

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(a, b):
    y1, m1, d1 = a
    y2, m2, d2 = b
    def feb_end(y, m, d):
        leap = (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
        return m == 2 and d == (29 if leap else 28)
    e1 = feb_end(y1, m1, d1)
    e2 = feb_end(y2, m2, d2)
    if e1 and e2:
        d2 = 30
    if e1:
        d1 = 30
    if d2 == 31 and d1 == 31:
        d2 = 30
    if d1 == 31:
        d1 = 30
    return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression d2 thirty-one condition 1', [[2003, 3, 4], [2004, 7, 31]], 507], ['regression d2 thirty-one condition 2', [[2054, 5, 29], [2055, 7, 31]], 422], ['partial repair probe 1', [[2065, 12, 30], [2067, 5, 31]], 510], ['partial repair probe 2', [[2004, 2, 29], [2004, 1, 31]], -30], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 2, 29], [2025, 2, 28]], 360], ['normal control 1', [[2015, 9, 30], [2015, 11, 1]], 31], ['normal control 2', [[2016, 2, 28], [2016, 6, 23]], 115]], [['regression d2 thirty-one condition 1', [[2010, 12, 29], [2011, 12, 31]], 362], ['regression d2 thirty-one condition 2', [[2016, 2, 28], [2017, 3, 31]], 393], ['partial repair probe 1', [[2082, 11, 30], [2084, 3, 31]], 480], ['partial repair probe 2', [[2004, 2, 29], [2005, 5, 31]], 450], ['boundary control 1', [[2024, 3, 15], [2024, 9, 15]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2001, 11, 21], [2003, 11, 23]], 722], ['normal control 2', [[2032, 7, 29], [2033, 2, 28]], 209]], [['regression d2 thirty-one condition 1', [[2077, 11, 25], [2077, 12, 31]], 36], ['regression d2 thirty-one condition 2', [[2030, 1, 14], [2033, 7, 31]], 1277], ['partial repair probe 1', [[2074, 1, 30], [2077, 12, 31]], 1410], ['partial repair probe 2', [[2047, 6, 30], [2050, 1, 31]], 930], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[2007, 3, 31], [2009, 2, 28]], 688], ['normal control 2', [[2065, 5, 31], [2068, 7, 31]], 1140]], [['regression d2 thirty-one condition 1', [[2065, 12, 23], [2069, 1, 31]], 1118], ['regression d2 thirty-one condition 2', [[2058, 1, 18], [2060, 1, 31]], 733], ['partial repair probe 1', [[2016, 2, 29], [2018, 12, 31]], 1020], ['partial repair probe 2', [[2096, 2, 29], [2097, 12, 31]], 660], ['boundary control 1', [[2024, 2, 29], [2025, 2, 28]], 360], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[1999, 12, 31], [1999, 3, 31]], -270], ['normal control 2', [[2066, 7, 31], [2069, 12, 30]], 1230]], [['regression d2 thirty-one condition 1', [[2080, 3, 21], [2080, 10, 31]], 220], ['regression d2 thirty-one condition 2', [[2038, 8, 15], [2039, 10, 31]], 436], ['partial repair probe 1', [[2030, 11, 30], [2033, 8, 31]], 990], ['partial repair probe 2', [[2051, 9, 30], [2053, 5, 31]], 600], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2091, 11, 20], [2092, 2, 29]], 99], ['normal control 2', [[2000, 2, 28], [2002, 2, 9]], 701]]]
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 d2 thirty-one condition 1507507Passed
regression d2 thirty-one condition 2422422Passed
partial repair probe 1511510Failed
partial repair probe 2-29-30Failed
boundary control 16060Passed
boundary control 2360360Passed
normal control 13131Passed
normal control 2115115Passed

SHA-256 / 682399de404af764cbe5ce54bc10b656f50a133180755fbc73d3388b3610c735

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(a, b):
    y1, m1, d1 = a
    y2, m2, d2 = b
    def feb_end(y, m, d):
        leap = (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
        return m == 2 and d == (29 if leap else 28)
    e1 = feb_end(y1, m1, d1)
    e2 = feb_end(y2, m2, d2)
    if e1 and e2:
        d2 = 30
    if e1:
        d1 = 30
    if d2 == 31 and d1 >= 30:
        d2 = 30
    if d1 == 31:
        d1 = 30
    return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression d2 thirty-one condition 1', [[2003, 3, 4], [2004, 7, 31]], 507], ['regression d2 thirty-one condition 2', [[2054, 5, 29], [2055, 7, 31]], 422], ['partial repair probe 1', [[2065, 12, 30], [2067, 5, 31]], 510], ['partial repair probe 2', [[2004, 2, 29], [2004, 1, 31]], -30], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 2, 29], [2025, 2, 28]], 360], ['normal control 1', [[2015, 9, 30], [2015, 11, 1]], 31], ['normal control 2', [[2016, 2, 28], [2016, 6, 23]], 115]], [['regression d2 thirty-one condition 1', [[2010, 12, 29], [2011, 12, 31]], 362], ['regression d2 thirty-one condition 2', [[2016, 2, 28], [2017, 3, 31]], 393], ['partial repair probe 1', [[2082, 11, 30], [2084, 3, 31]], 480], ['partial repair probe 2', [[2004, 2, 29], [2005, 5, 31]], 450], ['boundary control 1', [[2024, 3, 15], [2024, 9, 15]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2001, 11, 21], [2003, 11, 23]], 722], ['normal control 2', [[2032, 7, 29], [2033, 2, 28]], 209]], [['regression d2 thirty-one condition 1', [[2077, 11, 25], [2077, 12, 31]], 36], ['regression d2 thirty-one condition 2', [[2030, 1, 14], [2033, 7, 31]], 1277], ['partial repair probe 1', [[2074, 1, 30], [2077, 12, 31]], 1410], ['partial repair probe 2', [[2047, 6, 30], [2050, 1, 31]], 930], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[2007, 3, 31], [2009, 2, 28]], 688], ['normal control 2', [[2065, 5, 31], [2068, 7, 31]], 1140]], [['regression d2 thirty-one condition 1', [[2065, 12, 23], [2069, 1, 31]], 1118], ['regression d2 thirty-one condition 2', [[2058, 1, 18], [2060, 1, 31]], 733], ['partial repair probe 1', [[2016, 2, 29], [2018, 12, 31]], 1020], ['partial repair probe 2', [[2096, 2, 29], [2097, 12, 31]], 660], ['boundary control 1', [[2024, 2, 29], [2025, 2, 28]], 360], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[1999, 12, 31], [1999, 3, 31]], -270], ['normal control 2', [[2066, 7, 31], [2069, 12, 30]], 1230]], [['regression d2 thirty-one condition 1', [[2080, 3, 21], [2080, 10, 31]], 220], ['regression d2 thirty-one condition 2', [[2038, 8, 15], [2039, 10, 31]], 436], ['partial repair probe 1', [[2030, 11, 30], [2033, 8, 31]], 990], ['partial repair probe 2', [[2051, 9, 30], [2053, 5, 31]], 600], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2091, 11, 20], [2092, 2, 29]], 99], ['normal control 2', [[2000, 2, 28], [2002, 2, 9]], 701]]]
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 d2 thirty-one condition 1507507Passed
regression d2 thirty-one condition 2422422Passed
partial repair probe 1510510Passed
partial repair probe 2-30-30Passed
boundary control 16060Passed
boundary control 2360360Passed
normal control 13131Passed
normal control 2115115Passed

SHA-256 / e4cd8e2503f5ba540372c8d6ce8b355c4df922ba26749651146e0cfe7032c3db

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:49.333181+00:00.

Case digest / da02453ca76cb9b9ddd8b55274166d66836219b84f0ffd82c743ab8971705f09