FA-60846 / Bond day-count conventions / Open access
30/360 US bond basis: the 28th of a leap February counts as month end · case 01
Accruals starting on 28 February of a leap year are extended as if the month had ended.
ROOT CAUSE
The February-end test compares the day with 28 without consulting the leap-year rule.
VERIFIED REPAIR
Compare against 29 in leap years and 28 otherwise.
Unsuccessful approach: Accepting any day of at least 28 still treats 28 February in a leap year as month end.
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 == 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 february end detection 1', [[2096, 2, 28], [2097, 1, 29]], 331], ['regression february end detection 2', [[2015, 2, 28], [2016, 2, 29]], 360], ['partial repair probe 1', [[2024, 2, 28], [2025, 1, 5]], 307], ['partial repair probe 2', [[2004, 2, 28], [2005, 3, 31]], 393], ['boundary control 1', [[2024, 3, 15], [2024, 9, 15]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2018, 4, 30], [2021, 5, 31]], 1110], ['normal control 2', [[2049, 1, 31], [2052, 2, 29]], 1109]], [['regression february end detection 1', [[2000, 2, 29], [2002, 2, 28]], 720], ['regression february end detection 2', [[2024, 2, 29], [2027, 2, 28]], 1080], ['partial repair probe 1', [[2004, 2, 28], [2005, 12, 17]], 649], ['partial repair probe 2', [[2008, 2, 28], [2011, 4, 25]], 1137], ['boundary control 1', [[2023, 2, 28], [2023, 8, 31]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2047, 7, 31], [2050, 2, 28]], 928], ['normal control 2', [[2057, 2, 28], [2059, 5, 6]], 786]], [['regression february end detection 1', [[2000, 2, 29], [2000, 5, 30]], 90], ['regression february end detection 2', [[2000, 2, 28], [2003, 4, 30]], 1142], ['partial repair probe 1', [[2096, 2, 28], [2098, 1, 31]], 693], ['partial repair probe 2', [[2024, 2, 28], [2024, 11, 13]], 255], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2023, 5, 30], [2023, 7, 31]], 60], ['normal control 1', [[2089, 6, 30], [2091, 2, 28]], 598], ['normal control 2', [[2011, 6, 30], [2013, 7, 14]], 734]], [['regression february end detection 1', [[2096, 2, 28], [2098, 6, 1]], 813], ['regression february end detection 2', [[2016, 2, 28], [2016, 11, 30]], 272], ['partial repair probe 1', [[2000, 2, 28], [2001, 5, 31]], 453], ['partial repair probe 2', [[2024, 2, 28], [2027, 5, 1]], 1143], ['boundary control 1', [[2023, 5, 30], [2023, 7, 31]], 60], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[2062, 11, 30], [2064, 3, 26]], 476], ['normal control 2', [[2060, 11, 30], [2062, 12, 30]], 750]], [['regression february end detection 1', [[2096, 2, 28], [2096, 10, 31]], 243], ['regression february end detection 2', [[2004, 2, 29], [2006, 5, 30]], 810], ['partial repair probe 1', [[2096, 2, 28], [2097, 1, 8]], 310], ['partial repair probe 2', [[2004, 2, 28], [2005, 5, 31]], 453], ['boundary control 1', [[2023, 5, 30], [2023, 7, 31]], 60], ['boundary control 2', [[2023, 2, 28], [2023, 8, 31]], 180], ['normal control 1', [[2053, 1, 28], [2055, 2, 28]], 750], ['normal control 2', [[2011, 10, 20], [2012, 6, 19]], 239]]]
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 february end detection 1 | 329 | 331 | Failed |
| regression february end detection 2 | 359 | 360 | Failed |
| partial repair probe 1 | 305 | 307 | Failed |
| partial repair probe 2 | 390 | 393 | Failed |
| boundary control 1 | 180 | 180 | Passed |
| boundary control 2 | 0 | 0 | Passed |
| normal control 1 | 1110 | 1110 | Passed |
| normal control 2 | 1109 | 1109 | Passed |
SHA-256 / 1a9f43c38e4b30e180dafae4f984e31bff2db3bb4b9e708fd05a5da54112ca38
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 >= 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 february end detection 1', [[2096, 2, 28], [2097, 1, 29]], 331], ['regression february end detection 2', [[2015, 2, 28], [2016, 2, 29]], 360], ['partial repair probe 1', [[2024, 2, 28], [2025, 1, 5]], 307], ['partial repair probe 2', [[2004, 2, 28], [2005, 3, 31]], 393], ['boundary control 1', [[2024, 3, 15], [2024, 9, 15]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2018, 4, 30], [2021, 5, 31]], 1110], ['normal control 2', [[2049, 1, 31], [2052, 2, 29]], 1109]], [['regression february end detection 1', [[2000, 2, 29], [2002, 2, 28]], 720], ['regression february end detection 2', [[2024, 2, 29], [2027, 2, 28]], 1080], ['partial repair probe 1', [[2004, 2, 28], [2005, 12, 17]], 649], ['partial repair probe 2', [[2008, 2, 28], [2011, 4, 25]], 1137], ['boundary control 1', [[2023, 2, 28], [2023, 8, 31]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2047, 7, 31], [2050, 2, 28]], 928], ['normal control 2', [[2057, 2, 28], [2059, 5, 6]], 786]], [['regression february end detection 1', [[2000, 2, 29], [2000, 5, 30]], 90], ['regression february end detection 2', [[2000, 2, 28], [2003, 4, 30]], 1142], ['partial repair probe 1', [[2096, 2, 28], [2098, 1, 31]], 693], ['partial repair probe 2', [[2024, 2, 28], [2024, 11, 13]], 255], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2023, 5, 30], [2023, 7, 31]], 60], ['normal control 1', [[2089, 6, 30], [2091, 2, 28]], 598], ['normal control 2', [[2011, 6, 30], [2013, 7, 14]], 734]], [['regression february end detection 1', [[2096, 2, 28], [2098, 6, 1]], 813], ['regression february end detection 2', [[2016, 2, 28], [2016, 11, 30]], 272], ['partial repair probe 1', [[2000, 2, 28], [2001, 5, 31]], 453], ['partial repair probe 2', [[2024, 2, 28], [2027, 5, 1]], 1143], ['boundary control 1', [[2023, 5, 30], [2023, 7, 31]], 60], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[2062, 11, 30], [2064, 3, 26]], 476], ['normal control 2', [[2060, 11, 30], [2062, 12, 30]], 750]], [['regression february end detection 1', [[2096, 2, 28], [2096, 10, 31]], 243], ['regression february end detection 2', [[2004, 2, 29], [2006, 5, 30]], 810], ['partial repair probe 1', [[2096, 2, 28], [2097, 1, 8]], 310], ['partial repair probe 2', [[2004, 2, 28], [2005, 5, 31]], 453], ['boundary control 1', [[2023, 5, 30], [2023, 7, 31]], 60], ['boundary control 2', [[2023, 2, 28], [2023, 8, 31]], 180], ['normal control 1', [[2053, 1, 28], [2055, 2, 28]], 750], ['normal control 2', [[2011, 10, 20], [2012, 6, 19]], 239]]]
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 february end detection 1 | 329 | 331 | Failed |
| regression february end detection 2 | 360 | 360 | Passed |
| partial repair probe 1 | 305 | 307 | Failed |
| partial repair probe 2 | 390 | 393 | Failed |
| boundary control 1 | 180 | 180 | Passed |
| boundary control 2 | 0 | 0 | Passed |
| normal control 1 | 1110 | 1110 | Passed |
| normal control 2 | 1109 | 1109 | Passed |
SHA-256 / 722196da2d578439742402f21d45e4783c2e9441ade7bf589cf78398b58fd63f
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 february end detection 1', [[2096, 2, 28], [2097, 1, 29]], 331], ['regression february end detection 2', [[2015, 2, 28], [2016, 2, 29]], 360], ['partial repair probe 1', [[2024, 2, 28], [2025, 1, 5]], 307], ['partial repair probe 2', [[2004, 2, 28], [2005, 3, 31]], 393], ['boundary control 1', [[2024, 3, 15], [2024, 9, 15]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2018, 4, 30], [2021, 5, 31]], 1110], ['normal control 2', [[2049, 1, 31], [2052, 2, 29]], 1109]], [['regression february end detection 1', [[2000, 2, 29], [2002, 2, 28]], 720], ['regression february end detection 2', [[2024, 2, 29], [2027, 2, 28]], 1080], ['partial repair probe 1', [[2004, 2, 28], [2005, 12, 17]], 649], ['partial repair probe 2', [[2008, 2, 28], [2011, 4, 25]], 1137], ['boundary control 1', [[2023, 2, 28], [2023, 8, 31]], 180], ['boundary control 2', [[2024, 1, 1], [2024, 1, 1]], 0], ['normal control 1', [[2047, 7, 31], [2050, 2, 28]], 928], ['normal control 2', [[2057, 2, 28], [2059, 5, 6]], 786]], [['regression february end detection 1', [[2000, 2, 29], [2000, 5, 30]], 90], ['regression february end detection 2', [[2000, 2, 28], [2003, 4, 30]], 1142], ['partial repair probe 1', [[2096, 2, 28], [2098, 1, 31]], 693], ['partial repair probe 2', [[2024, 2, 28], [2024, 11, 13]], 255], ['boundary control 1', [[2023, 1, 31], [2023, 3, 31]], 60], ['boundary control 2', [[2023, 5, 30], [2023, 7, 31]], 60], ['normal control 1', [[2089, 6, 30], [2091, 2, 28]], 598], ['normal control 2', [[2011, 6, 30], [2013, 7, 14]], 734]], [['regression february end detection 1', [[2096, 2, 28], [2098, 6, 1]], 813], ['regression february end detection 2', [[2016, 2, 28], [2016, 11, 30]], 272], ['partial repair probe 1', [[2000, 2, 28], [2001, 5, 31]], 453], ['partial repair probe 2', [[2024, 2, 28], [2027, 5, 1]], 1143], ['boundary control 1', [[2023, 5, 30], [2023, 7, 31]], 60], ['boundary control 2', [[2024, 3, 15], [2024, 9, 15]], 180], ['normal control 1', [[2062, 11, 30], [2064, 3, 26]], 476], ['normal control 2', [[2060, 11, 30], [2062, 12, 30]], 750]], [['regression february end detection 1', [[2096, 2, 28], [2096, 10, 31]], 243], ['regression february end detection 2', [[2004, 2, 29], [2006, 5, 30]], 810], ['partial repair probe 1', [[2096, 2, 28], [2097, 1, 8]], 310], ['partial repair probe 2', [[2004, 2, 28], [2005, 5, 31]], 453], ['boundary control 1', [[2023, 5, 30], [2023, 7, 31]], 60], ['boundary control 2', [[2023, 2, 28], [2023, 8, 31]], 180], ['normal control 1', [[2053, 1, 28], [2055, 2, 28]], 750], ['normal control 2', [[2011, 10, 20], [2012, 6, 19]], 239]]]
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 february end detection 1 | 331 | 331 | Passed |
| regression february end detection 2 | 360 | 360 | Passed |
| partial repair probe 1 | 307 | 307 | Passed |
| partial repair probe 2 | 393 | 393 | Passed |
| boundary control 1 | 180 | 180 | Passed |
| boundary control 2 | 0 | 0 | Passed |
| normal control 1 | 1110 | 1110 | Passed |
| normal control 2 | 1109 | 1109 | Passed |
SHA-256 / d7acf55eb05f73442fc13213c4d94e4b46c6ae51f038016aee491bbf53b8e66f
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.370133+00:00.
Case digest / bffce8ec106d2bd0b5eb9696a3a602ff4e9e745c5aa2b986a51e16750bff224b