FA-84511 / Betting odds conversion / Open access
Each half of a split bet staked with the full amount · case 01
Quarter-line winners are paid double, or single lines are paid half.
ROOT CAUSE
The per-part stake is the full stake for every part.
VERIFIED REPAIR
Divide the stake by the number of parts.
Unsuccessful approach: Always halving the stake underpays whole and half lines.
Case contract
Asian handicap bet on the home side. line is a multiple of 0.25 (else "invalid line"). Whole and half lines are a single bet; quarter lines split the stake equally between line - 0.25 and line + 0.25. Each part: margin = home_goals - away_goals + part_line; positive wins stake_part * price, zero refunds stake_part, negative loses. Return [total return in cents rounded down, label] where the label is win, half-win, push, half-lose or lose from the summed part outcomes.
Why this case matters
Asian handicap settlement with split quarter lines is a common source of payout disputes.
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(line, home_goals, away_goals, stake_cents, price):
L = Fraction(line)
if (L * 4).denominator != 1:
return 'invalid line'
if (L * 2).denominator == 1:
parts = [L]
else:
parts = [L - Fraction(1, 4), L + Fraction(1, 4)]
d = Fraction(price)
share = Fraction(stake_cents)
ret = Fraction(0)
res = []
for p in parts:
m = home_goals - away_goals + p
if m > 0:
ret += share * d
res.append(1)
elif m == 0:
ret += share
res.append(0)
else:
res.append(-1)
score = sum(res) * 2 // len(parts)
label = {2: 'win', 1: 'half-win', 0: 'push', -1: 'half-lose', -2: 'lose'}[score]
return [math.floor(ret), label]
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 half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('-0.25', 3, 2, 250, '2.00'), [500, 'win']),
('regression: split stake share', ('0', 3, 3, 1000, '2.05'), [1000, 'push']),
('variant scenario 1', ('-1.75', 4, 0, 1000, '2.00'), [2000, 'win']),
('variant scenario 2', ('-0.75', 2, 4, 500, '2.00'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('-0.5', 4, 0, 999, '1.90'), [1898, 'win']),
('regression: split stake share', ('+0.25', 3, 3, 1000, '2.00'), [1500, 'half-win']),
('variant scenario 1', ('-0.3', 3, 3, 250, '1.90'), 'invalid line'),
('variant scenario 2', ('+0.75', 1, 3, 1000, '1.90'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+0.75', 4, 0, 250, '2.00'), [500, 'win']),
('regression: split stake share', ('+0.5', 2, 0, 999, '2.00'), [1998, 'win']),
('variant scenario 1', ('-1', 0, 2, 999, '2.00'), [0, 'lose']),
('variant scenario 2', ('+0.25', 1, 0, 250, '1.85'), [462, 'win'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+0.5', 4, 1, 250, '1.90'), [475, 'win']),
('regression: split stake share', ('+0.25', 3, 2, 1000, '1.85'), [1850, 'win']),
('variant scenario 1', ('+2', 1, 4, 500, '1.90'), [0, 'lose']),
('variant scenario 2', ('+0.75', 0, 4, 1000, '2.05'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+1.25', 1, 0, 500, '1.85'), [925, 'win']),
('regression: split stake share', ('0', 2, 0, 250, '1.90'), [475, 'win']),
('variant scenario 1', ('-1.75', 2, 0, 999, '2.00'), [1498, 'half-win']),
('variant scenario 2', ('-0.3', 2, 4, 1000, '2.00'), 'invalid line')]]
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 half line win | [1900, 'win'] | [1900, 'win'] | Passed |
| boundary whole line push | [1000, 'push'] | [1000, 'push'] | Passed |
| boundary quarter half-lose | [1000, 'half-lose'] | [500, 'half-lose'] | Failed |
| boundary quarter half-win | [3000, 'half-win'] | [1500, 'half-win'] | Failed |
| control lose | [0, 'lose'] | [0, 'lose'] | Passed |
| boundary off-grid line | invalid line | invalid line | Passed |
| regression: split stake share | [1000, 'win'] | [500, 'win'] | Failed |
| regression: split stake share | [1000, 'push'] | [1000, 'push'] | Passed |
| variant scenario 1 | [4000, 'win'] | [2000, 'win'] | Failed |
| variant scenario 2 | [0, 'lose'] | [0, 'lose'] | Passed |
SHA-256 / 78b8d85b12b8f3620eef570380aeb9a746dfe0286ada251eb6310c7faa4b9204
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(line, home_goals, away_goals, stake_cents, price):
L = Fraction(line)
if (L * 4).denominator != 1:
return 'invalid line'
if (L * 2).denominator == 1:
parts = [L]
else:
parts = [L - Fraction(1, 4), L + Fraction(1, 4)]
d = Fraction(price)
share = Fraction(stake_cents, 2)
ret = Fraction(0)
res = []
for p in parts:
m = home_goals - away_goals + p
if m > 0:
ret += share * d
res.append(1)
elif m == 0:
ret += share
res.append(0)
else:
res.append(-1)
score = sum(res) * 2 // len(parts)
label = {2: 'win', 1: 'half-win', 0: 'push', -1: 'half-lose', -2: 'lose'}[score]
return [math.floor(ret), label]
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 half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('-0.25', 3, 2, 250, '2.00'), [500, 'win']),
('regression: split stake share', ('0', 3, 3, 1000, '2.05'), [1000, 'push']),
('variant scenario 1', ('-1.75', 4, 0, 1000, '2.00'), [2000, 'win']),
('variant scenario 2', ('-0.75', 2, 4, 500, '2.00'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('-0.5', 4, 0, 999, '1.90'), [1898, 'win']),
('regression: split stake share', ('+0.25', 3, 3, 1000, '2.00'), [1500, 'half-win']),
('variant scenario 1', ('-0.3', 3, 3, 250, '1.90'), 'invalid line'),
('variant scenario 2', ('+0.75', 1, 3, 1000, '1.90'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+0.75', 4, 0, 250, '2.00'), [500, 'win']),
('regression: split stake share', ('+0.5', 2, 0, 999, '2.00'), [1998, 'win']),
('variant scenario 1', ('-1', 0, 2, 999, '2.00'), [0, 'lose']),
('variant scenario 2', ('+0.25', 1, 0, 250, '1.85'), [462, 'win'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+0.5', 4, 1, 250, '1.90'), [475, 'win']),
('regression: split stake share', ('+0.25', 3, 2, 1000, '1.85'), [1850, 'win']),
('variant scenario 1', ('+2', 1, 4, 500, '1.90'), [0, 'lose']),
('variant scenario 2', ('+0.75', 0, 4, 1000, '2.05'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+1.25', 1, 0, 500, '1.85'), [925, 'win']),
('regression: split stake share', ('0', 2, 0, 250, '1.90'), [475, 'win']),
('variant scenario 1', ('-1.75', 2, 0, 999, '2.00'), [1498, 'half-win']),
('variant scenario 2', ('-0.3', 2, 4, 1000, '2.00'), 'invalid line')]]
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 half line win | [950, 'win'] | [1900, 'win'] | Failed |
| boundary whole line push | [500, 'push'] | [1000, 'push'] | Failed |
| boundary quarter half-lose | [500, 'half-lose'] | [500, 'half-lose'] | Passed |
| boundary quarter half-win | [1500, 'half-win'] | [1500, 'half-win'] | Passed |
| control lose | [0, 'lose'] | [0, 'lose'] | Passed |
| boundary off-grid line | invalid line | invalid line | Passed |
| regression: split stake share | [500, 'win'] | [500, 'win'] | Passed |
| regression: split stake share | [500, 'push'] | [1000, 'push'] | Failed |
| variant scenario 1 | [2000, 'win'] | [2000, 'win'] | Passed |
| variant scenario 2 | [0, 'lose'] | [0, 'lose'] | Passed |
SHA-256 / 9371d609c47c5dba3647c370981bf774ff7377d5b6d049112f220412b2b65f8b
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(line, home_goals, away_goals, stake_cents, price):
L = Fraction(line)
if (L * 4).denominator != 1:
return 'invalid line'
if (L * 2).denominator == 1:
parts = [L]
else:
parts = [L - Fraction(1, 4), L + Fraction(1, 4)]
d = Fraction(price)
share = Fraction(stake_cents, len(parts))
ret = Fraction(0)
res = []
for p in parts:
m = home_goals - away_goals + p
if m > 0:
ret += share * d
res.append(1)
elif m == 0:
ret += share
res.append(0)
else:
res.append(-1)
score = sum(res) * 2 // len(parts)
label = {2: 'win', 1: 'half-win', 0: 'push', -1: 'half-lose', -2: 'lose'}[score]
return [math.floor(ret), label]
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 half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('-0.25', 3, 2, 250, '2.00'), [500, 'win']),
('regression: split stake share', ('0', 3, 3, 1000, '2.05'), [1000, 'push']),
('variant scenario 1', ('-1.75', 4, 0, 1000, '2.00'), [2000, 'win']),
('variant scenario 2', ('-0.75', 2, 4, 500, '2.00'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('-0.5', 4, 0, 999, '1.90'), [1898, 'win']),
('regression: split stake share', ('+0.25', 3, 3, 1000, '2.00'), [1500, 'half-win']),
('variant scenario 1', ('-0.3', 3, 3, 250, '1.90'), 'invalid line'),
('variant scenario 2', ('+0.75', 1, 3, 1000, '1.90'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+0.75', 4, 0, 250, '2.00'), [500, 'win']),
('regression: split stake share', ('+0.5', 2, 0, 999, '2.00'), [1998, 'win']),
('variant scenario 1', ('-1', 0, 2, 999, '2.00'), [0, 'lose']),
('variant scenario 2', ('+0.25', 1, 0, 250, '1.85'), [462, 'win'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+0.5', 4, 1, 250, '1.90'), [475, 'win']),
('regression: split stake share', ('+0.25', 3, 2, 1000, '1.85'), [1850, 'win']),
('variant scenario 1', ('+2', 1, 4, 500, '1.90'), [0, 'lose']),
('variant scenario 2', ('+0.75', 0, 4, 1000, '2.05'), [0, 'lose'])],
[('control half line win', ('-0.5', 1, 0, 1000, '1.90'), [1900, 'win']),
('boundary whole line push', ('-1', 2, 1, 1000, '1.90'), [1000, 'push']),
('boundary quarter half-lose', ('-0.25', 1, 1, 1000, '1.90'), [500, 'half-lose']),
('boundary quarter half-win', ('-0.75', 1, 0, 1000, '2.00'), [1500, 'half-win']),
('control lose', ('+0.5', 0, 2, 1000, '1.90'), [0, 'lose']),
('boundary off-grid line', ('-0.3', 1, 0, 1000, '1.90'), 'invalid line'),
('regression: split stake share', ('+1.25', 1, 0, 500, '1.85'), [925, 'win']),
('regression: split stake share', ('0', 2, 0, 250, '1.90'), [475, 'win']),
('variant scenario 1', ('-1.75', 2, 0, 999, '2.00'), [1498, 'half-win']),
('variant scenario 2', ('-0.3', 2, 4, 1000, '2.00'), 'invalid line')]]
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 half line win | [1900, 'win'] | [1900, 'win'] | Passed |
| boundary whole line push | [1000, 'push'] | [1000, 'push'] | Passed |
| boundary quarter half-lose | [500, 'half-lose'] | [500, 'half-lose'] | Passed |
| boundary quarter half-win | [1500, 'half-win'] | [1500, 'half-win'] | Passed |
| control lose | [0, 'lose'] | [0, 'lose'] | Passed |
| boundary off-grid line | invalid line | invalid line | Passed |
| regression: split stake share | [500, 'win'] | [500, 'win'] | Passed |
| regression: split stake share | [1000, 'push'] | [1000, 'push'] | Passed |
| variant scenario 1 | [2000, 'win'] | [2000, 'win'] | Passed |
| variant scenario 2 | [0, 'lose'] | [0, 'lose'] | Passed |
SHA-256 / 34cc7d82e5012a5678aa6e4aeb9cfc7fdfb4255eec152943e4013a6099b88317
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:31.658464+00:00.
Case digest / 3c26730634cf12253cc46577bfbb608ef9cbdf8a58c6250fee28a8b3a3a9531b