FAILURE MAP
← Case archive

FA-84201 / Sports scoring and tiebreakers / Open access

Bust only undoes the last dart · case 01

After a bust the remaining score keeps the earlier darts of the turn.

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

ROOT CAUSE

The bust handler adds back only the value of the busting dart.

VERIFIED REPAIR

Restore the score captured at the start of the turn.

Unsuccessful approach: Reverting to the leg starting score wipes out earlier completed turns.

Case contract

Double-out darts leg from a remaining score. darts lists thrown darts: S/D/T followed by 1-20, SB (25), DB (50, a double) or M (miss). Turns are three darts. After each dart: reaching exactly 0 with a double (D* or DB) checks out and later darts are ignored; a remaining score below 2 otherwise is a bust, the score reverts to its value at the start of the turn and the turn ends immediately (the next dart in the list starts a new turn). Return [remaining, turns used, checked_out].

Why this case matters

Darts scoring apps must implement bust reversion and double-out exactly.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(start, darts):
    def value(d):
        if d == 'M':
            return 0, False
        if d == 'SB':
            return 25, False
        if d == 'DB':
            return 50, True
        mult = {'S': 1, 'D': 2, 'T': 3}[d[0]]
        return mult * int(d[1:]), d[0] == 'D'
    score = start
    turns = 0
    i = 0
    while i < len(darts):
        turns += 1
        turn_start = score
        for k in range(3):
            if i >= len(darts):
                break
            v, dbl = value(darts[i])
            i += 1
            score -= v
            if score == 0 and dbl:
                return [0, turns, True]
            if score < 2:
                score += v
                break
    return [score, turns, False]
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 checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope',
   (20, ['S13', 'D5', 'T12', 'T17', 'D7', 'D13', 'S6']),
   [14, 5, False]),
  ('regression: bust reversion scope',
   (54, ['D13', 'S13', 'DB', 'M', 'S9', 'S16', 'D16', 'M']),
   [29, 4, False]),
  ('variant scenario 1',
   (45, ['T10', 'S14', 'S20', 'D1', 'SB', 'D19', 'D20', 'D16', 'S14']),
   [45, 4, False]),
  ('variant scenario 2',
   (36, ['S18', 'D12', 'D4', 'D15', 'D11', 'D12', 'D11', 'D11']),
   [36, 4, False])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (50, ['T3', 'D4', 'S8', 'T8', 'S9', 'SB']), [25, 3, False]),
  ('variant scenario 1', (32, ['D4', 'D14', 'SB', 'DB', 'D15', 'S4', 'S5', 'T5']), [12, 4, False]),
  ('variant scenario 2', (50, ['DB']), [0, 1, True])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (32, ['T2', 'S18', 'S12', 'D7']), [18, 2, False]),
  ('regression: bust reversion scope',
   (101, ['D11', 'D9', 'S5', 'D12', 'D11', 'DB']),
   [56, 2, False]),
  ('variant scenario 1', (3, ['D10', 'T9']), [3, 2, False]),
  ('variant scenario 2', (101, ['D15', 'S1', 'D1']), [68, 1, False])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (50, ['T4', 'S8', 'S4', 'T1', 'SB', 'T12']), [26, 3, False]),
  ('variant scenario 1', (3, ['S19', 'D6', 'D4', 'D19', 'D5', 'D9', 'T10', 'S14']), [3, 8, False]),
  ('variant scenario 2', (16, ['D13', 'D17', 'D8', 'S8']), [0, 3, True])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope',
   (10, ['S16', 'D18', 'T5', 'D20', 'D2', 'D4', 'S9', 'D16', 'D2']),
   [6, 8, False]),
  ('regression: bust reversion scope',
   (101, ['D9', 'T11', 'SB', 'D15', 'T19', 'S7']),
   [18, 4, False]),
  ('variant scenario 1', (3, ['M', 'D19', 'T10', 'T8', 'D5', 'S4', 'M', 'S3']), [3, 6, False]),
  ('variant scenario 2', (101, ['D5', 'D12']), [67, 1, False])]]
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 checkout on double[0, 1, True][0, 1, True]Passed
boundary finish on single busts[0, 2, True][0, 2, True]Passed
boundary leave one busts[20, 2, False][20, 2, False]Passed
control bull finish[0, 1, True][0, 1, True]Passed
boundary bust mid-turn reverts[22, 2, False][0, 2, True]Failed
control scoring turn[20, 1, False][20, 1, False]Passed
regression: bust reversion scope[7, 6, False][14, 5, False]Failed
regression: bust reversion scope[6, 4, False][29, 4, False]Failed
variant scenario 1[13, 7, False][45, 4, False]Failed
variant scenario 2[10, 6, False][36, 4, False]Failed

