FAILURE MAP
← Case archive

FA-84721 / Betting odds conversion / Open access

Minimum dividend floor set to the stake or applied only below 1.00 · case 01

Heavily backed winners pay 1.00 or 1.05 instead of the 1.10 minimum.

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

ROOT CAUSE

The minimum is set to 1.00.

VERIFIED REPAIR

Floor every dividend at 1.10.

Unsuccessful approach: Only lifting dividends below 1.00 leaves 1.00 and 1.05 payouts under the minimum.

Case contract

Pari-mutuel win dividend per unit stake. The net pool is pool * (100 - takeout_pct) / 100; with a dead heat it is split equally among the winning runners. Each runner's dividend is its share divided by the stakes on it, broken down to the 10-cent step below (breakage), with a minimum of 1.10. A winner with no stakes gets None. Return dividends as "D.D0" strings in winners order.

Why this case matters

Tote operators compute dividends with takeout, breakage and minimum-dividend rules.

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(pool_cents, takeout_pct, winners):
    net = Fraction(pool_cents) * (100 - Fraction(takeout_pct)) / 100
    share = net / len(winners)
    out = []
    for s in winners:
        if s == 0:
            out.append(None)
            continue
        dimes = math.floor(share / s * 10)
        dimes = max(dimes, 10)
        out.append('%d.%d0' % (dimes // 10, dimes % 10))
    return out
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 single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (250000, '16', [35604, 123268]), ['2.90', '1.10']),
  ('regression: minimum dividend', (250000, '0', [230658]), ['1.10']),
  ('variant scenario 1', (20000, '0', [12085]), ['1.60']),
  ('variant scenario 2', (50000, '15', [0]), [None])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend',
   (250000, '16', [10000, 250000, 97356]),
   ['7.00', '1.10', '1.10']),
  ('regression: minimum dividend', (50000, '15', [40000]), ['1.10']),
  ('variant scenario 1', (1234500, '16', [793963]), ['1.30']),
  ('variant scenario 2', (250000, '0', [333, 10000]), ['375.30', '12.50'])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (1234500, '15', [1156662]), ['1.10']),
  ('regression: minimum dividend', (50000, '15', [19428, 50000]), ['1.10', '1.10']),
  ('variant scenario 1', (50000, '15', [3875]), ['10.90']),
  ('variant scenario 2', (250000, '15', [0]), [None])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (250000, '20', [248216]), ['1.10']),
  ('regression: minimum dividend', (50000, '0', [50000]), ['1.10']),
  ('variant scenario 1', (100000, '15', [22149]), ['3.80']),
  ('variant scenario 2', (100000, '0', [333]), ['300.30'])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend',
   (1234500, '0', [1017834, 351582, 426153]),
   ['1.10', '1.10', '1.10']),
  ('regression: minimum dividend', (100000, '15', [50000, 40000]), ['1.10', '1.10']),
  ('variant scenario 1', (100000, '20', [50621]), ['1.50']),
  ('variant scenario 2', (50000, '0', [33751]), ['1.40'])]]
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 single winner['3.40']['3.40']Passed
boundary breakage down['2.80']['2.80']Passed
boundary minimum dividend['1.00']['1.10']Failed
boundary dead heat split['4.00', '1.00']['4.00', '1.10']Failed
control unbacked winner[None][None]Passed
regression: minimum dividend['2.90', '1.00']['2.90', '1.10']Failed
regression: minimum dividend['1.00']['1.10']Failed
variant scenario 1['1.60']['1.60']Passed
variant scenario 2[None][None]Passed

