FA-93266 / EV charging session scheduling / Open access
Arrival charger matching: charger availability start · case 01
Finish times are computed as if a busy charger were free now, or as if an idle one started in the past.
ROOT CAUSE
The session start ignores the current time.
VERIFIED REPAIR
Start at the later of now and free_at.
Unsuccessful approach: Ignoring free_at promises busy chargers immediately.
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 = 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: charger availability start',
[[[1, 11, 0], [2, 150, 120], [3, 22, 10], [4, 3.7, 0]], [5, 101, 7.4, False], 31],
[1, 72, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 150, 10], [2, 22, 120], [3, 150, 30], [4, 3.7, 120]], [20, 111, 3.7, False], 6],
[2, 445, 'late']],
['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: charger availability start',
[[[1, 150, 0], [2, 7.4, 120], [3, 50, 0]], [20, 67, 11, True], 8], [3, 32, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120]], [20, 345, 3.7, True], 47], [1, 445, 'late']],
['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: charger availability start',
[[[1, 11, 60], [2, 150, 30], [3, 7.4, 0], [4, 3.7, 0], [5, 7.4, 60]], [10, 35, 3.7, False], 25],
[3, 188, 'late']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120], [2, 7.4, 30]], [45, 240, 3.7, False], 22], [2, 760, 'late']],
['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: charger availability start',
[[[1, 22, 120], [2, 7.4, 10], [3, 50, 60], [4, 7.4, 0]], [20, 375, 7.4, True], 37],
[2, 200, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 7.4, 120]], [20, 342, 11, True], 40], [1, 283, '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: charger availability start', [[[1, 3.7, 0]], [45, 358, 3.7, False], 15],
[1, 745, 'late']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120], [2, 7.4, 0]], [20, 121, 11, True], 24], [2, 187, 'late']],
['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: charger availability start | [4, 82, 'ok'] | [1, 72, 'ok'] | Failed |
| regression: charger availability start (partial repair) | [2, 445, 'late'] | [2, 445, 'late'] | Passed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
SHA-256 / 08096459e1bb9d81718835ac0663e4d665d15620a9057abeab783180ff73fc97
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 = now
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: charger availability start',
[[[1, 11, 0], [2, 150, 120], [3, 22, 10], [4, 3.7, 0]], [5, 101, 7.4, False], 31],
[1, 72, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 150, 10], [2, 22, 120], [3, 150, 30], [4, 3.7, 120]], [20, 111, 3.7, False], 6],
[2, 445, 'late']],
['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: charger availability start',
[[[1, 150, 0], [2, 7.4, 120], [3, 50, 0]], [20, 67, 11, True], 8], [3, 32, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120]], [20, 345, 3.7, True], 47], [1, 445, 'late']],
['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: charger availability start',
[[[1, 11, 60], [2, 150, 30], [3, 7.4, 0], [4, 3.7, 0], [5, 7.4, 60]], [10, 35, 3.7, False], 25],
[3, 188, 'late']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120], [2, 7.4, 30]], [45, 240, 3.7, False], 22], [2, 760, 'late']],
['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: charger availability start',
[[[1, 22, 120], [2, 7.4, 10], [3, 50, 60], [4, 7.4, 0]], [20, 375, 7.4, True], 37],
[2, 200, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 7.4, 120]], [20, 342, 11, True], 40], [1, 283, '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: charger availability start', [[[1, 3.7, 0]], [45, 358, 3.7, False], 15],
[1, 745, 'late']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120], [2, 7.4, 0]], [20, 121, 11, True], 24], [2, 187, 'late']],
['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: charger availability start | [1, 72, 'ok'] | [1, 72, 'ok'] | Passed |
| regression: charger availability start (partial repair) | [2, 331, 'late'] | [2, 445, 'late'] | Failed |
| control 1 | [1, 36, 'ok'] | [1, 88, 'ok'] | Failed |
| control 2 | None | None | Passed |
SHA-256 / f3ecf136fca4bf06a98633a16fbf8cf2a42118f194ceaef2eca082e3521ec2f8
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: charger availability start',
[[[1, 11, 0], [2, 150, 120], [3, 22, 10], [4, 3.7, 0]], [5, 101, 7.4, False], 31],
[1, 72, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 150, 10], [2, 22, 120], [3, 150, 30], [4, 3.7, 120]], [20, 111, 3.7, False], 6],
[2, 445, 'late']],
['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: charger availability start',
[[[1, 150, 0], [2, 7.4, 120], [3, 50, 0]], [20, 67, 11, True], 8], [3, 32, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120]], [20, 345, 3.7, True], 47], [1, 445, 'late']],
['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: charger availability start',
[[[1, 11, 60], [2, 150, 30], [3, 7.4, 0], [4, 3.7, 0], [5, 7.4, 60]], [10, 35, 3.7, False], 25],
[3, 188, 'late']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120], [2, 7.4, 30]], [45, 240, 3.7, False], 22], [2, 760, 'late']],
['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: charger availability start',
[[[1, 22, 120], [2, 7.4, 10], [3, 50, 60], [4, 7.4, 0]], [20, 375, 7.4, True], 37],
[2, 200, 'ok']],
['regression: charger availability start (partial repair)',
[[[1, 7.4, 120]], [20, 342, 11, True], 40], [1, 283, '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: charger availability start', [[[1, 3.7, 0]], [45, 358, 3.7, False], 15],
[1, 745, 'late']],
['regression: charger availability start (partial repair)',
[[[1, 22, 120], [2, 7.4, 0]], [20, 121, 11, True], 24], [2, 187, 'late']],
['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: charger availability start | [1, 72, 'ok'] | [1, 72, 'ok'] | Passed |
| regression: charger availability start (partial repair) | [2, 445, 'late'] | [2, 445, 'late'] | Passed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
SHA-256 / 3e0c5c9589e7b8c2d7d08b8a289b31a097f47c47383fe81c50251469a5da4bfa
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.615209+00:00.
Case digest / 94c5d9ca00be364b43ded8d3504d4b764d7ad17179dc82f32fb9bfae667ea725