SHA-256 / b8f2ffd7bf5b2411af737cb190ddc1b5141e24bdabba49ddc27defcbfacd7a52

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(start, darts):
    def value(d):
        if d == 'M':
            return 0, False
        if d == 'SB':
            return 25, False
        if d == 'DB':
            return 50, True
        mult = {'S': 1, 'D': 2, 'T': 3}[d[0]]
        return mult * int(d[1:]), d[0] == 'D'
    score = start
    turns = 0
    i = 0
    while i < len(darts):
        turns += 1
        turn_start = score
        for k in range(3):
            if i >= len(darts):
                break
            v, dbl = value(darts[i])
            i += 1
            score -= v
            if score == 0 and dbl:
                return [0, turns, True]
            if score < 2:
                score = start
                break
    return [score, turns, False]
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 checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope',
   (20, ['S13', 'D5', 'T12', 'T17', 'D7', 'D13', 'S6']),
   [14, 5, False]),
  ('regression: bust reversion scope',
   (54, ['D13', 'S13', 'DB', 'M', 'S9', 'S16', 'D16', 'M']),
   [29, 4, False]),
  ('variant scenario 1',
   (45, ['T10', 'S14', 'S20', 'D1', 'SB', 'D19', 'D20', 'D16', 'S14']),
   [45, 4, False]),
  ('variant scenario 2',
   (36, ['S18', 'D12', 'D4', 'D15', 'D11', 'D12', 'D11', 'D11']),
   [36, 4, False])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (50, ['T3', 'D4', 'S8', 'T8', 'S9', 'SB']), [25, 3, False]),
  ('variant scenario 1', (32, ['D4', 'D14', 'SB', 'DB', 'D15', 'S4', 'S5', 'T5']), [12, 4, False]),
  ('variant scenario 2', (50, ['DB']), [0, 1, True])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (32, ['T2', 'S18', 'S12', 'D7']), [18, 2, False]),
  ('regression: bust reversion scope',
   (101, ['D11', 'D9', 'S5', 'D12', 'D11', 'DB']),
   [56, 2, False]),
  ('variant scenario 1', (3, ['D10', 'T9']), [3, 2, False]),
  ('variant scenario 2', (101, ['D15', 'S1', 'D1']), [68, 1, False])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (50, ['T4', 'S8', 'S4', 'T1', 'SB', 'T12']), [26, 3, False]),
  ('variant scenario 1', (3, ['S19', 'D6', 'D4', 'D19', 'D5', 'D9', 'T10', 'S14']), [3, 8, False]),
  ('variant scenario 2', (16, ['D13', 'D17', 'D8', 'S8']), [0, 3, True])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope',
   (10, ['S16', 'D18', 'T5', 'D20', 'D2', 'D4', 'S9', 'D16', 'D2']),
   [6, 8, False]),
  ('regression: bust reversion scope',
   (101, ['D9', 'T11', 'SB', 'D15', 'T19', 'S7']),
   [18, 4, False]),
  ('variant scenario 1', (3, ['M', 'D19', 'T10', 'T8', 'D5', 'S4', 'M', 'S3']), [3, 6, False]),
  ('variant scenario 2', (101, ['D5', 'D12']), [67, 1, False])]]
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 checkout on double[0, 1, True][0, 1, True]Passed
boundary finish on single busts[0, 2, True][0, 2, True]Passed
boundary leave one busts[20, 2, False][20, 2, False]Passed
control bull finish[0, 1, True][0, 1, True]Passed
boundary bust mid-turn reverts[0, 2, True][0, 2, True]Passed
control scoring turn[20, 1, False][20, 1, False]Passed
regression: bust reversion scope[14, 5, False][14, 5, False]Passed
regression: bust reversion scope[54, 4, False][29, 4, False]Failed
variant scenario 1[45, 4, False][45, 4, False]Passed
variant scenario 2[36, 4, False][36, 4, False]Passed

