FAILURE MAP
← Case archive

FA-84696 / Betting odds conversion / Open access

Settled winning leg dropped from the cash-out value · case 01

A multiple with a leg already won is valued as if that leg did not exist.

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

ROOT CAUSE

Won legs skip the multiplication by the price taken.

VERIFIED REPAIR

Multiply by the price taken for won legs and do not divide by anything.

Unsuccessful approach: Multiplying won legs by their profit only undervalues them.

Case contract

Cash-out offer for a single or multiple back bet. legs rows are [price taken, current] where current is a decimal price for an open leg, "won" or "lost". Any lost leg makes the offer [0, 0]. Otherwise value = stake * product of prices taken / product of current prices of open legs, reduced by margin_pct percent, rounded down to a cent. partial_cents 0 means full cash-out: return [value, 0]. A partial amount above the value returns "invalid"; otherwise return [partial, remaining stake] with remaining = floor(stake * (1 - partial / value)).

Why this case matters

Cash-out and partial cash-out offers are recomputed from live prices on every tick.

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(legs, stake_cents, margin_pct, partial_cents):
    value = Fraction(stake_cents)
    for price, cur in legs:
        if cur == 'lost':
            return [0, 0]
        if cur == 'won':
            continue
        value *= Fraction(price)
        if cur != 'won':
            value /= Fraction(cur)
    value = value * (100 - Fraction(margin_pct)) / 100
    full = math.floor(value)
    if partial_cents == 0:
        return [full, 0]
    if partial_cents > full:
        return 'invalid'
    remaining = math.floor(stake_cents * (1 - Fraction(partial_cents, full)))
    return [partial_cents, remaining]
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 single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['2.34', 'won'], ['2.34', 'won']], 1000, '0', 200), [200, 963]),
  ('variant scenario 1', ([['3.31', '1.25']], 1000, '7.5', 200), [200, 918]),
  ('variant scenario 2', ([['1.52', 'lost'], ['4.56', '2.64']], 1000, '7.5', 500), [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['3.22', 'won']], 500, '5', 0), [1529, 0]),
  ('variant scenario 1',
   ([['4.04', '1.83'], ['1.86', '2.30'], ['1.41', 'lost']], 2500, '5', 0),
   [0, 0]),
  ('variant scenario 2',
   ([['4.07', 'lost'], ['1.73', '4.97'], ['4.67', 'won'], ['1.95', 'won']], 1000, '5', 0),
   [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['1.96', 'won'], ['4.86', 'won']], 500, '7.5', 500), [500, 443]),
  ('variant scenario 1', ([['3.99', 'won'], ['3.43', 'lost']], 1000, '0', 800), [0, 0]),
  ('variant scenario 2',
   ([['2.83', '3.24'], ['4.46', '3.35'], ['3.41', 'won'], ['4.39', '5.31']], 2500, '0', 800),
   [800, 2255])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['1.88', '2.96'], ['4.98', 'won']], 500, '0', 0), [1581, 0]),
  ('variant scenario 1',
   ([['3.69', '3.54'], ['2.84', '5.65'], ['1.59', 'lost']], 2500, '7.5', 0),
   [0, 0]),
  ('variant scenario 2',
   ([['3.74', '3.53'], ['4.23', 'lost'], ['3.97', 'won'], ['2.51', 'lost']], 2500, '5', 800),
   [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg',
   ([['2.64', 'won'], ['3.03', '3.29'], ['4.82', '4.42'], ['3.27', '4.34']], 2500, '5', 800),
   [800, 2078]),
  ('variant scenario 1',
   ([['2.27', 'lost'], ['3.11', '2.62'], ['2.35', '5.79'], ['2.20', '1.56']], 1000, '5', 0),
   [0, 0]),
  ('variant scenario 2', ([['3.88', '4.62'], ['1.58', 'lost']], 2500, '7.5', 0), [0, 0])]]
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 fixtureActualExpectedOutcome
control single shortened[1500, 0][1500, 0]Passed
control margin applied[1425, 0][1425, 0]Passed
boundary won leg keeps price[1333, 0][2666, 0]Failed
boundary partial cash out[500, 666][500, 666]Passed
control lost leg[0, 0][0, 0]Passed
boundary partial above valueinvalidinvalidPassed
regression: settled leg[200, 800][200, 963]Failed
variant scenario 1[200, 918][200, 918]Passed
variant scenario 2[0, 0][0, 0]Passed

