FA-93006 / EV charging session scheduling / Open access
PV surplus following with hysteresis: start threshold comparison · case 01
Surplus exactly at the start threshold never starts charging.
ROOT CAUSE
The start qualification uses a strict comparison.
VERIFIED REPAIR
Count samples with surplus >= start_w.
Unsuccessful approach: Qualifying against the lower stop threshold starts charging on too little surplus.
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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[1383, 3471, 4209, 3007, 3092, 4130, 867, 4816, 5640, 2694, 3409, 891, 1847, 5749], 2000, 1400,
2, 1],
[[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2]]],
[['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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[3891, 1697, 5264, 4956, 5195, 2229, 1384, 5164, 2148, 4795, 1650, 5684, 1327, 5638, 2016],
2500, 1000, 3, 2],
[[0, 0, 0, 0, 3680, 2229, 1384, 3680, 2148, 3680, 1650, 3680, 1380, 3680, 2016], 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: start threshold comparison (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]],
['control 3',
[[2013, 328, 0, 0, 4433, 1982, 4223, 1757, 3755, 2681, 4171, 2453, 0, 2324], 1400, 1000, 1, 2],
[[2013, 1380, 0, 0, 3680, 1982, 3680, 1757, 3680, 2681, 3680, 2453, 1380, 2324], 2]]],
[['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: start threshold comparison (partial repair)',
[[815, 1005, 1941, 0, 2807, 870, 2493, 0, 931, 417, 963, 0, 0], 2000, 800, 2, 1],
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]],
['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]],
['control 3', [[1873, 4610, 989, 2113, 4201, 1521], 2500, 800, 2, 2], [[0, 0, 0, 0, 0, 0], 0]]],
[['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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[2094, 1100, 2881, 1794, 1218, 2481, 5490, 2037, 3975, 3503, 4445], 2000, 1400, 3, 2],
[[0, 0, 0, 0, 0, 0, 0, 2037, 3680, 3503, 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, 0, 0, 0], 0] | [[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, 0, 3000], 2] | [[3000, 3000, 1380, 3000, 1380, 0, 3000], 2] | Passed |
| regression: start threshold comparison (partial repair) | [[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 |
| 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 |
| control 3 | [[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2] | [[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2] | Passed |
SHA-256 / 60aac292fb3471ff115759309aa9f213c34fd781c5573995089d7af20986a33e
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 >= stop_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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[1383, 3471, 4209, 3007, 3092, 4130, 867, 4816, 5640, 2694, 3409, 891, 1847, 5749], 2000, 1400,
2, 1],
[[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2]]],
[['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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[3891, 1697, 5264, 4956, 5195, 2229, 1384, 5164, 2148, 4795, 1650, 5684, 1327, 5638, 2016],
2500, 1000, 3, 2],
[[0, 0, 0, 0, 3680, 2229, 1384, 3680, 2148, 3680, 1650, 3680, 1380, 3680, 2016], 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: start threshold comparison (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]],
['control 3',
[[2013, 328, 0, 0, 4433, 1982, 4223, 1757, 3755, 2681, 4171, 2453, 0, 2324], 1400, 1000, 1, 2],
[[2013, 1380, 0, 0, 3680, 1982, 3680, 1757, 3680, 2681, 3680, 2453, 1380, 2324], 2]]],
[['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: start threshold comparison (partial repair)',
[[815, 1005, 1941, 0, 2807, 870, 2493, 0, 931, 417, 963, 0, 0], 2000, 800, 2, 1],
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]],
['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]],
['control 3', [[1873, 4610, 989, 2113, 4201, 1521], 2500, 800, 2, 2], [[0, 0, 0, 0, 0, 0], 0]]],
[['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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[2094, 1100, 2881, 1794, 1218, 2481, 5490, 2037, 3975, 3503, 4445], 2000, 1400, 3, 2],
[[0, 0, 0, 0, 0, 0, 0, 2037, 3680, 3503, 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: start threshold comparison (partial repair) | [[0, 3340, 1407, 3680, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1580], 2] | [[0, 0, 0, 0, 3528, 2938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 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 |
| control 3 | [[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 3680], 3] | [[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2] | Failed |
SHA-256 / 90e80256a55effba39852863687fc671bf4493d91395f2777d3ab530530192fa
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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[1383, 3471, 4209, 3007, 3092, 4130, 867, 4816, 5640, 2694, 3409, 891, 1847, 5749], 2000, 1400,
2, 1],
[[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2]]],
[['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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[3891, 1697, 5264, 4956, 5195, 2229, 1384, 5164, 2148, 4795, 1650, 5684, 1327, 5638, 2016],
2500, 1000, 3, 2],
[[0, 0, 0, 0, 3680, 2229, 1384, 3680, 2148, 3680, 1650, 3680, 1380, 3680, 2016], 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: start threshold comparison (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]],
['control 3',
[[2013, 328, 0, 0, 4433, 1982, 4223, 1757, 3755, 2681, 4171, 2453, 0, 2324], 1400, 1000, 1, 2],
[[2013, 1380, 0, 0, 3680, 1982, 3680, 1757, 3680, 2681, 3680, 2453, 1380, 2324], 2]]],
[['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: start threshold comparison (partial repair)',
[[815, 1005, 1941, 0, 2807, 870, 2493, 0, 931, 417, 963, 0, 0], 2000, 800, 2, 1],
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0]],
['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]],
['control 3', [[1873, 4610, 989, 2113, 4201, 1521], 2500, 800, 2, 2], [[0, 0, 0, 0, 0, 0], 0]]],
[['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: start threshold comparison (partial repair)',
[[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]],
['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]],
['control 3',
[[2094, 1100, 2881, 1794, 1218, 2481, 5490, 2037, 3975, 3503, 4445], 2000, 1400, 3, 2],
[[0, 0, 0, 0, 0, 0, 0, 2037, 3680, 3503, 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: start threshold comparison (partial repair) | [[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 |
| 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 |
| control 3 | [[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2] | [[0, 0, 3680, 3007, 3092, 3680, 0, 0, 3680, 2694, 3409, 0, 0, 0], 2] | Passed |
SHA-256 / 1f56d5569823e8db0da95febfb33cb6b042ba415d0d966db972cbafd21515e7f
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.119094+00:00.
Case digest / 3c3778bd4c5c35b15c684640b4da4f88b261665c98d94c53f846f5cec24d3c6a