FA-68691 / Toll and parking fee computation / Open access
EV charging session and idle fee: energy is billed in whole kWh · case 01
EV charging session and idle fee returns a wrong result when energy is billed in whole kWh.
ROOT CAUSE
Truncating to whole kWh gives away up to one kWh per session.
VERIFIED REPAIR
Restore the energy charge rule so that the step reads `-(-x['wh'] * x['price_per_kwh'] // 1000)`.
Unsuccessful approach: Rounding kWh to nearest still bills whole kWh, not delivered energy.
Case contract
Input {plug_in, charge_end, unplug (minutes), wh, price_per_kwh, idle_grace, idle_rate (per started 10 min), idle_cap, session_fee, min_fee}. Energy = ceil(wh*price/1000). Idle minutes = max(0, unplug - charge_end - grace); idle fee = min(idle_cap, started 10-minute blocks * idle_rate). Total = max(min_fee, session_fee + energy + idle). Return {energy, idle, total}.
Why this case matters
Fee engines bill customers in integer cents; a wrong boundary, rounding stage or cap scope silently over- or under-charges.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
energy = x['wh'] // 1000 * x['price_per_kwh']
idle = max(0, x['unplug'] - x['charge_end'] - x['idle_grace'])
idle_fee = min(x['idle_cap'], -(-idle // 10) * x['idle_rate'])
total = x['session_fee'] + energy + idle_fee
return {'energy': energy, 'idle': idle_fee, 'total': max(x['min_fee'], total)}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'plug_in': 351, 'charge_end': 512, 'unplug': 522, 'wh': 7509, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 263, 'idle': 0, 'total': 500}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 21, 'charge_end': 121, 'unplug': 136, 'wh': 56596, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2547, 'idle': 40, 'total': 2687}), ({'plug_in': 145, 'charge_end': 298, 'unplug': 303, 'wh': 58365, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 300}, {'energy': 2627, 'idle': 0, 'total': 2777}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 186, 'charge_end': 330, 'unplug': 355, 'wh': 23566, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 500}, {'energy': 684, 'idle': 100, 'total': 934}), ({'plug_in': 195, 'charge_end': 466, 'unplug': 471, 'wh': 49517, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1436, 'idle': 0, 'total': 1536}), ({'plug_in': 33, 'charge_end': 60, 'unplug': 85, 'wh': 12076, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 544, 'idle': 100, 'total': 794})], [({'plug_in': 559, 'charge_end': 572, 'unplug': 772, 'wh': 45833, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2384, 'idle': 950, 'total': 3434}), ({'plug_in': 159, 'charge_end': 336, 'unplug': 352, 'wh': 25795, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 500}, {'energy': 903, 'idle': 100, 'total': 1103}), ({'plug_in': 194, 'charge_end': 435, 'unplug': 440, 'wh': 59915, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 500}, {'energy': 1738, 'idle': 0, 'total': 1738}), ({'plug_in': 528, 'charge_end': 654, 'unplug': 669, 'wh': 12153, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 353, 'idle': 0, 'total': 353}), ({'plug_in': 431, 'charge_end': 619, 'unplug': 624, 'wh': 55493, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 200}, {'energy': 2886, 'idle': 0, 'total': 3036}), ({'plug_in': 81, 'charge_end': 343, 'unplug': 543, 'wh': 5132, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 500}, {'energy': 149, 'idle': 1000, 'total': 1249}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588})], [({'plug_in': 304, 'charge_end': 396, 'unplug': 411, 'wh': 5781, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 168, 'idle': 0, 'total': 318}), ({'plug_in': 185, 'charge_end': 272, 'unplug': 277, 'wh': 54298, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 300}, {'energy': 1901, 'idle': 0, 'total': 1901}), ({'plug_in': 517, 'charge_end': 530, 'unplug': 545, 'wh': 32951, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 956, 'idle': 100, 'total': 1156}), ({'plug_in': 516, 'charge_end': 713, 'unplug': 713, 'wh': 4148, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 146, 'idle': 0, 'total': 200}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 368, 'charge_end': 458, 'unplug': 468, 'wh': 47000, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 200}, {'energy': 2115, 'idle': 0, 'total': 2115}), ({'plug_in': 372, 'charge_end': 436, 'unplug': 446, 'wh': 50026, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1451, 'idle': 0, 'total': 1551}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024})], [({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 225, 'charge_end': 273, 'unplug': 278, 'wh': 11802, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 300}, {'energy': 343, 'idle': 0, 'total': 443}), ({'plug_in': 205, 'charge_end': 441, 'unplug': 501, 'wh': 10080, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 454, 'idle': 250, 'total': 704}), ({'plug_in': 287, 'charge_end': 319, 'unplug': 329, 'wh': 40679, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1180, 'idle': 0, 'total': 1280}), ({'plug_in': 188, 'charge_end': 300, 'unplug': 700, 'wh': 27871, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 300}, {'energy': 976, 'idle': 1000, 'total': 1976}), ({'plug_in': 295, 'charge_end': 451, 'unplug': 466, 'wh': 26332, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 922, 'idle': 0, 'total': 1072}), ({'plug_in': 51, 'charge_end': 100, 'unplug': 110, 'wh': 10852, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 565, 'idle': 0, 'total': 665})], [({'plug_in': 581, 'charge_end': 789, 'unplug': 805, 'wh': 25000, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 875, 'idle': 50, 'total': 1025}), ({'plug_in': 375, 'charge_end': 498, 'unplug': 514, 'wh': 1169, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 34, 'idle': 50, 'total': 500}), ({'plug_in': 159, 'charge_end': 387, 'unplug': 412, 'wh': 39938, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 500}, {'energy': 1398, 'idle': 100, 'total': 1598}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 124, 'charge_end': 356, 'unplug': 372, 'wh': 55526, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2888, 'idle': 100, 'total': 3088}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 72, 'charge_end': 247, 'unplug': 263, 'wh': 14417, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 500}, {'energy': 505, 'idle': 50, 'total': 555}), ({'plug_in': 292, 'charge_end': 503, 'unplug': 503, 'wh': 48283, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1401, 'idle': 0, 'total': 1501})]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check('fee oracle' + ' %d' % i, 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 |
|---|---|---|---|
| fee oracle 0 | {'energy': 245, 'idle': 0, 'total': 500} | {'energy': 263, 'idle': 0, 'total': 500} | Failed |
| fee oracle 1 | {'energy': 0, 'idle': 1000, 'total': 1000} | {'energy': 24, 'idle': 1000, 'total': 1024} | Failed |
| fee oracle 2 | {'energy': 2520, 'idle': 40, 'total': 2660} | {'energy': 2547, 'idle': 40, 'total': 2687} | Failed |
| fee oracle 3 | {'energy': 2610, 'idle': 0, 'total': 2760} | {'energy': 2627, 'idle': 0, 'total': 2777} | Failed |
| fee oracle 4 | {'energy': 420, 'idle': 50, 'total': 570} | {'energy': 438, 'idle': 50, 'total': 588} | Failed |
| fee oracle 5 | {'energy': 667, 'idle': 100, 'total': 917} | {'energy': 684, 'idle': 100, 'total': 934} | Failed |
| fee oracle 6 | {'energy': 1421, 'idle': 0, 'total': 1521} | {'energy': 1436, 'idle': 0, 'total': 1536} | Failed |
| fee oracle 7 | {'energy': 540, 'idle': 100, 'total': 790} | {'energy': 544, 'idle': 100, 'total': 794} | Failed |
SHA-256 / 9e70ff02168055c9a02d4f19680f91acfce38bce3dac19e7618a727ebad7cd36
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
energy = round(x['wh'] / 1000) * x['price_per_kwh']
idle = max(0, x['unplug'] - x['charge_end'] - x['idle_grace'])
idle_fee = min(x['idle_cap'], -(-idle // 10) * x['idle_rate'])
total = x['session_fee'] + energy + idle_fee
return {'energy': energy, 'idle': idle_fee, 'total': max(x['min_fee'], total)}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'plug_in': 351, 'charge_end': 512, 'unplug': 522, 'wh': 7509, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 263, 'idle': 0, 'total': 500}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 21, 'charge_end': 121, 'unplug': 136, 'wh': 56596, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2547, 'idle': 40, 'total': 2687}), ({'plug_in': 145, 'charge_end': 298, 'unplug': 303, 'wh': 58365, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 300}, {'energy': 2627, 'idle': 0, 'total': 2777}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 186, 'charge_end': 330, 'unplug': 355, 'wh': 23566, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 500}, {'energy': 684, 'idle': 100, 'total': 934}), ({'plug_in': 195, 'charge_end': 466, 'unplug': 471, 'wh': 49517, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1436, 'idle': 0, 'total': 1536}), ({'plug_in': 33, 'charge_end': 60, 'unplug': 85, 'wh': 12076, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 544, 'idle': 100, 'total': 794})], [({'plug_in': 559, 'charge_end': 572, 'unplug': 772, 'wh': 45833, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2384, 'idle': 950, 'total': 3434}), ({'plug_in': 159, 'charge_end': 336, 'unplug': 352, 'wh': 25795, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 500}, {'energy': 903, 'idle': 100, 'total': 1103}), ({'plug_in': 194, 'charge_end': 435, 'unplug': 440, 'wh': 59915, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 500}, {'energy': 1738, 'idle': 0, 'total': 1738}), ({'plug_in': 528, 'charge_end': 654, 'unplug': 669, 'wh': 12153, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 353, 'idle': 0, 'total': 353}), ({'plug_in': 431, 'charge_end': 619, 'unplug': 624, 'wh': 55493, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 200}, {'energy': 2886, 'idle': 0, 'total': 3036}), ({'plug_in': 81, 'charge_end': 343, 'unplug': 543, 'wh': 5132, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 500}, {'energy': 149, 'idle': 1000, 'total': 1249}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588})], [({'plug_in': 304, 'charge_end': 396, 'unplug': 411, 'wh': 5781, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 168, 'idle': 0, 'total': 318}), ({'plug_in': 185, 'charge_end': 272, 'unplug': 277, 'wh': 54298, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 300}, {'energy': 1901, 'idle': 0, 'total': 1901}), ({'plug_in': 517, 'charge_end': 530, 'unplug': 545, 'wh': 32951, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 956, 'idle': 100, 'total': 1156}), ({'plug_in': 516, 'charge_end': 713, 'unplug': 713, 'wh': 4148, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 146, 'idle': 0, 'total': 200}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 368, 'charge_end': 458, 'unplug': 468, 'wh': 47000, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 200}, {'energy': 2115, 'idle': 0, 'total': 2115}), ({'plug_in': 372, 'charge_end': 436, 'unplug': 446, 'wh': 50026, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1451, 'idle': 0, 'total': 1551}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024})], [({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 225, 'charge_end': 273, 'unplug': 278, 'wh': 11802, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 300}, {'energy': 343, 'idle': 0, 'total': 443}), ({'plug_in': 205, 'charge_end': 441, 'unplug': 501, 'wh': 10080, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 454, 'idle': 250, 'total': 704}), ({'plug_in': 287, 'charge_end': 319, 'unplug': 329, 'wh': 40679, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1180, 'idle': 0, 'total': 1280}), ({'plug_in': 188, 'charge_end': 300, 'unplug': 700, 'wh': 27871, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 300}, {'energy': 976, 'idle': 1000, 'total': 1976}), ({'plug_in': 295, 'charge_end': 451, 'unplug': 466, 'wh': 26332, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 922, 'idle': 0, 'total': 1072}), ({'plug_in': 51, 'charge_end': 100, 'unplug': 110, 'wh': 10852, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 565, 'idle': 0, 'total': 665})], [({'plug_in': 581, 'charge_end': 789, 'unplug': 805, 'wh': 25000, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 875, 'idle': 50, 'total': 1025}), ({'plug_in': 375, 'charge_end': 498, 'unplug': 514, 'wh': 1169, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 34, 'idle': 50, 'total': 500}), ({'plug_in': 159, 'charge_end': 387, 'unplug': 412, 'wh': 39938, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 500}, {'energy': 1398, 'idle': 100, 'total': 1598}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 124, 'charge_end': 356, 'unplug': 372, 'wh': 55526, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2888, 'idle': 100, 'total': 3088}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 72, 'charge_end': 247, 'unplug': 263, 'wh': 14417, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 500}, {'energy': 505, 'idle': 50, 'total': 555}), ({'plug_in': 292, 'charge_end': 503, 'unplug': 503, 'wh': 48283, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1401, 'idle': 0, 'total': 1501})]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check('fee oracle' + ' %d' % i, 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 |
|---|---|---|---|
| fee oracle 0 | {'energy': 280, 'idle': 0, 'total': 500} | {'energy': 263, 'idle': 0, 'total': 500} | Failed |
| fee oracle 1 | {'energy': 29, 'idle': 1000, 'total': 1029} | {'energy': 24, 'idle': 1000, 'total': 1024} | Failed |
| fee oracle 2 | {'energy': 2565, 'idle': 40, 'total': 2705} | {'energy': 2547, 'idle': 40, 'total': 2687} | Failed |
| fee oracle 3 | {'energy': 2610, 'idle': 0, 'total': 2760} | {'energy': 2627, 'idle': 0, 'total': 2777} | Failed |
| fee oracle 4 | {'energy': 420, 'idle': 50, 'total': 570} | {'energy': 438, 'idle': 50, 'total': 588} | Failed |
| fee oracle 5 | {'energy': 696, 'idle': 100, 'total': 946} | {'energy': 684, 'idle': 100, 'total': 934} | Failed |
| fee oracle 6 | {'energy': 1450, 'idle': 0, 'total': 1550} | {'energy': 1436, 'idle': 0, 'total': 1536} | Failed |
| fee oracle 7 | {'energy': 540, 'idle': 100, 'total': 790} | {'energy': 544, 'idle': 100, 'total': 794} | Failed |
SHA-256 / f109211e271de29ae784cdcd24164bda87ace7e265c0b240f2af88c3ed9ed024
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
energy = -(-x['wh'] * x['price_per_kwh'] // 1000)
idle = max(0, x['unplug'] - x['charge_end'] - x['idle_grace'])
idle_fee = min(x['idle_cap'], -(-idle // 10) * x['idle_rate'])
total = x['session_fee'] + energy + idle_fee
return {'energy': energy, 'idle': idle_fee, 'total': max(x['min_fee'], total)}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'plug_in': 351, 'charge_end': 512, 'unplug': 522, 'wh': 7509, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 263, 'idle': 0, 'total': 500}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 21, 'charge_end': 121, 'unplug': 136, 'wh': 56596, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2547, 'idle': 40, 'total': 2687}), ({'plug_in': 145, 'charge_end': 298, 'unplug': 303, 'wh': 58365, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 300}, {'energy': 2627, 'idle': 0, 'total': 2777}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 186, 'charge_end': 330, 'unplug': 355, 'wh': 23566, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 500}, {'energy': 684, 'idle': 100, 'total': 934}), ({'plug_in': 195, 'charge_end': 466, 'unplug': 471, 'wh': 49517, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1436, 'idle': 0, 'total': 1536}), ({'plug_in': 33, 'charge_end': 60, 'unplug': 85, 'wh': 12076, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 544, 'idle': 100, 'total': 794})], [({'plug_in': 559, 'charge_end': 572, 'unplug': 772, 'wh': 45833, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2384, 'idle': 950, 'total': 3434}), ({'plug_in': 159, 'charge_end': 336, 'unplug': 352, 'wh': 25795, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 500}, {'energy': 903, 'idle': 100, 'total': 1103}), ({'plug_in': 194, 'charge_end': 435, 'unplug': 440, 'wh': 59915, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 500}, {'energy': 1738, 'idle': 0, 'total': 1738}), ({'plug_in': 528, 'charge_end': 654, 'unplug': 669, 'wh': 12153, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 353, 'idle': 0, 'total': 353}), ({'plug_in': 431, 'charge_end': 619, 'unplug': 624, 'wh': 55493, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 200}, {'energy': 2886, 'idle': 0, 'total': 3036}), ({'plug_in': 81, 'charge_end': 343, 'unplug': 543, 'wh': 5132, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 500}, {'energy': 149, 'idle': 1000, 'total': 1249}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588})], [({'plug_in': 304, 'charge_end': 396, 'unplug': 411, 'wh': 5781, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 168, 'idle': 0, 'total': 318}), ({'plug_in': 185, 'charge_end': 272, 'unplug': 277, 'wh': 54298, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 300}, {'energy': 1901, 'idle': 0, 'total': 1901}), ({'plug_in': 517, 'charge_end': 530, 'unplug': 545, 'wh': 32951, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 956, 'idle': 100, 'total': 1156}), ({'plug_in': 516, 'charge_end': 713, 'unplug': 713, 'wh': 4148, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 146, 'idle': 0, 'total': 200}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 368, 'charge_end': 458, 'unplug': 468, 'wh': 47000, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 200}, {'energy': 2115, 'idle': 0, 'total': 2115}), ({'plug_in': 372, 'charge_end': 436, 'unplug': 446, 'wh': 50026, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1451, 'idle': 0, 'total': 1551}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024})], [({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 225, 'charge_end': 273, 'unplug': 278, 'wh': 11802, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 300}, {'energy': 343, 'idle': 0, 'total': 443}), ({'plug_in': 205, 'charge_end': 441, 'unplug': 501, 'wh': 10080, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 454, 'idle': 250, 'total': 704}), ({'plug_in': 287, 'charge_end': 319, 'unplug': 329, 'wh': 40679, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1180, 'idle': 0, 'total': 1280}), ({'plug_in': 188, 'charge_end': 300, 'unplug': 700, 'wh': 27871, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 300}, {'energy': 976, 'idle': 1000, 'total': 1976}), ({'plug_in': 295, 'charge_end': 451, 'unplug': 466, 'wh': 26332, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 922, 'idle': 0, 'total': 1072}), ({'plug_in': 51, 'charge_end': 100, 'unplug': 110, 'wh': 10852, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 565, 'idle': 0, 'total': 665})], [({'plug_in': 581, 'charge_end': 789, 'unplug': 805, 'wh': 25000, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 875, 'idle': 50, 'total': 1025}), ({'plug_in': 375, 'charge_end': 498, 'unplug': 514, 'wh': 1169, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 34, 'idle': 50, 'total': 500}), ({'plug_in': 159, 'charge_end': 387, 'unplug': 412, 'wh': 39938, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 500}, {'energy': 1398, 'idle': 100, 'total': 1598}), ({'plug_in': 30, 'charge_end': 45, 'unplug': 400, 'wh': 800, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 500}, {'energy': 24, 'idle': 1000, 'total': 1024}), ({'plug_in': 124, 'charge_end': 356, 'unplug': 372, 'wh': 55526, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2888, 'idle': 100, 'total': 3088}), ({'plug_in': 0, 'charge_end': 90, 'unplug': 106, 'wh': 12500, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 300}, {'energy': 438, 'idle': 50, 'total': 588}), ({'plug_in': 72, 'charge_end': 247, 'unplug': 263, 'wh': 14417, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 500}, {'energy': 505, 'idle': 50, 'total': 555}), ({'plug_in': 292, 'charge_end': 503, 'unplug': 503, 'wh': 48283, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1401, 'idle': 0, 'total': 1501})]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check('fee oracle' + ' %d' % i, 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 |
|---|---|---|---|
| fee oracle 0 | {'energy': 263, 'idle': 0, 'total': 500} | {'energy': 263, 'idle': 0, 'total': 500} | Passed |
| fee oracle 1 | {'energy': 24, 'idle': 1000, 'total': 1024} | {'energy': 24, 'idle': 1000, 'total': 1024} | Passed |
| fee oracle 2 | {'energy': 2547, 'idle': 40, 'total': 2687} | {'energy': 2547, 'idle': 40, 'total': 2687} | Passed |
| fee oracle 3 | {'energy': 2627, 'idle': 0, 'total': 2777} | {'energy': 2627, 'idle': 0, 'total': 2777} | Passed |
| fee oracle 4 | {'energy': 438, 'idle': 50, 'total': 588} | {'energy': 438, 'idle': 50, 'total': 588} | Passed |
| fee oracle 5 | {'energy': 684, 'idle': 100, 'total': 934} | {'energy': 684, 'idle': 100, 'total': 934} | Passed |
| fee oracle 6 | {'energy': 1436, 'idle': 0, 'total': 1536} | {'energy': 1436, 'idle': 0, 'total': 1536} | Passed |
| fee oracle 7 | {'energy': 544, 'idle': 100, 'total': 794} | {'energy': 544, 'idle': 100, 'total': 794} | Passed |
SHA-256 / 57851bbe23795e2e3dd3de5a6b404d0d0ccffc219802cd18a38a06a87bc84142
Verification & scope
A deterministic, bounded toy model with a stipulated contract; it makes no claim of conformance to any agency manual or standard. 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:48:04.526272+00:00.
Case digest / daf6c9fa61aa8cbd281cdfba705a9732c526703a1c88641967533039b588a3ba