SHA-256 / 13e865b330c60f1119d49af52f6edc1a23e12164639aae369858cca7fa655c3f

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(legs, stake_cents, margin_pct, partial_cents):
    value = Fraction(stake_cents)
    for price, cur in legs:
        if cur == 'lost':
            return [0, 0]
        value *= Fraction(price) - (1 if cur == 'won' else 0)
        if cur != 'won':
            value /= Fraction(cur)
    value = value * (100 - Fraction(margin_pct)) / 100
    full = math.floor(value)
    if partial_cents == 0:
        return [full, 0]
    if partial_cents > full:
        return 'invalid'
    remaining = math.floor(stake_cents * (1 - Fraction(partial_cents, full)))
    return [partial_cents, remaining]
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 single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['2.34', 'won'], ['2.34', 'won']], 1000, '0', 200), [200, 963]),
  ('variant scenario 1', ([['3.31', '1.25']], 1000, '7.5', 200), [200, 918]),
  ('variant scenario 2', ([['1.52', 'lost'], ['4.56', '2.64']], 1000, '7.5', 500), [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['3.22', 'won']], 500, '5', 0), [1529, 0]),
  ('variant scenario 1',
   ([['4.04', '1.83'], ['1.86', '2.30'], ['1.41', 'lost']], 2500, '5', 0),
   [0, 0]),
  ('variant scenario 2',
   ([['4.07', 'lost'], ['1.73', '4.97'], ['4.67', 'won'], ['1.95', 'won']], 1000, '5', 0),
   [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['1.96', 'won'], ['4.86', 'won']], 500, '7.5', 500), [500, 443]),
  ('variant scenario 1', ([['3.99', 'won'], ['3.43', 'lost']], 1000, '0', 800), [0, 0]),
  ('variant scenario 2',
   ([['2.83', '3.24'], ['4.46', '3.35'], ['3.41', 'won'], ['4.39', '5.31']], 2500, '0', 800),
   [800, 2255])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['1.88', '2.96'], ['4.98', 'won']], 500, '0', 0), [1581, 0]),
  ('variant scenario 1',
   ([['3.69', '3.54'], ['2.84', '5.65'], ['1.59', 'lost']], 2500, '7.5', 0),
   [0, 0]),
  ('variant scenario 2',
   ([['3.74', '3.53'], ['4.23', 'lost'], ['3.97', 'won'], ['2.51', 'lost']], 2500, '5', 800),
   [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg',
   ([['2.64', 'won'], ['3.03', '3.29'], ['4.82', '4.42'], ['3.27', '4.34']], 2500, '5', 800),
   [800, 2078]),
  ('variant scenario 1',
   ([['2.27', 'lost'], ['3.11', '2.62'], ['2.35', '5.79'], ['2.20', '1.56']], 1000, '5', 0),
   [0, 0]),
  ('variant scenario 2', ([['3.88', '4.62'], ['1.58', 'lost']], 2500, '7.5', 0), [0, 0])]]
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 fixtureActualExpectedOutcome
control single shortened[1500, 0][1500, 0]Passed
control margin applied[1425, 0][1425, 0]Passed
boundary won leg keeps price[1333, 0][2666, 0]Failed
boundary partial cash out[500, 666][500, 666]Passed
control lost leg[0, 0][0, 0]Passed
boundary partial above valueinvalidinvalidPassed
regression: settled leg[200, 888][200, 963]Failed
variant scenario 1[200, 918][200, 918]Passed
variant scenario 2[0, 0][0, 0]Passed

