FA-84371 / Betting odds conversion / Open access
Moneylines below 100 accepted · case 01
A "+50" or "-99" line is expanded instead of rejected.
ROOT CAUSE
The guard only rejects non-positive magnitudes.
VERIFIED REPAIR
Reject magnitudes below 100 for both signs.
Unsuccessful approach: Checking the minimum only for positive lines still accepts "-99".
Case contract
Expand an American moneyline ("+150", "150" or "-200"; magnitude at least 100, otherwise "invalid"). Profit per unit is N/100 for positive or unsigned lines and 100/N for negative lines. Return [decimal price with two decimals, reduced fractional profit "a/b", implied probability percent with one decimal], all computed exactly and rounded half up.
Why this case matters
Odds screens show American, decimal, fractional and implied-probability columns for one price.
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(american):
s = american.strip()
neg = s.startswith('-')
n = int(s.lstrip('+-'))
if n <= 0:
return 'invalid'
profit = Fraction(100, n) if neg else Fraction(n, 100)
dec = 1 + profit
def fmt(x, places):
q = 10 ** places
v = math.floor(x * q + Fraction(1, 2))
return '%d.%0*d' % (v // q, places, v % q)
prob = Fraction(n, n + 100) * 100 if neg else Fraction(100, n + 100) * 100
return [fmt(dec, 2), '%d/%d' % (profit.numerator, profit.denominator), fmt(prob, 1)]
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 underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('110',), ['2.10', '11/10', '47.6']),
('variant scenario 2', ('+1135',), ['12.35', '227/20', '8.1'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('-175',), ['1.57', '4/7', '63.6']),
('variant scenario 2', ('846',), ['9.46', '423/50', '10.6'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('+655',), ['7.55', '131/20', '13.2']),
('variant scenario 2', ('+800',), ['9.00', '8/1', '11.1'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('+1106',), ['12.06', '553/50', '8.3']),
('variant scenario 2', ('-772',), ['1.13', '25/193', '88.5'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('-115',), ['1.87', '20/23', '53.5']),
('variant scenario 2', ('100',), ['2.00', '1/1', '50.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 underdog | ['2.50', '3/2', '40.0'] | ['2.50', '3/2', '40.0'] | Passed |
| control favourite | ['1.50', '1/2', '66.7'] | ['1.50', '1/2', '66.7'] | Passed |
| boundary even money | ['2.00', '1/1', '50.0'] | ['2.00', '1/1', '50.0'] | Passed |
| boundary unsigned line | ['3.50', '5/2', '28.6'] | ['3.50', '5/2', '28.6'] | Passed |
| boundary below minimum | ['1.50', '1/2', '66.7'] | invalid | Failed |
| control half-up decimal | ['1.13', '1/8', '88.9'] | ['1.13', '1/8', '88.9'] | Passed |
| regression: magnitude minimum | ['1.50', '1/2', '66.7'] | invalid | Failed |
| regression: magnitude minimum | ['2.01', '100/99', '49.7'] | invalid | Failed |
| variant scenario 1 | ['2.10', '11/10', '47.6'] | ['2.10', '11/10', '47.6'] | Passed |
| variant scenario 2 | ['12.35', '227/20', '8.1'] | ['12.35', '227/20', '8.1'] | Passed |
SHA-256 / e4ce2f9bf302ac4138410c160bf9a8fe19ea49d13a2ae1373c322ce0b3603b85
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(american):
s = american.strip()
neg = s.startswith('-')
n = int(s.lstrip('+-'))
if n < 100 and not neg:
return 'invalid'
profit = Fraction(100, n) if neg else Fraction(n, 100)
dec = 1 + profit
def fmt(x, places):
q = 10 ** places
v = math.floor(x * q + Fraction(1, 2))
return '%d.%0*d' % (v // q, places, v % q)
prob = Fraction(n, n + 100) * 100 if neg else Fraction(100, n + 100) * 100
return [fmt(dec, 2), '%d/%d' % (profit.numerator, profit.denominator), fmt(prob, 1)]
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 underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('110',), ['2.10', '11/10', '47.6']),
('variant scenario 2', ('+1135',), ['12.35', '227/20', '8.1'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('-175',), ['1.57', '4/7', '63.6']),
('variant scenario 2', ('846',), ['9.46', '423/50', '10.6'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('+655',), ['7.55', '131/20', '13.2']),
('variant scenario 2', ('+800',), ['9.00', '8/1', '11.1'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('+1106',), ['12.06', '553/50', '8.3']),
('variant scenario 2', ('-772',), ['1.13', '25/193', '88.5'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('-115',), ['1.87', '20/23', '53.5']),
('variant scenario 2', ('100',), ['2.00', '1/1', '50.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 underdog | ['2.50', '3/2', '40.0'] | ['2.50', '3/2', '40.0'] | Passed |
| control favourite | ['1.50', '1/2', '66.7'] | ['1.50', '1/2', '66.7'] | Passed |
| boundary even money | ['2.00', '1/1', '50.0'] | ['2.00', '1/1', '50.0'] | Passed |
| boundary unsigned line | ['3.50', '5/2', '28.6'] | ['3.50', '5/2', '28.6'] | Passed |
| boundary below minimum | invalid | invalid | Passed |
| control half-up decimal | ['1.13', '1/8', '88.9'] | ['1.13', '1/8', '88.9'] | Passed |
| regression: magnitude minimum | invalid | invalid | Passed |
| regression: magnitude minimum | ['2.01', '100/99', '49.7'] | invalid | Failed |
| variant scenario 1 | ['2.10', '11/10', '47.6'] | ['2.10', '11/10', '47.6'] | Passed |
| variant scenario 2 | ['12.35', '227/20', '8.1'] | ['12.35', '227/20', '8.1'] | Passed |
SHA-256 / 31a1b4228505199efec473657545286cae3c6e821e38708765d14eb54d0382cb
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(american):
s = american.strip()
neg = s.startswith('-')
n = int(s.lstrip('+-'))
if n < 100:
return 'invalid'
profit = Fraction(100, n) if neg else Fraction(n, 100)
dec = 1 + profit
def fmt(x, places):
q = 10 ** places
v = math.floor(x * q + Fraction(1, 2))
return '%d.%0*d' % (v // q, places, v % q)
prob = Fraction(n, n + 100) * 100 if neg else Fraction(100, n + 100) * 100
return [fmt(dec, 2), '%d/%d' % (profit.numerator, profit.denominator), fmt(prob, 1)]
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 underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('110',), ['2.10', '11/10', '47.6']),
('variant scenario 2', ('+1135',), ['12.35', '227/20', '8.1'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('-175',), ['1.57', '4/7', '63.6']),
('variant scenario 2', ('846',), ['9.46', '423/50', '10.6'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('+655',), ['7.55', '131/20', '13.2']),
('variant scenario 2', ('+800',), ['9.00', '8/1', '11.1'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('+1106',), ['12.06', '553/50', '8.3']),
('variant scenario 2', ('-772',), ['1.13', '25/193', '88.5'])],
[('control underdog', ('+150',), ['2.50', '3/2', '40.0']),
('control favourite', ('-200',), ['1.50', '1/2', '66.7']),
('boundary even money', ('+100',), ['2.00', '1/1', '50.0']),
('boundary unsigned line', ('250',), ['3.50', '5/2', '28.6']),
('boundary below minimum', ('+50',), 'invalid'),
('control half-up decimal', ('-800',), ['1.13', '1/8', '88.9']),
('regression: magnitude minimum', ('+50',), 'invalid'),
('regression: magnitude minimum', ('-99',), 'invalid'),
('variant scenario 1', ('-115',), ['1.87', '20/23', '53.5']),
('variant scenario 2', ('100',), ['2.00', '1/1', '50.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 underdog | ['2.50', '3/2', '40.0'] | ['2.50', '3/2', '40.0'] | Passed |
| control favourite | ['1.50', '1/2', '66.7'] | ['1.50', '1/2', '66.7'] | Passed |
| boundary even money | ['2.00', '1/1', '50.0'] | ['2.00', '1/1', '50.0'] | Passed |
| boundary unsigned line | ['3.50', '5/2', '28.6'] | ['3.50', '5/2', '28.6'] | Passed |
| boundary below minimum | invalid | invalid | Passed |
| control half-up decimal | ['1.13', '1/8', '88.9'] | ['1.13', '1/8', '88.9'] | Passed |
| regression: magnitude minimum | invalid | invalid | Passed |
| regression: magnitude minimum | invalid | invalid | Passed |
| variant scenario 1 | ['2.10', '11/10', '47.6'] | ['2.10', '11/10', '47.6'] | Passed |
| variant scenario 2 | ['12.35', '227/20', '8.1'] | ['12.35', '227/20', '8.1'] | Passed |
SHA-256 / 6eb3e9f332a76eb3ba39b58cd279d6594bb44c7d7938c77aa364b6d21df18841
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:30.357662+00:00.
Case digest / f32c4c2302d1196933f5ed5cf2bfed22adede4375ee82fdbdb81fa6531bd44ee