FAILURE MAP
← Case archive

FA-85306 / Fantasy sports scoring / Open access

Live projection prorated by elapsed time · case 01

A player at kickoff shows no remaining projection while a nearly finished game shows the whole projection.

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

ROOT CAUSE

The projection is scaled by elapsed rather than remaining seconds.

VERIFIED REPAIR

Scale the projection by remaining seconds over 3600.

Unsuccessful approach: Subtracting the floored elapsed share rounds the remaining share up instead of down.

Case contract

Projected final lineup score in tenths. Each player is [actual, full-game projection, status, game seconds left]. Final games count actual points; not-started games count the full projection; live games count actual plus the projection prorated by remaining time over 3600 seconds (floored per player; overtime reports negative seconds, treated as 0 remaining); postponed (ppd) games count 0.

Why this case matters

Live projections are shown to millions of users during games; status handling and proration must be exact.

1 / The failure

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

N = 1
observations = []
def solve(players):
    total = 0
    for actual, proj, status, left in players:
        if status == 'final':
            total += actual
        elif status == 'pre':
            total += proj
        elif status == 'live':
            left = max(left, 0)
            total += actual + proj * (3600 - left) // 3600
    return total
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: remaining time proration',
   [[[213, 180, 'final', 3600], [200, 180, 'live', -300], [102, 95, 'live', 1800]]], 562),
  ('partial repair probe: remaining time proration',
   [[[36, 0, 'live', 1800], [17, 180, 'live', 900], [72, 0, 'live', 1800], [137, 180, 'pre', -300],
     [221, 180, 'live', 1], [154, 0, 'live', 1800]]],
   725),
  ('second regression', [[[237, 95, 'live', 900], [48, 95, 'live', 3600], [237, 180, 'live', 1800]]], 730),
  ('normal control 1', [[[110, 0, 'final', 900], [154, 95, 'ppd', 3600]]], 110),
  ('normal control 2',
   [[[130, 0, 'live', 0], [150, 120, 'final', 3600], [231, 0, 'live', 1800], [86, 0, 'ppd', 1],
     [148, 0, 'live', -300], [234, 0, 'final', -300]]],
   893),
  ('normal control 3', [[[173, 180, 'pre', 1], [126, 180, 'ppd', 0], [32, 0, 'final', 0]]], 212),
  ('normal control 4',
   [[[101, 120, 'ppd', 900], [78, 180, 'ppd', 0], [57, 180, 'final', 900], [220, 120, 'pre', 1800],
     [192, 120, 'live', 1800]]],
   429)],
 [('regression: remaining time proration',
   [[[115, 120, 'live', 1800], [221, 180, 'live', 900], [144, 95, 'ppd', 900], [237, 180, 'live', 3600],
     [48, 180, 'ppd', 1], [92, 180, 'pre', -300]]],
   1038),
  ('partial repair probe: remaining time proration', [[[113, 180, 'pre', 3600], [57, 95, 'live', 1]]], 237),
  ('second regression', [[[172, 120, 'live', 900], [5, 0, 'final', 3600]]], 207),
  ('normal control 1',
   [[[18, 120, 'ppd', 900], [72, 120, 'ppd', 3600], [129, 120, 'pre', 1800], [3, 120, 'pre', 3600],
     [224, 180, 'pre', 1800]]],
   420),
  ('normal control 2',
   [[[145, 180, 'final', 900], [133, 120, 'pre', 0], [42, 120, 'live', 1800], [39, 120, 'final', -300]]],
   406),
  ('normal control 3',
   [[[250, 180, 'ppd', 1], [227, 0, 'live', 0], [205, 180, 'pre', 1800], [89, 0, 'pre', 0],
     [49, 180, 'pre', -300]]],
   587),
  ('normal control 4', [[[58, 95, 'final', 0], [232, 180, 'final', 1], [166, 95, 'final', 3600]]], 456)],
 [('regression: remaining time proration',
   [[[-14, 95, 'live', 900], [174, 95, 'ppd', 3600], [40, 180, 'final', -300]]], 49),
  ('partial repair probe: remaining time proration',
   [[[150, 120, 'ppd', 1], [80, 95, 'ppd', 900], [4, 120, 'final', 1], [-20, 120, 'live', 1]]], -16),
  ('second regression',
   [[[156, 120, 'live', -300], [207, 0, 'ppd', 0], [96, 95, 'live', 3600], [1, 180, 'live', 1800]]], 438),
  ('normal control 1',
   [[[131, 180, 'pre', 1], [11, 180, 'ppd', 900], [12, 0, 'ppd', 3600], [73, 0, 'final', 0],
     [55, 0, 'live', 3600], [86, 120, 'pre', 0]]],
   428),
  ('normal control 2', [[[13, 120, 'pre', 0], [212, 0, 'pre', 900]]], 120),
  ('normal control 3', [[[230, 95, 'ppd', 3600], [245, 0, 'live', 0]]], 245),
  ('normal control 4',
   [[[95, 120, 'ppd', 900], [245, 0, 'pre', 1], [37, 0, 'pre', 0], [194, 0, 'final', 0],
     [94, 180, 'ppd', 1800]]],
   194)],
 [('regression: remaining time proration',
   [[[52, 120, 'ppd', 900], [184, 95, 'live', 1], [6, 0, 'pre', 0], [198, 180, 'final', 1],
     [118, 95, 'live', 0]]],
   500),
  ('partial repair probe: remaining time proration',
   [[[170, 95, 'pre', 1800], [64, 180, 'ppd', 900], [212, 120, 'live', 1], [68, 180, 'final', -300],
     [61, 0, 'pre', 3600], [102, 120, 'pre', 1]]],
   495),
  ('second regression',
   [[[68, 180, 'live', 1], [84, 95, 'final', 3600], [73, 120, 'ppd', 900], [49, 0, 'live', 0],
     [48, 0, 'pre', 3600]]],
   201),
  ('normal control 1',
   [[[35, 180, 'pre', 1], [168, 0, 'pre', 900], [69, 95, 'pre', 1], [85, 0, 'live', 900],
     [43, 0, 'live', 900]]],
   403),
  ('normal control 2',
   [[[23, 0, 'pre', -300], [210, 95, 'pre', 3600], [9, 0, 'live', 900], [3, 0, 'live', -300],
     [166, 180, 'pre', 3600], [174, 95, 'final', 1800]]],
   461),
  ('normal control 3', [[[80, 180, 'final', 1], [118, 180, 'ppd', 3600], [249, 95, 'pre', -300]]], 175),
  ('normal control 4', [[[185, 120, 'final', 3600], [223, 0, 'pre', 3600]]], 185)],
 [('regression: remaining time proration',
   [[[231, 0, 'live', 0], [195, 95, 'live', -300], [191, 120, 'ppd', -300]]], 426),
  ('partial repair probe: remaining time proration',
   [[[188, 180, 'live', 0], [66, 95, 'pre', 900], [105, 95, 'live', 1800], [227, 120, 'ppd', 900],
     [124, 0, 'live', 1]]],
   559),
  ('second regression', [[[154, 0, 'live', 0], [250, 180, 'live', -300], [44, 120, 'final', 1800]]], 448),
  ('normal control 1', [[[170, 120, 'ppd', 1800], [186, 180, 'final', 1]]], 186),
  ('normal control 2', [[[230, 120, 'ppd', 1], [209, 95, 'pre', 1]]], 95),
  ('normal control 3',
   [[[171, 0, 'pre', 3600], [55, 120, 'pre', 1800], [204, 0, 'final', 1], [35, 95, 'final', 3600],
     [211, 120, 'final', 3600]]],
   570),
  ('normal control 4',
   [[[38, 0, 'live', 1800], [-1, 0, 'live', 3600], [94, 120, 'pre', 1], [12, 0, 'live', 1800],
     [139, 120, 'pre', 0]]],
   289)]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*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
