FA-93276 / EV charging session scheduling / Open access
Arrival charger matching: deadline inclusivity · case 01
A charger finishing exactly at departure is reported as late.
ROOT CAUSE
The feasibility test is strict.
VERIFIED REPAIR
A finish equal to depart is feasible.
Unsuccessful approach: Requiring an extra quarter hour rejects feasible chargers.
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)
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: deadline inclusivity (partial repair)',
[[[1, 7.4, 60], [2, 150, 60], [3, 3.7, 0]], [30, 74, 11, True], 46], [2, 72, '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],
['control 3', [[[1, 7.4, 120], [2, 50, 0], [3, 50, 0], [4, 50, 120]], [45, 375, 11, True], 13],
[2, 67, '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: deadline inclusivity (partial repair)',
[[[1, 50, 120], [2, 7.4, 0], [3, 3.7, 0], [4, 7.4, 60], [5, 50, 10]], [20, 64, 3.7, True], 31],
[5, 55, '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']],
['control 3', [[[1, 150, 120], [2, 7.4, 60]], [20, 386, 11, True], 0], [2, 223, '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: deadline inclusivity (partial repair)',
[[[1, 50, 0], [2, 50, 120], [3, 7.4, 10], [4, 3.7, 0]], [5, 54, 7.4, True], 37], [1, 43, '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']],
['control 3',
[[[1, 22, 120], [2, 50, 30], [3, 150, 0], [4, 7.4, 60], [5, 7.4, 120]], [5, 316, 7.4, True], 35],
[4, 101, '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: deadline inclusivity (partial repair)',
[[[1, 7.4, 0], [2, 50, 10], [3, 50, 0], [4, 150, 30], [5, 22, 0]], [10, 143, 7.4, True], 58],
[1, 140, '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']],
['control 3', [[[1, 3.7, 10], [2, 50, 60], [3, 22, 10], [4, 7.4, 10]], [30, 289, 7.4, True], 35],
[3, 279, '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: deadline inclusivity (partial repair)',
[[[1, 7.4, 0], [2, 50, 10], [3, 50, 0], [4, 150, 30], [5, 22, 0]], [10, 143, 7.4, True], 58],
[1, 140, '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']],
['control 3', [[[1, 50, 0]], [5, 182, 7.4, False], 45], None]]]
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, 'late'] | [1, 300, 'ok'] | Failed |
| boundary: only DC and no DC support | None | None | Passed |
| regression: deadline inclusivity (partial repair) | [2, 72, 'ok'] | [2, 72, 'ok'] | Passed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
| control 3 | [2, 67, 'ok'] | [2, 67, 'ok'] | Passed |
SHA-256 / a52e0895d112dd5f70f1ec218b6a3d33f0e2b934765a19aca8a861641004f5fb
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] + 15 <= 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: deadline inclusivity (partial repair)',
[[[1, 7.4, 60], [2, 150, 60], [3, 3.7, 0]], [30, 74, 11, True], 46], [2, 72, '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],
['control 3', [[[1, 7.4, 120], [2, 50, 0], [3, 50, 0], [4, 50, 120]], [45, 375, 11, True], 13],
[2, 67, '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: deadline inclusivity (partial repair)',
[[[1, 50, 120], [2, 7.4, 0], [3, 3.7, 0], [4, 7.4, 60], [5, 50, 10]], [20, 64, 3.7, True], 31],
[5, 55, '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']],
['control 3', [[[1, 150, 120], [2, 7.4, 60]], [20, 386, 11, True], 0], [2, 223, '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: deadline inclusivity (partial repair)',
[[[1, 50, 0], [2, 50, 120], [3, 7.4, 10], [4, 3.7, 0]], [5, 54, 7.4, True], 37], [1, 43, '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']],
['control 3',
[[[1, 22, 120], [2, 50, 30], [3, 150, 0], [4, 7.4, 60], [5, 7.4, 120]], [5, 316, 7.4, True], 35],
[4, 101, '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: deadline inclusivity (partial repair)',
[[[1, 7.4, 0], [2, 50, 10], [3, 50, 0], [4, 150, 30], [5, 22, 0]], [10, 143, 7.4, True], 58],
[1, 140, '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']],
['control 3', [[[1, 3.7, 10], [2, 50, 60], [3, 22, 10], [4, 7.4, 10]], [30, 289, 7.4, True], 35],
[3, 279, '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: deadline inclusivity (partial repair)',
[[[1, 7.4, 0], [2, 50, 10], [3, 50, 0], [4, 150, 30], [5, 22, 0]], [10, 143, 7.4, True], 58],
[1, 140, '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']],
['control 3', [[[1, 50, 0]], [5, 182, 7.4, False], 45], None]]]
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, 'late'] | [1, 300, 'ok'] | Failed |
| boundary: only DC and no DC support | None | None | Passed |
| regression: deadline inclusivity (partial repair) | [2, 72, 'late'] | [2, 72, 'ok'] | Failed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
| control 3 | [2, 67, 'ok'] | [2, 67, 'ok'] | Passed |
SHA-256 / fb4f5f9fdae5ca0026ae726cefa0b5e372f85e6e9ed89d00a468dcd049ea7f76
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: deadline inclusivity (partial repair)',
[[[1, 7.4, 60], [2, 150, 60], [3, 3.7, 0]], [30, 74, 11, True], 46], [2, 72, '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],
['control 3', [[[1, 7.4, 120], [2, 50, 0], [3, 50, 0], [4, 50, 120]], [45, 375, 11, True], 13],
[2, 67, '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: deadline inclusivity (partial repair)',
[[[1, 50, 120], [2, 7.4, 0], [3, 3.7, 0], [4, 7.4, 60], [5, 50, 10]], [20, 64, 3.7, True], 31],
[5, 55, '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']],
['control 3', [[[1, 150, 120], [2, 7.4, 60]], [20, 386, 11, True], 0], [2, 223, '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: deadline inclusivity (partial repair)',
[[[1, 50, 0], [2, 50, 120], [3, 7.4, 10], [4, 3.7, 0]], [5, 54, 7.4, True], 37], [1, 43, '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']],
['control 3',
[[[1, 22, 120], [2, 50, 30], [3, 150, 0], [4, 7.4, 60], [5, 7.4, 120]], [5, 316, 7.4, True], 35],
[4, 101, '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: deadline inclusivity (partial repair)',
[[[1, 7.4, 0], [2, 50, 10], [3, 50, 0], [4, 150, 30], [5, 22, 0]], [10, 143, 7.4, True], 58],
[1, 140, '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']],
['control 3', [[[1, 3.7, 10], [2, 50, 60], [3, 22, 10], [4, 7.4, 10]], [30, 289, 7.4, True], 35],
[3, 279, '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: deadline inclusivity (partial repair)',
[[[1, 7.4, 0], [2, 50, 10], [3, 50, 0], [4, 150, 30], [5, 22, 0]], [10, 143, 7.4, True], 58],
[1, 140, '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']],
['control 3', [[[1, 50, 0]], [5, 182, 7.4, False], 45], None]]]
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: deadline inclusivity (partial repair) | [2, 72, 'ok'] | [2, 72, 'ok'] | Passed |
| control 1 | [1, 88, 'ok'] | [1, 88, 'ok'] | Passed |
| control 2 | None | None | Passed |
| control 3 | [2, 67, 'ok'] | [2, 67, 'ok'] | Passed |
SHA-256 / 4c39c8ed699da7c681a7d6e73ef79e504f86dee8a055329049d208699bee2827
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.641281+00:00.
Case digest / fec821d9532d280432afcf4cc21c95106b2de7751af4cf7a48c3e43080876bab