FA-84706 / Betting odds conversion / Open access
Partial cash-out leaves the wrong remaining stake · case 01
After cashing out half the value, the remaining stake is the cashed portion or the stake minus cents.
ROOT CAUSE
The remaining stake is computed as stake minus the cashed amount.
VERIFIED REPAIR
Reduce the stake by the cashed fraction of the value.
Unsuccessful approach: Using the cashed proportion instead of the remaining proportion swaps the two parts.
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]
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 = stake_cents - partial_cents
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: partial remaining stake', ([['2.79', 'won']], 500, '5', 800), [800, 198]),
('variant scenario 1',
([['1.51', 'won'], ['3.49', 'won'], ['3.39', 'lost'], ['1.99', 'won']], 500, '7.5', 0),
[0, 0]),
('variant scenario 2',
([['3.71', 'lost'], ['1.47', '4.60'], ['1.32', 'won'], ['1.57', '2.91']], 1000, '5', 200),
[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: partial remaining stake',
([['3.43', '4.22'], ['4.58', 'won'], ['2.70', 'won']], 1000, '5', 500),
[500, 947]),
('variant scenario 1', ([['5.00', '5.10']], 500, '0', 0), [490, 0]),
('variant scenario 2',
([['4.09', '4.06'], ['1.44', 'lost'], ['4.51', '1.56'], ['4.68', 'won']], 1000, '0', 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: partial remaining stake', ([['3.79', '2.66']], 1000, '7.5', 500), [500, 620]),
('variant scenario 1', ([['4.71', 'won']], 1000, '0', 0), [4710, 0]),
('variant scenario 2', ([['1.46', '1.60']], 500, '5', 500), 'invalid')],
[('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: partial remaining stake',
([['3.65', 'won'], ['2.14', '1.31'], ['2.44', '2.91']], 1000, '5', 500),
[500, 894]),
('variant scenario 1',
([['3.39', 'won'], ['2.49', '5.36'], ['1.49', '4.00'], ['3.15', '5.06']], 2500, '5', 0),
[867, 0]),
('variant scenario 2', ([['2.52', 'lost'], ['4.68', '4.00']], 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: partial remaining stake', ([['4.93', 'won']], 2500, '5', 500), [500, 2393]),
('variant scenario 1',
([['3.53', '1.91'], ['3.32', 'lost'], ['1.63', 'won'], ['2.97', '4.57']], 500, '0', 500),
[0, 0]),
('variant scenario 2', ([['2.73', 'won'], ['2.11', '4.03']], 1000, '0', 0), [1429, 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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, 500] | [500, 666] | Failed |
| control lost leg | [0, 0] | [0, 0] | Passed |
| boundary partial above value | invalid | invalid | Passed |
| regression: partial remaining stake | [800, -300] | [800, 198] | Failed |
| variant scenario 1 | [0, 0] | [0, 0] | Passed |
| variant scenario 2 | [0, 0] | [0, 0] | Passed |
SHA-256 / 3f0213d417d3bb65b230cdf24b360a97ff42082fd2ce223d80ab528dd47b6c8e
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)
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 * 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: partial remaining stake', ([['2.79', 'won']], 500, '5', 800), [800, 198]),
('variant scenario 1',
([['1.51', 'won'], ['3.49', 'won'], ['3.39', 'lost'], ['1.99', 'won']], 500, '7.5', 0),
[0, 0]),
('variant scenario 2',
([['3.71', 'lost'], ['1.47', '4.60'], ['1.32', 'won'], ['1.57', '2.91']], 1000, '5', 200),
[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: partial remaining stake',
([['3.43', '4.22'], ['4.58', 'won'], ['2.70', 'won']], 1000, '5', 500),
[500, 947]),
('variant scenario 1', ([['5.00', '5.10']], 500, '0', 0), [490, 0]),
('variant scenario 2',
([['4.09', '4.06'], ['1.44', 'lost'], ['4.51', '1.56'], ['4.68', 'won']], 1000, '0', 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: partial remaining stake', ([['3.79', '2.66']], 1000, '7.5', 500), [500, 620]),
('variant scenario 1', ([['4.71', 'won']], 1000, '0', 0), [4710, 0]),
('variant scenario 2', ([['1.46', '1.60']], 500, '5', 500), 'invalid')],
[('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: partial remaining stake',
([['3.65', 'won'], ['2.14', '1.31'], ['2.44', '2.91']], 1000, '5', 500),
[500, 894]),
('variant scenario 1',
([['3.39', 'won'], ['2.49', '5.36'], ['1.49', '4.00'], ['3.15', '5.06']], 2500, '5', 0),
[867, 0]),
('variant scenario 2', ([['2.52', 'lost'], ['4.68', '4.00']], 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: partial remaining stake', ([['4.93', 'won']], 2500, '5', 500), [500, 2393]),
('variant scenario 1',
([['3.53', '1.91'], ['3.32', 'lost'], ['1.63', 'won'], ['2.97', '4.57']], 500, '0', 500),
[0, 0]),
('variant scenario 2', ([['2.73', 'won'], ['2.11', '4.03']], 1000, '0', 0), [1429, 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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, 333] | [500, 666] | Failed |
| control lost leg | [0, 0] | [0, 0] | Passed |
| boundary partial above value | invalid | invalid | Passed |
| regression: partial remaining stake | [800, 301] | [800, 198] | Failed |
| variant scenario 1 | [0, 0] | [0, 0] | Passed |
| variant scenario 2 | [0, 0] | [0, 0] | Passed |
SHA-256 / 3afc395fa1325b9e09aba30aacb3ba3863ce11bf274f518c0e43313ecdeeb5f8
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: partial remaining stake', ([['2.79', 'won']], 500, '5', 800), [800, 198]),
('variant scenario 1',
([['1.51', 'won'], ['3.49', 'won'], ['3.39', 'lost'], ['1.99', 'won']], 500, '7.5', 0),
[0, 0]),
('variant scenario 2',
([['3.71', 'lost'], ['1.47', '4.60'], ['1.32', 'won'], ['1.57', '2.91']], 1000, '5', 200),
[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: partial remaining stake',
([['3.43', '4.22'], ['4.58', 'won'], ['2.70', 'won']], 1000, '5', 500),
[500, 947]),
('variant scenario 1', ([['5.00', '5.10']], 500, '0', 0), [490, 0]),
('variant scenario 2',
([['4.09', '4.06'], ['1.44', 'lost'], ['4.51', '1.56'], ['4.68', 'won']], 1000, '0', 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: partial remaining stake', ([['3.79', '2.66']], 1000, '7.5', 500), [500, 620]),
('variant scenario 1', ([['4.71', 'won']], 1000, '0', 0), [4710, 0]),
('variant scenario 2', ([['1.46', '1.60']], 500, '5', 500), 'invalid')],
[('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: partial remaining stake',
([['3.65', 'won'], ['2.14', '1.31'], ['2.44', '2.91']], 1000, '5', 500),
[500, 894]),
('variant scenario 1',
([['3.39', 'won'], ['2.49', '5.36'], ['1.49', '4.00'], ['3.15', '5.06']], 2500, '5', 0),
[867, 0]),
('variant scenario 2', ([['2.52', 'lost'], ['4.68', '4.00']], 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: partial remaining stake', ([['4.93', 'won']], 2500, '5', 500), [500, 2393]),
('variant scenario 1',
([['3.53', '1.91'], ['3.32', 'lost'], ['1.63', 'won'], ['2.97', '4.57']], 500, '0', 500),
[0, 0]),
('variant scenario 2', ([['2.73', 'won'], ['2.11', '4.03']], 1000, '0', 0), [1429, 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 value | invalid | invalid | Passed |
| regression: partial remaining stake | [800, 198] | [800, 198] | Passed |
| variant scenario 1 | [0, 0] | [0, 0] | Passed |
| variant scenario 2 | [0, 0] | [0, 0] | Passed |
SHA-256 / 4c4de9e9f848a291031d8594401d680559c3e9351a97b0ca4057956b3f2845c7
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.495728+00:00.
Case digest / f811913df339d15bfc96358628de340fd7b59ff813aa00a3311484d7e3622c2d