FA-93021 / EV charging session scheduling / Open access
PV surplus following with hysteresis: stop delay comparison · case 01
Charging continues one sample longer than the configured stop delay.
ROOT CAUSE
The stop streak must exceed the delay instead of reach it.
VERIFIED REPAIR
Stop when the streak reaches stop_delay.
Unsuccessful approach: Subtracting one stops a sample too early.
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:
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: stop delay comparison',
[[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: stop delay comparison (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: stop delay comparison',
[[3009, 3188, 1176, 956, 2989, 1246, 110, 1401, 1727, 0, 2027], 2500, 800, 1, 1],
[[3009, 3188, 1380, 1380, 2989, 1380, 0, 0, 0, 0, 0], 1]],
['regression: stop delay comparison (partial repair)',
[[4817, 2001, 3378, 6211, 4249, 4419, 4018, 3735, 5976, 5858, 1801, 2940, 2878, 5255, 4134,
4693],
1400, 800, 2, 1],
[[0, 2001, 3378, 3680, 3680, 3680, 3680, 3680, 3680, 3680, 1801, 2940, 2878, 3680, 3680, 3680],
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: stop delay comparison',
[[0, 0, 0, 422, 2620, 2189, 1006, 1799, 972, 0, 0, 121, 0, 0], 2000, 1000, 1, 1],
[[0, 0, 0, 0, 2620, 2189, 1380, 1799, 0, 0, 0, 0, 0, 0], 1]],
['regression: stop delay comparison (partial repair)',
[[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]],
['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: stop delay comparison',
[[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]],
['regression: stop delay comparison (partial repair)',
[[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]],
['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: stop delay comparison',
[[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: stop delay comparison (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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| boundary: surplus exactly at start threshold | [[0, 2000, 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 | [[3000, 3000, 1380, 3000, 1380, 1380, 3000], 1] | [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2] | Failed |
| regression: stop delay comparison | [[0, 0, 0, 0, 3528, 2938, 1380, 2002, 1380, 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: stop delay comparison (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 / 93ec94a68429fc4819489c543e2a28883f975d0711e38919638cac2e6b9b0619
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 - 1:
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: stop delay comparison',
[[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: stop delay comparison (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: stop delay comparison',
[[3009, 3188, 1176, 956, 2989, 1246, 110, 1401, 1727, 0, 2027], 2500, 800, 1, 1],
[[3009, 3188, 1380, 1380, 2989, 1380, 0, 0, 0, 0, 0], 1]],
['regression: stop delay comparison (partial repair)',
[[4817, 2001, 3378, 6211, 4249, 4419, 4018, 3735, 5976, 5858, 1801, 2940, 2878, 5255, 4134,
4693],
1400, 800, 2, 1],
[[0, 2001, 3378, 3680, 3680, 3680, 3680, 3680, 3680, 3680, 1801, 2940, 2878, 3680, 3680, 3680],
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: stop delay comparison',
[[0, 0, 0, 422, 2620, 2189, 1006, 1799, 972, 0, 0, 121, 0, 0], 2000, 1000, 1, 1],
[[0, 0, 0, 0, 2620, 2189, 1380, 1799, 0, 0, 0, 0, 0, 0], 1]],
['regression: stop delay comparison (partial repair)',
[[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]],
['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: stop delay comparison',
[[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]],
['regression: stop delay comparison (partial repair)',
[[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]],
['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: stop delay comparison',
[[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: stop delay comparison (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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| boundary: surplus exactly at start threshold | [[0, 2000, 0, 0], 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 | [[3000, 3000, 0, 3000, 0, 0, 3000], 3] | [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2] | Failed |
| regression: stop delay comparison | [[0, 0, 0, 0, 3528, 0, 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] | Failed |
| regression: stop delay comparison (partial repair) | [[0, 0, 0, 0, 3394, 1380, 3397, 1759, 1380, 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 / 74992b9e27072f2434f31bc97c9b0e651d6ee62f1c20b7e2bb1989925891176b
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: stop delay comparison',
[[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: stop delay comparison (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: stop delay comparison',
[[3009, 3188, 1176, 956, 2989, 1246, 110, 1401, 1727, 0, 2027], 2500, 800, 1, 1],
[[3009, 3188, 1380, 1380, 2989, 1380, 0, 0, 0, 0, 0], 1]],
['regression: stop delay comparison (partial repair)',
[[4817, 2001, 3378, 6211, 4249, 4419, 4018, 3735, 5976, 5858, 1801, 2940, 2878, 5255, 4134,
4693],
1400, 800, 2, 1],
[[0, 2001, 3378, 3680, 3680, 3680, 3680, 3680, 3680, 3680, 1801, 2940, 2878, 3680, 3680, 3680],
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: stop delay comparison',
[[0, 0, 0, 422, 2620, 2189, 1006, 1799, 972, 0, 0, 121, 0, 0], 2000, 1000, 1, 1],
[[0, 0, 0, 0, 2620, 2189, 1380, 1799, 0, 0, 0, 0, 0, 0], 1]],
['regression: stop delay comparison (partial repair)',
[[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]],
['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: stop delay comparison',
[[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]],
['regression: stop delay comparison (partial repair)',
[[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]],
['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: stop delay comparison',
[[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: stop delay comparison (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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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: stop delay comparison | [[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: stop delay comparison (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 / 43938d48be635aaec019b57ba83403ded3be59d5c290d3b71789e11fc63e9510
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.249212+00:00.
Case digest / 91d6661029c654a34e1803dd76560ea463cd8b2f0210507cfc734b0d0ac93a4e