FAILURE MAP
← Case archive

FA-84501 / Betting odds conversion / Open access

Winner excluded from the place part or last place unpaid · case 01

The winner of an each-way bet receives only the win part, or the last paying place is missed.

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

ROOT CAUSE

The place condition uses position < places_paid.

VERIFIED REPAIR

Pay the place part for any position up to and including places_paid.

Unsuccessful approach: Excluding the winner from the place part misreads each-way as win-or-place.

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 + 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 eligibility', (250, '14/2', '1/5', 1, 4, 2), 1600),
  ('regression: place eligibility', (1000, '1/5', '1/4', 2, 2, 3), 350),
  ('variant scenario 1', (250, '2/5', '1/4', 3, 4, 3), 183),
  ('variant scenario 2', (100, '27/1', '1/5', 1, 4, 2), 2040)],
 [('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 eligibility', (250, '16/1', '1/5', 1, 2, 1), 5300),
  ('regression: place eligibility', (250, '17/1', '1/5', 3, 3, 2), 550),
  ('variant scenario 1', (250, '19/2', '1/5', 2, 5, 2), 725),
  ('variant scenario 2', (250, '21/5', '1/5', 2, 5, 3), 460)],
 [('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 eligibility', (250, '10/2', '1/4', 1, 3, 1), 2062),
  ('regression: place eligibility', (1000, '1/1', '1/4', 2, 2, 2), 625),
  ('variant scenario 1', (100, '24/1', '1/4', 3, 2, 3), 0),
  ('variant scenario 2', (100, '2/2', '1/5', 4, 3, 2), 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: place eligibility', (500, '18/1', '1/5', 1, 4, 2), 7050),
  ('regression: place eligibility', (250, '11/1', '1/5', 3, 3, 1), 800),
  ('variant scenario 1', (250, '28/5', '1/4', 3, 2, 1), 0),
  ('variant scenario 2', (250, '31/4', '1/5', 2, 4, 3), 637)],
 [('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 eligibility', (1000, '15/2', '1/5', 1, 4, 3), 5333),
  ('regression: place eligibility', (250, '29/1', '1/5', 2, 2, 1), 1700),
  ('variant scenario 1', (500, '19/5', '1/5', 2, 4, 1), 880),
  ('variant scenario 2', (500, '33/1', '1/4', 3, 5, 3), 4625)]]
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 place01500Failed
regression: place eligibility16001600Passed
regression: place eligibility0350Failed
variant scenario 1183183Passed
variant scenario 220402040Passed

SHA-256 / 9e1783677dc83edbe15b7b2894bf33e328fbac01774ceb855d79f4e3671132e7

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 1 < 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 eligibility', (250, '14/2', '1/5', 1, 4, 2), 1600),
  ('regression: place eligibility', (1000, '1/5', '1/4', 2, 2, 3), 350),
  ('variant scenario 1', (250, '2/5', '1/4', 3, 4, 3), 183),
  ('variant scenario 2', (100, '27/1', '1/5', 1, 4, 2), 2040)],
 [('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 eligibility', (250, '16/1', '1/5', 1, 2, 1), 5300),
  ('regression: place eligibility', (250, '17/1', '1/5', 3, 3, 2), 550),
  ('variant scenario 1', (250, '19/2', '1/5', 2, 5, 2), 725),
  ('variant scenario 2', (250, '21/5', '1/5', 2, 5, 3), 460)],
 [('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 eligibility', (250, '10/2', '1/4', 1, 3, 1), 2062),
  ('regression: place eligibility', (1000, '1/1', '1/4', 2, 2, 2), 625),
  ('variant scenario 1', (100, '24/1', '1/4', 3, 2, 3), 0),
  ('variant scenario 2', (100, '2/2', '1/5', 4, 3, 2), 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: place eligibility', (500, '18/1', '1/5', 1, 4, 2), 7050),
  ('regression: place eligibility', (250, '11/1', '1/5', 3, 3, 1), 800),
  ('variant scenario 1', (250, '28/5', '1/4', 3, 2, 1), 0),
  ('variant scenario 2', (250, '31/4', '1/5', 2, 4, 3), 637)],
 [('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 eligibility', (1000, '15/2', '1/5', 1, 4, 3), 5333),
  ('regression: place eligibility', (250, '29/1', '1/5', 2, 2, 1), 1700),
  ('variant scenario 1', (500, '19/5', '1/5', 2, 4, 1), 880),
  ('variant scenario 2', (500, '33/1', '1/4', 3, 5, 3), 4625)]]
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 winner50007000Failed
control placed20002000Passed
control unplaced00Passed
boundary dead heat for the win25004300Failed
boundary dead heat for last place15001500Passed
regression: place eligibility10001600Failed
regression: place eligibility350350Passed
variant scenario 1183183Passed
variant scenario 214002040Failed

SHA-256 / e0246cd78f36c0951efe83f18206c3530b52d75e4cdb16bb61017f262b4359f9

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 eligibility', (250, '14/2', '1/5', 1, 4, 2), 1600),
  ('regression: place eligibility', (1000, '1/5', '1/4', 2, 2, 3), 350),
  ('variant scenario 1', (250, '2/5', '1/4', 3, 4, 3), 183),
  ('variant scenario 2', (100, '27/1', '1/5', 1, 4, 2), 2040)],
 [('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 eligibility', (250, '16/1', '1/5', 1, 2, 1), 5300),
  ('regression: place eligibility', (250, '17/1', '1/5', 3, 3, 2), 550),
  ('variant scenario 1', (250, '19/2', '1/5', 2, 5, 2), 725),
  ('variant scenario 2', (250, '21/5', '1/5', 2, 5, 3), 460)],
 [('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 eligibility', (250, '10/2', '1/4', 1, 3, 1), 2062),
  ('regression: place eligibility', (1000, '1/1', '1/4', 2, 2, 2), 625),
  ('variant scenario 1', (100, '24/1', '1/4', 3, 2, 3), 0),
  ('variant scenario 2', (100, '2/2', '1/5', 4, 3, 2), 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: place eligibility', (500, '18/1', '1/5', 1, 4, 2), 7050),
  ('regression: place eligibility', (250, '11/1', '1/5', 3, 3, 1), 800),
  ('variant scenario 1', (250, '28/5', '1/4', 3, 2, 1), 0),
  ('variant scenario 2', (250, '31/4', '1/5', 2, 4, 3), 637)],
 [('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 eligibility', (1000, '15/2', '1/5', 1, 4, 3), 5333),
  ('regression: place eligibility', (250, '29/1', '1/5', 2, 2, 1), 1700),
  ('variant scenario 1', (500, '19/5', '1/5', 2, 4, 1), 880),
  ('variant scenario 2', (500, '33/1', '1/4', 3, 5, 3), 4625)]]
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 eligibility16001600Passed
regression: place eligibility350350Passed
variant scenario 1183183Passed
variant scenario 220402040Passed

SHA-256 / f82fae75f3a978ea4cd5afcf5fcf56e8ed9d8c802b4c1bc8e7891db2d03b60dc

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

Case digest / 8c79f6b300b665c80585b3abecd9cc6448c8edfe9be2bd65a31e1e7894cf1b52