FAILURE MAP
← Case archive

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

30E+/360 end-of-month rollover: an end on the 31st is clamped to 30 like 30E/360 · case 01

Periods ending on the 31st are one day short.

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

ROOT CAUSE

The end-day rule was copied from 30E/360 and clamps to 30 instead of rolling to the 1st of the next month.

VERIFIED REPAIR

Map D2=31 to day 1 of the following month.

Unsuccessful approach: Setting the day to 1 without advancing the month loses a whole month.

Case contract

Inputs two dates [y,m,d]. If D1 is 31 it becomes 30. If D2 is 31 it becomes 1 and M2 increases by one (the formula absorbs a month 13). Return 360*(Y2-Y1)+30*(M2-M1)+(D2-D1).

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
    if d1 == 31:
        d1 = 30
    if d2 == 31:
        d2 = 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 end day rollover 1', [[2033, 11, 1], [2034, 12, 31]], 420], ['regression end day rollover 2', [[2040, 10, 29], [2041, 12, 31]], 422], ['partial repair probe 1', [[2027, 5, 31], [2029, 5, 31]], 721], ['partial repair probe 2', [[2045, 10, 17], [2047, 10, 31]], 734], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2026, 2, 28], [2027, 6, 11]], 463], ['normal control 2', [[2052, 7, 31], [2054, 6, 11]], 671], ['normal control 3', [[2046, 9, 30], [2047, 12, 12]], 432]], [['regression end day rollover 1', [[2019, 2, 22], [2021, 10, 31]], 969], ['regression end day rollover 2', [[2033, 3, 31], [2033, 12, 31]], 271], ['partial repair probe 1', [[2034, 6, 30], [2036, 3, 31]], 631], ['partial repair probe 2', [[2042, 3, 31], [2043, 7, 31]], 481], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2046, 8, 29], [2048, 12, 9]], 820], ['normal control 2', [[2054, 6, 1], [2056, 11, 1]], 870], ['normal control 3', [[2013, 1, 30], [2013, 9, 27]], 237]], [['regression end day rollover 1', [[2002, 6, 30], [2003, 12, 31]], 541], ['regression end day rollover 2', [[2049, 11, 14], [2050, 8, 31]], 287], ['partial repair probe 1', [[2005, 10, 1], [2008, 5, 31]], 960], ['partial repair probe 2', [[2026, 4, 18], [2027, 5, 31]], 403], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2001, 1, 1], [2003, 6, 30]], 899], ['normal control 2', [[2021, 9, 28], [2021, 4, 30]], -148], ['normal control 3', [[2044, 4, 30], [2046, 8, 29]], 839]], [['regression end day rollover 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['regression end day rollover 2', [[2006, 3, 18], [2006, 7, 31]], 133], ['partial repair probe 1', [[2038, 3, 31], [2039, 12, 31]], 631], ['partial repair probe 2', [[2049, 4, 30], [2051, 5, 31]], 751], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2029, 1, 1], [2030, 6, 22]], 531], ['normal control 2', [[2053, 3, 31], [2054, 2, 28]], 328], ['normal control 3', [[2026, 1, 13], [2027, 6, 2]], 499]], [['regression end day rollover 1', [[2003, 6, 30], [2003, 1, 31]], -149], ['regression end day rollover 2', [[2048, 9, 30], [2049, 3, 31]], 181], ['partial repair probe 1', [[2033, 1, 19], [2033, 1, 31]], 12], ['partial repair probe 2', [[2036, 1, 31], [2037, 3, 31]], 421], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2052, 1, 3], [2052, 11, 28]], 325], ['normal control 2', [[2012, 7, 31], [2013, 9, 30]], 420], ['normal control 3', [[2015, 2, 28], [2015, 9, 30]], 212]]]
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 end day rollover 1419420Failed
regression end day rollover 2421422Failed
partial repair probe 1720721Failed
partial repair probe 2733734Failed
boundary control 13131Passed
normal control 1463463Passed
normal control 2671671Passed
normal control 3432432Passed

