FAILURE MAP
← Case archive

FA-84686 / Betting odds conversion / Open access

Explicit plus-sign American lines parsed as decimals · case 01

"+150" is read as a 150.00 decimal price, or empty input crashes.

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

ROOT CAUSE

Only a leading minus sign selects the American branch.

VERIFIED REPAIR

Treat a leading + or - as American and keep empty input invalid.

Unsuccessful approach: Indexing the first character crashes on empty input.

Case contract

Normalise user-typed odds to a decimal price string with two decimals (half up). Detection order: text containing "/" is fractional a/b; text starting with "+" or "-" is American (magnitude >= 100); an unsigned integer >= 100 is a positive American line; anything else is a decimal price, where a comma is the decimal separator ("2,50"). Unparseable input, zero denominators, magnitudes below 100 and results not above 1 return "invalid".

Why this case matters

Bet-slip inputs accept several odds formats and must not misclassify ambiguous text.

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(text):
    t = text.strip()
    try:
        if '/' in t:
            a, b = t.split('/')
            dec = 1 + Fraction(int(a), int(b))
        elif t[:1] == '-':
            n = int(t[1:])
            if n < 100:
                return 'invalid'
            dec = 1 + (Fraction(n, 100) if t[0] == '+' else Fraction(100, n))
        elif t.isdigit() and int(t) >= 100:
            dec = 1 + Fraction(int(t), 100)
        else:
            dec = Fraction(t.replace(',', '.'))
    except (ValueError, ZeroDivisionError):
        return 'invalid'
    if dec <= 1:
        return 'invalid'
    c = math.floor(dec * 100 + Fraction(1, 2))
    return '%d.%02d' % (c // 100, c % 100)
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 fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+487',), '5.87'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('3,36',), '3.36'),
  ('variant scenario 2', ('3/1',), '4.00')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+319',), '4.19'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('-595',), '1.17'),
  ('variant scenario 2', ('13/2',), '7.50')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('regression: plus sign detection', ('+100',), '2.00'),
  ('variant scenario 1', ('3,07',), '3.07'),
  ('variant scenario 2', ('256',), '3.56')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+150',), '2.50'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('1.84',), '1.84'),
  ('variant scenario 2', ('6,57',), '6.57')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+553',), '6.53'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('-513',), '1.19'),
  ('variant scenario 2', ('191',), '2.91')]]
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 fractional3.503.50Passed
control negative american1.911.91Passed
boundary unsigned hundred2.002.00Passed
boundary small integer is decimal3.003.00Passed
boundary decimal comma2.502.50Passed
control empty inputinvalidinvalidPassed
regression: plus sign detection487.005.87Failed
regression: plus sign detectioninvalidinvalidPassed
variant scenario 13.363.36Passed
variant scenario 24.004.00Passed

SHA-256 / 65e7c81a562b960bbe3134a15718508715be9a7c245d74fd35c5d712b929c0c5

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(text):
    t = text.strip()
    try:
        if '/' in t:
            a, b = t.split('/')
            dec = 1 + Fraction(int(a), int(b))
        elif t[0] in '+-':
            n = int(t[1:])
            if n < 100:
                return 'invalid'
            dec = 1 + (Fraction(n, 100) if t[0] == '+' else Fraction(100, n))
        elif t.isdigit() and int(t) >= 100:
            dec = 1 + Fraction(int(t), 100)
        else:
            dec = Fraction(t.replace(',', '.'))
    except (ValueError, ZeroDivisionError):
        return 'invalid'
    if dec <= 1:
        return 'invalid'
    c = math.floor(dec * 100 + Fraction(1, 2))
    return '%d.%02d' % (c // 100, c % 100)
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 fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+487',), '5.87'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('3,36',), '3.36'),
  ('variant scenario 2', ('3/1',), '4.00')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+319',), '4.19'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('-595',), '1.17'),
  ('variant scenario 2', ('13/2',), '7.50')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('regression: plus sign detection', ('+100',), '2.00'),
  ('variant scenario 1', ('3,07',), '3.07'),
  ('variant scenario 2', ('256',), '3.56')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+150',), '2.50'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('1.84',), '1.84'),
  ('variant scenario 2', ('6,57',), '6.57')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+553',), '6.53'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('-513',), '1.19'),
  ('variant scenario 2', ('191',), '2.91')]]
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 fractional3.503.50Passed
control negative american1.911.91Passed
boundary unsigned hundred2.002.00Passed
boundary small integer is decimal3.003.00Passed
boundary decimal comma2.502.50Passed
control empty inputraised IndexErrorinvalidFailed
regression: plus sign detection5.875.87Passed
regression: plus sign detectionraised IndexErrorinvalidFailed
variant scenario 13.363.36Passed
variant scenario 24.004.00Passed

SHA-256 / 993959a7ec9fa4a515520a42b99985ca1fea52f1596f7169fb7ff893ac17a3a3

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(text):
    t = text.strip()
    try:
        if '/' in t:
            a, b = t.split('/')
            dec = 1 + Fraction(int(a), int(b))
        elif t[:1] in ('+', '-'):
            n = int(t[1:])
            if n < 100:
                return 'invalid'
            dec = 1 + (Fraction(n, 100) if t[0] == '+' else Fraction(100, n))
        elif t.isdigit() and int(t) >= 100:
            dec = 1 + Fraction(int(t), 100)
        else:
            dec = Fraction(t.replace(',', '.'))
    except (ValueError, ZeroDivisionError):
        return 'invalid'
    if dec <= 1:
        return 'invalid'
    c = math.floor(dec * 100 + Fraction(1, 2))
    return '%d.%02d' % (c // 100, c % 100)
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 fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+487',), '5.87'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('3,36',), '3.36'),
  ('variant scenario 2', ('3/1',), '4.00')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+319',), '4.19'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('-595',), '1.17'),
  ('variant scenario 2', ('13/2',), '7.50')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('regression: plus sign detection', ('+100',), '2.00'),
  ('variant scenario 1', ('3,07',), '3.07'),
  ('variant scenario 2', ('256',), '3.56')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+150',), '2.50'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('1.84',), '1.84'),
  ('variant scenario 2', ('6,57',), '6.57')],
 [('control fractional', ('5/2',), '3.50'),
  ('control negative american', ('-110',), '1.91'),
  ('boundary unsigned hundred', ('100',), '2.00'),
  ('boundary small integer is decimal', ('3',), '3.00'),
  ('boundary decimal comma', ('2,50',), '2.50'),
  ('control empty input', ('',), 'invalid'),
  ('regression: plus sign detection', ('+553',), '6.53'),
  ('regression: plus sign detection', ('',), 'invalid'),
  ('variant scenario 1', ('-513',), '1.19'),
  ('variant scenario 2', ('191',), '2.91')]]
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 fractional3.503.50Passed
control negative american1.911.91Passed
boundary unsigned hundred2.002.00Passed
boundary small integer is decimal3.003.00Passed
boundary decimal comma2.502.50Passed
control empty inputinvalidinvalidPassed
regression: plus sign detection5.875.87Passed
regression: plus sign detectioninvalidinvalidPassed
variant scenario 13.363.36Passed
variant scenario 24.004.00Passed

SHA-256 / fc7786f59e1cd476e8265c4754aeb95b3451bcbb655a88b1321284d9e056dbf2

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

Case digest / 43a91961fac70e4d814d27a5a0107d3e98219530c2538c976cc9da74fb8b9383