FAILURE MAP
← Case archive

FA-84386 / Betting odds conversion / Open access

Implied probability uses one formula for both signs · case 01

Underdog probabilities come out above 50 percent.

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

ROOT CAUSE

The favourite formula N / (N + 100) is applied to every line.

VERIFIED REPAIR

Use 100 / (N + 100) for positive lines and N / (N + 100) for negative lines.

Unsuccessful approach: Using the underdog formula everywhere gives favourites probabilities below 50 percent.

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 < 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
    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: implied probability sign', ('-247',), ['1.40', '100/247', '71.2']),
  ('regression: implied probability sign', ('491',), ['5.91', '491/100', '16.9']),
  ('variant scenario 1', ('-446',), ['1.22', '50/223', '81.7']),
  ('variant scenario 2', ('-636',), ['1.16', '25/159', '86.4'])],
 [('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: implied probability sign', ('602',), ['7.02', '301/50', '14.2']),
  ('regression: implied probability sign', ('-310',), ['1.32', '10/31', '75.6']),
  ('variant scenario 1', ('+328',), ['4.28', '82/25', '23.4']),
  ('variant scenario 2', ('+732',), ['8.32', '183/25', '12.0'])],
 [('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: implied probability sign', ('-283',), ['1.35', '100/283', '73.9']),
  ('regression: implied probability sign', ('+757',), ['8.57', '757/100', '11.7']),
  ('variant scenario 1', ('-466',), ['1.21', '50/233', '82.3']),
  ('variant scenario 2', ('100',), ['2.00', '1/1', '50.0'])],
 [('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: implied probability sign', ('-800',), ['1.13', '1/8', '88.9']),
  ('regression: implied probability sign', ('+284',), ['3.84', '71/25', '26.0']),
  ('variant scenario 1', ('+448',), ['5.48', '112/25', '18.2']),
  ('variant scenario 2', ('-131',), ['1.76', '100/131', '56.7'])],
 [('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: implied probability sign', ('+234',), ['3.34', '117/50', '29.9']),
  ('regression: implied probability sign', ('-110',), ['1.91', '10/11', '52.4']),
  ('variant scenario 1', ('430',), ['5.30', '43/10', '18.9']),
  ('variant scenario 2', ('+115',), ['2.15', '23/20', '46.5'])]]
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 underdog['2.50', '3/2', '60.0']['2.50', '3/2', '40.0']Failed
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', '71.4']['3.50', '5/2', '28.6']Failed
boundary below minimuminvalidinvalidPassed
control half-up decimal['1.13', '1/8', '88.9']['1.13', '1/8', '88.9']Passed
regression: implied probability sign['1.40', '100/247', '71.2']['1.40', '100/247', '71.2']Passed
regression: implied probability sign['5.91', '491/100', '83.1']['5.91', '491/100', '16.9']Failed
variant scenario 1['1.22', '50/223', '81.7']['1.22', '50/223', '81.7']Passed
variant scenario 2['1.16', '25/159', '86.4']['1.16', '25/159', '86.4']Passed