SHA-256 / a858f242b5ddc8c26ecc852696ef9be7e5d34f89739b1d37cc5cdd1efcd8a02d

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(legs, stake_cents, margin_pct, partial_cents):
    value = Fraction(stake_cents)
    for price, cur in legs:
        if cur == 'lost':
            return [0, 0]
        value *= Fraction(price)
        if cur != 'won':
            value /= Fraction(cur)
    value = value * (100 - Fraction(margin_pct)) / 100
    full = math.floor(value)
    if partial_cents == 0:
        return [full, 0]
    if partial_cents > full:
        return 'invalid'
    remaining = math.floor(stake_cents * (1 - Fraction(partial_cents, full)))
    return [partial_cents, remaining]
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 single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['2.34', 'won'], ['2.34', 'won']], 1000, '0', 200), [200, 963]),
  ('variant scenario 1', ([['3.31', '1.25']], 1000, '7.5', 200), [200, 918]),
  ('variant scenario 2', ([['1.52', 'lost'], ['4.56', '2.64']], 1000, '7.5', 500), [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['3.22', 'won']], 500, '5', 0), [1529, 0]),
  ('variant scenario 1',
   ([['4.04', '1.83'], ['1.86', '2.30'], ['1.41', 'lost']], 2500, '5', 0),
   [0, 0]),
  ('variant scenario 2',
   ([['4.07', 'lost'], ['1.73', '4.97'], ['4.67', 'won'], ['1.95', 'won']], 1000, '5', 0),
   [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['1.96', 'won'], ['4.86', 'won']], 500, '7.5', 500), [500, 443]),
  ('variant scenario 1', ([['3.99', 'won'], ['3.43', 'lost']], 1000, '0', 800), [0, 0]),
  ('variant scenario 2',
   ([['2.83', '3.24'], ['4.46', '3.35'], ['3.41', 'won'], ['4.39', '5.31']], 2500, '0', 800),
   [800, 2255])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg', ([['1.88', '2.96'], ['4.98', 'won']], 500, '0', 0), [1581, 0]),
  ('variant scenario 1',
   ([['3.69', '3.54'], ['2.84', '5.65'], ['1.59', 'lost']], 2500, '7.5', 0),
   [0, 0]),
  ('variant scenario 2',
   ([['3.74', '3.53'], ['4.23', 'lost'], ['3.97', 'won'], ['2.51', 'lost']], 2500, '5', 800),
   [0, 0])],
 [('control single shortened', ([['3.00', '2.00']], 1000, '0', 0), [1500, 0]),
  ('control margin applied', ([['3.00', '2.00']], 1000, '5', 0), [1425, 0]),
  ('boundary won leg keeps price', ([['2.00', 'won'], ['2.00', '1.50']], 1000, '0', 0), [2666, 0]),
  ('boundary partial cash out', ([['3.00', '2.00']], 1000, '0', 500), [500, 666]),
  ('control lost leg', ([['2.00', 'lost'], ['2.00', '1.50']], 1000, '0', 0), [0, 0]),
  ('boundary partial above value', ([['2.00', '4.00']], 1000, '0', 600), 'invalid'),
  ('regression: settled leg',
   ([['2.64', 'won'], ['3.03', '3.29'], ['4.82', '4.42'], ['3.27', '4.34']], 2500, '5', 800),
   [800, 2078]),
  ('variant scenario 1',
   ([['2.27', 'lost'], ['3.11', '2.62'], ['2.35', '5.79'], ['2.20', '1.56']], 1000, '5', 0),
   [0, 0]),
  ('variant scenario 2', ([['3.88', '4.62'], ['1.58', 'lost']], 2500, '7.5', 0), [0, 0])]]
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 fixtureActualExpectedOutcome
control single shortened[1500, 0][1500, 0]Passed
control margin applied[1425, 0][1425, 0]Passed
boundary won leg keeps price[2666, 0][2666, 0]Passed
boundary partial cash out[500, 666][500, 666]Passed
control lost leg[0, 0][0, 0]Passed
boundary partial above valueinvalidinvalidPassed
regression: settled leg[200, 963][200, 963]Passed
variant scenario 1[200, 918][200, 918]Passed
variant scenario 2[0, 0][0, 0]Passed

SHA-256 / e7a5edc7d506e917ad67b50569dff3ffae7e538fb8a6ba5495eee4b39cc4afbe

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

Case digest / 5cd5e3d2270babcca244f2ca270f6cf18aec7619c4d14fe2be8ab57776c91bd7