regression: remaining time proration742562Failed
partial repair probe: remaining time proration994725Failed
second regression683730Failed
normal control 1110110Passed
normal control 2893893Passed
normal control 3212212Passed
normal control 4429429Passed

SHA-256 / bf682f0e0d28d836d17ef36627335ec1ebc5f943675b76fc450dcac017db2457

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(players):
    total = 0
    for actual, proj, status, left in players:
        if status == 'final':
            total += actual
        elif status == 'pre':
            total += proj
        elif status == 'live':
            left = max(left, 0)
            total += actual + proj - proj * (3600 - left) // 3600
    return total
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: remaining time proration',
   [[[213, 180, 'final', 3600], [200, 180, 'live', -300], [102, 95, 'live', 1800]]], 562),
  ('partial repair probe: remaining time proration',
   [[[36, 0, 'live', 1800], [17, 180, 'live', 900], [72, 0, 'live', 1800], [137, 180, 'pre', -300],
     [221, 180, 'live', 1], [154, 0, 'live', 1800]]],
   725),
  ('second regression', [[[237, 95, 'live', 900], [48, 95, 'live', 3600], [237, 180, 'live', 1800]]], 730),
  ('normal control 1', [[[110, 0, 'final', 900], [154, 95, 'ppd', 3600]]], 110),
  ('normal control 2',
   [[[130, 0, 'live', 0], [150, 120, 'final', 3600], [231, 0, 'live', 1800], [86, 0, 'ppd', 1],
     [148, 0, 'live', -300], [234, 0, 'final', -300]]],
   893),
  ('normal control 3', [[[173, 180, 'pre', 1], [126, 180, 'ppd', 0], [32, 0, 'final', 0]]], 212),
  ('normal control 4',
   [[[101, 120, 'ppd', 900], [78, 180, 'ppd', 0], [57, 180, 'final', 900], [220, 120, 'pre', 1800],
     [192, 120, 'live', 1800]]],
   429)],
 [('regression: remaining time proration',
   [[[115, 120, 'live', 1800], [221, 180, 'live', 900], [144, 95, 'ppd', 900], [237, 180, 'live', 3600],
     [48, 180, 'ppd', 1], [92, 180, 'pre', -300]]],
   1038),
  ('partial repair probe: remaining time proration', [[[113, 180, 'pre', 3600], [57, 95, 'live', 1]]], 237),
  ('second regression', [[[172, 120, 'live', 900], [5, 0, 'final', 3600]]], 207),
  ('normal control 1',
   [[[18, 120, 'ppd', 900], [72, 120, 'ppd', 3600], [129, 120, 'pre', 1800], [3, 120, 'pre', 3600],
     [224, 180, 'pre', 1800]]],
   420),
  ('normal control 2',
   [[[145, 180, 'final', 900], [133, 120, 'pre', 0], [42, 120, 'live', 1800], [39, 120, 'final', -300]]],
   406),
  ('normal control 3',
   [[[250, 180, 'ppd', 1], [227, 0, 'live', 0], [205, 180, 'pre', 1800], [89, 0, 'pre', 0],
     [49, 180, 'pre', -300]]],
   587),
  ('normal control 4', [[[58, 95, 'final', 0], [232, 180, 'final', 1], [166, 95, 'final', 3600]]], 456)],
 [('regression: remaining time proration',
   [[[-14, 95, 'live', 900], [174, 95, 'ppd', 3600], [40, 180, 'final', -300]]], 49),
  ('partial repair probe: remaining time proration',
   [[[150, 120, 'ppd', 1], [80, 95, 'ppd', 900], [4, 120, 'final', 1], [-20, 120, 'live', 1]]], -16),
  ('second regression',
   [[[156, 120, 'live', -300], [207, 0, 'ppd', 0], [96, 95, 'live', 3600], [1, 180, 'live', 1800]]], 438),
  ('normal control 1',
   [[[131, 180, 'pre', 1], [11, 180, 'ppd', 900], [12, 0, 'ppd', 3600], [73, 0, 'final', 0],
     [55, 0, 'live', 3600], [86, 120, 'pre', 0]]],
   428),
  ('normal control 2', [[[13, 120, 'pre', 0], [212, 0, 'pre', 900]]], 120),
  ('normal control 3', [[[230, 95, 'ppd', 3600], [245, 0, 'live', 0]]], 245),
  ('normal control 4',
   [[[95, 120, 'ppd', 900], [245, 0, 'pre', 1], [37, 0, 'pre', 0], [194, 0, 'final', 0],
     [94, 180, 'ppd', 1800]]],
   194)],
 [('regression: remaining time proration',
   [[[52, 120, 'ppd', 900], [184, 95, 'live', 1], [6, 0, 'pre', 0], [198, 180, 'final', 1],
     [118, 95, 'live', 0]]],
   500),
  ('partial repair probe: remaining time proration',
   [[[170, 95, 'pre', 1800], [64, 180, 'ppd', 900], [212, 120, 'live', 1], [68, 180, 'final', -300],
     [61, 0, 'pre', 3600], [102, 120, 'pre', 1]]],
   495),
  ('second regression',
   [[[68, 180, 'live', 1], [84, 95, 'final', 3600], [73, 120, 'ppd', 900], [49, 0, 'live', 0],
     [48, 0, 'pre', 3600]]],
   201),
  ('normal control 1',
   [[[35, 180, 'pre', 1], [168, 0, 'pre', 900], [69, 95, 'pre', 1], [85, 0, 'live', 900],
     [43, 0, 'live', 900]]],
   403),
  ('normal control 2',
   [[[23, 0, 'pre', -300], [210, 95, 'pre', 3600], [9, 0, 'live', 900], [3, 0, 'live', -300],
     [166, 180, 'pre', 3600], [174, 95, 'final', 1800]]],
   461),
  ('normal control 3', [[[80, 180, 'final', 1], [118, 180, 'ppd', 3600], [249, 95, 'pre', -300]]], 175),
  ('normal control 4', [[[185, 120, 'final', 3600], [223, 0, 'pre', 3600]]], 185)],
 [('regression: remaining time proration',
   [[[231, 0, 'live', 0], [195, 95, 'live', -300], [191, 120, 'ppd', -300]]], 426),
  ('partial repair probe: remaining time proration',
   [[[188, 180, 'live', 0], [66, 95, 'pre', 900], [105, 95, 'live', 1800], [227, 120, 'ppd', 900],
     [124, 0, 'live', 1]]],
   559),
  ('second regression', [[[154, 0, 'live', 0], [250, 180, 'live', -300], [44, 120, 'final', 1800]]], 448),
  ('normal control 1', [[[170, 120, 'ppd', 1800], [186, 180, 'final', 1]]], 186),
  ('normal control 2', [[[230, 120, 'ppd', 1], [209, 95, 'pre', 1]]], 95),
  ('normal control 3',
   [[[171, 0, 'pre', 3600], [55, 120, 'pre', 1800], [204, 0, 'final', 1], [35, 95, 'final', 3600],
     [211, 120, 'final', 3600]]],
   570),
  ('normal control 4',
   [[[38, 0, 'live', 1800], [-1, 0, 'live', 3600], [94, 120, 'pre', 1], [12, 0, 'live', 1800],
     [139, 120, 'pre', 0]]],
   289)]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*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
