FAILURE MAP
← Case archive

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

Canadian-style semi-annual accrued interest: the 183rd day still uses forward accrual · case 01

Settlements exactly 183 days into the period use the wrong formula.

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

ROOT CAUSE

The branch test uses days > 183.

VERIFIED REPAIR

Switch to the complement at 183 accrued days or more.

Unsuccessful approach: Lowering the threshold to 182 switches a day too early.

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 * days / 365
    return round(acc, 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression complement threshold 1', [[2016, 8, 1], [2017, 2, 1], [2017, 1, 31], 0.0825], 4.102397], ['regression complement threshold 2', [[2022, 7, 31], [2023, 1, 31], [2023, 1, 30], 0.0825], 4.102397], ['partial repair probe 1', [[2015, 12, 7], [2016, 6, 7], [2016, 6, 6], 0.0125], 0.623288], ['partial repair probe 2', [[2034, 3, 30], [2034, 9, 30], [2034, 9, 28], 0.0375], 1.869863], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2035, 10, 31], [2036, 4, 30], [2036, 4, 29], 0.0125], 0.619863], ['normal control 2', [[2036, 10, 12], [2037, 4, 12], [2037, 4, 11], 0.025], 1.239726], ['normal control 3', [[2039, 11, 29], [2040, 5, 29], [2040, 5, 28], 0.0375], 1.859589]], [['regression complement threshold 1', [[2016, 5, 30], [2016, 11, 30], [2016, 11, 29], 0.0825], 4.102397], ['regression complement threshold 2', [[2033, 7, 30], [2034, 1, 30], [2034, 1, 29], 0.0375], 1.864726], ['partial repair probe 1', [[2015, 12, 7], [2016, 6, 7], [2016, 6, 6], 0.025], 1.246575], ['partial repair probe 2', [[2024, 5, 28], [2024, 11, 28], [2024, 11, 26], 0.05], 2.493151], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2025, 9, 30], [2026, 3, 30], [2026, 3, 29], 0.0825], 4.068493], ['normal control 2', [[2027, 9, 6], [2028, 3, 6], [2028, 3, 5], 0.05], 2.479452], ['normal control 3', [[2039, 11, 1], [2040, 5, 1], [2040, 1, 22], 0.025], 0.561644]], [['regression complement threshold 1', [[2012, 5, 29], [2012, 11, 29], [2012, 11, 28], 0.025], 1.243151], ['regression complement threshold 2', [[2036, 7, 13], [2037, 1, 13], [2037, 1, 12], 0.025], 1.243151], ['partial repair probe 1', [[2025, 5, 14], [2025, 11, 14], [2025, 11, 12], 0.0125], 0.623288], ['partial repair probe 2', [[2011, 7, 30], [2012, 1, 30], [2012, 1, 28], 0.0375], 1.869863], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2023, 11, 28], [2024, 5, 28], [2024, 5, 27], 0.05], 2.479452], ['normal control 2', [[2032, 2, 27], [2032, 8, 27], [2032, 8, 13], 0.0825], 3.79726], ['normal control 3', [[2013, 5, 3], [2013, 11, 3], [2013, 6, 11], 0.0825], 0.881507]], [['regression complement threshold 1', [[2036, 7, 1], [2037, 1, 1], [2036, 12, 31], 0.0825], 4.102397], ['regression complement threshold 2', [[2037, 7, 27], [2038, 1, 27], [2038, 1, 26], 0.05], 2.486301], ['partial repair probe 1', [[2032, 5, 31], [2032, 11, 30], [2032, 11, 29], 0.0825], 4.113699], ['partial repair probe 2', [[2021, 5, 13], [2021, 11, 13], [2021, 11, 11], 0.05], 2.493151], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2011, 5, 30], [2011, 11, 30], [2011, 6, 10], 0.05], 0.150685], ['normal control 2', [[2021, 1, 7], [2021, 7, 7], [2021, 7, 6], 0.025], 1.232877], ['normal control 3', [[2030, 2, 27], [2030, 8, 27], [2030, 8, 26], 0.0125], 0.616438]], [['regression complement threshold 1', [[2016, 3, 2], [2016, 9, 2], [2016, 9, 1], 0.0825], 4.102397], ['regression complement threshold 2', [[2017, 5, 30], [2017, 11, 30], [2017, 11, 29], 0.05], 2.486301], ['partial repair probe 1', [[2014, 6, 11], [2014, 12, 11], [2014, 12, 10], 0.0125], 0.623288], ['partial repair probe 2', [[2029, 3, 23], [2029, 9, 23], [2029, 9, 21], 0.0825], 4.113699], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2031, 11, 28], [2032, 5, 28], [2032, 5, 27], 0.0375], 1.859589], ['normal control 2', [[2018, 9, 9], [2019, 3, 9], [2019, 3, 6], 0.0125], 0.609589], ['normal control 3', [[2015, 2, 18], [2015, 8, 18], [2015, 8, 17], 0.025], 1.232877]]]
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 complement threshold 14.1363014.102397Failed
regression complement threshold 24.1363014.102397Failed
partial repair probe 10.6232880.623288Passed
partial repair probe 21.8698631.869863Passed
boundary control 10.00.0Passed
normal control 10.6198630.619863Passed
normal control 21.2397261.239726Passed
normal control 31.8595891.859589Passed

SHA-256 / 78f390c015e468d66feb7867992bae6472cdc1a7ae04b1977f91e4ddf364cbd3

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 >= 182:
        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 complement threshold 1', [[2016, 8, 1], [2017, 2, 1], [2017, 1, 31], 0.0825], 4.102397], ['regression complement threshold 2', [[2022, 7, 31], [2023, 1, 31], [2023, 1, 30], 0.0825], 4.102397], ['partial repair probe 1', [[2015, 12, 7], [2016, 6, 7], [2016, 6, 6], 0.0125], 0.623288], ['partial repair probe 2', [[2034, 3, 30], [2034, 9, 30], [2034, 9, 28], 0.0375], 1.869863], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2035, 10, 31], [2036, 4, 30], [2036, 4, 29], 0.0125], 0.619863], ['normal control 2', [[2036, 10, 12], [2037, 4, 12], [2037, 4, 11], 0.025], 1.239726], ['normal control 3', [[2039, 11, 29], [2040, 5, 29], [2040, 5, 28], 0.0375], 1.859589]], [['regression complement threshold 1', [[2016, 5, 30], [2016, 11, 30], [2016, 11, 29], 0.0825], 4.102397], ['regression complement threshold 2', [[2033, 7, 30], [2034, 1, 30], [2034, 1, 29], 0.0375], 1.864726], ['partial repair probe 1', [[2015, 12, 7], [2016, 6, 7], [2016, 6, 6], 0.025], 1.246575], ['partial repair probe 2', [[2024, 5, 28], [2024, 11, 28], [2024, 11, 26], 0.05], 2.493151], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2025, 9, 30], [2026, 3, 30], [2026, 3, 29], 0.0825], 4.068493], ['normal control 2', [[2027, 9, 6], [2028, 3, 6], [2028, 3, 5], 0.05], 2.479452], ['normal control 3', [[2039, 11, 1], [2040, 5, 1], [2040, 1, 22], 0.025], 0.561644]], [['regression complement threshold 1', [[2012, 5, 29], [2012, 11, 29], [2012, 11, 28], 0.025], 1.243151], ['regression complement threshold 2', [[2036, 7, 13], [2037, 1, 13], [2037, 1, 12], 0.025], 1.243151], ['partial repair probe 1', [[2025, 5, 14], [2025, 11, 14], [2025, 11, 12], 0.0125], 0.623288], ['partial repair probe 2', [[2011, 7, 30], [2012, 1, 30], [2012, 1, 28], 0.0375], 1.869863], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2023, 11, 28], [2024, 5, 28], [2024, 5, 27], 0.05], 2.479452], ['normal control 2', [[2032, 2, 27], [2032, 8, 27], [2032, 8, 13], 0.0825], 3.79726], ['normal control 3', [[2013, 5, 3], [2013, 11, 3], [2013, 6, 11], 0.0825], 0.881507]], [['regression complement threshold 1', [[2036, 7, 1], [2037, 1, 1], [2036, 12, 31], 0.0825], 4.102397], ['regression complement threshold 2', [[2037, 7, 27], [2038, 1, 27], [2038, 1, 26], 0.05], 2.486301], ['partial repair probe 1', [[2032, 5, 31], [2032, 11, 30], [2032, 11, 29], 0.0825], 4.113699], ['partial repair probe 2', [[2021, 5, 13], [2021, 11, 13], [2021, 11, 11], 0.05], 2.493151], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2011, 5, 30], [2011, 11, 30], [2011, 6, 10], 0.05], 0.150685], ['normal control 2', [[2021, 1, 7], [2021, 7, 7], [2021, 7, 6], 0.025], 1.232877], ['normal control 3', [[2030, 2, 27], [2030, 8, 27], [2030, 8, 26], 0.0125], 0.616438]], [['regression complement threshold 1', [[2016, 3, 2], [2016, 9, 2], [2016, 9, 1], 0.0825], 4.102397], ['regression complement threshold 2', [[2017, 5, 30], [2017, 11, 30], [2017, 11, 29], 0.05], 2.486301], ['partial repair probe 1', [[2014, 6, 11], [2014, 12, 11], [2014, 12, 10], 0.0125], 0.623288], ['partial repair probe 2', [[2029, 3, 23], [2029, 9, 23], [2029, 9, 21], 0.0825], 4.113699], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2031, 11, 28], [2032, 5, 28], [2032, 5, 27], 0.0375], 1.859589], ['normal control 2', [[2018, 9, 9], [2019, 3, 9], [2019, 3, 6], 0.0125], 0.609589], ['normal control 3', [[2015, 2, 18], [2015, 8, 18], [2015, 8, 17], 0.025], 1.232877]]]
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 complement threshold 14.1023974.102397Passed
regression complement threshold 24.1023974.102397Passed
partial repair probe 10.6215750.623288Failed
partial repair probe 21.8544521.869863Failed
boundary control 10.00.0Passed
normal control 10.6198630.619863Passed
normal control 21.2397261.239726Passed
normal control 31.8595891.859589Passed

SHA-256 / 40f8627fe841f8257813472a6fa8ed9a651eddd634fe2235098a0e398e44b712

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 complement threshold 1', [[2016, 8, 1], [2017, 2, 1], [2017, 1, 31], 0.0825], 4.102397], ['regression complement threshold 2', [[2022, 7, 31], [2023, 1, 31], [2023, 1, 30], 0.0825], 4.102397], ['partial repair probe 1', [[2015, 12, 7], [2016, 6, 7], [2016, 6, 6], 0.0125], 0.623288], ['partial repair probe 2', [[2034, 3, 30], [2034, 9, 30], [2034, 9, 28], 0.0375], 1.869863], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2035, 10, 31], [2036, 4, 30], [2036, 4, 29], 0.0125], 0.619863], ['normal control 2', [[2036, 10, 12], [2037, 4, 12], [2037, 4, 11], 0.025], 1.239726], ['normal control 3', [[2039, 11, 29], [2040, 5, 29], [2040, 5, 28], 0.0375], 1.859589]], [['regression complement threshold 1', [[2016, 5, 30], [2016, 11, 30], [2016, 11, 29], 0.0825], 4.102397], ['regression complement threshold 2', [[2033, 7, 30], [2034, 1, 30], [2034, 1, 29], 0.0375], 1.864726], ['partial repair probe 1', [[2015, 12, 7], [2016, 6, 7], [2016, 6, 6], 0.025], 1.246575], ['partial repair probe 2', [[2024, 5, 28], [2024, 11, 28], [2024, 11, 26], 0.05], 2.493151], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2025, 9, 30], [2026, 3, 30], [2026, 3, 29], 0.0825], 4.068493], ['normal control 2', [[2027, 9, 6], [2028, 3, 6], [2028, 3, 5], 0.05], 2.479452], ['normal control 3', [[2039, 11, 1], [2040, 5, 1], [2040, 1, 22], 0.025], 0.561644]], [['regression complement threshold 1', [[2012, 5, 29], [2012, 11, 29], [2012, 11, 28], 0.025], 1.243151], ['regression complement threshold 2', [[2036, 7, 13], [2037, 1, 13], [2037, 1, 12], 0.025], 1.243151], ['partial repair probe 1', [[2025, 5, 14], [2025, 11, 14], [2025, 11, 12], 0.0125], 0.623288], ['partial repair probe 2', [[2011, 7, 30], [2012, 1, 30], [2012, 1, 28], 0.0375], 1.869863], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2023, 11, 28], [2024, 5, 28], [2024, 5, 27], 0.05], 2.479452], ['normal control 2', [[2032, 2, 27], [2032, 8, 27], [2032, 8, 13], 0.0825], 3.79726], ['normal control 3', [[2013, 5, 3], [2013, 11, 3], [2013, 6, 11], 0.0825], 0.881507]], [['regression complement threshold 1', [[2036, 7, 1], [2037, 1, 1], [2036, 12, 31], 0.0825], 4.102397], ['regression complement threshold 2', [[2037, 7, 27], [2038, 1, 27], [2038, 1, 26], 0.05], 2.486301], ['partial repair probe 1', [[2032, 5, 31], [2032, 11, 30], [2032, 11, 29], 0.0825], 4.113699], ['partial repair probe 2', [[2021, 5, 13], [2021, 11, 13], [2021, 11, 11], 0.05], 2.493151], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2011, 5, 30], [2011, 11, 30], [2011, 6, 10], 0.05], 0.150685], ['normal control 2', [[2021, 1, 7], [2021, 7, 7], [2021, 7, 6], 0.025], 1.232877], ['normal control 3', [[2030, 2, 27], [2030, 8, 27], [2030, 8, 26], 0.0125], 0.616438]], [['regression complement threshold 1', [[2016, 3, 2], [2016, 9, 2], [2016, 9, 1], 0.0825], 4.102397], ['regression complement threshold 2', [[2017, 5, 30], [2017, 11, 30], [2017, 11, 29], 0.05], 2.486301], ['partial repair probe 1', [[2014, 6, 11], [2014, 12, 11], [2014, 12, 10], 0.0125], 0.623288], ['partial repair probe 2', [[2029, 3, 23], [2029, 9, 23], [2029, 9, 21], 0.0825], 4.113699], ['boundary control 1', [[2024, 1, 1], [2024, 7, 1], [2024, 1, 1], 0.05], 0.0], ['normal control 1', [[2031, 11, 28], [2032, 5, 28], [2032, 5, 27], 0.0375], 1.859589], ['normal control 2', [[2018, 9, 9], [2019, 3, 9], [2019, 3, 6], 0.0125], 0.609589], ['normal control 3', [[2015, 2, 18], [2015, 8, 18], [2015, 8, 17], 0.025], 1.232877]]]
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 complement threshold 14.1023974.102397Passed
regression complement threshold 24.1023974.102397Passed
partial repair probe 10.6232880.623288Passed
partial repair probe 21.8698631.869863Passed
boundary control 10.00.0Passed
normal control 10.6198630.619863Passed
normal control 21.2397261.239726Passed
normal control 31.8595891.859589Passed

SHA-256 / 8072e06f20147dcb76db4e3b228aca9276ffedbefd5210e6b12e0885218602a9

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

Case digest / 11a9deb2b20f1fcc4f96067a16c29040aac84041926d9a5dd3c1b960d808f7f3