FA-93281 / EV charging session scheduling / Open access
Arrival charger matching: feasible charger preference · case 01
Short-stay vehicles take fast DC chargers that slower AC points could serve in time.
ROOT CAUSE
Feasible chargers are ranked by finish time instead of lowest sufficient power.
VERIFIED REPAIR
Rank feasible chargers by power, then finish, then id.
Unsuccessful approach: Ranking by power alone leaves equal-power ties in list order.
Case contract
chargers are [id, kw, free_at]; kw > 22 is DC (usable only if dc_ok, full kw), otherwise AC limited to the vehicle onboard max_ac. vehicle is [need_kwh, depart, max_ac, dc_ok]. Finish = max(now, free_at) + ceil(need*60/power) minutes. Among chargers finishing by depart pick the lowest power, then earliest finish, then id; otherwise the earliest finish (then id) with status 'late'. Return [id, finish, status] or None when no charger is usable.
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
import math
N = 1
observations = []
def solve(chargers, vehicle, now):
need, depart, max_ac, dc_ok = vehicle
opts = []
for cid, kw, free_at in chargers:
if kw > 22:
if not dc_ok:
continue
pw = kw
else:
pw = min(kw, max_ac)
start = max(now, free_at)
finish = start + math.ceil(need * 60 / pw)
opts.append([pw, finish, cid])
if not opts:
return None
ok = [o for o in opts if o[1] <= depart]
if ok:
pw, finish, cid = min(ok, key=lambda o: (o[1], o[2]))
return [cid, finish, 'ok']
pw, finish, cid = min(opts, key=lambda o: (o[1], o[2]))
return [cid, finish, 'late']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 3.7, 30], [2, 3.7, 60], [3, 11, 30], [4, 22, 120]], [10, 332, 11, True], 57],
[1, 220, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 50, 30], [2, 22, 30], [3, 50, 120], [4, 22, 0]], [5, 150, 7.4, True], 10], [4, 51, 'ok']],
['control 1', [[[1, 22, 60]], [5, 244, 11, False], 8], [1, 88, 'ok']],
['control 2', [[[1, 50, 0], [2, 50, 0]], [5, 160, 11, False], 39], None]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 150, 0], [2, 7.4, 120], [3, 50, 0]], [20, 67, 11, True], 8], [3, 32, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 3.7, 10], [2, 7.4, 0], [3, 50, 60], [4, 50, 30], [5, 7.4, 10]], [20, 252, 3.7, True], 34],
[4, 58, 'ok']],
['control 1', [[[1, 50, 0]], [45, 63, 7.4, True], 12], [1, 66, 'late']],
['control 2',
[[[1, 7.4, 60], [2, 7.4, 10], [3, 22, 10], [4, 11, 120], [5, 50, 120]], [45, 353, 7.4, True],
45],
[5, 174, 'ok']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 150, 0], [2, 7.4, 30], [3, 7.4, 0], [4, 3.7, 60], [5, 7.4, 60]], [5, 300, 3.7, True], 48],
[2, 130, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 150, 120], [2, 50, 0], [3, 50, 10], [4, 22, 60], [5, 22, 0]], [20, 374, 7.4, True], 19],
[5, 182, 'ok']],
['control 1', [[[1, 7.4, 10], [2, 7.4, 0]], [45, 88, 7.4, True], 40], [1, 405, 'late']],
['control 2', [[[1, 3.7, 10], [2, 3.7, 120], [3, 11, 10], [4, 50, 0]], [5, 42, 7.4, True], 27],
[4, 33, 'ok']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 22, 120], [2, 7.4, 10], [3, 50, 60], [4, 7.4, 0]], [20, 375, 7.4, True], 37],
[2, 200, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 150, 0], [2, 150, 10], [3, 22, 30], [4, 7.4, 10]], [10, 278, 7.4, False], 17],
[4, 99, 'ok']],
['control 1', [[[1, 7.4, 60]], [30, 240, 3.7, True], 21], [1, 547, 'late']],
['control 2', [[[1, 3.7, 60], [2, 3.7, 120], [3, 150, 30], [4, 150, 0]], [45, 67, 11, False], 57],
[1, 790, 'late']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 50, 60], [2, 11, 0], [3, 7.4, 0]], [45, 352, 11, True], 50], [2, 296, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 50, 30], [2, 50, 60], [3, 50, 0]], [10, 216, 3.7, True], 29], [3, 41, 'ok']],
['control 1', [[[1, 50, 60], [2, 50, 60]], [45, 130, 7.4, True], 48], [1, 114, 'ok']],
['control 2', [[[1, 150, 0], [2, 7.4, 10]], [10, 89, 3.7, True], 57], [1, 61, 'ok']]]]
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: 22 kW AC charger | [1, 60, 'ok'] | [1, 60, 'ok'] | Passed |
| boundary: finish exactly at departure | [1, 300, 'ok'] | [1, 300, 'ok'] | Passed |
| boundary: only DC and no DC support | None | None | Passed |
| regression: feasible charger preference | [3, 112, 'ok'] | [1, 220, 'ok'] | Failed |
| regression: feasible charger preference (partial repair) | [1, 36, 'ok'] | [4, 51, 'ok'] | Failed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
SHA-256 / bf6fd0f98e95111182603fca23c107f42fc5d030954c3b932f3549bef8e5ffa0
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(chargers, vehicle, now):
need, depart, max_ac, dc_ok = vehicle
opts = []
for cid, kw, free_at in chargers:
if kw > 22:
if not dc_ok:
continue
pw = kw
else:
pw = min(kw, max_ac)
start = max(now, free_at)
finish = start + math.ceil(need * 60 / pw)
opts.append([pw, finish, cid])
if not opts:
return None
ok = [o for o in opts if o[1] <= depart]
if ok:
pw, finish, cid = min(ok, key=lambda o: o[0])
return [cid, finish, 'ok']
pw, finish, cid = min(opts, key=lambda o: (o[1], o[2]))
return [cid, finish, 'late']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 3.7, 30], [2, 3.7, 60], [3, 11, 30], [4, 22, 120]], [10, 332, 11, True], 57],
[1, 220, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 50, 30], [2, 22, 30], [3, 50, 120], [4, 22, 0]], [5, 150, 7.4, True], 10], [4, 51, 'ok']],
['control 1', [[[1, 22, 60]], [5, 244, 11, False], 8], [1, 88, 'ok']],
['control 2', [[[1, 50, 0], [2, 50, 0]], [5, 160, 11, False], 39], None]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 150, 0], [2, 7.4, 120], [3, 50, 0]], [20, 67, 11, True], 8], [3, 32, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 3.7, 10], [2, 7.4, 0], [3, 50, 60], [4, 50, 30], [5, 7.4, 10]], [20, 252, 3.7, True], 34],
[4, 58, 'ok']],
['control 1', [[[1, 50, 0]], [45, 63, 7.4, True], 12], [1, 66, 'late']],
['control 2',
[[[1, 7.4, 60], [2, 7.4, 10], [3, 22, 10], [4, 11, 120], [5, 50, 120]], [45, 353, 7.4, True],
45],
[5, 174, 'ok']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 150, 0], [2, 7.4, 30], [3, 7.4, 0], [4, 3.7, 60], [5, 7.4, 60]], [5, 300, 3.7, True], 48],
[2, 130, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 150, 120], [2, 50, 0], [3, 50, 10], [4, 22, 60], [5, 22, 0]], [20, 374, 7.4, True], 19],
[5, 182, 'ok']],
['control 1', [[[1, 7.4, 10], [2, 7.4, 0]], [45, 88, 7.4, True], 40], [1, 405, 'late']],
['control 2', [[[1, 3.7, 10], [2, 3.7, 120], [3, 11, 10], [4, 50, 0]], [5, 42, 7.4, True], 27],
[4, 33, 'ok']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 22, 120], [2, 7.4, 10], [3, 50, 60], [4, 7.4, 0]], [20, 375, 7.4, True], 37],
[2, 200, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 150, 0], [2, 150, 10], [3, 22, 30], [4, 7.4, 10]], [10, 278, 7.4, False], 17],
[4, 99, 'ok']],
['control 1', [[[1, 7.4, 60]], [30, 240, 3.7, True], 21], [1, 547, 'late']],
['control 2', [[[1, 3.7, 60], [2, 3.7, 120], [3, 150, 30], [4, 150, 0]], [45, 67, 11, False], 57],
[1, 790, 'late']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 50, 60], [2, 11, 0], [3, 7.4, 0]], [45, 352, 11, True], 50], [2, 296, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 50, 30], [2, 50, 60], [3, 50, 0]], [10, 216, 3.7, True], 29], [3, 41, 'ok']],
['control 1', [[[1, 50, 60], [2, 50, 60]], [45, 130, 7.4, True], 48], [1, 114, 'ok']],
['control 2', [[[1, 150, 0], [2, 7.4, 10]], [10, 89, 3.7, True], 57], [1, 61, 'ok']]]]
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: 22 kW AC charger | [1, 60, 'ok'] | [1, 60, 'ok'] | Passed |
| boundary: finish exactly at departure | [1, 300, 'ok'] | [1, 300, 'ok'] | Passed |
| boundary: only DC and no DC support | None | None | Passed |
| regression: feasible charger preference | [1, 220, 'ok'] | [1, 220, 'ok'] | Passed |
| regression: feasible charger preference (partial repair) | [2, 71, 'ok'] | [4, 51, 'ok'] | Failed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
SHA-256 / 8f6dbe16a150fa461fb2f69236b1039e2bbfafc4ff1196bb4d4ab0df28c4d074
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(chargers, vehicle, now):
need, depart, max_ac, dc_ok = vehicle
opts = []
for cid, kw, free_at in chargers:
if kw > 22:
if not dc_ok:
continue
pw = kw
else:
pw = min(kw, max_ac)
start = max(now, free_at)
finish = start + math.ceil(need * 60 / pw)
opts.append([pw, finish, cid])
if not opts:
return None
ok = [o for o in opts if o[1] <= depart]
if ok:
pw, finish, cid = min(ok)
return [cid, finish, 'ok']
pw, finish, cid = min(opts, key=lambda o: (o[1], o[2]))
return [cid, finish, 'late']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 3.7, 30], [2, 3.7, 60], [3, 11, 30], [4, 22, 120]], [10, 332, 11, True], 57],
[1, 220, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 50, 30], [2, 22, 30], [3, 50, 120], [4, 22, 0]], [5, 150, 7.4, True], 10], [4, 51, 'ok']],
['control 1', [[[1, 22, 60]], [5, 244, 11, False], 8], [1, 88, 'ok']],
['control 2', [[[1, 50, 0], [2, 50, 0]], [5, 160, 11, False], 39], None]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 150, 0], [2, 7.4, 120], [3, 50, 0]], [20, 67, 11, True], 8], [3, 32, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 3.7, 10], [2, 7.4, 0], [3, 50, 60], [4, 50, 30], [5, 7.4, 10]], [20, 252, 3.7, True], 34],
[4, 58, 'ok']],
['control 1', [[[1, 50, 0]], [45, 63, 7.4, True], 12], [1, 66, 'late']],
['control 2',
[[[1, 7.4, 60], [2, 7.4, 10], [3, 22, 10], [4, 11, 120], [5, 50, 120]], [45, 353, 7.4, True],
45],
[5, 174, 'ok']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 150, 0], [2, 7.4, 30], [3, 7.4, 0], [4, 3.7, 60], [5, 7.4, 60]], [5, 300, 3.7, True], 48],
[2, 130, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 150, 120], [2, 50, 0], [3, 50, 10], [4, 22, 60], [5, 22, 0]], [20, 374, 7.4, True], 19],
[5, 182, 'ok']],
['control 1', [[[1, 7.4, 10], [2, 7.4, 0]], [45, 88, 7.4, True], 40], [1, 405, 'late']],
['control 2', [[[1, 3.7, 10], [2, 3.7, 120], [3, 11, 10], [4, 50, 0]], [5, 42, 7.4, True], 27],
[4, 33, 'ok']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 22, 120], [2, 7.4, 10], [3, 50, 60], [4, 7.4, 0]], [20, 375, 7.4, True], 37],
[2, 200, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 150, 0], [2, 150, 10], [3, 22, 30], [4, 7.4, 10]], [10, 278, 7.4, False], 17],
[4, 99, 'ok']],
['control 1', [[[1, 7.4, 60]], [30, 240, 3.7, True], 21], [1, 547, 'late']],
['control 2', [[[1, 3.7, 60], [2, 3.7, 120], [3, 150, 30], [4, 150, 0]], [45, 67, 11, False], 57],
[1, 790, 'late']]],
[['boundary: 22 kW AC charger', [[[1, 22, 0]], [11, 300, 11, False], 0], [1, 60, 'ok']],
['boundary: finish exactly at departure', [[[1, 7.4, 0]], [37, 300, 7.4, True], 0],
[1, 300, 'ok']],
['boundary: only DC and no DC support', [[[1, 50, 0]], [10, 100, 11, False], 0], None],
['regression: feasible charger preference',
[[[1, 50, 60], [2, 11, 0], [3, 7.4, 0]], [45, 352, 11, True], 50], [2, 296, 'ok']],
['regression: feasible charger preference (partial repair)',
[[[1, 50, 30], [2, 50, 60], [3, 50, 0]], [10, 216, 3.7, True], 29], [3, 41, 'ok']],
['control 1', [[[1, 50, 60], [2, 50, 60]], [45, 130, 7.4, True], 48], [1, 114, 'ok']],
['control 2', [[[1, 150, 0], [2, 7.4, 10]], [10, 89, 3.7, True], 57], [1, 61, 'ok']]]]
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: 22 kW AC charger | [1, 60, 'ok'] | [1, 60, 'ok'] | Passed |
| boundary: finish exactly at departure | [1, 300, 'ok'] | [1, 300, 'ok'] | Passed |
| boundary: only DC and no DC support | None | None | Passed |
| regression: feasible charger preference | [1, 220, 'ok'] | [1, 220, 'ok'] | Passed |
| regression: feasible charger preference (partial repair) | [4, 51, 'ok'] | [4, 51, 'ok'] | Passed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
SHA-256 / ec205f6017e8ce9581d219ea12d8ae6e4b15e77afbd2440ab8df5a834c606b4d
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.680046+00:00.
Case digest / 56a2069850fc04827c4704595c857f5726a1adc1792c6cd9d810e415839dc626