FAILURE MAP
← Case archive

FA-84486 / Betting odds conversion / Open access

Place terms applied to the decimal price · case 01

Placed each-way bets return a fraction of the stake instead of stake plus place winnings.

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

ROOT CAUSE

The place part multiplies the whole decimal price by the terms.

VERIFIED REPAIR

Apply the terms to the fractional odds and add back the stake.

Unsuccessful approach: Applying the terms to the fractional odds but not returning the stake still underpays.

Case contract

Each-way settlement with dead heats. stake_cents is the stake of each part (win and place). odds is fractional "a/b"; terms "1/4" or "1/5" is the place fraction of the odds. position is the finishing position shared by dead_heat runners (1 = no dead heat), occupying positions position .. position + dead_heat - 1. Win part: paid if position == 1 with stake / dead_heat at 1 + a/b. Place part: paid if position <= places_paid, with stake scaled by min(dead_heat, places_paid - position + 1) / dead_heat at 1 + (a/b) * terms. Return the total return in cents rounded down.

Why this case matters

Horse-racing settlement applies place terms and dead-heat reductions to each part separately.

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(stake_cents, odds, terms, position, places_paid, dead_heat):
    a, b = map(int, odds.split('/'))
    f = Fraction(a, b)
    tn, td = map(int, terms.split('/'))
    place_f = f * Fraction(tn, td)
    ret = Fraction(0)
    if position == 1:
        ret += Fraction(stake_cents, dead_heat) * (1 + f)
    if position <= places_paid:
        share = Fraction(min(dead_heat, places_paid - position + 1), dead_heat)
        ret += stake_cents * share * (1 + f) * Fraction(tn, td)
    return math.floor(ret)
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 winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (100, '14/5', '1/5', 4, 4, 1), 156),
  ('variant scenario 1', (100, '8/4', '1/4', 6, 5, 2), 0),
  ('variant scenario 2', (100, '6/2', '1/5', 1, 2, 2), 360)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (1000, '7/4', '1/4', 2, 4, 1), 1437),
  ('variant scenario 1', (500, '26/5', '1/5', 3, 5, 3), 1020),
  ('variant scenario 2', (500, '18/1', '1/5', 2, 3, 1), 2300)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (500, '15/1', '1/5', 2, 4, 2), 2000),
  ('variant scenario 1', (500, '10/1', '1/5', 3, 2, 1), 0),
  ('variant scenario 2', (250, '10/2', '1/4', 5, 5, 1), 562)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (100, '27/1', '1/4', 5, 5, 1), 775),
  ('variant scenario 1', (250, '3/4', '1/4', 3, 2, 1), 0),
  ('variant scenario 2', (1000, '18/5', '1/4', 4, 5, 2), 1900)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (500, '17/1', '1/5', 4, 4, 1), 2200),
  ('variant scenario 1', (1000, '22/1', '1/4', 5, 4, 1), 0),
  ('variant scenario 2', (100, '20/5', '1/5', 1, 4, 2), 430)]]
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 winner62507000Failed
control placed12502000Failed
control unplaced00Passed
boundary dead heat for the win35004300Failed
boundary dead heat for last place11001500Failed
regression: place odds fraction76156Failed
variant scenario 100Passed
variant scenario 2280360Failed

