FAILURE MAP
← Case archive

FA-93031 / EV charging session scheduling / Open access

PV surplus following with hysteresis: power reported at transition sample · case 01

The power profile lags the charging state by one minute.

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

ROOT CAUSE

Power is recorded before the state machine processes the current sample.

VERIFIED REPAIR

Record power after updating the charging state for the sample.

Unsuccessful approach: Suppressing power while a stop streak is building hides real charging minutes.

Case contract

samples are per-minute PV surplus watts. Charging starts on the sample completing start_delay consecutive samples >= start_w, and stops on the sample completing stop_delay consecutive samples < stop_w; counters reset on each transition and on any interrupting sample. While charging the power is the surplus clamped to [1380, 3680] W, else 0. Return [powers, number of starts].

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(samples, start_w, stop_w, start_delay, stop_delay):
    on = False
    run = 0
    out = []
    starts = 0
    for s in samples:
        out.append(min(max(s, 1380), 3680) if on else 0)
        if not on:
            run = run + 1 if s >= start_w else 0
            if run >= start_delay:
                on = True
                starts += 1
                run = 0
        else:
            run = run + 1 if s < stop_w else 0
            if run >= stop_delay:
                on = False
                run = 0
    return [out, starts]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[1686, 3340, 1407, 3891, 3528, 2938, 328, 2002, 686, 0, 2304, 1141, 635, 0, 3641, 1580], 2500,
    1400, 2, 1],
   [[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[0, 0, 0, 2234, 3394, 627, 3397, 1759, 0, 0], 1400, 1000, 2, 3],
   [[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1]],
  ['control 1', [[1632, 1402, 0, 1011, 1056, 2204, 0, 0, 0, 0, 0, 2059, 0], 1400, 1400, 3, 1],
   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]],
  ['control 2',
   [[5160, 1495, 4246, 2693, 3633, 943, 5200, 3902, 2959, 1685, 2602], 1400, 800, 3, 2],
   [[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[690, 2994, 1129, 4991, 4743, 987, 2592, 1912, 4532], 2500, 1000, 1, 3],
   [[0, 2994, 1380, 3680, 3680, 1380, 2592, 1912, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[0, 1601, 1934, 1322, 3170, 2829, 3542, 898, 0, 284, 0], 1400, 800, 3, 3],
   [[0, 0, 0, 0, 0, 0, 3542, 1380, 1380, 1380, 0], 1]],
  ['control 1', [[2491, 6454, 5581, 5791, 7280, 4927, 5591, 6410], 1400, 1000, 1, 1],
   [[2491, 3680, 3680, 3680, 3680, 3680, 3680, 3680], 1]],
  ['control 2', [[3110, 2987, 3876, 6142, 2422, 5132, 2143, 6887, 4896, 4908], 2000, 1000, 3, 2],
   [[0, 0, 3680, 3680, 2422, 3680, 2143, 3680, 3680, 3680], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[1961, 5023, 3923, 3896, 4035, 3052, 1335, 3723, 1391, 1973, 5218], 1400, 1000, 1, 1],
   [[1961, 3680, 3680, 3680, 3680, 3052, 1380, 3680, 1391, 1973, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[2067, 4963, 1306, 1989, 1340, 4956, 2993, 3711, 1472, 4753, 796, 4896, 2670], 2000, 800, 3, 3],
   [[0, 0, 0, 0, 0, 0, 0, 3680, 1472, 3680, 1380, 3680, 2670], 1]],
  ['control 1', [[5534, 5945, 5877, 6991, 3580, 5525, 6786, 5530, 2720, 6795], 2000, 800, 1, 1],
   [[3680, 3680, 3680, 3680, 3580, 3680, 3680, 3680, 2720, 3680], 1]],
  ['control 2',
   [[3289, 1459, 5221, 3468, 1247, 4575, 1243, 1923, 2108, 3912, 3417, 2756, 1675, 1378, 5487],
    2000, 1400, 3, 2],
   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3417, 2756, 1675, 1380, 3680], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[2294, 2603, 2597, 3913, 3600, 2378, 4027, 3674, 5100, 4341], 2000, 1000, 1, 1],
   [[2294, 2603, 2597, 3680, 3600, 2378, 3680, 3674, 3680, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[1375, 4072, 3054, 2932, 1996, 2236, 194, 2264, 1091, 0], 2500, 1400, 1, 2],
   [[0, 3680, 3054, 2932, 1996, 2236, 1380, 2264, 1380, 0], 1]],
  ['control 1', [[2567, 1353, 0, 2085, 0, 0, 116, 324, 1725, 810], 1400, 1400, 1, 2],
   [[2567, 1380, 0, 2085, 1380, 0, 0, 0, 1725, 1380], 3]],
  ['control 2',
   [[3612, 3481, 805, 1117, 2494, 200, 653, 4188, 280, 752, 4261, 4604], 1400, 1000, 1, 1],
   [[3612, 3481, 0, 0, 2494, 0, 0, 3680, 0, 0, 3680, 3680], 4]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[391, 1113, 0, 2478, 0, 0, 0, 0, 0, 0, 2459], 2000, 800, 1, 3],
   [[0, 0, 0, 2478, 1380, 1380, 0, 0, 0, 0, 2459], 2]],
  ['regression: power reported at transition sample (partial repair)',
   [[1556, 2553, 1392, 829, 1166, 3311, 4436, 560, 2803, 1972, 4425, 4180], 1400, 1000, 1, 2],
   [[1556, 2553, 1392, 1380, 1380, 3311, 3680, 1380, 2803, 1972, 3680, 3680], 1]],
  ['control 1', [[1756, 0, 1045, 0, 1278, 3133, 2829, 2511, 2201, 3176, 1898], 2000, 1400, 3, 3],
   [[0, 0, 0, 0, 0, 0, 0, 2511, 2201, 3176, 1898], 1]],
  ['control 2', [[3627, 2896, 3017, 2824, 6221, 3547, 1687, 5138], 1400, 800, 2, 2],
   [[0, 2896, 3017, 2824, 3680, 3547, 1687, 3680], 1]]]]
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: surplus exactly at start threshold[[0, 0, 2000, 1380], 1][[0, 2000, 2000, 0], 1]Failed
boundary: never enough sun[[0, 0, 0, 0, 0, 0], 0][[0, 0, 0, 0, 0, 0], 0]Passed
boundary: cloud dip shorter than stop delay[[0, 3000, 1380, 3000, 1380, 1380, 0], 2][[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]Failed
regression: power reported at transition sample[[0, 0, 0, 0, 0, 2938, 1380, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1][[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1]Failed
regression: power reported at transition sample (partial repair)[[0, 0, 0, 0, 0, 1380, 3397, 1759, 1380, 1380], 1][[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1]Failed
control 1[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0][[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]Passed
control 2[[0, 0, 0, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1][[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1]Failed

SHA-256 / 383a100eb41e0813b0e6fc278d640eb0f2707217b044f62d2964f2a6f40f100e

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(samples, start_w, stop_w, start_delay, stop_delay):
    on = False
    run = 0
    out = []
    starts = 0
    for s in samples:
        if not on:
            run = run + 1 if s >= start_w else 0
            if run >= start_delay:
                on = True
                starts += 1
                run = 0
        else:
            run = run + 1 if s < stop_w else 0
            if run >= stop_delay:
                on = False
                run = 0
        out.append(min(max(s, 1380), 3680) if on and run == 0 else 0)
    return [out, starts]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[1686, 3340, 1407, 3891, 3528, 2938, 328, 2002, 686, 0, 2304, 1141, 635, 0, 3641, 1580], 2500,
    1400, 2, 1],
   [[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[0, 0, 0, 2234, 3394, 627, 3397, 1759, 0, 0], 1400, 1000, 2, 3],
   [[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1]],
  ['control 1', [[1632, 1402, 0, 1011, 1056, 2204, 0, 0, 0, 0, 0, 2059, 0], 1400, 1400, 3, 1],
   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]],
  ['control 2',
   [[5160, 1495, 4246, 2693, 3633, 943, 5200, 3902, 2959, 1685, 2602], 1400, 800, 3, 2],
   [[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[690, 2994, 1129, 4991, 4743, 987, 2592, 1912, 4532], 2500, 1000, 1, 3],
   [[0, 2994, 1380, 3680, 3680, 1380, 2592, 1912, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[0, 1601, 1934, 1322, 3170, 2829, 3542, 898, 0, 284, 0], 1400, 800, 3, 3],
   [[0, 0, 0, 0, 0, 0, 3542, 1380, 1380, 1380, 0], 1]],
  ['control 1', [[2491, 6454, 5581, 5791, 7280, 4927, 5591, 6410], 1400, 1000, 1, 1],
   [[2491, 3680, 3680, 3680, 3680, 3680, 3680, 3680], 1]],
  ['control 2', [[3110, 2987, 3876, 6142, 2422, 5132, 2143, 6887, 4896, 4908], 2000, 1000, 3, 2],
   [[0, 0, 3680, 3680, 2422, 3680, 2143, 3680, 3680, 3680], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[1961, 5023, 3923, 3896, 4035, 3052, 1335, 3723, 1391, 1973, 5218], 1400, 1000, 1, 1],
   [[1961, 3680, 3680, 3680, 3680, 3052, 1380, 3680, 1391, 1973, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[2067, 4963, 1306, 1989, 1340, 4956, 2993, 3711, 1472, 4753, 796, 4896, 2670], 2000, 800, 3, 3],
   [[0, 0, 0, 0, 0, 0, 0, 3680, 1472, 3680, 1380, 3680, 2670], 1]],
  ['control 1', [[5534, 5945, 5877, 6991, 3580, 5525, 6786, 5530, 2720, 6795], 2000, 800, 1, 1],
   [[3680, 3680, 3680, 3680, 3580, 3680, 3680, 3680, 2720, 3680], 1]],
  ['control 2',
   [[3289, 1459, 5221, 3468, 1247, 4575, 1243, 1923, 2108, 3912, 3417, 2756, 1675, 1378, 5487],
    2000, 1400, 3, 2],
   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3417, 2756, 1675, 1380, 3680], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[2294, 2603, 2597, 3913, 3600, 2378, 4027, 3674, 5100, 4341], 2000, 1000, 1, 1],
   [[2294, 2603, 2597, 3680, 3600, 2378, 3680, 3674, 3680, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[1375, 4072, 3054, 2932, 1996, 2236, 194, 2264, 1091, 0], 2500, 1400, 1, 2],
   [[0, 3680, 3054, 2932, 1996, 2236, 1380, 2264, 1380, 0], 1]],
  ['control 1', [[2567, 1353, 0, 2085, 0, 0, 116, 324, 1725, 810], 1400, 1400, 1, 2],
   [[2567, 1380, 0, 2085, 1380, 0, 0, 0, 1725, 1380], 3]],
  ['control 2',
   [[3612, 3481, 805, 1117, 2494, 200, 653, 4188, 280, 752, 4261, 4604], 1400, 1000, 1, 1],
   [[3612, 3481, 0, 0, 2494, 0, 0, 3680, 0, 0, 3680, 3680], 4]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[391, 1113, 0, 2478, 0, 0, 0, 0, 0, 0, 2459], 2000, 800, 1, 3],
   [[0, 0, 0, 2478, 1380, 1380, 0, 0, 0, 0, 2459], 2]],
  ['regression: power reported at transition sample (partial repair)',
   [[1556, 2553, 1392, 829, 1166, 3311, 4436, 560, 2803, 1972, 4425, 4180], 1400, 1000, 1, 2],
   [[1556, 2553, 1392, 1380, 1380, 3311, 3680, 1380, 2803, 1972, 3680, 3680], 1]],
  ['control 1', [[1756, 0, 1045, 0, 1278, 3133, 2829, 2511, 2201, 3176, 1898], 2000, 1400, 3, 3],
   [[0, 0, 0, 0, 0, 0, 0, 2511, 2201, 3176, 1898], 1]],
  ['control 2', [[3627, 2896, 3017, 2824, 6221, 3547, 1687, 5138], 1400, 800, 2, 2],
   [[0, 2896, 3017, 2824, 3680, 3547, 1687, 3680], 1]]]]
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: surplus exactly at start threshold[[0, 2000, 2000, 0], 1][[0, 2000, 2000, 0], 1]Passed
boundary: never enough sun[[0, 0, 0, 0, 0, 0], 0][[0, 0, 0, 0, 0, 0], 0]Passed
boundary: cloud dip shorter than stop delay[[3000, 3000, 0, 3000, 0, 0, 3000], 2][[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]Failed
regression: power reported at transition sample[[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1][[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1]Passed
regression: power reported at transition sample (partial repair)[[0, 0, 0, 0, 3394, 0, 3397, 1759, 0, 0], 1][[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1]Failed
control 1[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0][[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]Passed
control 2[[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1][[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1]Passed

SHA-256 / b1abfa55fb1834aff0d165bb5ecd4504404733ff7471768ab1641b8ed951f26d

3 / The verified repair

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

N = 1
observations = []
def solve(samples, start_w, stop_w, start_delay, stop_delay):
    on = False
    run = 0
    out = []
    starts = 0
    for s in samples:
        if not on:
            run = run + 1 if s >= start_w else 0
            if run >= start_delay:
                on = True
                starts += 1
                run = 0
        else:
            run = run + 1 if s < stop_w else 0
            if run >= stop_delay:
                on = False
                run = 0
        out.append(min(max(s, 1380), 3680) if on else 0)
    return [out, starts]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[1686, 3340, 1407, 3891, 3528, 2938, 328, 2002, 686, 0, 2304, 1141, 635, 0, 3641, 1580], 2500,
    1400, 2, 1],
   [[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[0, 0, 0, 2234, 3394, 627, 3397, 1759, 0, 0], 1400, 1000, 2, 3],
   [[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1]],
  ['control 1', [[1632, 1402, 0, 1011, 1056, 2204, 0, 0, 0, 0, 0, 2059, 0], 1400, 1400, 3, 1],
   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]],
  ['control 2',
   [[5160, 1495, 4246, 2693, 3633, 943, 5200, 3902, 2959, 1685, 2602], 1400, 800, 3, 2],
   [[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[690, 2994, 1129, 4991, 4743, 987, 2592, 1912, 4532], 2500, 1000, 1, 3],
   [[0, 2994, 1380, 3680, 3680, 1380, 2592, 1912, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[0, 1601, 1934, 1322, 3170, 2829, 3542, 898, 0, 284, 0], 1400, 800, 3, 3],
   [[0, 0, 0, 0, 0, 0, 3542, 1380, 1380, 1380, 0], 1]],
  ['control 1', [[2491, 6454, 5581, 5791, 7280, 4927, 5591, 6410], 1400, 1000, 1, 1],
   [[2491, 3680, 3680, 3680, 3680, 3680, 3680, 3680], 1]],
  ['control 2', [[3110, 2987, 3876, 6142, 2422, 5132, 2143, 6887, 4896, 4908], 2000, 1000, 3, 2],
   [[0, 0, 3680, 3680, 2422, 3680, 2143, 3680, 3680, 3680], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[1961, 5023, 3923, 3896, 4035, 3052, 1335, 3723, 1391, 1973, 5218], 1400, 1000, 1, 1],
   [[1961, 3680, 3680, 3680, 3680, 3052, 1380, 3680, 1391, 1973, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[2067, 4963, 1306, 1989, 1340, 4956, 2993, 3711, 1472, 4753, 796, 4896, 2670], 2000, 800, 3, 3],
   [[0, 0, 0, 0, 0, 0, 0, 3680, 1472, 3680, 1380, 3680, 2670], 1]],
  ['control 1', [[5534, 5945, 5877, 6991, 3580, 5525, 6786, 5530, 2720, 6795], 2000, 800, 1, 1],
   [[3680, 3680, 3680, 3680, 3580, 3680, 3680, 3680, 2720, 3680], 1]],
  ['control 2',
   [[3289, 1459, 5221, 3468, 1247, 4575, 1243, 1923, 2108, 3912, 3417, 2756, 1675, 1378, 5487],
    2000, 1400, 3, 2],
   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3417, 2756, 1675, 1380, 3680], 1]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[2294, 2603, 2597, 3913, 3600, 2378, 4027, 3674, 5100, 4341], 2000, 1000, 1, 1],
   [[2294, 2603, 2597, 3680, 3600, 2378, 3680, 3674, 3680, 3680], 1]],
  ['regression: power reported at transition sample (partial repair)',
   [[1375, 4072, 3054, 2932, 1996, 2236, 194, 2264, 1091, 0], 2500, 1400, 1, 2],
   [[0, 3680, 3054, 2932, 1996, 2236, 1380, 2264, 1380, 0], 1]],
  ['control 1', [[2567, 1353, 0, 2085, 0, 0, 116, 324, 1725, 810], 1400, 1400, 1, 2],
   [[2567, 1380, 0, 2085, 1380, 0, 0, 0, 1725, 1380], 3]],
  ['control 2',
   [[3612, 3481, 805, 1117, 2494, 200, 653, 4188, 280, 752, 4261, 4604], 1400, 1000, 1, 1],
   [[3612, 3481, 0, 0, 2494, 0, 0, 3680, 0, 0, 3680, 3680], 4]]],
 [['boundary: surplus exactly at start threshold', [[2000, 2000, 2000, 500], 2000, 1000, 2, 1],
   [[0, 2000, 2000, 0], 1]],
  ['boundary: never enough sun', [[100, 200, 300, 400, 500, 600], 1400, 800, 1, 1],
   [[0, 0, 0, 0, 0, 0], 0]],
  ['boundary: cloud dip shorter than stop delay',
   [[3000, 3000, 500, 3000, 500, 500, 3000], 1400, 800, 1, 2],
   [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]],
  ['regression: power reported at transition sample',
   [[391, 1113, 0, 2478, 0, 0, 0, 0, 0, 0, 2459], 2000, 800, 1, 3],
   [[0, 0, 0, 2478, 1380, 1380, 0, 0, 0, 0, 2459], 2]],
  ['regression: power reported at transition sample (partial repair)',
   [[1556, 2553, 1392, 829, 1166, 3311, 4436, 560, 2803, 1972, 4425, 4180], 1400, 1000, 1, 2],
   [[1556, 2553, 1392, 1380, 1380, 3311, 3680, 1380, 2803, 1972, 3680, 3680], 1]],
  ['control 1', [[1756, 0, 1045, 0, 1278, 3133, 2829, 2511, 2201, 3176, 1898], 2000, 1400, 3, 3],
   [[0, 0, 0, 0, 0, 0, 0, 2511, 2201, 3176, 1898], 1]],
  ['control 2', [[3627, 2896, 3017, 2824, 6221, 3547, 1687, 5138], 1400, 800, 2, 2],
   [[0, 2896, 3017, 2824, 3680, 3547, 1687, 3680], 1]]]]
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: surplus exactly at start threshold[[0, 2000, 2000, 0], 1][[0, 2000, 2000, 0], 1]Passed
boundary: never enough sun[[0, 0, 0, 0, 0, 0], 0][[0, 0, 0, 0, 0, 0], 0]Passed
boundary: cloud dip shorter than stop delay[[3000, 3000, 1380, 3000, 1380, 0, 3000], 2][[3000, 3000, 1380, 3000, 1380, 0, 3000], 2]Passed
regression: power reported at transition sample[[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1][[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 1]Passed
regression: power reported at transition sample (partial repair)[[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1][[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 1380], 1]Passed
control 1[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0][[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]Passed
control 2[[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1][[0, 0, 3680, 2693, 3633, 1380, 3680, 3680, 2959, 1685, 2602], 1]Passed

SHA-256 / 440bed1f1052e7af6f1596812001eaea0ea78a4fcfe09ae4acb6e5a89dbc0376

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

Case digest / 1daf53e6dad9d452bdb00415a82a54cb3655ff633d6e5e2c434f648d44837283