FAILURE MAP
← Case archive

FA-84491 / Betting odds conversion / Open access

Dead heat for first ignored or applied to profit only · case 01

A dead-heated winner is paid as a solo winner.

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

ROOT CAUSE

The win part uses the full stake regardless of the dead heat.

VERIFIED REPAIR

Divide the win stake by the number of runners dead-heating.

Unsuccessful approach: Dividing only the winnings keeps the full stake and overpays.

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 += stake_cents * (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: win dead heat', (1000, '4/4', '1/4', 1, 2, 2), 2250),
  ('variant scenario 1', (250, '10/5', '1/4', 2, 3, 2), 375),
  ('variant scenario 2', (250, '19/4', '1/5', 1, 2, 1), 1925)],
 [('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: win dead heat', (1000, '18/2', '1/5', 1, 5, 3), 6133),
  ('variant scenario 1', (100, '9/4', '1/4', 4, 5, 1), 156),
  ('variant scenario 2', (100, '31/5', '1/5', 4, 5, 1), 224)],
 [('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: win dead heat', (1000, '23/4', '1/5', 1, 5, 2), 5525),
  ('variant scenario 1', (1000, '10/2', '1/5', 5, 5, 1), 2000),
  ('variant scenario 2', (100, '11/2', '1/5', 5, 3, 1), 0)],
 [('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: win dead heat', (250, '20/1', '1/5', 1, 3, 2), 3875),
  ('variant scenario 1', (500, '5/1', '1/5', 2, 5, 2), 1000),
  ('variant scenario 2', (100, '16/2', '1/4', 4, 4, 1), 300)],
 [('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: win dead heat', (100, '9/1', '1/4', 1, 2, 3), 550),
  ('variant scenario 1', (1000, '10/1', '1/4', 2, 3, 1), 3500),
  ('variant scenario 2', (1000, '18/5', '1/4', 5, 3, 2), 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 fixtureActualExpectedOutcome
control winner70007000Passed
control placed20002000Passed
control unplaced00Passed
boundary dead heat for the win68004300Failed
boundary dead heat for last place15001500Passed
regression: win dead heat32502250Failed
variant scenario 1375375Passed
variant scenario 219251925Passed

SHA-256 / ff67128ad93d2e0f9ea402ec3e350ef89f186cf579a4eaed02f9adfc1b24fab0

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 += stake_cents * (1 + f / dead_heat)
    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: win dead heat', (1000, '4/4', '1/4', 1, 2, 2), 2250),
  ('variant scenario 1', (250, '10/5', '1/4', 2, 3, 2), 375),
  ('variant scenario 2', (250, '19/4', '1/5', 1, 2, 1), 1925)],
 [('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: win dead heat', (1000, '18/2', '1/5', 1, 5, 3), 6133),
  ('variant scenario 1', (100, '9/4', '1/4', 4, 5, 1), 156),
  ('variant scenario 2', (100, '31/5', '1/5', 4, 5, 1), 224)],
 [('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: win dead heat', (1000, '23/4', '1/5', 1, 5, 2), 5525),
  ('variant scenario 1', (1000, '10/2', '1/5', 5, 5, 1), 2000),
  ('variant scenario 2', (100, '11/2', '1/5', 5, 3, 1), 0)],
 [('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: win dead heat', (250, '20/1', '1/5', 1, 3, 2), 3875),
  ('variant scenario 1', (500, '5/1', '1/5', 2, 5, 2), 1000),
  ('variant scenario 2', (100, '16/2', '1/4', 4, 4, 1), 300)],
 [('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: win dead heat', (100, '9/1', '1/4', 1, 2, 3), 550),
  ('variant scenario 1', (1000, '10/1', '1/4', 2, 3, 1), 3500),
  ('variant scenario 2', (1000, '18/5', '1/4', 5, 3, 2), 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 fixtureActualExpectedOutcome
control winner70007000Passed
control placed20002000Passed
control unplaced00Passed
boundary dead heat for the win48004300Failed
boundary dead heat for last place15001500Passed
regression: win dead heat27502250Failed
variant scenario 1375375Passed
variant scenario 219251925Passed

SHA-256 / 88fd749a285b8b782cde82c81bde12044890f15a261757d2eb1dc26bbed2e087

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: win dead heat', (1000, '4/4', '1/4', 1, 2, 2), 2250),
  ('variant scenario 1', (250, '10/5', '1/4', 2, 3, 2), 375),
  ('variant scenario 2', (250, '19/4', '1/5', 1, 2, 1), 1925)],
 [('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: win dead heat', (1000, '18/2', '1/5', 1, 5, 3), 6133),
  ('variant scenario 1', (100, '9/4', '1/4', 4, 5, 1), 156),
  ('variant scenario 2', (100, '31/5', '1/5', 4, 5, 1), 224)],
 [('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: win dead heat', (1000, '23/4', '1/5', 1, 5, 2), 5525),
  ('variant scenario 1', (1000, '10/2', '1/5', 5, 5, 1), 2000),
  ('variant scenario 2', (100, '11/2', '1/5', 5, 3, 1), 0)],
 [('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: win dead heat', (250, '20/1', '1/5', 1, 3, 2), 3875),
  ('variant scenario 1', (500, '5/1', '1/5', 2, 5, 2), 1000),
  ('variant scenario 2', (100, '16/2', '1/4', 4, 4, 1), 300)],
 [('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: win dead heat', (100, '9/1', '1/4', 1, 2, 3), 550),
  ('variant scenario 1', (1000, '10/1', '1/4', 2, 3, 1), 3500),
  ('variant scenario 2', (1000, '18/5', '1/4', 5, 3, 2), 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 fixtureActualExpectedOutcome
control winner70007000Passed
control placed20002000Passed
control unplaced00Passed
boundary dead heat for the win43004300Passed
boundary dead heat for last place15001500Passed
regression: win dead heat22502250Passed
variant scenario 1375375Passed
variant scenario 219251925Passed

SHA-256 / d057efaa8d451e828880cd52f0d3c02d608944fd11722cf36383edda439f2082

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

Case digest / 16e3f393b8958ddd10d001f7c12dbf71de501d1830afb46146c966da18978cc1