SHA-256 / 87bbe782a7c24a462a3a0b39996d155171255564a07e8509ed9b10c989b29716

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
    if d1 == 31:
        d1 = 30
    if d2 == 31:
        d2 = 1
    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 end day rollover 1', [[2033, 11, 1], [2034, 12, 31]], 420], ['regression end day rollover 2', [[2040, 10, 29], [2041, 12, 31]], 422], ['partial repair probe 1', [[2027, 5, 31], [2029, 5, 31]], 721], ['partial repair probe 2', [[2045, 10, 17], [2047, 10, 31]], 734], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2026, 2, 28], [2027, 6, 11]], 463], ['normal control 2', [[2052, 7, 31], [2054, 6, 11]], 671], ['normal control 3', [[2046, 9, 30], [2047, 12, 12]], 432]], [['regression end day rollover 1', [[2019, 2, 22], [2021, 10, 31]], 969], ['regression end day rollover 2', [[2033, 3, 31], [2033, 12, 31]], 271], ['partial repair probe 1', [[2034, 6, 30], [2036, 3, 31]], 631], ['partial repair probe 2', [[2042, 3, 31], [2043, 7, 31]], 481], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2046, 8, 29], [2048, 12, 9]], 820], ['normal control 2', [[2054, 6, 1], [2056, 11, 1]], 870], ['normal control 3', [[2013, 1, 30], [2013, 9, 27]], 237]], [['regression end day rollover 1', [[2002, 6, 30], [2003, 12, 31]], 541], ['regression end day rollover 2', [[2049, 11, 14], [2050, 8, 31]], 287], ['partial repair probe 1', [[2005, 10, 1], [2008, 5, 31]], 960], ['partial repair probe 2', [[2026, 4, 18], [2027, 5, 31]], 403], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2001, 1, 1], [2003, 6, 30]], 899], ['normal control 2', [[2021, 9, 28], [2021, 4, 30]], -148], ['normal control 3', [[2044, 4, 30], [2046, 8, 29]], 839]], [['regression end day rollover 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['regression end day rollover 2', [[2006, 3, 18], [2006, 7, 31]], 133], ['partial repair probe 1', [[2038, 3, 31], [2039, 12, 31]], 631], ['partial repair probe 2', [[2049, 4, 30], [2051, 5, 31]], 751], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2029, 1, 1], [2030, 6, 22]], 531], ['normal control 2', [[2053, 3, 31], [2054, 2, 28]], 328], ['normal control 3', [[2026, 1, 13], [2027, 6, 2]], 499]], [['regression end day rollover 1', [[2003, 6, 30], [2003, 1, 31]], -149], ['regression end day rollover 2', [[2048, 9, 30], [2049, 3, 31]], 181], ['partial repair probe 1', [[2033, 1, 19], [2033, 1, 31]], 12], ['partial repair probe 2', [[2036, 1, 31], [2037, 3, 31]], 421], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2052, 1, 3], [2052, 11, 28]], 325], ['normal control 2', [[2012, 7, 31], [2013, 9, 30]], 420], ['normal control 3', [[2015, 2, 28], [2015, 9, 30]], 212]]]
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 end day rollover 1390420Failed
regression end day rollover 2392422Failed
partial repair probe 1691721Failed
partial repair probe 2704734Failed
boundary control 13131Passed
normal control 1463463Passed
normal control 2671671Passed
normal control 3432432Passed

SHA-256 / cefa6fae81888f8defbf3e552fa3d3b6e1e529c9459c450d1115eaf62b26b94c

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
    if d1 == 31:
        d1 = 30
    if d2 == 31:
        d2 = 1
        m2 += 1
    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 end day rollover 1', [[2033, 11, 1], [2034, 12, 31]], 420], ['regression end day rollover 2', [[2040, 10, 29], [2041, 12, 31]], 422], ['partial repair probe 1', [[2027, 5, 31], [2029, 5, 31]], 721], ['partial repair probe 2', [[2045, 10, 17], [2047, 10, 31]], 734], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2026, 2, 28], [2027, 6, 11]], 463], ['normal control 2', [[2052, 7, 31], [2054, 6, 11]], 671], ['normal control 3', [[2046, 9, 30], [2047, 12, 12]], 432]], [['regression end day rollover 1', [[2019, 2, 22], [2021, 10, 31]], 969], ['regression end day rollover 2', [[2033, 3, 31], [2033, 12, 31]], 271], ['partial repair probe 1', [[2034, 6, 30], [2036, 3, 31]], 631], ['partial repair probe 2', [[2042, 3, 31], [2043, 7, 31]], 481], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2046, 8, 29], [2048, 12, 9]], 820], ['normal control 2', [[2054, 6, 1], [2056, 11, 1]], 870], ['normal control 3', [[2013, 1, 30], [2013, 9, 27]], 237]], [['regression end day rollover 1', [[2002, 6, 30], [2003, 12, 31]], 541], ['regression end day rollover 2', [[2049, 11, 14], [2050, 8, 31]], 287], ['partial repair probe 1', [[2005, 10, 1], [2008, 5, 31]], 960], ['partial repair probe 2', [[2026, 4, 18], [2027, 5, 31]], 403], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2001, 1, 1], [2003, 6, 30]], 899], ['normal control 2', [[2021, 9, 28], [2021, 4, 30]], -148], ['normal control 3', [[2044, 4, 30], [2046, 8, 29]], 839]], [['regression end day rollover 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['regression end day rollover 2', [[2006, 3, 18], [2006, 7, 31]], 133], ['partial repair probe 1', [[2038, 3, 31], [2039, 12, 31]], 631], ['partial repair probe 2', [[2049, 4, 30], [2051, 5, 31]], 751], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2029, 1, 1], [2030, 6, 22]], 531], ['normal control 2', [[2053, 3, 31], [2054, 2, 28]], 328], ['normal control 3', [[2026, 1, 13], [2027, 6, 2]], 499]], [['regression end day rollover 1', [[2003, 6, 30], [2003, 1, 31]], -149], ['regression end day rollover 2', [[2048, 9, 30], [2049, 3, 31]], 181], ['partial repair probe 1', [[2033, 1, 19], [2033, 1, 31]], 12], ['partial repair probe 2', [[2036, 1, 31], [2037, 3, 31]], 421], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2052, 1, 3], [2052, 11, 28]], 325], ['normal control 2', [[2012, 7, 31], [2013, 9, 30]], 420], ['normal control 3', [[2015, 2, 28], [2015, 9, 30]], 212]]]
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 end day rollover 1420420Passed
regression end day rollover 2422422Passed
partial repair probe 1721721Passed
partial repair probe 2734734Passed
boundary control 13131Passed
normal control 1463463Passed
normal control 2671671Passed
normal control 3432432Passed

SHA-256 / cb3ae5d7ecf89ce0995e21911d9fe7925e3b4fdfd9e3b26f4ada70fe6f0581bc

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

Case digest / 635a57d2264af4538cb4b40ee792baca510af427cf6d02e65f41bbbdffd6427b