FAILURE MAP
← Case archive

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

Canadian-style semi-annual accrued interest: early-period accrual uses the actual period length · case 01

Accrued interest follows an actual/actual pattern instead of the 365-day basis.

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

ROOT CAUSE

The early branch divides by the coupon period days and pays half a coupon per period.

VERIFIED REPAIR

Accrue c*days/365 in the early part of the period.

Unsuccessful approach: Using 366 in leap years is still not the fixed 365-day basis.

Case contract

Inputs prev and next coupon dates, settlement in [prev, next) and annual rate (semi-annual coupons). c = 100*rate, days = days(prev, settle). If days >= 183 accrued = c/2 - c*days(settle, next)/365, else accrued = c*days/365. Round to 6 decimals.

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(prev, nxt, settle, rate):
    P = datetime.date(*prev)
    Q = datetime.date(*nxt)
    S = datetime.date(*settle)
    days = (S - P).days
    c = 100 * rate
    if days >= 183:
        acc = c / 2 - c * (Q - S).days / 365
    else:
        acc = c / 2 * days / (Q - P).days
    return round(acc, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression forward accrual basis 1', [[2027, 9, 8], [2028, 3, 8], [2028, 3, 7], 0.0825], 4.091096], ['regression forward accrual basis 2', [[2029, 9, 13], [2030, 3, 13], [2030, 3, 12], 0.05], 2.465753], ['partial repair probe 1', [[2032, 10, 3], [2033, 4, 3], [2032, 10, 16], 0.0825], 0.293836], ['partial repair probe 2', [[2016, 8, 27], [2017, 2, 27], [2016, 11, 15], 0.025], 0.547945], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2027, 7, 31], [2028, 1, 31], [2028, 1, 30], 0.05], 2.486301], ['normal control 2', [[2015, 7, 7], [2016, 1, 7], [2016, 1, 6], 0.025], 1.243151], ['normal control 3', [[2019, 3, 22], [2019, 9, 22], [2019, 9, 21], 0.05], 2.486301]], [['regression forward accrual basis 1', [[2022, 1, 16], [2022, 7, 16], [2022, 7, 15], 0.025], 1.232877], ['regression forward accrual basis 2', [[2038, 9, 30], [2039, 3, 30], [2039, 3, 29], 0.025], 1.232877], ['partial repair probe 1', [[2032, 7, 4], [2033, 1, 4], [2032, 8, 12], 0.025], 0.267123], ['partial repair probe 2', [[2040, 5, 31], [2040, 11, 30], [2040, 11, 29], 0.0125], 0.623288], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2018, 5, 18], [2018, 11, 18], [2018, 11, 17], 0.0125], 0.621575], ['normal control 2', [[2027, 3, 9], [2027, 9, 9], [2027, 9, 8], 0.025], 1.243151], ['normal control 3', [[2035, 5, 1], [2035, 11, 1], [2035, 10, 31], 0.025], 1.243151]], [['regression forward accrual basis 1', [[2020, 2, 28], [2020, 8, 28], [2020, 8, 26], 0.0125], 0.616438], ['regression forward accrual basis 2', [[2015, 8, 30], [2016, 2, 29], [2016, 2, 28], 0.0375], 1.869863], ['partial repair probe 1', [[2036, 6, 30], [2036, 12, 30], [2036, 12, 29], 0.0825], 4.113699], ['partial repair probe 2', [[2040, 4, 25], [2040, 10, 25], [2040, 10, 23], 0.0825], 4.091096], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2034, 5, 18], [2034, 11, 18], [2034, 11, 17], 0.025], 1.243151], ['normal control 2', [[2017, 8, 12], [2018, 2, 12], [2018, 2, 11], 0.05], 2.486301], ['normal control 3', [[2015, 8, 25], [2016, 2, 25], [2016, 2, 24], 0.0825], 4.102397]], [['regression forward accrual basis 1', [[2018, 4, 11], [2018, 10, 11], [2018, 10, 10], 0.0375], 1.869863], ['regression forward accrual basis 2', [[2021, 6, 30], [2021, 12, 30], [2021, 12, 29], 0.0125], 0.623288], ['partial repair probe 1', [[2028, 2, 28], [2028, 8, 28], [2028, 8, 27], 0.0125], 0.619863], ['partial repair probe 2', [[2016, 9, 30], [2017, 3, 30], [2016, 10, 31], 0.025], 0.212329], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2015, 7, 11], [2016, 1, 11], [2016, 1, 10], 0.0125], 0.621575], ['normal control 2', [[2020, 3, 18], [2020, 9, 18], [2020, 9, 17], 0.05], 2.486301], ['normal control 3', [[2038, 8, 4], [2039, 2, 4], [2039, 2, 3], 0.05], 2.486301]], [['regression forward accrual basis 1', [[2019, 11, 1], [2020, 5, 1], [2020, 4, 27], 0.0825], 4.023288], ['regression forward accrual basis 2', [[2040, 2, 28], [2040, 8, 28], [2040, 8, 25], 0.0125], 0.613014], ['partial repair probe 1', [[2016, 8, 20], [2017, 2, 20], [2016, 8, 31], 0.05], 0.150685], ['partial repair probe 2', [[2028, 4, 2], [2028, 10, 2], [2028, 10, 1], 0.0125], 0.623288], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2021, 5, 9], [2021, 11, 9], [2021, 11, 8], 0.025], 1.243151], ['normal control 2', [[2037, 5, 1], [2037, 11, 1], [2037, 10, 31], 0.025], 1.243151], ['normal control 3', [[2027, 5, 5], [2027, 11, 5], [2027, 11, 4], 0.025], 1.243151]]]
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 forward accrual basis 14.1023354.091096Failed
regression forward accrual basis 22.4861882.465753Failed
partial repair probe 10.2946430.293836Failed
partial repair probe 20.5434780.547945Failed
boundary control 10.00.0Passed
normal control 12.4863012.486301Passed
normal control 21.2431511.243151Passed
normal control 32.4863012.486301Passed

SHA-256 / fad35280c46a674af068c7f31f3ba20037dc9129fdeaaf3c3140c74c8f80dd49

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(prev, nxt, settle, rate):
    P = datetime.date(*prev)
    Q = datetime.date(*nxt)
    S = datetime.date(*settle)
    days = (S - P).days
    c = 100 * rate
    if days >= 183:
        acc = c / 2 - c * (Q - S).days / 365
    else:
        acc = c * days / (366 if P.year % 4 == 0 else 365)
    return round(acc, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression forward accrual basis 1', [[2027, 9, 8], [2028, 3, 8], [2028, 3, 7], 0.0825], 4.091096], ['regression forward accrual basis 2', [[2029, 9, 13], [2030, 3, 13], [2030, 3, 12], 0.05], 2.465753], ['partial repair probe 1', [[2032, 10, 3], [2033, 4, 3], [2032, 10, 16], 0.0825], 0.293836], ['partial repair probe 2', [[2016, 8, 27], [2017, 2, 27], [2016, 11, 15], 0.025], 0.547945], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2027, 7, 31], [2028, 1, 31], [2028, 1, 30], 0.05], 2.486301], ['normal control 2', [[2015, 7, 7], [2016, 1, 7], [2016, 1, 6], 0.025], 1.243151], ['normal control 3', [[2019, 3, 22], [2019, 9, 22], [2019, 9, 21], 0.05], 2.486301]], [['regression forward accrual basis 1', [[2022, 1, 16], [2022, 7, 16], [2022, 7, 15], 0.025], 1.232877], ['regression forward accrual basis 2', [[2038, 9, 30], [2039, 3, 30], [2039, 3, 29], 0.025], 1.232877], ['partial repair probe 1', [[2032, 7, 4], [2033, 1, 4], [2032, 8, 12], 0.025], 0.267123], ['partial repair probe 2', [[2040, 5, 31], [2040, 11, 30], [2040, 11, 29], 0.0125], 0.623288], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2018, 5, 18], [2018, 11, 18], [2018, 11, 17], 0.0125], 0.621575], ['normal control 2', [[2027, 3, 9], [2027, 9, 9], [2027, 9, 8], 0.025], 1.243151], ['normal control 3', [[2035, 5, 1], [2035, 11, 1], [2035, 10, 31], 0.025], 1.243151]], [['regression forward accrual basis 1', [[2020, 2, 28], [2020, 8, 28], [2020, 8, 26], 0.0125], 0.616438], ['regression forward accrual basis 2', [[2015, 8, 30], [2016, 2, 29], [2016, 2, 28], 0.0375], 1.869863], ['partial repair probe 1', [[2036, 6, 30], [2036, 12, 30], [2036, 12, 29], 0.0825], 4.113699], ['partial repair probe 2', [[2040, 4, 25], [2040, 10, 25], [2040, 10, 23], 0.0825], 4.091096], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2034, 5, 18], [2034, 11, 18], [2034, 11, 17], 0.025], 1.243151], ['normal control 2', [[2017, 8, 12], [2018, 2, 12], [2018, 2, 11], 0.05], 2.486301], ['normal control 3', [[2015, 8, 25], [2016, 2, 25], [2016, 2, 24], 0.0825], 4.102397]], [['regression forward accrual basis 1', [[2018, 4, 11], [2018, 10, 11], [2018, 10, 10], 0.0375], 1.869863], ['regression forward accrual basis 2', [[2021, 6, 30], [2021, 12, 30], [2021, 12, 29], 0.0125], 0.623288], ['partial repair probe 1', [[2028, 2, 28], [2028, 8, 28], [2028, 8, 27], 0.0125], 0.619863], ['partial repair probe 2', [[2016, 9, 30], [2017, 3, 30], [2016, 10, 31], 0.025], 0.212329], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2015, 7, 11], [2016, 1, 11], [2016, 1, 10], 0.0125], 0.621575], ['normal control 2', [[2020, 3, 18], [2020, 9, 18], [2020, 9, 17], 0.05], 2.486301], ['normal control 3', [[2038, 8, 4], [2039, 2, 4], [2039, 2, 3], 0.05], 2.486301]], [['regression forward accrual basis 1', [[2019, 11, 1], [2020, 5, 1], [2020, 4, 27], 0.0825], 4.023288], ['regression forward accrual basis 2', [[2040, 2, 28], [2040, 8, 28], [2040, 8, 25], 0.0125], 0.613014], ['partial repair probe 1', [[2016, 8, 20], [2017, 2, 20], [2016, 8, 31], 0.05], 0.150685], ['partial repair probe 2', [[2028, 4, 2], [2028, 10, 2], [2028, 10, 1], 0.0125], 0.623288], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2021, 5, 9], [2021, 11, 9], [2021, 11, 8], 0.025], 1.243151], ['normal control 2', [[2037, 5, 1], [2037, 11, 1], [2037, 10, 31], 0.025], 1.243151], ['normal control 3', [[2027, 5, 5], [2027, 11, 5], [2027, 11, 4], 0.025], 1.243151]]]
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 forward accrual basis 14.0910964.091096Passed
regression forward accrual basis 22.4657532.465753Passed
partial repair probe 10.2930330.293836Failed
partial repair probe 20.5464480.547945Failed
boundary control 10.00.0Passed
normal control 12.4863012.486301Passed
normal control 21.2431511.243151Passed
normal control 32.4863012.486301Passed

SHA-256 / ab43774304bec9f02db69ff0ee295fa19a664fb1e25a8fa31b63d6a5472aec0f

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(prev, nxt, settle, rate):
    P = datetime.date(*prev)
    Q = datetime.date(*nxt)
    S = datetime.date(*settle)
    days = (S - P).days
    c = 100 * rate
    if days >= 183:
        acc = c / 2 - c * (Q - S).days / 365
    else:
        acc = c * days / 365
    return round(acc, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression forward accrual basis 1', [[2027, 9, 8], [2028, 3, 8], [2028, 3, 7], 0.0825], 4.091096], ['regression forward accrual basis 2', [[2029, 9, 13], [2030, 3, 13], [2030, 3, 12], 0.05], 2.465753], ['partial repair probe 1', [[2032, 10, 3], [2033, 4, 3], [2032, 10, 16], 0.0825], 0.293836], ['partial repair probe 2', [[2016, 8, 27], [2017, 2, 27], [2016, 11, 15], 0.025], 0.547945], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2027, 7, 31], [2028, 1, 31], [2028, 1, 30], 0.05], 2.486301], ['normal control 2', [[2015, 7, 7], [2016, 1, 7], [2016, 1, 6], 0.025], 1.243151], ['normal control 3', [[2019, 3, 22], [2019, 9, 22], [2019, 9, 21], 0.05], 2.486301]], [['regression forward accrual basis 1', [[2022, 1, 16], [2022, 7, 16], [2022, 7, 15], 0.025], 1.232877], ['regression forward accrual basis 2', [[2038, 9, 30], [2039, 3, 30], [2039, 3, 29], 0.025], 1.232877], ['partial repair probe 1', [[2032, 7, 4], [2033, 1, 4], [2032, 8, 12], 0.025], 0.267123], ['partial repair probe 2', [[2040, 5, 31], [2040, 11, 30], [2040, 11, 29], 0.0125], 0.623288], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2018, 5, 18], [2018, 11, 18], [2018, 11, 17], 0.0125], 0.621575], ['normal control 2', [[2027, 3, 9], [2027, 9, 9], [2027, 9, 8], 0.025], 1.243151], ['normal control 3', [[2035, 5, 1], [2035, 11, 1], [2035, 10, 31], 0.025], 1.243151]], [['regression forward accrual basis 1', [[2020, 2, 28], [2020, 8, 28], [2020, 8, 26], 0.0125], 0.616438], ['regression forward accrual basis 2', [[2015, 8, 30], [2016, 2, 29], [2016, 2, 28], 0.0375], 1.869863], ['partial repair probe 1', [[2036, 6, 30], [2036, 12, 30], [2036, 12, 29], 0.0825], 4.113699], ['partial repair probe 2', [[2040, 4, 25], [2040, 10, 25], [2040, 10, 23], 0.0825], 4.091096], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2034, 5, 18], [2034, 11, 18], [2034, 11, 17], 0.025], 1.243151], ['normal control 2', [[2017, 8, 12], [2018, 2, 12], [2018, 2, 11], 0.05], 2.486301], ['normal control 3', [[2015, 8, 25], [2016, 2, 25], [2016, 2, 24], 0.0825], 4.102397]], [['regression forward accrual basis 1', [[2018, 4, 11], [2018, 10, 11], [2018, 10, 10], 0.0375], 1.869863], ['regression forward accrual basis 2', [[2021, 6, 30], [2021, 12, 30], [2021, 12, 29], 0.0125], 0.623288], ['partial repair probe 1', [[2028, 2, 28], [2028, 8, 28], [2028, 8, 27], 0.0125], 0.619863], ['partial repair probe 2', [[2016, 9, 30], [2017, 3, 30], [2016, 10, 31], 0.025], 0.212329], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2015, 7, 11], [2016, 1, 11], [2016, 1, 10], 0.0125], 0.621575], ['normal control 2', [[2020, 3, 18], [2020, 9, 18], [2020, 9, 17], 0.05], 2.486301], ['normal control 3', [[2038, 8, 4], [2039, 2, 4], [2039, 2, 3], 0.05], 2.486301]], [['regression forward accrual basis 1', [[2019, 11, 1], [2020, 5, 1], [2020, 4, 27], 0.0825], 4.023288], ['regression forward accrual basis 2', [[2040, 2, 28], [2040, 8, 28], [2040, 8, 25], 0.0125], 0.613014], ['partial repair probe 1', [[2016, 8, 20], [2017, 2, 20], [2016, 8, 31], 0.05], 0.150685], ['partial repair probe 2', [[2028, 4, 2], [2028, 10, 2], [2028, 10, 1], 0.0125], 0.623288], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2021, 5, 9], [2021, 11, 9], [2021, 11, 8], 0.025], 1.243151], ['normal control 2', [[2037, 5, 1], [2037, 11, 1], [2037, 10, 31], 0.025], 1.243151], ['normal control 3', [[2027, 5, 5], [2027, 11, 5], [2027, 11, 4], 0.025], 1.243151]]]
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 forward accrual basis 14.0910964.091096Passed
regression forward accrual basis 22.4657532.465753Passed
partial repair probe 10.2938360.293836Passed
partial repair probe 20.5479450.547945Passed
boundary control 10.00.0Passed
normal control 12.4863012.486301Passed
normal control 21.2431511.243151Passed
normal control 32.4863012.486301Passed

SHA-256 / a0bf2f05b1e711e5db5ebda6e236d5aa1e7ef44217eec091adac8fe3c66fc6f2

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

Case digest / b3b05db8a0629d8abde3a84a7dd5a7be1c09b33b8ee0cdd158f76bde432679a8