FA-84656 / Betting odds conversion / Open access
Withdrawn price on a band limit takes the next band · case 01
A withdrawn 2.50 shot yields a 35p deduction instead of 40p.
ROOT CAUSE
The band test uses p < limit.
VERIFIED REPAIR
A price equal to a band limit belongs to that band.
Unsuccessful approach: Looking up the last band whose limit is at or below the price is off by one band.
Case contract
Non-runner deduction for a winning bet. Each withdrawn runner's decimal price maps to pence-in-the-pound from the first band whose limit it does not exceed: [('1.30', 75), ('1.40', 70), ('1.53', 65), ('1.62', 60), ('1.80', 55), ('1.95', 50), ('2.20', 45), ('2.50', 40), ('2.75', 35), ('3.25', 30), ('4.00', 25), ('5.00', 20), ('6.50', 15), ('10.00', 10), ('15.00', 5)]; above 15.00 it is 0. Deductions from several withdrawals are summed and capped at 75. The deduction applies to winnings only: return = stake + floor(stake * (price - 1) * (100 - deduction) / 100). Return [deduction, return cents].
Why this case matters
Racing settlement reduces winnings when a runner is withdrawn after prices were struck.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(stake_cents, price, withdrawn):
TABLE = [('1.30', 75), ('1.40', 70), ('1.53', 65), ('1.62', 60), ('1.80', 55), ('1.95', 50), ('2.20', 45), ('2.50', 40), ('2.75', 35), ('3.25', 30), ('4.00', 25), ('5.00', 20), ('6.50', 15), ('10.00', 10), ('15.00', 5)]
def ded(p):
p = Fraction(p)
for limit, pence in TABLE:
if p < Fraction(limit):
return pence
return 0
total = min(75, sum(ded(w) for w in withdrawn))
profit = stake_cents * (Fraction(price) - 1)
return [total, stake_cents + math.floor(profit * (100 - total) / 100)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
try:
return solve(*args)
except Exception as exc:
return 'raised ' + type(exc).__name__
cases = [[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '7.06', ['12.59', '11.90', '14.46']), [15, 1537]),
('regression: band limit inclusive', (250, '4.38', ['13.48', '1.53', '13.32']), [75, 461]),
('variant scenario 1', (250, '6.38', ['11.94', '1.40', '1.95']), [75, 586]),
('variant scenario 2', (250, '9.32', ['14.14']), [5, 2226])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '7.26', ['12.22', '5.00']), [25, 1423]),
('variant scenario 1', (500, '10.70', ['2.20']), [45, 3167]),
('variant scenario 2', (1000, '4.24', []), [0, 4240])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (500, '3.32', ['7.59']), [10, 1544]),
('regression: band limit inclusive', (500, '5.82', ['6.50', '4.00']), [40, 1946]),
('variant scenario 1', (250, '7.03', []), [0, 1757]),
('variant scenario 2', (250, '8.15', ['16.13']), [0, 2037])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (1000, '7.86', ['15.00', '16.53', '5.00']), [25, 6145]),
('variant scenario 1', (500, '6.13', []), [0, 3065]),
('variant scenario 2', (250, '10.38', ['9.25', '2.20']), [55, 1305])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '6.56', ['4.63']), [20, 1362]),
('regression: band limit inclusive', (250, '7.41', ['1.40']), [70, 730]),
('variant scenario 1', (1000, '4.49', []), [0, 4490]),
('variant scenario 2', (500, '7.05', []), [0, 3525])]]
for label, args, expected in cases[N - 1]:
check(label, run(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 |
|---|---|---|---|
| control no withdrawal | [0, 5000] | [0, 5000] | Passed |
| boundary price on band limit | [35, 3600] | [40, 3400] | Failed |
| control long-shot withdrawal | [0, 5000] | [0, 5000] | Passed |
| boundary cap at 75 | [75, 1500] | [75, 1500] | Passed |
| control two withdrawals | [35, 2300] | [40, 2200] | Failed |
| regression: band limit inclusive | [15, 1537] | [15, 1537] | Passed |
| regression: band limit inclusive | [70, 503] | [75, 461] | Failed |
| variant scenario 1 | [75, 586] | [75, 586] | Passed |
| variant scenario 2 | [5, 2226] | [5, 2226] | Passed |
SHA-256 / 8b9b71315a9f564d06ab638793369d81b3023ae68e3a5f3c7ef3353e283f2f22
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(stake_cents, price, withdrawn):
TABLE = [('1.30', 75), ('1.40', 70), ('1.53', 65), ('1.62', 60), ('1.80', 55), ('1.95', 50), ('2.20', 45), ('2.50', 40), ('2.75', 35), ('3.25', 30), ('4.00', 25), ('5.00', 20), ('6.50', 15), ('10.00', 10), ('15.00', 5)]
def ded(p):
p = Fraction(p)
for limit, pence in reversed(TABLE):
if p >= Fraction(limit):
return pence
return 0
total = min(75, sum(ded(w) for w in withdrawn))
profit = stake_cents * (Fraction(price) - 1)
return [total, stake_cents + math.floor(profit * (100 - total) / 100)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
try:
return solve(*args)
except Exception as exc:
return 'raised ' + type(exc).__name__
cases = [[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '7.06', ['12.59', '11.90', '14.46']), [15, 1537]),
('regression: band limit inclusive', (250, '4.38', ['13.48', '1.53', '13.32']), [75, 461]),
('variant scenario 1', (250, '6.38', ['11.94', '1.40', '1.95']), [75, 586]),
('variant scenario 2', (250, '9.32', ['14.14']), [5, 2226])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '7.26', ['12.22', '5.00']), [25, 1423]),
('variant scenario 1', (500, '10.70', ['2.20']), [45, 3167]),
('variant scenario 2', (1000, '4.24', []), [0, 4240])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (500, '3.32', ['7.59']), [10, 1544]),
('regression: band limit inclusive', (500, '5.82', ['6.50', '4.00']), [40, 1946]),
('variant scenario 1', (250, '7.03', []), [0, 1757]),
('variant scenario 2', (250, '8.15', ['16.13']), [0, 2037])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (1000, '7.86', ['15.00', '16.53', '5.00']), [25, 6145]),
('variant scenario 1', (500, '6.13', []), [0, 3065]),
('variant scenario 2', (250, '10.38', ['9.25', '2.20']), [55, 1305])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '6.56', ['4.63']), [20, 1362]),
('regression: band limit inclusive', (250, '7.41', ['1.40']), [70, 730]),
('variant scenario 1', (1000, '4.49', []), [0, 4490]),
('variant scenario 2', (500, '7.05', []), [0, 3525])]]
for label, args, expected in cases[N - 1]:
check(label, run(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 |
|---|---|---|---|
| control no withdrawal | [0, 5000] | [0, 5000] | Passed |
| boundary price on band limit | [40, 3400] | [40, 3400] | Passed |
| control long-shot withdrawal | [5, 4800] | [0, 5000] | Failed |
| boundary cap at 75 | [75, 1500] | [75, 1500] | Passed |
| control two withdrawals | [45, 2100] | [40, 2200] | Failed |
| regression: band limit inclusive | [30, 1310] | [15, 1537] | Failed |
| regression: band limit inclusive | [75, 461] | [75, 461] | Passed |
| variant scenario 1 | [75, 586] | [75, 586] | Passed |
| variant scenario 2 | [10, 2122] | [5, 2226] | Failed |
SHA-256 / 461f3feefd111a1bc90e27e17c31fce402b6cdadb8e29353895c537c0f042ec7
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(stake_cents, price, withdrawn):
TABLE = [('1.30', 75), ('1.40', 70), ('1.53', 65), ('1.62', 60), ('1.80', 55), ('1.95', 50), ('2.20', 45), ('2.50', 40), ('2.75', 35), ('3.25', 30), ('4.00', 25), ('5.00', 20), ('6.50', 15), ('10.00', 10), ('15.00', 5)]
def ded(p):
p = Fraction(p)
for limit, pence in TABLE:
if p <= Fraction(limit):
return pence
return 0
total = min(75, sum(ded(w) for w in withdrawn))
profit = stake_cents * (Fraction(price) - 1)
return [total, stake_cents + math.floor(profit * (100 - total) / 100)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
def run(args):
try:
return solve(*args)
except Exception as exc:
return 'raised ' + type(exc).__name__
cases = [[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '7.06', ['12.59', '11.90', '14.46']), [15, 1537]),
('regression: band limit inclusive', (250, '4.38', ['13.48', '1.53', '13.32']), [75, 461]),
('variant scenario 1', (250, '6.38', ['11.94', '1.40', '1.95']), [75, 586]),
('variant scenario 2', (250, '9.32', ['14.14']), [5, 2226])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '7.26', ['12.22', '5.00']), [25, 1423]),
('variant scenario 1', (500, '10.70', ['2.20']), [45, 3167]),
('variant scenario 2', (1000, '4.24', []), [0, 4240])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (500, '3.32', ['7.59']), [10, 1544]),
('regression: band limit inclusive', (500, '5.82', ['6.50', '4.00']), [40, 1946]),
('variant scenario 1', (250, '7.03', []), [0, 1757]),
('variant scenario 2', (250, '8.15', ['16.13']), [0, 2037])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (1000, '7.86', ['15.00', '16.53', '5.00']), [25, 6145]),
('variant scenario 1', (500, '6.13', []), [0, 3065]),
('variant scenario 2', (250, '10.38', ['9.25', '2.20']), [55, 1305])],
[('control no withdrawal', (1000, '5.00', []), [0, 5000]),
('boundary price on band limit', (1000, '5.00', ['2.50']), [40, 3400]),
('control long-shot withdrawal', (1000, '5.00', ['21.00']), [0, 5000]),
('boundary cap at 75', (1000, '3.00', ['1.50', '1.50']), [75, 1500]),
('control two withdrawals', (1000, '3.00', ['4.00', '6.00']), [40, 2200]),
('regression: band limit inclusive', (250, '6.56', ['4.63']), [20, 1362]),
('regression: band limit inclusive', (250, '7.41', ['1.40']), [70, 730]),
('variant scenario 1', (1000, '4.49', []), [0, 4490]),
('variant scenario 2', (500, '7.05', []), [0, 3525])]]
for label, args, expected in cases[N - 1]:
check(label, run(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 |
|---|---|---|---|
| control no withdrawal | [0, 5000] | [0, 5000] | Passed |
| boundary price on band limit | [40, 3400] | [40, 3400] | Passed |
| control long-shot withdrawal | [0, 5000] | [0, 5000] | Passed |
| boundary cap at 75 | [75, 1500] | [75, 1500] | Passed |
| control two withdrawals | [40, 2200] | [40, 2200] | Passed |
| regression: band limit inclusive | [15, 1537] | [15, 1537] | Passed |
| regression: band limit inclusive | [75, 461] | [75, 461] | Passed |
| variant scenario 1 | [75, 586] | [75, 586] | Passed |
| variant scenario 2 | [5, 2226] | [5, 2226] | Passed |
SHA-256 / f86ea0ea282273eff08d44156b19ecd51ff71f8c81bb2a1f7f19670d306213e3
Verification & scope
Stipulated, bounded toy contract stated in the contract field; not a claim of conformance with any operator, exchange or regulator rule set. 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:50:33.069451+00:00.
Case digest / adb96e68c00f19e1f2ac13f841af2485de5673587decc11d0e78e726e9301dc8