SHA-256 / 3ad16dd61a9ec4fdd5ce24bf9b90dc4e306d353cb24defd196ce0625af532a4d

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(pool_cents, takeout_pct, winners):
    net = Fraction(pool_cents) * (100 - Fraction(takeout_pct)) / 100
    share = net / len(winners)
    out = []
    for s in winners:
        if s == 0:
            out.append(None)
            continue
        dimes = math.floor(share / s * 10)
        dimes = dimes if dimes >= 10 else 11
        out.append('%d.%d0' % (dimes // 10, dimes % 10))
    return out
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 single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (250000, '16', [35604, 123268]), ['2.90', '1.10']),
  ('regression: minimum dividend', (250000, '0', [230658]), ['1.10']),
  ('variant scenario 1', (20000, '0', [12085]), ['1.60']),
  ('variant scenario 2', (50000, '15', [0]), [None])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend',
   (250000, '16', [10000, 250000, 97356]),
   ['7.00', '1.10', '1.10']),
  ('regression: minimum dividend', (50000, '15', [40000]), ['1.10']),
  ('variant scenario 1', (1234500, '16', [793963]), ['1.30']),
  ('variant scenario 2', (250000, '0', [333, 10000]), ['375.30', '12.50'])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (1234500, '15', [1156662]), ['1.10']),
  ('regression: minimum dividend', (50000, '15', [19428, 50000]), ['1.10', '1.10']),
  ('variant scenario 1', (50000, '15', [3875]), ['10.90']),
  ('variant scenario 2', (250000, '15', [0]), [None])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (250000, '20', [248216]), ['1.10']),
  ('regression: minimum dividend', (50000, '0', [50000]), ['1.10']),
  ('variant scenario 1', (100000, '15', [22149]), ['3.80']),
  ('variant scenario 2', (100000, '0', [333]), ['300.30'])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend',
   (1234500, '0', [1017834, 351582, 426153]),
   ['1.10', '1.10', '1.10']),
  ('regression: minimum dividend', (100000, '15', [50000, 40000]), ['1.10', '1.10']),
  ('variant scenario 1', (100000, '20', [50621]), ['1.50']),
  ('variant scenario 2', (50000, '0', [33751]), ['1.40'])]]
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 single winner['3.40']['3.40']Passed
boundary breakage down['2.80']['2.80']Passed
boundary minimum dividend['1.10']['1.10']Passed
boundary dead heat split['4.00', '1.00']['4.00', '1.10']Failed
control unbacked winner[None][None]Passed
regression: minimum dividend['2.90', '1.10']['2.90', '1.10']Passed
regression: minimum dividend['1.00']['1.10']Failed
variant scenario 1['1.60']['1.60']Passed
variant scenario 2[None][None]Passed

SHA-256 / 83fe85fe3b343bb2745f27fe5f64f259d3d00b9d275798cb7c988d5928bebb56

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(pool_cents, takeout_pct, winners):
    net = Fraction(pool_cents) * (100 - Fraction(takeout_pct)) / 100
    share = net / len(winners)
    out = []
    for s in winners:
        if s == 0:
            out.append(None)
            continue
        dimes = math.floor(share / s * 10)
        dimes = max(dimes, 11)
        out.append('%d.%d0' % (dimes // 10, dimes % 10))
    return out
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 single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (250000, '16', [35604, 123268]), ['2.90', '1.10']),
  ('regression: minimum dividend', (250000, '0', [230658]), ['1.10']),
  ('variant scenario 1', (20000, '0', [12085]), ['1.60']),
  ('variant scenario 2', (50000, '15', [0]), [None])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend',
   (250000, '16', [10000, 250000, 97356]),
   ['7.00', '1.10', '1.10']),
  ('regression: minimum dividend', (50000, '15', [40000]), ['1.10']),
  ('variant scenario 1', (1234500, '16', [793963]), ['1.30']),
  ('variant scenario 2', (250000, '0', [333, 10000]), ['375.30', '12.50'])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (1234500, '15', [1156662]), ['1.10']),
  ('regression: minimum dividend', (50000, '15', [19428, 50000]), ['1.10', '1.10']),
  ('variant scenario 1', (50000, '15', [3875]), ['10.90']),
  ('variant scenario 2', (250000, '15', [0]), [None])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend', (250000, '20', [248216]), ['1.10']),
  ('regression: minimum dividend', (50000, '0', [50000]), ['1.10']),
  ('variant scenario 1', (100000, '15', [22149]), ['3.80']),
  ('variant scenario 2', (100000, '0', [333]), ['300.30'])],
 [('control single winner', (100000, '15', [25000]), ['3.40']),
  ('boundary breakage down', (100000, '16', [30000]), ['2.80']),
  ('boundary minimum dividend', (100000, '20', [90000]), ['1.10']),
  ('boundary dead heat split', (100000, '20', [10000, 40000]), ['4.00', '1.10']),
  ('control unbacked winner', (100000, '15', [0]), [None]),
  ('regression: minimum dividend',
   (1234500, '0', [1017834, 351582, 426153]),
   ['1.10', '1.10', '1.10']),
  ('regression: minimum dividend', (100000, '15', [50000, 40000]), ['1.10', '1.10']),
  ('variant scenario 1', (100000, '20', [50621]), ['1.50']),
  ('variant scenario 2', (50000, '0', [33751]), ['1.40'])]]
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 single winner['3.40']['3.40']Passed
boundary breakage down['2.80']['2.80']Passed
boundary minimum dividend['1.10']['1.10']Passed
boundary dead heat split['4.00', '1.10']['4.00', '1.10']Passed
control unbacked winner[None][None]Passed
regression: minimum dividend['2.90', '1.10']['2.90', '1.10']Passed
regression: minimum dividend['1.10']['1.10']Passed
variant scenario 1['1.60']['1.60']Passed
variant scenario 2[None][None]Passed

SHA-256 / 9803bb918722437174c61c22ad662c396f1def1f2b8166fc07251c0542e37723

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

Case digest / f98190e958dc937a15709b684b0fe8db730c7ffa65d29f49b1784e413b9d39ec