FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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