FA-93231 / EV charging session scheduling / Open access
Contiguous cheap charging blocks: final run flush · case 01
A cheap run that lasts until the end of the horizon is never used.
ROOT CAUSE
The run being collected when the loop ends is not appended.
VERIFIED REPAIR
Flush the trailing run after the loop.
Unsuccessful approach: Flushing it only when longer than min_len still drops trailing runs of exactly min_len.
Case contract
Slots with price <= threshold form runs of consecutive slots; runs shorter than min_len are ignored to avoid contactor cycling. Slots of qualifying runs are taken chronologically until need_slots are chosen. If still short, the remaining cheapest unchosen slots (ties: earlier) are added regardless of runs and fallback is True. Return [sorted slots, fallback].
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, threshold, min_len, need_slots):
runs = []
cur = []
for i, p in enumerate(prices):
if p <= threshold:
cur.append(i)
else:
if cur:
runs.append(cur)
cur = []
chosen = []
for run in runs:
if len(run) >= min_len:
for i in run:
if len(chosen) < need_slots:
chosen.append(i)
fallback = False
if len(chosen) < need_slots:
fallback = True
rest = sorted((p, i) for i, p in enumerate(prices) if i not in chosen)
for p, i in rest[:need_slots - len(chosen)]:
chosen.append(i)
return [sorted(chosen), fallback]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[8, 0, 12, 15, 10, 12, 12, 20, 10, 10, 8, 10, 8, 0], 10, 2, 3],
[[0, 1, 8], False]],
['regression: final run flush (partial repair)', [[12, 15, 30, 5, 5, 5, 15, 10, 5, -2], 12, 3, 5],
[[3, 4, 5, 7, 8], False]],
['control 1', [[5, 20, 15, 10, -2], 10, 3, 5], [[0, 1, 2, 3, 4], True]],
['control 2', [[30, 30, 0, -2, 20, 8, 5, 20, 0, 20], 0, 4, 1], [[3], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush',
[[20, 5, 15, 12, 15, 30, 5, 20, 0, 20, 10, 0, 5, -2, 10], 12, 4, 6],
[[8, 10, 11, 12, 13, 14], True]],
['regression: final run flush (partial repair)',
[[-2, 30, 15, -2, 30, 30, 8, 5, 5, 8, 10, 0, -2], 0, 2, 2], [[11, 12], False]],
['control 1', [[30, -2, 5, 12, 8, 20, 20, 20], 12, 1, 7], [[1, 2, 3, 4, 5, 6, 7], True]],
['control 2', [[30, 8, 15, 0, 15], 8, 2, 2], [[1, 3], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[20, 30, 5, 5, 5], 10, 2, 3], [[2, 3, 4], False]],
['regression: final run flush (partial repair)',
[[-2, 30, 15, -2, 30, 30, 8, 5, 5, 8, 10, 0, -2], 0, 2, 2], [[11, 12], False]],
['control 1', [[20, -2, 10, 8, 15, 10, 0, 8, 12, 5, 8, 0, 8], 0, 1, 1], [[1], False]],
['control 2', [[-2, 8, 8, 12, -2, -2, -2, 10, 12, 15], 0, 2, 7], [[0, 1, 2, 4, 5, 6, 7], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[10, 20, -2, 10, 10, 30, 12, 0], 12, 1, 5],
[[0, 2, 3, 4, 6], False]],
['regression: final run flush (partial repair)',
[[0, 15, 15, 0, 8, 30, 20, 10, 8, 5, 10, 15, 30, 20, 0, 0], 10, 2, 7],
[[3, 4, 7, 8, 9, 10, 14], False]],
['control 1', [[-2, 12, 30, 10, 10, 10, 15, 0, 15, 10, -2, 20, 0], 12, 4, 5],
[[0, 3, 7, 10, 12], True]],
['control 2', [[10, 30, 15, 20, -2, 20, 10, 20, -2, 8, 5, 0, 20], 8, 3, 1], [[8], False]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[8, 5, 20, 0, 0, 0, -2, -2, -2, -2, -2, 0, -2], 10, 3, 8],
[[3, 4, 5, 6, 7, 8, 9, 10], False]],
['regression: final run flush (partial repair)', [[12, 15, 30, 5, 5, 5, 15, 10, 5, -2], 12, 3, 5],
[[3, 4, 5, 7, 8], False]],
['control 1', [[20, 15, 8, 8, -2, 8, -2, 30, 12, 30, 10], 10, 2, 1], [[2], False]],
['control 2', [[5, 12, 20, 0, 15, -2], 12, 4, 6], [[0, 1, 2, 3, 4, 5], True]]]]
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: run ending at horizon | [[2, 3], True] | [[2, 3], False] | Failed |
| boundary: run exactly min_len | [[0, 1], False] | [[0, 1], False] | Passed |
| boundary: nothing needed | [[], False] | [[], False] | Passed |
| regression: final run flush | [[0, 1, 13], True] | [[0, 1, 8], False] | Failed |
| regression: final run flush (partial repair) | [[3, 4, 5, 8, 9], True] | [[3, 4, 5, 7, 8], False] | Failed |
| control 1 | [[0, 1, 2, 3, 4], True] | [[0, 1, 2, 3, 4], True] | Passed |
| control 2 | [[3], True] | [[3], True] | Passed |
SHA-256 / a1878fa2f3ab1367f266e2efcf30554fbf85d70f6063cf244aec65ba51ee763a
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(prices, threshold, min_len, need_slots):
runs = []
cur = []
for i, p in enumerate(prices):
if p <= threshold:
cur.append(i)
else:
if cur:
runs.append(cur)
cur = []
if len(cur) > min_len:
runs.append(cur)
chosen = []
for run in runs:
if len(run) >= min_len:
for i in run:
if len(chosen) < need_slots:
chosen.append(i)
fallback = False
if len(chosen) < need_slots:
fallback = True
rest = sorted((p, i) for i, p in enumerate(prices) if i not in chosen)
for p, i in rest[:need_slots - len(chosen)]:
chosen.append(i)
return [sorted(chosen), fallback]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[8, 0, 12, 15, 10, 12, 12, 20, 10, 10, 8, 10, 8, 0], 10, 2, 3],
[[0, 1, 8], False]],
['regression: final run flush (partial repair)', [[12, 15, 30, 5, 5, 5, 15, 10, 5, -2], 12, 3, 5],
[[3, 4, 5, 7, 8], False]],
['control 1', [[5, 20, 15, 10, -2], 10, 3, 5], [[0, 1, 2, 3, 4], True]],
['control 2', [[30, 30, 0, -2, 20, 8, 5, 20, 0, 20], 0, 4, 1], [[3], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush',
[[20, 5, 15, 12, 15, 30, 5, 20, 0, 20, 10, 0, 5, -2, 10], 12, 4, 6],
[[8, 10, 11, 12, 13, 14], True]],
['regression: final run flush (partial repair)',
[[-2, 30, 15, -2, 30, 30, 8, 5, 5, 8, 10, 0, -2], 0, 2, 2], [[11, 12], False]],
['control 1', [[30, -2, 5, 12, 8, 20, 20, 20], 12, 1, 7], [[1, 2, 3, 4, 5, 6, 7], True]],
['control 2', [[30, 8, 15, 0, 15], 8, 2, 2], [[1, 3], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[20, 30, 5, 5, 5], 10, 2, 3], [[2, 3, 4], False]],
['regression: final run flush (partial repair)',
[[-2, 30, 15, -2, 30, 30, 8, 5, 5, 8, 10, 0, -2], 0, 2, 2], [[11, 12], False]],
['control 1', [[20, -2, 10, 8, 15, 10, 0, 8, 12, 5, 8, 0, 8], 0, 1, 1], [[1], False]],
['control 2', [[-2, 8, 8, 12, -2, -2, -2, 10, 12, 15], 0, 2, 7], [[0, 1, 2, 4, 5, 6, 7], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[10, 20, -2, 10, 10, 30, 12, 0], 12, 1, 5],
[[0, 2, 3, 4, 6], False]],
['regression: final run flush (partial repair)',
[[0, 15, 15, 0, 8, 30, 20, 10, 8, 5, 10, 15, 30, 20, 0, 0], 10, 2, 7],
[[3, 4, 7, 8, 9, 10, 14], False]],
['control 1', [[-2, 12, 30, 10, 10, 10, 15, 0, 15, 10, -2, 20, 0], 12, 4, 5],
[[0, 3, 7, 10, 12], True]],
['control 2', [[10, 30, 15, 20, -2, 20, 10, 20, -2, 8, 5, 0, 20], 8, 3, 1], [[8], False]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[8, 5, 20, 0, 0, 0, -2, -2, -2, -2, -2, 0, -2], 10, 3, 8],
[[3, 4, 5, 6, 7, 8, 9, 10], False]],
['regression: final run flush (partial repair)', [[12, 15, 30, 5, 5, 5, 15, 10, 5, -2], 12, 3, 5],
[[3, 4, 5, 7, 8], False]],
['control 1', [[20, 15, 8, 8, -2, 8, -2, 30, 12, 30, 10], 10, 2, 1], [[2], False]],
['control 2', [[5, 12, 20, 0, 15, -2], 12, 4, 6], [[0, 1, 2, 3, 4, 5], True]]]]
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: run ending at horizon | [[2, 3], True] | [[2, 3], False] | Failed |
| boundary: run exactly min_len | [[0, 1], False] | [[0, 1], False] | Passed |
| boundary: nothing needed | [[], False] | [[], False] | Passed |
| regression: final run flush | [[0, 1, 8], False] | [[0, 1, 8], False] | Passed |
| regression: final run flush (partial repair) | [[3, 4, 5, 8, 9], True] | [[3, 4, 5, 7, 8], False] | Failed |
| control 1 | [[0, 1, 2, 3, 4], True] | [[0, 1, 2, 3, 4], True] | Passed |
| control 2 | [[3], True] | [[3], True] | Passed |
SHA-256 / 2674372f6b574a1edbf59c0b78679a6c3a91c7c0facd9fcb7c667c46883854d2
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(prices, threshold, min_len, need_slots):
runs = []
cur = []
for i, p in enumerate(prices):
if p <= threshold:
cur.append(i)
else:
if cur:
runs.append(cur)
cur = []
if cur:
runs.append(cur)
chosen = []
for run in runs:
if len(run) >= min_len:
for i in run:
if len(chosen) < need_slots:
chosen.append(i)
fallback = False
if len(chosen) < need_slots:
fallback = True
rest = sorted((p, i) for i, p in enumerate(prices) if i not in chosen)
for p, i in rest[:need_slots - len(chosen)]:
chosen.append(i)
return [sorted(chosen), fallback]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[8, 0, 12, 15, 10, 12, 12, 20, 10, 10, 8, 10, 8, 0], 10, 2, 3],
[[0, 1, 8], False]],
['regression: final run flush (partial repair)', [[12, 15, 30, 5, 5, 5, 15, 10, 5, -2], 12, 3, 5],
[[3, 4, 5, 7, 8], False]],
['control 1', [[5, 20, 15, 10, -2], 10, 3, 5], [[0, 1, 2, 3, 4], True]],
['control 2', [[30, 30, 0, -2, 20, 8, 5, 20, 0, 20], 0, 4, 1], [[3], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush',
[[20, 5, 15, 12, 15, 30, 5, 20, 0, 20, 10, 0, 5, -2, 10], 12, 4, 6],
[[8, 10, 11, 12, 13, 14], True]],
['regression: final run flush (partial repair)',
[[-2, 30, 15, -2, 30, 30, 8, 5, 5, 8, 10, 0, -2], 0, 2, 2], [[11, 12], False]],
['control 1', [[30, -2, 5, 12, 8, 20, 20, 20], 12, 1, 7], [[1, 2, 3, 4, 5, 6, 7], True]],
['control 2', [[30, 8, 15, 0, 15], 8, 2, 2], [[1, 3], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[20, 30, 5, 5, 5], 10, 2, 3], [[2, 3, 4], False]],
['regression: final run flush (partial repair)',
[[-2, 30, 15, -2, 30, 30, 8, 5, 5, 8, 10, 0, -2], 0, 2, 2], [[11, 12], False]],
['control 1', [[20, -2, 10, 8, 15, 10, 0, 8, 12, 5, 8, 0, 8], 0, 1, 1], [[1], False]],
['control 2', [[-2, 8, 8, 12, -2, -2, -2, 10, 12, 15], 0, 2, 7], [[0, 1, 2, 4, 5, 6, 7], True]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[10, 20, -2, 10, 10, 30, 12, 0], 12, 1, 5],
[[0, 2, 3, 4, 6], False]],
['regression: final run flush (partial repair)',
[[0, 15, 15, 0, 8, 30, 20, 10, 8, 5, 10, 15, 30, 20, 0, 0], 10, 2, 7],
[[3, 4, 7, 8, 9, 10, 14], False]],
['control 1', [[-2, 12, 30, 10, 10, 10, 15, 0, 15, 10, -2, 20, 0], 12, 4, 5],
[[0, 3, 7, 10, 12], True]],
['control 2', [[10, 30, 15, 20, -2, 20, 10, 20, -2, 8, 5, 0, 20], 8, 3, 1], [[8], False]]],
[['boundary: run ending at horizon', [[20, 20, 5, 5], 8, 2, 2], [[2, 3], False]],
['boundary: run exactly min_len', [[5, 5, 20, 5], 8, 2, 2], [[0, 1], False]],
['boundary: nothing needed', [[5, 5, 5], 8, 1, 0], [[], False]],
['regression: final run flush', [[8, 5, 20, 0, 0, 0, -2, -2, -2, -2, -2, 0, -2], 10, 3, 8],
[[3, 4, 5, 6, 7, 8, 9, 10], False]],
['regression: final run flush (partial repair)', [[12, 15, 30, 5, 5, 5, 15, 10, 5, -2], 12, 3, 5],
[[3, 4, 5, 7, 8], False]],
['control 1', [[20, 15, 8, 8, -2, 8, -2, 30, 12, 30, 10], 10, 2, 1], [[2], False]],
['control 2', [[5, 12, 20, 0, 15, -2], 12, 4, 6], [[0, 1, 2, 3, 4, 5], True]]]]
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: run ending at horizon | [[2, 3], False] | [[2, 3], False] | Passed |
| boundary: run exactly min_len | [[0, 1], False] | [[0, 1], False] | Passed |
| boundary: nothing needed | [[], False] | [[], False] | Passed |
| regression: final run flush | [[0, 1, 8], False] | [[0, 1, 8], False] | Passed |
| regression: final run flush (partial repair) | [[3, 4, 5, 7, 8], False] | [[3, 4, 5, 7, 8], False] | Passed |
| control 1 | [[0, 1, 2, 3, 4], True] | [[0, 1, 2, 3, 4], True] | Passed |
| control 2 | [[3], True] | [[3], True] | Passed |
SHA-256 / 010ccc68e34da0e8197e8f01581cf397f6106aa8e7ceee592aaaee59db6ce86f
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:53.204209+00:00.
Case digest / 7418e72a229498d14c28d9409dcc777795a2641d539455cece65db978b5fbd0d