SHA-256 / b280b92d3d170a91f83be5a9d9880dfe2dab769f5bbf7a2c030f8be9e89d5eb0

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:
        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(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: implied probability sign', ('-247',), ['1.40', '100/247', '71.2']),
  ('regression: implied probability sign', ('491',), ['5.91', '491/100', '16.9']),
  ('variant scenario 1', ('-446',), ['1.22', '50/223', '81.7']),
  ('variant scenario 2', ('-636',), ['1.16', '25/159', '86.4'])],
 [('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: implied probability sign', ('602',), ['7.02', '301/50', '14.2']),
  ('regression: implied probability sign', ('-310',), ['1.32', '10/31', '75.6']),
  ('variant scenario 1', ('+328',), ['4.28', '82/25', '23.4']),
  ('variant scenario 2', ('+732',), ['8.32', '183/25', '12.0'])],
 [('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: implied probability sign', ('-283',), ['1.35', '100/283', '73.9']),
  ('regression: implied probability sign', ('+757',), ['8.57', '757/100', '11.7']),
  ('variant scenario 1', ('-466',), ['1.21', '50/233', '82.3']),
  ('variant scenario 2', ('100',), ['2.00', '1/1', '50.0'])],
 [('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: implied probability sign', ('-800',), ['1.13', '1/8', '88.9']),
  ('regression: implied probability sign', ('+284',), ['3.84', '71/25', '26.0']),
  ('variant scenario 1', ('+448',), ['5.48', '112/25', '18.2']),
  ('variant scenario 2', ('-131',), ['1.76', '100/131', '56.7'])],
 [('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: implied probability sign', ('+234',), ['3.34', '117/50', '29.9']),
  ('regression: implied probability sign', ('-110',), ['1.91', '10/11', '52.4']),
  ('variant scenario 1', ('430',), ['5.30', '43/10', '18.9']),
  ('variant scenario 2', ('+115',), ['2.15', '23/20', '46.5'])]]
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 underdog['2.50', '3/2', '40.0']['2.50', '3/2', '40.0']Passed
control favourite['1.50', '1/2', '33.3']['1.50', '1/2', '66.7']Failed
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 minimuminvalidinvalidPassed
control half-up decimal['1.13', '1/8', '11.1']['1.13', '1/8', '88.9']Failed
regression: implied probability sign['1.40', '100/247', '28.8']['1.40', '100/247', '71.2']Failed
regression: implied probability sign['5.91', '491/100', '16.9']['5.91', '491/100', '16.9']Passed
variant scenario 1['1.22', '50/223', '18.3']['1.22', '50/223', '81.7']Failed
variant scenario 2['1.16', '25/159', '13.6']['1.16', '25/159', '86.4']Failed

SHA-256 / bff2bfc46f92370b3c0ba9b05dbb803b9ca77cb5309ec6b62a42b4b8ae5b0e1d

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: implied probability sign', ('-247',), ['1.40', '100/247', '71.2']),
  ('regression: implied probability sign', ('491',), ['5.91', '491/100', '16.9']),
  ('variant scenario 1', ('-446',), ['1.22', '50/223', '81.7']),
  ('variant scenario 2', ('-636',), ['1.16', '25/159', '86.4'])],
 [('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: implied probability sign', ('602',), ['7.02', '301/50', '14.2']),
  ('regression: implied probability sign', ('-310',), ['1.32', '10/31', '75.6']),
  ('variant scenario 1', ('+328',), ['4.28', '82/25', '23.4']),
  ('variant scenario 2', ('+732',), ['8.32', '183/25', '12.0'])],
 [('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: implied probability sign', ('-283',), ['1.35', '100/283', '73.9']),
  ('regression: implied probability sign', ('+757',), ['8.57', '757/100', '11.7']),
  ('variant scenario 1', ('-466',), ['1.21', '50/233', '82.3']),
  ('variant scenario 2', ('100',), ['2.00', '1/1', '50.0'])],
 [('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: implied probability sign', ('-800',), ['1.13', '1/8', '88.9']),
  ('regression: implied probability sign', ('+284',), ['3.84', '71/25', '26.0']),
  ('variant scenario 1', ('+448',), ['5.48', '112/25', '18.2']),
  ('variant scenario 2', ('-131',), ['1.76', '100/131', '56.7'])],
 [('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: implied probability sign', ('+234',), ['3.34', '117/50', '29.9']),
  ('regression: implied probability sign', ('-110',), ['1.91', '10/11', '52.4']),
  ('variant scenario 1', ('430',), ['5.30', '43/10', '18.9']),
  ('variant scenario 2', ('+115',), ['2.15', '23/20', '46.5'])]]
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 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 minimuminvalidinvalidPassed
control half-up decimal['1.13', '1/8', '88.9']['1.13', '1/8', '88.9']Passed
regression: implied probability sign['1.40', '100/247', '71.2']['1.40', '100/247', '71.2']Passed
regression: implied probability sign['5.91', '491/100', '16.9']['5.91', '491/100', '16.9']Passed
variant scenario 1['1.22', '50/223', '81.7']['1.22', '50/223', '81.7']Passed
variant scenario 2['1.16', '25/159', '86.4']['1.16', '25/159', '86.4']Passed

SHA-256 / 56aca2d1b67bf35290c6ee80ec06e43fca85024f2ac338b71d33b1dea6b9794a

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

Case digest / 0b1b3abe0a0bb9cbf71fde742fd9931bbe8f0f280b9bb6350724ac36a8bf81ef