regression: remaining time proration563562Failed
partial repair probe: remaining time proration726725Failed
second regression731730Failed
normal control 1110110Passed
normal control 2893893Passed
normal control 3212212Passed
normal control 4429429Passed

SHA-256 / d1bfb1ce158505a82510740b8319f91e6cfe1c8ea1d7df524fc2c2513e29e922

3 / The verified repair

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

N = 1
observations = []
def solve(players):
    total = 0
    for actual, proj, status, left in players:
        if status == 'final':
            total += actual
        elif status == 'pre':
            total += proj
        elif status == 'live':
            left = max(left, 0)
            total += actual + proj * left // 3600
    return total
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: remaining time proration',
   [[[213, 180, 'final', 3600], [200, 180, 'live', -300], [102, 95, 'live', 1800]]], 562),
  ('partial repair probe: remaining time proration',
   [[[36, 0, 'live', 1800], [17, 180, 'live', 900], [72, 0, 'live', 1800], [137, 180, 'pre', -300],
     [221, 180, 'live', 1], [154, 0, 'live', 1800]]],
   725),
  ('second regression', [[[237, 95, 'live', 900], [48, 95, 'live', 3600], [237, 180, 'live', 1800]]], 730),
  ('normal control 1', [[[110, 0, 'final', 900], [154, 95, 'ppd', 3600]]], 110),
  ('normal control 2',
   [[[130, 0, 'live', 0], [150, 120, 'final', 3600], [231, 0, 'live', 1800], [86, 0, 'ppd', 1],
     [148, 0, 'live', -300], [234, 0, 'final', -300]]],
   893),
  ('normal control 3', [[[173, 180, 'pre', 1], [126, 180, 'ppd', 0], [32, 0, 'final', 0]]], 212),
  ('normal control 4',
   [[[101, 120, 'ppd', 900], [78, 180, 'ppd', 0], [57, 180, 'final', 900], [220, 120, 'pre', 1800],
     [192, 120, 'live', 1800]]],
   429)],
 [('regression: remaining time proration',
   [[[115, 120, 'live', 1800], [221, 180, 'live', 900], [144, 95, 'ppd', 900], [237, 180, 'live', 3600],
     [48, 180, 'ppd', 1], [92, 180, 'pre', -300]]],
   1038),
  ('partial repair probe: remaining time proration', [[[113, 180, 'pre', 3600], [57, 95, 'live', 1]]], 237),
  ('second regression', [[[172, 120, 'live', 900], [5, 0, 'final', 3600]]], 207),
  ('normal control 1',
   [[[18, 120, 'ppd', 900], [72, 120, 'ppd', 3600], [129, 120, 'pre', 1800], [3, 120, 'pre', 3600],
     [224, 180, 'pre', 1800]]],
   420),
  ('normal control 2',
   [[[145, 180, 'final', 900], [133, 120, 'pre', 0], [42, 120, 'live', 1800], [39, 120, 'final', -300]]],
   406),
  ('normal control 3',
   [[[250, 180, 'ppd', 1], [227, 0, 'live', 0], [205, 180, 'pre', 1800], [89, 0, 'pre', 0],
     [49, 180, 'pre', -300]]],
   587),
  ('normal control 4', [[[58, 95, 'final', 0], [232, 180, 'final', 1], [166, 95, 'final', 3600]]], 456)],
 [('regression: remaining time proration',
   [[[-14, 95, 'live', 900], [174, 95, 'ppd', 3600], [40, 180, 'final', -300]]], 49),
  ('partial repair probe: remaining time proration',
   [[[150, 120, 'ppd', 1], [80, 95, 'ppd', 900], [4, 120, 'final', 1], [-20, 120, 'live', 1]]], -16),
  ('second regression',
   [[[156, 120, 'live', -300], [207, 0, 'ppd', 0], [96, 95, 'live', 3600], [1, 180, 'live', 1800]]], 438),
  ('normal control 1',
   [[[131, 180, 'pre', 1], [11, 180, 'ppd', 900], [12, 0, 'ppd', 3600], [73, 0, 'final', 0],
     [55, 0, 'live', 3600], [86, 120, 'pre', 0]]],
   428),
  ('normal control 2', [[[13, 120, 'pre', 0], [212, 0, 'pre', 900]]], 120),
  ('normal control 3', [[[230, 95, 'ppd', 3600], [245, 0, 'live', 0]]], 245),
  ('normal control 4',
   [[[95, 120, 'ppd', 900], [245, 0, 'pre', 1], [37, 0, 'pre', 0], [194, 0, 'final', 0],
     [94, 180, 'ppd', 1800]]],
   194)],
 [('regression: remaining time proration',
   [[[52, 120, 'ppd', 900], [184, 95, 'live', 1], [6, 0, 'pre', 0], [198, 180, 'final', 1],
     [118, 95, 'live', 0]]],
   500),
  ('partial repair probe: remaining time proration',
   [[[170, 95, 'pre', 1800], [64, 180, 'ppd', 900], [212, 120, 'live', 1], [68, 180, 'final', -300],
     [61, 0, 'pre', 3600], [102, 120, 'pre', 1]]],
   495),
  ('second regression',
   [[[68, 180, 'live', 1], [84, 95, 'final', 3600], [73, 120, 'ppd', 900], [49, 0, 'live', 0],
     [48, 0, 'pre', 3600]]],
   201),
  ('normal control 1',
   [[[35, 180, 'pre', 1], [168, 0, 'pre', 900], [69, 95, 'pre', 1], [85, 0, 'live', 900],
     [43, 0, 'live', 900]]],
   403),
  ('normal control 2',
   [[[23, 0, 'pre', -300], [210, 95, 'pre', 3600], [9, 0, 'live', 900], [3, 0, 'live', -300],
     [166, 180, 'pre', 3600], [174, 95, 'final', 1800]]],
   461),
  ('normal control 3', [[[80, 180, 'final', 1], [118, 180, 'ppd', 3600], [249, 95, 'pre', -300]]], 175),
  ('normal control 4', [[[185, 120, 'final', 3600], [223, 0, 'pre', 3600]]], 185)],
 [('regression: remaining time proration',
   [[[231, 0, 'live', 0], [195, 95, 'live', -300], [191, 120, 'ppd', -300]]], 426),
  ('partial repair probe: remaining time proration',
   [[[188, 180, 'live', 0], [66, 95, 'pre', 900], [105, 95, 'live', 1800], [227, 120, 'ppd', 900],
     [124, 0, 'live', 1]]],
   559),
  ('second regression', [[[154, 0, 'live', 0], [250, 180, 'live', -300], [44, 120, 'final', 1800]]], 448),
  ('normal control 1', [[[170, 120, 'ppd', 1800], [186, 180, 'final', 1]]], 186),
  ('normal control 2', [[[230, 120, 'ppd', 1], [209, 95, 'pre', 1]]], 95),
  ('normal control 3',
   [[[171, 0, 'pre', 3600], [55, 120, 'pre', 1800], [204, 0, 'final', 1], [35, 95, 'final', 3600],
     [211, 120, 'final', 3600]]],
   570),
  ('normal control 4',
   [[[38, 0, 'live', 1800], [-1, 0, 'live', 3600], [94, 120, 'pre', 1], [12, 0, 'live', 1800],
     [139, 120, 'pre', 0]]],
   289)]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*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
regression: remaining time proration562562Passed
partial repair probe: remaining time proration725725Passed
second regression730730Passed
normal control 1110110Passed
normal control 2893893Passed
normal control 3212212Passed
normal control 4429429Passed

SHA-256 / bd2031f4f656c2f50fbc88e9f88f739d1f7b6faf7ca661c74351eb3516187312

Verification & scope

A deterministic toy scoring contract stipulated for this example; it is not the rulebook of any real fantasy platform. 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:39.204850+00:00.

Case digest / 82e56cc4ebd949a46e177119cdf702a28b12d71d5a5693be57dac868a09ef850