SHA-256 / 1991203535b6f4034ae749d588e07e2e23abb53f69582e8f3ac786fcff582515

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(start, darts):
    def value(d):
        if d == 'M':
            return 0, False
        if d == 'SB':
            return 25, False
        if d == 'DB':
            return 50, True
        mult = {'S': 1, 'D': 2, 'T': 3}[d[0]]
        return mult * int(d[1:]), d[0] == 'D'
    score = start
    turns = 0
    i = 0
    while i < len(darts):
        turns += 1
        turn_start = score
        for k in range(3):
            if i >= len(darts):
                break
            v, dbl = value(darts[i])
            i += 1
            score -= v
            if score == 0 and dbl:
                return [0, turns, True]
            if score < 2:
                score = turn_start
                break
    return [score, turns, False]
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 checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope',
   (20, ['S13', 'D5', 'T12', 'T17', 'D7', 'D13', 'S6']),
   [14, 5, False]),
  ('regression: bust reversion scope',
   (54, ['D13', 'S13', 'DB', 'M', 'S9', 'S16', 'D16', 'M']),
   [29, 4, False]),
  ('variant scenario 1',
   (45, ['T10', 'S14', 'S20', 'D1', 'SB', 'D19', 'D20', 'D16', 'S14']),
   [45, 4, False]),
  ('variant scenario 2',
   (36, ['S18', 'D12', 'D4', 'D15', 'D11', 'D12', 'D11', 'D11']),
   [36, 4, False])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (50, ['T3', 'D4', 'S8', 'T8', 'S9', 'SB']), [25, 3, False]),
  ('variant scenario 1', (32, ['D4', 'D14', 'SB', 'DB', 'D15', 'S4', 'S5', 'T5']), [12, 4, False]),
  ('variant scenario 2', (50, ['DB']), [0, 1, True])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (32, ['T2', 'S18', 'S12', 'D7']), [18, 2, False]),
  ('regression: bust reversion scope',
   (101, ['D11', 'D9', 'S5', 'D12', 'D11', 'DB']),
   [56, 2, False]),
  ('variant scenario 1', (3, ['D10', 'T9']), [3, 2, False]),
  ('variant scenario 2', (101, ['D15', 'S1', 'D1']), [68, 1, False])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope', (50, ['T4', 'S8', 'S4', 'T1', 'SB', 'T12']), [26, 3, False]),
  ('variant scenario 1', (3, ['S19', 'D6', 'D4', 'D19', 'D5', 'D9', 'T10', 'S14']), [3, 8, False]),
  ('variant scenario 2', (16, ['D13', 'D17', 'D8', 'S8']), [0, 3, True])],
 [('control checkout on double', (40, ['D20']), [0, 1, True]),
  ('boundary finish on single busts', (20, ['S20', 'D10']), [0, 2, True]),
  ('boundary leave one busts', (21, ['S20', 'S1']), [20, 2, False]),
  ('control bull finish', (50, ['DB']), [0, 1, True]),
  ('boundary bust mid-turn reverts', (32, ['S10', 'T20', 'D16']), [0, 2, True]),
  ('control scoring turn', (101, ['T20', 'S1', 'S20']), [20, 1, False]),
  ('regression: bust reversion scope',
   (10, ['S16', 'D18', 'T5', 'D20', 'D2', 'D4', 'S9', 'D16', 'D2']),
   [6, 8, False]),
  ('regression: bust reversion scope',
   (101, ['D9', 'T11', 'SB', 'D15', 'T19', 'S7']),
   [18, 4, False]),
  ('variant scenario 1', (3, ['M', 'D19', 'T10', 'T8', 'D5', 'S4', 'M', 'S3']), [3, 6, False]),
  ('variant scenario 2', (101, ['D5', 'D12']), [67, 1, False])]]
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 checkout on double[0, 1, True][0, 1, True]Passed
boundary finish on single busts[0, 2, True][0, 2, True]Passed
boundary leave one busts[20, 2, False][20, 2, False]Passed
control bull finish[0, 1, True][0, 1, True]Passed
boundary bust mid-turn reverts[0, 2, True][0, 2, True]Passed
control scoring turn[20, 1, False][20, 1, False]Passed
regression: bust reversion scope[14, 5, False][14, 5, False]Passed
regression: bust reversion scope[29, 4, False][29, 4, False]Passed
variant scenario 1[45, 4, False][45, 4, False]Passed
variant scenario 2[36, 4, False][36, 4, False]Passed

SHA-256 / 5ed3d0a1d01361928cf7df381f473e690c20f94221af572a9df5feafdbad60b8

Verification & scope

Stipulated, bounded toy contract stated in the contract field; not a claim of conformance with any governing body rulebook or operator house rules. 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:28.535308+00:00.

Case digest / c38866168016f32c113ab744a5e01c93ca15ed05195352feb33d1c42daed3c18