FAILURE MAP
← Case archive

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

30E+/360 end-of-month rollover: a start on the 31st is also rolled to the next month · case 01

Periods starting on the 31st are one day short.

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

ROOT CAUSE

The rollover rule is applied symmetrically to D1.

VERIFIED REPAIR

Clamp D1=31 to 30; only D2 rolls forward.

Unsuccessful approach: Clamping D1 only when the original end day is also 31 misses most periods.

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 = 1
        m1 += 1
    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 start day treatment 1', [[2024, 12, 31], [2026, 3, 22]], 442], ['regression start day treatment 2', [[2042, 7, 31], [2042, 8, 31]], 31], ['partial repair probe 1', [[2042, 3, 31], [2042, 8, 5]], 125], ['partial repair probe 2', [[2023, 1, 31], [2024, 2, 29]], 389], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2030, 7, 9], [2031, 9, 20]], 431], ['normal control 2', [[2031, 10, 27], [2032, 6, 3]], 216]], [['regression start day treatment 1', [[2015, 1, 31], [2016, 8, 31]], 571], ['regression start day treatment 2', [[2022, 8, 31], [2022, 9, 30]], 30], ['partial repair probe 1', [[2028, 10, 31], [2030, 1, 13]], 433], ['partial repair probe 2', [[2030, 8, 31], [2031, 3, 13]], 193], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2027, 9, 27], [2029, 4, 30]], 573], ['normal control 2', [[2039, 11, 30], [2041, 12, 28]], 748]], [['regression start day treatment 1', [[2054, 7, 31], [2056, 1, 31]], 541], ['regression start day treatment 2', [[2007, 1, 31], [2008, 12, 31]], 691], ['partial repair probe 1', [[2017, 8, 31], [2019, 11, 2]], 782], ['partial repair probe 2', [[2028, 1, 31], [2030, 6, 30]], 870], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2000, 9, 30], [2002, 8, 1]], 661], ['normal control 2', [[2012, 1, 28], [2014, 11, 30]], 1022]], [['regression start day treatment 1', [[2059, 8, 31], [2059, 9, 29]], 29], ['regression start day treatment 2', [[2000, 10, 31], [2002, 3, 31]], 511], ['partial repair probe 1', [[2017, 12, 31], [2018, 1, 10]], 10], ['partial repair probe 2', [[2046, 12, 31], [2047, 12, 17]], 347], ['boundary control 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['boundary control 2', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2042, 6, 30], [2043, 2, 7]], 217], ['normal control 2', [[2006, 5, 21], [2008, 1, 31]], 610]], [['regression start day treatment 1', [[2013, 7, 31], [2014, 12, 27]], 507], ['regression start day treatment 2', [[2004, 8, 31], [2006, 9, 1]], 721], ['partial repair probe 1', [[2047, 7, 31], [2049, 11, 23]], 833], ['partial repair probe 2', [[2023, 7, 31], [2025, 12, 19]], 859], ['boundary control 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['boundary control 2', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2043, 3, 30], [2043, 9, 7]], 157], ['normal control 2', [[2055, 4, 30], [2057, 10, 1]], 871]]]
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 start day treatment 1441442Failed
regression start day treatment 23031Failed
partial repair probe 1124125Failed
partial repair probe 2388389Failed
boundary control 13131Passed
boundary control 21616Passed
normal control 1431431Passed
normal control 2216216Passed

SHA-256 / bf9e6b2dae8efbc75d3be26fd4681b6e1288c9e5afabbd856689cf0d9bbdf6cf

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 and b[2] == 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 start day treatment 1', [[2024, 12, 31], [2026, 3, 22]], 442], ['regression start day treatment 2', [[2042, 7, 31], [2042, 8, 31]], 31], ['partial repair probe 1', [[2042, 3, 31], [2042, 8, 5]], 125], ['partial repair probe 2', [[2023, 1, 31], [2024, 2, 29]], 389], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2030, 7, 9], [2031, 9, 20]], 431], ['normal control 2', [[2031, 10, 27], [2032, 6, 3]], 216]], [['regression start day treatment 1', [[2015, 1, 31], [2016, 8, 31]], 571], ['regression start day treatment 2', [[2022, 8, 31], [2022, 9, 30]], 30], ['partial repair probe 1', [[2028, 10, 31], [2030, 1, 13]], 433], ['partial repair probe 2', [[2030, 8, 31], [2031, 3, 13]], 193], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2027, 9, 27], [2029, 4, 30]], 573], ['normal control 2', [[2039, 11, 30], [2041, 12, 28]], 748]], [['regression start day treatment 1', [[2054, 7, 31], [2056, 1, 31]], 541], ['regression start day treatment 2', [[2007, 1, 31], [2008, 12, 31]], 691], ['partial repair probe 1', [[2017, 8, 31], [2019, 11, 2]], 782], ['partial repair probe 2', [[2028, 1, 31], [2030, 6, 30]], 870], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2000, 9, 30], [2002, 8, 1]], 661], ['normal control 2', [[2012, 1, 28], [2014, 11, 30]], 1022]], [['regression start day treatment 1', [[2059, 8, 31], [2059, 9, 29]], 29], ['regression start day treatment 2', [[2000, 10, 31], [2002, 3, 31]], 511], ['partial repair probe 1', [[2017, 12, 31], [2018, 1, 10]], 10], ['partial repair probe 2', [[2046, 12, 31], [2047, 12, 17]], 347], ['boundary control 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['boundary control 2', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2042, 6, 30], [2043, 2, 7]], 217], ['normal control 2', [[2006, 5, 21], [2008, 1, 31]], 610]], [['regression start day treatment 1', [[2013, 7, 31], [2014, 12, 27]], 507], ['regression start day treatment 2', [[2004, 8, 31], [2006, 9, 1]], 721], ['partial repair probe 1', [[2047, 7, 31], [2049, 11, 23]], 833], ['partial repair probe 2', [[2023, 7, 31], [2025, 12, 19]], 859], ['boundary control 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['boundary control 2', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2043, 3, 30], [2043, 9, 7]], 157], ['normal control 2', [[2055, 4, 30], [2057, 10, 1]], 871]]]
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 start day treatment 1441442Failed
regression start day treatment 23131Passed
partial repair probe 1124125Failed
partial repair probe 2388389Failed
boundary control 13131Passed
boundary control 21616Passed
normal control 1431431Passed
normal control 2216216Passed

SHA-256 / af60ea8dac34c41337364240c4609bc39945e4319e50ed0e785c1ccaa6ac887c

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 start day treatment 1', [[2024, 12, 31], [2026, 3, 22]], 442], ['regression start day treatment 2', [[2042, 7, 31], [2042, 8, 31]], 31], ['partial repair probe 1', [[2042, 3, 31], [2042, 8, 5]], 125], ['partial repair probe 2', [[2023, 1, 31], [2024, 2, 29]], 389], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2030, 7, 9], [2031, 9, 20]], 431], ['normal control 2', [[2031, 10, 27], [2032, 6, 3]], 216]], [['regression start day treatment 1', [[2015, 1, 31], [2016, 8, 31]], 571], ['regression start day treatment 2', [[2022, 8, 31], [2022, 9, 30]], 30], ['partial repair probe 1', [[2028, 10, 31], [2030, 1, 13]], 433], ['partial repair probe 2', [[2030, 8, 31], [2031, 3, 13]], 193], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2027, 9, 27], [2029, 4, 30]], 573], ['normal control 2', [[2039, 11, 30], [2041, 12, 28]], 748]], [['regression start day treatment 1', [[2054, 7, 31], [2056, 1, 31]], 541], ['regression start day treatment 2', [[2007, 1, 31], [2008, 12, 31]], 691], ['partial repair probe 1', [[2017, 8, 31], [2019, 11, 2]], 782], ['partial repair probe 2', [[2028, 1, 31], [2030, 6, 30]], 870], ['boundary control 1', [[2024, 2, 29], [2024, 3, 30]], 31], ['boundary control 2', [[2024, 1, 15], [2024, 1, 31]], 16], ['normal control 1', [[2000, 9, 30], [2002, 8, 1]], 661], ['normal control 2', [[2012, 1, 28], [2014, 11, 30]], 1022]], [['regression start day treatment 1', [[2059, 8, 31], [2059, 9, 29]], 29], ['regression start day treatment 2', [[2000, 10, 31], [2002, 3, 31]], 511], ['partial repair probe 1', [[2017, 12, 31], [2018, 1, 10]], 10], ['partial repair probe 2', [[2046, 12, 31], [2047, 12, 17]], 347], ['boundary control 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['boundary control 2', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2042, 6, 30], [2043, 2, 7]], 217], ['normal control 2', [[2006, 5, 21], [2008, 1, 31]], 610]], [['regression start day treatment 1', [[2013, 7, 31], [2014, 12, 27]], 507], ['regression start day treatment 2', [[2004, 8, 31], [2006, 9, 1]], 721], ['partial repair probe 1', [[2047, 7, 31], [2049, 11, 23]], 833], ['partial repair probe 2', [[2023, 7, 31], [2025, 12, 19]], 859], ['boundary control 1', [[2024, 1, 15], [2024, 1, 31]], 16], ['boundary control 2', [[2024, 2, 29], [2024, 3, 30]], 31], ['normal control 1', [[2043, 3, 30], [2043, 9, 7]], 157], ['normal control 2', [[2055, 4, 30], [2057, 10, 1]], 871]]]
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 start day treatment 1442442Passed
regression start day treatment 23131Passed
partial repair probe 1125125Passed
partial repair probe 2389389Passed
boundary control 13131Passed
boundary control 21616Passed
normal control 1431431Passed
normal control 2216216Passed

SHA-256 / 782f8753ee8b8bb67ac7f403110458fc6c7cddb7cf04644f4b68441ae214088f

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

Case digest / e562c6efee5b6f5963a0d896c1680b80d82b865033aeaa0a91239f5552b24b39