SHA-256 / fb3e2ce600f85bc7c11c7a7d3bd57a57bb772832e678ef017ca2a74e04d8cf6d

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(stake_cents, odds, terms, position, places_paid, dead_heat):
    a, b = map(int, odds.split('/'))
    f = Fraction(a, b)
    tn, td = map(int, terms.split('/'))
    place_f = f * Fraction(tn, td)
    ret = Fraction(0)
    if position == 1:
        ret += Fraction(stake_cents, dead_heat) * (1 + f)
    if position <= places_paid:
        share = Fraction(min(dead_heat, places_paid - position + 1), dead_heat)
        ret += stake_cents * share * place_f
    return math.floor(ret)
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 winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (100, '14/5', '1/5', 4, 4, 1), 156),
  ('variant scenario 1', (100, '8/4', '1/4', 6, 5, 2), 0),
  ('variant scenario 2', (100, '6/2', '1/5', 1, 2, 2), 360)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (1000, '7/4', '1/4', 2, 4, 1), 1437),
  ('variant scenario 1', (500, '26/5', '1/5', 3, 5, 3), 1020),
  ('variant scenario 2', (500, '18/1', '1/5', 2, 3, 1), 2300)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (500, '15/1', '1/5', 2, 4, 2), 2000),
  ('variant scenario 1', (500, '10/1', '1/5', 3, 2, 1), 0),
  ('variant scenario 2', (250, '10/2', '1/4', 5, 5, 1), 562)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (100, '27/1', '1/4', 5, 5, 1), 775),
  ('variant scenario 1', (250, '3/4', '1/4', 3, 2, 1), 0),
  ('variant scenario 2', (1000, '18/5', '1/4', 4, 5, 2), 1900)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (500, '17/1', '1/5', 4, 4, 1), 2200),
  ('variant scenario 1', (1000, '22/1', '1/4', 5, 4, 1), 0),
  ('variant scenario 2', (100, '20/5', '1/5', 1, 4, 2), 430)]]
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 winner60007000Failed
control placed10002000Failed
control unplaced00Passed
boundary dead heat for the win33004300Failed
boundary dead heat for last place10001500Failed
regression: place odds fraction56156Failed
variant scenario 100Passed
variant scenario 2260360Failed

SHA-256 / 3a287bd9e5709802003e84d360b2d71b65939af4b2869ff48230e3e8bb199478

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(stake_cents, odds, terms, position, places_paid, dead_heat):
    a, b = map(int, odds.split('/'))
    f = Fraction(a, b)
    tn, td = map(int, terms.split('/'))
    place_f = f * Fraction(tn, td)
    ret = Fraction(0)
    if position == 1:
        ret += Fraction(stake_cents, dead_heat) * (1 + f)
    if position <= places_paid:
        share = Fraction(min(dead_heat, places_paid - position + 1), dead_heat)
        ret += stake_cents * share * (1 + place_f)
    return math.floor(ret)
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 winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (100, '14/5', '1/5', 4, 4, 1), 156),
  ('variant scenario 1', (100, '8/4', '1/4', 6, 5, 2), 0),
  ('variant scenario 2', (100, '6/2', '1/5', 1, 2, 2), 360)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (1000, '7/4', '1/4', 2, 4, 1), 1437),
  ('variant scenario 1', (500, '26/5', '1/5', 3, 5, 3), 1020),
  ('variant scenario 2', (500, '18/1', '1/5', 2, 3, 1), 2300)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (500, '15/1', '1/5', 2, 4, 2), 2000),
  ('variant scenario 1', (500, '10/1', '1/5', 3, 2, 1), 0),
  ('variant scenario 2', (250, '10/2', '1/4', 5, 5, 1), 562)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (100, '27/1', '1/4', 5, 5, 1), 775),
  ('variant scenario 1', (250, '3/4', '1/4', 3, 2, 1), 0),
  ('variant scenario 2', (1000, '18/5', '1/4', 4, 5, 2), 1900)],
 [('control winner', (1000, '4/1', '1/4', 1, 3, 1), 7000),
  ('control placed', (1000, '4/1', '1/4', 2, 3, 1), 2000),
  ('control unplaced', (1000, '4/1', '1/4', 4, 3, 1), 0),
  ('boundary dead heat for the win', (1000, '4/1', '1/5', 1, 3, 2), 4300),
  ('boundary dead heat for last place', (1000, '10/1', '1/5', 3, 3, 2), 1500),
  ('regression: place odds fraction', (500, '17/1', '1/5', 4, 4, 1), 2200),
  ('variant scenario 1', (1000, '22/1', '1/4', 5, 4, 1), 0),
  ('variant scenario 2', (100, '20/5', '1/5', 1, 4, 2), 430)]]
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 winner70007000Passed
control placed20002000Passed
control unplaced00Passed
boundary dead heat for the win43004300Passed
boundary dead heat for last place15001500Passed
regression: place odds fraction156156Passed
variant scenario 100Passed
variant scenario 2360360Passed

SHA-256 / 6c2fb088048cce24987c1ffb4412c812520836eac41c16cb93dbb1409435bb10

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

Case digest / fd5d8077338af50976b1a38d0d40bd359380e13d8f2016b7061022eda3f703d1