FA-61201 / Bond day-count conventions / Open access
Settlement date from a business-day lag across two calendars: the lag is added in calendar days and then rolled forward · case 01
Trades before weekends and holidays settle too early.
ROOT CAUSE
The lag is applied as calendar days followed by a single roll to a business day.
VERIFIED REPAIR
Count n business days one at a time.
Unsuccessful approach: Counting weekdays and rolling past holidays at the end misses holidays inside the lag.
Case contract
Inputs a trade date (a business day), a lag n and two holiday lists. A business day is a weekday that is a holiday in neither calendar. Settlement is the n-th business day strictly after trade (trade date for n=0). Return [y,m,d].
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
import datetime
N = 1
observations = []
def solve(trade, n, hol_a, hol_b):
T = datetime.date(*trade)
HA = {datetime.date(*h) for h in hol_a}
HB = {datetime.date(*h) for h in hol_b}
def biz(x):
return x.weekday() < 5 and x not in HA and x not in HB
x = T
k = 0
x = T + datetime.timedelta(days=n)
while not biz(x):
x += datetime.timedelta(days=1)
return [x.year, x.month, x.day]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression calendar lag then roll 1', [[2024, 11, 28], 5, [[2024, 12, 5], [2024, 12, 7]], [[2024, 12, 4], [2024, 12, 6]]], [2024, 12, 10]], ['regression calendar lag then roll 2', [[2024, 8, 8], 5, [], [[2024, 8, 11], [2024, 8, 15]]], [2024, 8, 16]], ['partial repair probe 1', [[2024, 2, 16], 5, [[2024, 2, 21], [2024, 2, 18]], []], [2024, 2, 26]], ['partial repair probe 2', [[2022, 5, 2], 3, [[2022, 5, 10]], [[2022, 5, 11], [2022, 5, 3]]], [2022, 5, 6]], ['boundary control 1', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['boundary control 2', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['normal control 1', [[2025, 6, 18], 0, [[2025, 6, 27], [2025, 6, 19]], []], [2025, 6, 18]], ['normal control 2', [[2021, 12, 30], 0, [[2021, 12, 31], [2022, 1, 1]], []], [2021, 12, 30]]], [['regression calendar lag then roll 1', [[2030, 7, 26], 2, [[2030, 7, 29], [2030, 7, 28]], [[2030, 8, 4]]], [2030, 7, 31]], ['regression calendar lag then roll 2', [[2029, 11, 22], 5, [[2029, 11, 25]], []], [2029, 11, 29]], ['partial repair probe 1', [[2027, 12, 30], 2, [[2028, 1, 3], [2028, 1, 6]], [[2027, 12, 31]]], [2028, 1, 5]], ['partial repair probe 2', [[2030, 10, 31], 3, [[2030, 11, 9], [2030, 11, 3]], [[2030, 11, 4]]], [2030, 11, 6]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2026, 3, 16], 1, [[2026, 3, 23], [2026, 3, 23]], [[2026, 3, 25]]], [2026, 3, 17]], ['normal control 2', [[2019, 2, 28], 1, [[2019, 3, 7], [2019, 3, 8]], []], [2019, 3, 1]]], [['regression calendar lag then roll 1', [[2020, 4, 21], 5, [[2020, 4, 25]], [[2020, 4, 30]]], [2020, 4, 28]], ['regression calendar lag then roll 2', [[2022, 4, 1], 2, [[2022, 4, 10], [2022, 4, 2]], [[2022, 4, 8], [2022, 4, 2]]], [2022, 4, 5]], ['partial repair probe 1', [[2020, 9, 30], 5, [[2020, 10, 1], [2020, 10, 5]], []], [2020, 10, 9]], ['partial repair probe 2', [[2028, 1, 31], 3, [], [[2028, 2, 3], [2028, 2, 1]]], [2028, 2, 7]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2029, 4, 30], 2, [], [[2029, 5, 3], [2029, 5, 8]]], [2029, 5, 2]], ['normal control 2', [[2021, 2, 23], 1, [[2021, 2, 28], [2021, 3, 3]], [[2021, 2, 25], [2021, 3, 3]]], [2021, 2, 24]]], [['regression calendar lag then roll 1', [[2025, 7, 31], 5, [[2025, 8, 5]], []], [2025, 8, 8]], ['regression calendar lag then roll 2', [[2025, 2, 11], 5, [[2025, 2, 17], [2025, 2, 18]], [[2025, 2, 13], [2025, 2, 16]]], [2025, 2, 21]], ['partial repair probe 1', [[2023, 10, 31], 3, [[2023, 11, 7]], [[2023, 11, 2], [2023, 11, 1]]], [2023, 11, 8]], ['partial repair probe 2', [[2028, 9, 18], 5, [[2028, 9, 24], [2028, 9, 19]], [[2028, 9, 22], [2028, 9, 26]]], [2028, 9, 28]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2019, 12, 2], 5, [[2019, 12, 11]], []], [2019, 12, 9]], ['normal control 2', [[2029, 6, 4], 3, [], [[2029, 6, 11], [2029, 6, 12]]], [2029, 6, 7]]], [['regression calendar lag then roll 1', [[2030, 4, 1], 3, [[2030, 4, 6]], [[2030, 4, 2], [2030, 4, 8]]], [2030, 4, 5]], ['regression calendar lag then roll 2', [[2029, 2, 28], 5, [[2029, 3, 6], [2029, 3, 7]], []], [2029, 3, 9]], ['partial repair probe 1', [[2029, 8, 30], 5, [[2029, 9, 8], [2029, 9, 2]], [[2029, 9, 5], [2029, 9, 2]]], [2029, 9, 7]], ['partial repair probe 2', [[2022, 3, 14], 3, [], [[2022, 3, 16]]], [2022, 3, 18]], ['boundary control 1', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['boundary control 2', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['normal control 1', [[2020, 10, 12], 1, [], [[2020, 10, 18]]], [2020, 10, 13]], ['normal control 2', [[2024, 4, 10], 2, [[2024, 4, 19], [2024, 4, 19]], [[2024, 4, 15]]], [2024, 4, 12]]]]
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 calendar lag then roll 1 | [2024, 12, 3] | [2024, 12, 10] | Failed |
| regression calendar lag then roll 2 | [2024, 8, 13] | [2024, 8, 16] | Failed |
| partial repair probe 1 | [2024, 2, 22] | [2024, 2, 26] | Failed |
| partial repair probe 2 | [2022, 5, 5] | [2022, 5, 6] | Failed |
| boundary control 1 | [2024, 5, 8] | [2024, 5, 8] | Passed |
| boundary control 2 | [2024, 5, 3] | [2024, 5, 3] | Passed |
| normal control 1 | [2025, 6, 18] | [2025, 6, 18] | Passed |
| normal control 2 | [2021, 12, 30] | [2021, 12, 30] | Passed |
SHA-256 / ebf389299fe41014c27c6cc70bfdb78ed9e55727aea5879f480f9636671ed125
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(trade, n, hol_a, hol_b):
T = datetime.date(*trade)
HA = {datetime.date(*h) for h in hol_a}
HB = {datetime.date(*h) for h in hol_b}
def biz(x):
return x.weekday() < 5 and x not in HA and x not in HB
x = T
k = 0
while k < n:
x += datetime.timedelta(days=1)
if x.weekday() < 5:
k += 1
while not biz(x):
x += datetime.timedelta(days=1)
return [x.year, x.month, x.day]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression calendar lag then roll 1', [[2024, 11, 28], 5, [[2024, 12, 5], [2024, 12, 7]], [[2024, 12, 4], [2024, 12, 6]]], [2024, 12, 10]], ['regression calendar lag then roll 2', [[2024, 8, 8], 5, [], [[2024, 8, 11], [2024, 8, 15]]], [2024, 8, 16]], ['partial repair probe 1', [[2024, 2, 16], 5, [[2024, 2, 21], [2024, 2, 18]], []], [2024, 2, 26]], ['partial repair probe 2', [[2022, 5, 2], 3, [[2022, 5, 10]], [[2022, 5, 11], [2022, 5, 3]]], [2022, 5, 6]], ['boundary control 1', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['boundary control 2', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['normal control 1', [[2025, 6, 18], 0, [[2025, 6, 27], [2025, 6, 19]], []], [2025, 6, 18]], ['normal control 2', [[2021, 12, 30], 0, [[2021, 12, 31], [2022, 1, 1]], []], [2021, 12, 30]]], [['regression calendar lag then roll 1', [[2030, 7, 26], 2, [[2030, 7, 29], [2030, 7, 28]], [[2030, 8, 4]]], [2030, 7, 31]], ['regression calendar lag then roll 2', [[2029, 11, 22], 5, [[2029, 11, 25]], []], [2029, 11, 29]], ['partial repair probe 1', [[2027, 12, 30], 2, [[2028, 1, 3], [2028, 1, 6]], [[2027, 12, 31]]], [2028, 1, 5]], ['partial repair probe 2', [[2030, 10, 31], 3, [[2030, 11, 9], [2030, 11, 3]], [[2030, 11, 4]]], [2030, 11, 6]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2026, 3, 16], 1, [[2026, 3, 23], [2026, 3, 23]], [[2026, 3, 25]]], [2026, 3, 17]], ['normal control 2', [[2019, 2, 28], 1, [[2019, 3, 7], [2019, 3, 8]], []], [2019, 3, 1]]], [['regression calendar lag then roll 1', [[2020, 4, 21], 5, [[2020, 4, 25]], [[2020, 4, 30]]], [2020, 4, 28]], ['regression calendar lag then roll 2', [[2022, 4, 1], 2, [[2022, 4, 10], [2022, 4, 2]], [[2022, 4, 8], [2022, 4, 2]]], [2022, 4, 5]], ['partial repair probe 1', [[2020, 9, 30], 5, [[2020, 10, 1], [2020, 10, 5]], []], [2020, 10, 9]], ['partial repair probe 2', [[2028, 1, 31], 3, [], [[2028, 2, 3], [2028, 2, 1]]], [2028, 2, 7]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2029, 4, 30], 2, [], [[2029, 5, 3], [2029, 5, 8]]], [2029, 5, 2]], ['normal control 2', [[2021, 2, 23], 1, [[2021, 2, 28], [2021, 3, 3]], [[2021, 2, 25], [2021, 3, 3]]], [2021, 2, 24]]], [['regression calendar lag then roll 1', [[2025, 7, 31], 5, [[2025, 8, 5]], []], [2025, 8, 8]], ['regression calendar lag then roll 2', [[2025, 2, 11], 5, [[2025, 2, 17], [2025, 2, 18]], [[2025, 2, 13], [2025, 2, 16]]], [2025, 2, 21]], ['partial repair probe 1', [[2023, 10, 31], 3, [[2023, 11, 7]], [[2023, 11, 2], [2023, 11, 1]]], [2023, 11, 8]], ['partial repair probe 2', [[2028, 9, 18], 5, [[2028, 9, 24], [2028, 9, 19]], [[2028, 9, 22], [2028, 9, 26]]], [2028, 9, 28]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2019, 12, 2], 5, [[2019, 12, 11]], []], [2019, 12, 9]], ['normal control 2', [[2029, 6, 4], 3, [], [[2029, 6, 11], [2029, 6, 12]]], [2029, 6, 7]]], [['regression calendar lag then roll 1', [[2030, 4, 1], 3, [[2030, 4, 6]], [[2030, 4, 2], [2030, 4, 8]]], [2030, 4, 5]], ['regression calendar lag then roll 2', [[2029, 2, 28], 5, [[2029, 3, 6], [2029, 3, 7]], []], [2029, 3, 9]], ['partial repair probe 1', [[2029, 8, 30], 5, [[2029, 9, 8], [2029, 9, 2]], [[2029, 9, 5], [2029, 9, 2]]], [2029, 9, 7]], ['partial repair probe 2', [[2022, 3, 14], 3, [], [[2022, 3, 16]]], [2022, 3, 18]], ['boundary control 1', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['boundary control 2', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['normal control 1', [[2020, 10, 12], 1, [], [[2020, 10, 18]]], [2020, 10, 13]], ['normal control 2', [[2024, 4, 10], 2, [[2024, 4, 19], [2024, 4, 19]], [[2024, 4, 15]]], [2024, 4, 12]]]]
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 calendar lag then roll 1 | [2024, 12, 9] | [2024, 12, 10] | Failed |
| regression calendar lag then roll 2 | [2024, 8, 16] | [2024, 8, 16] | Passed |
| partial repair probe 1 | [2024, 2, 23] | [2024, 2, 26] | Failed |
| partial repair probe 2 | [2022, 5, 5] | [2022, 5, 6] | Failed |
| boundary control 1 | [2024, 5, 8] | [2024, 5, 8] | Passed |
| boundary control 2 | [2024, 5, 3] | [2024, 5, 3] | Passed |
| normal control 1 | [2025, 6, 18] | [2025, 6, 18] | Passed |
| normal control 2 | [2021, 12, 30] | [2021, 12, 30] | Passed |
SHA-256 / 11a7708aeb4b13bb07c68f001636d89aabefbf9d1e3b5c97e065ab2acbddd2e6
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(trade, n, hol_a, hol_b):
T = datetime.date(*trade)
HA = {datetime.date(*h) for h in hol_a}
HB = {datetime.date(*h) for h in hol_b}
def biz(x):
return x.weekday() < 5 and x not in HA and x not in HB
x = T
k = 0
while k < n:
x += datetime.timedelta(days=1)
if biz(x):
k += 1
return [x.year, x.month, x.day]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression calendar lag then roll 1', [[2024, 11, 28], 5, [[2024, 12, 5], [2024, 12, 7]], [[2024, 12, 4], [2024, 12, 6]]], [2024, 12, 10]], ['regression calendar lag then roll 2', [[2024, 8, 8], 5, [], [[2024, 8, 11], [2024, 8, 15]]], [2024, 8, 16]], ['partial repair probe 1', [[2024, 2, 16], 5, [[2024, 2, 21], [2024, 2, 18]], []], [2024, 2, 26]], ['partial repair probe 2', [[2022, 5, 2], 3, [[2022, 5, 10]], [[2022, 5, 11], [2022, 5, 3]]], [2022, 5, 6]], ['boundary control 1', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['boundary control 2', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['normal control 1', [[2025, 6, 18], 0, [[2025, 6, 27], [2025, 6, 19]], []], [2025, 6, 18]], ['normal control 2', [[2021, 12, 30], 0, [[2021, 12, 31], [2022, 1, 1]], []], [2021, 12, 30]]], [['regression calendar lag then roll 1', [[2030, 7, 26], 2, [[2030, 7, 29], [2030, 7, 28]], [[2030, 8, 4]]], [2030, 7, 31]], ['regression calendar lag then roll 2', [[2029, 11, 22], 5, [[2029, 11, 25]], []], [2029, 11, 29]], ['partial repair probe 1', [[2027, 12, 30], 2, [[2028, 1, 3], [2028, 1, 6]], [[2027, 12, 31]]], [2028, 1, 5]], ['partial repair probe 2', [[2030, 10, 31], 3, [[2030, 11, 9], [2030, 11, 3]], [[2030, 11, 4]]], [2030, 11, 6]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2026, 3, 16], 1, [[2026, 3, 23], [2026, 3, 23]], [[2026, 3, 25]]], [2026, 3, 17]], ['normal control 2', [[2019, 2, 28], 1, [[2019, 3, 7], [2019, 3, 8]], []], [2019, 3, 1]]], [['regression calendar lag then roll 1', [[2020, 4, 21], 5, [[2020, 4, 25]], [[2020, 4, 30]]], [2020, 4, 28]], ['regression calendar lag then roll 2', [[2022, 4, 1], 2, [[2022, 4, 10], [2022, 4, 2]], [[2022, 4, 8], [2022, 4, 2]]], [2022, 4, 5]], ['partial repair probe 1', [[2020, 9, 30], 5, [[2020, 10, 1], [2020, 10, 5]], []], [2020, 10, 9]], ['partial repair probe 2', [[2028, 1, 31], 3, [], [[2028, 2, 3], [2028, 2, 1]]], [2028, 2, 7]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2029, 4, 30], 2, [], [[2029, 5, 3], [2029, 5, 8]]], [2029, 5, 2]], ['normal control 2', [[2021, 2, 23], 1, [[2021, 2, 28], [2021, 3, 3]], [[2021, 2, 25], [2021, 3, 3]]], [2021, 2, 24]]], [['regression calendar lag then roll 1', [[2025, 7, 31], 5, [[2025, 8, 5]], []], [2025, 8, 8]], ['regression calendar lag then roll 2', [[2025, 2, 11], 5, [[2025, 2, 17], [2025, 2, 18]], [[2025, 2, 13], [2025, 2, 16]]], [2025, 2, 21]], ['partial repair probe 1', [[2023, 10, 31], 3, [[2023, 11, 7]], [[2023, 11, 2], [2023, 11, 1]]], [2023, 11, 8]], ['partial repair probe 2', [[2028, 9, 18], 5, [[2028, 9, 24], [2028, 9, 19]], [[2028, 9, 22], [2028, 9, 26]]], [2028, 9, 28]], ['boundary control 1', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['boundary control 2', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['normal control 1', [[2019, 12, 2], 5, [[2019, 12, 11]], []], [2019, 12, 9]], ['normal control 2', [[2029, 6, 4], 3, [], [[2029, 6, 11], [2029, 6, 12]]], [2029, 6, 7]]], [['regression calendar lag then roll 1', [[2030, 4, 1], 3, [[2030, 4, 6]], [[2030, 4, 2], [2030, 4, 8]]], [2030, 4, 5]], ['regression calendar lag then roll 2', [[2029, 2, 28], 5, [[2029, 3, 6], [2029, 3, 7]], []], [2029, 3, 9]], ['partial repair probe 1', [[2029, 8, 30], 5, [[2029, 9, 8], [2029, 9, 2]], [[2029, 9, 5], [2029, 9, 2]]], [2029, 9, 7]], ['partial repair probe 2', [[2022, 3, 14], 3, [], [[2022, 3, 16]]], [2022, 3, 18]], ['boundary control 1', [[2024, 5, 6], 1, [[2024, 5, 7]], []], [2024, 5, 8]], ['boundary control 2', [[2024, 5, 3], 0, [], []], [2024, 5, 3]], ['normal control 1', [[2020, 10, 12], 1, [], [[2020, 10, 18]]], [2020, 10, 13]], ['normal control 2', [[2024, 4, 10], 2, [[2024, 4, 19], [2024, 4, 19]], [[2024, 4, 15]]], [2024, 4, 12]]]]
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 calendar lag then roll 1 | [2024, 12, 10] | [2024, 12, 10] | Passed |
| regression calendar lag then roll 2 | [2024, 8, 16] | [2024, 8, 16] | Passed |
| partial repair probe 1 | [2024, 2, 26] | [2024, 2, 26] | Passed |
| partial repair probe 2 | [2022, 5, 6] | [2022, 5, 6] | Passed |
| boundary control 1 | [2024, 5, 8] | [2024, 5, 8] | Passed |
| boundary control 2 | [2024, 5, 3] | [2024, 5, 3] | Passed |
| normal control 1 | [2025, 6, 18] | [2025, 6, 18] | Passed |
| normal control 2 | [2021, 12, 30] | [2021, 12, 30] | Passed |
SHA-256 / b64b219d7c477ee3ebcc002f01aeba7ecda2e3ee5f1462cddf8b5d3dca533ae5
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:52.972241+00:00.
Case digest / c157878e3b242bb66655bcd682537c99d1c356bd5d5f874effd30abc76ae03ad