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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression end day rollover 1 | 419 | 420 | Failed |
| regression end day rollover 2 | 421 | 422 | Failed |
| partial repair probe 1 | 720 | 721 | Failed |
| partial repair probe 2 | 733 | 734 | Failed |
| boundary control 1 | 31 | 31 | Passed |
| normal control 1 | 463 | 463 | Passed |
| normal control 2 | 671 | 671 | Passed |
| normal control 3 | 432 | 432 | Passed |
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression end day rollover 1 | 390 | 420 | Failed |
| regression end day rollover 2 | 392 | 422 | Failed |
| partial repair probe 1 | 691 | 721 | Failed |
| partial repair probe 2 | 704 | 734 | Failed |
| boundary control 1 | 31 | 31 | Passed |
| normal control 1 | 463 | 463 | Passed |
| normal control 2 | 671 | 671 | Passed |
| normal control 3 | 432 | 432 | Passed |
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression end day rollover 1 | 420 | 420 | Passed |
| regression end day rollover 2 | 422 | 422 | Passed |
| partial repair probe 1 | 721 | 721 | Passed |
| partial repair probe 2 | 734 | 734 | Passed |
| boundary control 1 | 31 | 31 | Passed |
| normal control 1 | 463 | 463 | Passed |
| normal control 2 | 671 | 671 | Passed |
| normal control 3 | 432 | 432 | Passed |
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