FAILURE MAP
← Case archive

FA-92861 / EV charging session scheduling / Open access

Time-of-use cheapest slot plan: stop after request is met · case 01

Plans list extra slots with zero energy after the request is already satisfied.

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

ROOT CAUSE

The loop never stops once the remaining energy reaches zero and keeps appending empty slot entries.

VERIFIED REPAIR

Break as soon as the remaining energy is zero or less.

Unsuccessful approach: Breaking only on a negative remainder never triggers because take never overshoots.

Case contract

prices[i] is the tariff in cents/kWh of 15-minute slot i. The car is present for slots arrive..depart-1 (depart exclusive) clipped to the tariff horizon; arrive may be negative. Each slot delivers at most max_w//4 Wh. Fill the cheapest slots first (equal price: earlier slot first), the last slot partially. Return [[slot, wh] sorted by slot, cost in millicents (sum wh*price), unmet wh]. need_wh<=0 or max_w<=0 returns [[], 0, max(need_wh,0)].

Why this case matters

Depot, workplace and public EV chargers schedule sessions against prices, circuit limits and departure deadlines; a wrong decision silently strands a driver or overloads a feeder.

1 / The failure

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

N = 1
observations = []
def solve(prices, arrive, depart, need_wh, max_w):
    if need_wh <= 0 or max_w <= 0:
        return [[], 0, max(need_wh, 0)]
    slot_wh = max_w // 4
    lo = max(arrive, 0)
    hi = min(depart, len(prices))
    window = list(range(lo, hi))
    ranked = sorted(window, key=lambda s: (prices[s], s))
    plan = []
    left = need_wh
    for s in ranked:
        take = min(slot_wh, left)
        plan.append([s, take])
        left -= take
    plan.sort()
    cost = sum(wh * prices[s] for s, wh in plan)
    return [plan, cost, left]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[12, 10, 8, 25, 30, 10, 20, 10, 8, 10, 10, 25, 25], 3, 16, 1500, 3700],
   [[[5, 575], [8, 925]], 13150, 0]],
  ['regression: stop after request is met (partial repair)',
   [[30, 8, 15, 8, 20], -3, 4, 4000, 11000], [[[1, 2750], [3, 1250]], 32000, 0]],
  ['control 1', [[25, 30, 20, 12, 12], 2, 2, 20000, 11000], [[], 0, 20000]],
  ['control 2', [[8, 15, 12, 10, 8, 25, 12, 8, 8, 20, 20, 25, 12, 8], -3, 15, 7000, 3700],
   [[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[30, 12, 20, 30, 25, 30, 12, 30, 20, 10, 20, 8, 15], 7, 12, 4000, 11000],
   [[[9, 1250], [11, 2750]], 34500, 0]],
  ['regression: stop after request is met (partial repair)',
   [[30, 10, 8, 15, 12, 12, 30, 25, 12], -1, 8, 4000, 7400],
   [[[1, 1850], [2, 1850], [4, 300]], 36900, 0]],
  ['control 1', [[12, 12, 25, 30, 8, 20, 12, 12], 3, 11, 9000, 3700],
   [[[3, 925], [4, 925], [5, 925], [6, 925], [7, 925]], 75850, 4375]],
  ['control 2', [[12, 15, 8, 12, 25, 15, 8, 30], -1, 6, 20000, 3700],
   [[[0, 925], [1, 925], [2, 925], [3, 925], [4, 925], [5, 925]], 80475, 14450]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[15, 25, 10, 15, 8, 10, 12, 25, 15, 10, 10, 15, 10, 8], 4, 8, 4000, 11000],
   [[[4, 2750], [5, 1250]], 34500, 0]],
  ['regression: stop after request is met (partial repair)',
   [[12, 15, 10, 25, 30, 25, 10, 12, 10, 30, 15, 10, 10, 10], 8, 17, 4000, 7400],
   [[[8, 1850], [11, 1850], [12, 300]], 40000, 0]],
  ['control 1', [[12, 10, 15, 25, 30], 4, 4, 12500, 7400], [[], 0, 12500]],
  ['control 2', [[30, 12, 15, 12, 30, 15, 12, 20, 20], -2, 1, 9000, 0], [[], 0, 9000]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[20, 15, 25, 30, 8, 15, 10, 15, 20, 25, 25], -2, 9, 1500, 7400], [[[4, 1500]], 12000, 0]],
  ['regression: stop after request is met (partial repair)',
   [[10, 10, 12, 25, 30], 2, 7, 1500, 7400], [[[2, 1500]], 18000, 0]],
  ['control 1', [[12, 20, 8, 15, 10, 8, 25, 12, 30, 12], 2, 12, 20000, 11000],
   [[[2, 2750], [3, 2750], [4, 2750], [5, 2750], [6, 2750], [7, 2750], [8, 750], [9, 2750]], 270000,
    0]],
  ['control 2', [[30, 30, 20, 12, 12, 15, 12, 10], -1, 8, 7000, 7400],
   [[[3, 1850], [4, 1850], [6, 1450], [7, 1850]], 80300, 0]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[12, 20, 12, 12, 12, 12, 20, 15, 10, 12], 0, 11, 4000, 7400],
   [[[0, 1850], [2, 300], [8, 1850]], 44300, 0]],
  ['regression: stop after request is met (partial repair)',
   [[12, 15, 15, 8, 12, 15, 10, 25, 25, 20, 20], 0, 14, 9000, 3700],
   [[[0, 925], [1, 925], [2, 925], [3, 925], [4, 925], [5, 925], [6, 925], [7, 675], [9, 925],
     [10, 925]],
    134350, 0]],
  ['control 1', [[12, 12, 8, 15, 10, 12, 20, 15, 12, 10, 12, 12, 15, 15], 12, 13, 1500, 3700],
   [[[12, 925]], 13875, 575]],
  ['control 2', [[10, 12, 10, 8, 10, 12, 12], 2, 5, 4000, 11000],
   [[[2, 1250], [3, 2750]], 34500, 0]]]]
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
boundary: nothing needed[[], 0, 0][[], 0, 0]Passed
boundary: empty window[[], 0, 5000][[], 0, 5000]Passed
boundary: departure beyond tariff horizon[[[1, 1850], [2, 1850], [3, 1300]], 63000, 0][[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]Passed
regression: stop after request is met[[[3, 0], [4, 0], [5, 575], [6, 0], [7, 0], [8, 925], [9, 0], [10, 0], [11, 0], [12, 0]], 13150, 0][[[5, 575], [8, 925]], 13150, 0]Failed
regression: stop after request is met (partial repair)[[[0, 0], [1, 2750], [2, 0], [3, 1250]], 32000, 0][[[1, 2750], [3, 1250]], 32000, 0]Failed
control 1[[], 0, 20000][[], 0, 20000]Passed
control 2[[[0, 925], [1, 0], [2, 925], [3, 925], [4, 925], [5, 0], [6, 525], [7, 925], [8, 925], [9, 0], [10, 0], [11, 0], [12, 0], [13, 925]], 63650, 0][[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0]Failed

SHA-256 / 9ec493c4385bb8151dff5fcea8ae58e522de6d9acab3c24f68f5cdcd25374e51

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(prices, arrive, depart, need_wh, max_w):
    if need_wh <= 0 or max_w <= 0:
        return [[], 0, max(need_wh, 0)]
    slot_wh = max_w // 4
    lo = max(arrive, 0)
    hi = min(depart, len(prices))
    window = list(range(lo, hi))
    ranked = sorted(window, key=lambda s: (prices[s], s))
    plan = []
    left = need_wh
    for s in ranked:
        if left < 0:
            break
        take = min(slot_wh, left)
        plan.append([s, take])
        left -= take
    plan.sort()
    cost = sum(wh * prices[s] for s, wh in plan)
    return [plan, cost, left]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[12, 10, 8, 25, 30, 10, 20, 10, 8, 10, 10, 25, 25], 3, 16, 1500, 3700],
   [[[5, 575], [8, 925]], 13150, 0]],
  ['regression: stop after request is met (partial repair)',
   [[30, 8, 15, 8, 20], -3, 4, 4000, 11000], [[[1, 2750], [3, 1250]], 32000, 0]],
  ['control 1', [[25, 30, 20, 12, 12], 2, 2, 20000, 11000], [[], 0, 20000]],
  ['control 2', [[8, 15, 12, 10, 8, 25, 12, 8, 8, 20, 20, 25, 12, 8], -3, 15, 7000, 3700],
   [[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[30, 12, 20, 30, 25, 30, 12, 30, 20, 10, 20, 8, 15], 7, 12, 4000, 11000],
   [[[9, 1250], [11, 2750]], 34500, 0]],
  ['regression: stop after request is met (partial repair)',
   [[30, 10, 8, 15, 12, 12, 30, 25, 12], -1, 8, 4000, 7400],
   [[[1, 1850], [2, 1850], [4, 300]], 36900, 0]],
  ['control 1', [[12, 12, 25, 30, 8, 20, 12, 12], 3, 11, 9000, 3700],
   [[[3, 925], [4, 925], [5, 925], [6, 925], [7, 925]], 75850, 4375]],
  ['control 2', [[12, 15, 8, 12, 25, 15, 8, 30], -1, 6, 20000, 3700],
   [[[0, 925], [1, 925], [2, 925], [3, 925], [4, 925], [5, 925]], 80475, 14450]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[15, 25, 10, 15, 8, 10, 12, 25, 15, 10, 10, 15, 10, 8], 4, 8, 4000, 11000],
   [[[4, 2750], [5, 1250]], 34500, 0]],
  ['regression: stop after request is met (partial repair)',
   [[12, 15, 10, 25, 30, 25, 10, 12, 10, 30, 15, 10, 10, 10], 8, 17, 4000, 7400],
   [[[8, 1850], [11, 1850], [12, 300]], 40000, 0]],
  ['control 1', [[12, 10, 15, 25, 30], 4, 4, 12500, 7400], [[], 0, 12500]],
  ['control 2', [[30, 12, 15, 12, 30, 15, 12, 20, 20], -2, 1, 9000, 0], [[], 0, 9000]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[20, 15, 25, 30, 8, 15, 10, 15, 20, 25, 25], -2, 9, 1500, 7400], [[[4, 1500]], 12000, 0]],
  ['regression: stop after request is met (partial repair)',
   [[10, 10, 12, 25, 30], 2, 7, 1500, 7400], [[[2, 1500]], 18000, 0]],
  ['control 1', [[12, 20, 8, 15, 10, 8, 25, 12, 30, 12], 2, 12, 20000, 11000],
   [[[2, 2750], [3, 2750], [4, 2750], [5, 2750], [6, 2750], [7, 2750], [8, 750], [9, 2750]], 270000,
    0]],
  ['control 2', [[30, 30, 20, 12, 12, 15, 12, 10], -1, 8, 7000, 7400],
   [[[3, 1850], [4, 1850], [6, 1450], [7, 1850]], 80300, 0]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[12, 20, 12, 12, 12, 12, 20, 15, 10, 12], 0, 11, 4000, 7400],
   [[[0, 1850], [2, 300], [8, 1850]], 44300, 0]],
  ['regression: stop after request is met (partial repair)',
   [[12, 15, 15, 8, 12, 15, 10, 25, 25, 20, 20], 0, 14, 9000, 3700],
   [[[0, 925], [1, 925], [2, 925], [3, 925], [4, 925], [5, 925], [6, 925], [7, 675], [9, 925],
     [10, 925]],
    134350, 0]],
  ['control 1', [[12, 12, 8, 15, 10, 12, 20, 15, 12, 10, 12, 12, 15, 15], 12, 13, 1500, 3700],
   [[[12, 925]], 13875, 575]],
  ['control 2', [[10, 12, 10, 8, 10, 12, 12], 2, 5, 4000, 11000],
   [[[2, 1250], [3, 2750]], 34500, 0]]]]
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
boundary: nothing needed[[], 0, 0][[], 0, 0]Passed
boundary: empty window[[], 0, 5000][[], 0, 5000]Passed
boundary: departure beyond tariff horizon[[[1, 1850], [2, 1850], [3, 1300]], 63000, 0][[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]Passed
regression: stop after request is met[[[3, 0], [4, 0], [5, 575], [6, 0], [7, 0], [8, 925], [9, 0], [10, 0], [11, 0], [12, 0]], 13150, 0][[[5, 575], [8, 925]], 13150, 0]Failed
regression: stop after request is met (partial repair)[[[0, 0], [1, 2750], [2, 0], [3, 1250]], 32000, 0][[[1, 2750], [3, 1250]], 32000, 0]Failed
control 1[[], 0, 20000][[], 0, 20000]Passed
control 2[[[0, 925], [1, 0], [2, 925], [3, 925], [4, 925], [5, 0], [6, 525], [7, 925], [8, 925], [9, 0], [10, 0], [11, 0], [12, 0], [13, 925]], 63650, 0][[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0]Failed

SHA-256 / 5afddfef072a2143006625ca31a52b29b338b65ae0a1b3de38fc416a7ba04611

3 / The verified repair

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

N = 1
observations = []
def solve(prices, arrive, depart, need_wh, max_w):
    if need_wh <= 0 or max_w <= 0:
        return [[], 0, max(need_wh, 0)]
    slot_wh = max_w // 4
    lo = max(arrive, 0)
    hi = min(depart, len(prices))
    window = list(range(lo, hi))
    ranked = sorted(window, key=lambda s: (prices[s], s))
    plan = []
    left = need_wh
    for s in ranked:
        if left <= 0:
            break
        take = min(slot_wh, left)
        plan.append([s, take])
        left -= take
    plan.sort()
    cost = sum(wh * prices[s] for s, wh in plan)
    return [plan, cost, left]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[12, 10, 8, 25, 30, 10, 20, 10, 8, 10, 10, 25, 25], 3, 16, 1500, 3700],
   [[[5, 575], [8, 925]], 13150, 0]],
  ['regression: stop after request is met (partial repair)',
   [[30, 8, 15, 8, 20], -3, 4, 4000, 11000], [[[1, 2750], [3, 1250]], 32000, 0]],
  ['control 1', [[25, 30, 20, 12, 12], 2, 2, 20000, 11000], [[], 0, 20000]],
  ['control 2', [[8, 15, 12, 10, 8, 25, 12, 8, 8, 20, 20, 25, 12, 8], -3, 15, 7000, 3700],
   [[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[30, 12, 20, 30, 25, 30, 12, 30, 20, 10, 20, 8, 15], 7, 12, 4000, 11000],
   [[[9, 1250], [11, 2750]], 34500, 0]],
  ['regression: stop after request is met (partial repair)',
   [[30, 10, 8, 15, 12, 12, 30, 25, 12], -1, 8, 4000, 7400],
   [[[1, 1850], [2, 1850], [4, 300]], 36900, 0]],
  ['control 1', [[12, 12, 25, 30, 8, 20, 12, 12], 3, 11, 9000, 3700],
   [[[3, 925], [4, 925], [5, 925], [6, 925], [7, 925]], 75850, 4375]],
  ['control 2', [[12, 15, 8, 12, 25, 15, 8, 30], -1, 6, 20000, 3700],
   [[[0, 925], [1, 925], [2, 925], [3, 925], [4, 925], [5, 925]], 80475, 14450]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[15, 25, 10, 15, 8, 10, 12, 25, 15, 10, 10, 15, 10, 8], 4, 8, 4000, 11000],
   [[[4, 2750], [5, 1250]], 34500, 0]],
  ['regression: stop after request is met (partial repair)',
   [[12, 15, 10, 25, 30, 25, 10, 12, 10, 30, 15, 10, 10, 10], 8, 17, 4000, 7400],
   [[[8, 1850], [11, 1850], [12, 300]], 40000, 0]],
  ['control 1', [[12, 10, 15, 25, 30], 4, 4, 12500, 7400], [[], 0, 12500]],
  ['control 2', [[30, 12, 15, 12, 30, 15, 12, 20, 20], -2, 1, 9000, 0], [[], 0, 9000]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[20, 15, 25, 30, 8, 15, 10, 15, 20, 25, 25], -2, 9, 1500, 7400], [[[4, 1500]], 12000, 0]],
  ['regression: stop after request is met (partial repair)',
   [[10, 10, 12, 25, 30], 2, 7, 1500, 7400], [[[2, 1500]], 18000, 0]],
  ['control 1', [[12, 20, 8, 15, 10, 8, 25, 12, 30, 12], 2, 12, 20000, 11000],
   [[[2, 2750], [3, 2750], [4, 2750], [5, 2750], [6, 2750], [7, 2750], [8, 750], [9, 2750]], 270000,
    0]],
  ['control 2', [[30, 30, 20, 12, 12, 15, 12, 10], -1, 8, 7000, 7400],
   [[[3, 1850], [4, 1850], [6, 1450], [7, 1850]], 80300, 0]]],
 [['boundary: nothing needed', [[10, 20, 30], 0, 3, 0, 7400], [[], 0, 0]],
  ['boundary: empty window', [[10, 20, 30], 2, 2, 5000, 7400], [[], 0, 5000]],
  ['boundary: departure beyond tariff horizon', [[30, 10, 10, 20], 1, 9, 5000, 7400],
   [[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]],
  ['regression: stop after request is met',
   [[12, 20, 12, 12, 12, 12, 20, 15, 10, 12], 0, 11, 4000, 7400],
   [[[0, 1850], [2, 300], [8, 1850]], 44300, 0]],
  ['regression: stop after request is met (partial repair)',
   [[12, 15, 15, 8, 12, 15, 10, 25, 25, 20, 20], 0, 14, 9000, 3700],
   [[[0, 925], [1, 925], [2, 925], [3, 925], [4, 925], [5, 925], [6, 925], [7, 675], [9, 925],
     [10, 925]],
    134350, 0]],
  ['control 1', [[12, 12, 8, 15, 10, 12, 20, 15, 12, 10, 12, 12, 15, 15], 12, 13, 1500, 3700],
   [[[12, 925]], 13875, 575]],
  ['control 2', [[10, 12, 10, 8, 10, 12, 12], 2, 5, 4000, 11000],
   [[[2, 1250], [3, 2750]], 34500, 0]]]]
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
boundary: nothing needed[[], 0, 0][[], 0, 0]Passed
boundary: empty window[[], 0, 5000][[], 0, 5000]Passed
boundary: departure beyond tariff horizon[[[1, 1850], [2, 1850], [3, 1300]], 63000, 0][[[1, 1850], [2, 1850], [3, 1300]], 63000, 0]Passed
regression: stop after request is met[[[5, 575], [8, 925]], 13150, 0][[[5, 575], [8, 925]], 13150, 0]Passed
regression: stop after request is met (partial repair)[[[1, 2750], [3, 1250]], 32000, 0][[[1, 2750], [3, 1250]], 32000, 0]Passed
control 1[[], 0, 20000][[], 0, 20000]Passed
control 2[[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0][[[0, 925], [2, 925], [3, 925], [4, 925], [6, 525], [7, 925], [8, 925], [13, 925]], 63650, 0]Passed

SHA-256 / 17869eac8ee6dead49cec493ab998ecdf0342c7fe50d879aeb8f62d9a6278f05

Verification & scope

Deterministic stipulated toy contract for teaching; no claim of conformance with any standard, vendor protocol or production controller. 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:51:49.814786+00:00.

Case digest / e63e05e0ae8e24fbdd59542619946ff9aa31b0e890d4afd3f6115bf73a9ea7b3