FAILURE MAP
← Case archive

FA-68706 / Toll and parking fee computation / Open access

EV charging session and idle fee: the idle cap limits block count instead of cents · case 01

EV charging session and idle fee returns a wrong result when the idle cap limits block count instead of cents.

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

ROOT CAUSE

Idle fees grow without the posted cap.

VERIFIED REPAIR

Restore the idle cap rule so that the step reads `min(x['idle_cap'], -(-idle // 10) * x['idle_rate'])`.

Unsuccessful approach: Comparing a block count with a cents cap caps at the wrong magnitude.

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'] * x['price_per_kwh'] // 1000)
    idle = max(0, x['unplug'] - x['charge_end'] - x['idle_grace'])
    idle_fee = -(-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': 131, 'charge_end': 273, 'unplug': 283, 'wh': 37842, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1325, 'idle': 0, 'total': 1475}), ({'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': 241, 'charge_end': 257, 'unplug': 457, 'wh': 25918, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 752, 'idle': 1000, 'total': 1902}), ({'plug_in': 407, 'charge_end': 459, 'unplug': 659, 'wh': 2348, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 83, 'idle': 1000, 'total': 1233}), ({'plug_in': 406, 'charge_end': 466, 'unplug': 476, 'wh': 46986, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1645, 'idle': 0, 'total': 1745}), ({'plug_in': 577, 'charge_end': 673, 'unplug': 698, 'wh': 33233, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1729, 'idle': 50, 'total': 1929}), ({'plug_in': 357, 'charge_end': 490, 'unplug': 490, 'wh': 37874, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1326, 'idle': 0, 'total': 1426}), ({'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': 567, 'charge_end': 630, 'unplug': 1030, 'wh': 36618, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1905, 'idle': 3000, 'total': 5055}), ({'plug_in': 240, 'charge_end': 417, 'unplug': 442, 'wh': 22897, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 1191, 'idle': 100, 'total': 1291}), ({'plug_in': 412, 'charge_end': 513, 'unplug': 913, 'wh': 37562, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 1954, 'idle': 1000, 'total': 3104}), ({'plug_in': 577, 'charge_end': 875, 'unplug': 890, 'wh': 36979, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1295, 'idle': 0, 'total': 1395}), ({'plug_in': 507, 'charge_end': 619, 'unplug': 624, 'wh': 58769, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2645, 'idle': 0, 'total': 2745}), ({'plug_in': 219, 'charge_end': 302, 'unplug': 502, 'wh': 7040, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 200}, {'energy': 247, 'idle': 1900, 'total': 2147}), ({'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': 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': 431, 'charge_end': 515, 'unplug': 520, 'wh': 37388, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1309, 'idle': 0, 'total': 1409}), ({'plug_in': 355, 'charge_end': 644, 'unplug': 659, 'wh': 31439, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 500}, {'energy': 912, 'idle': 0, 'total': 1062}), ({'plug_in': 361, 'charge_end': 432, 'unplug': 832, 'wh': 39144, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 2036, 'idle': 1000, 'total': 3186}), ({'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': 281, 'charge_end': 329, 'unplug': 529, 'wh': 43856, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1535, 'idle': 950, 'total': 2585}), ({'plug_in': 14, 'charge_end': 237, 'unplug': 637, 'wh': 4090, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 119, 'idle': 1000, 'total': 1269}), ({'plug_in': 525, 'charge_end': 752, 'unplug': 767, 'wh': 24814, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 300}, {'energy': 720, 'idle': 100, 'total': 970})], [({'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': 489, 'charge_end': 568, 'unplug': 768, 'wh': 1647, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 48, 'idle': 1000, 'total': 1198}), ({'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': 231, 'charge_end': 437, 'unplug': 442, 'wh': 31724, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1111, 'idle': 0, 'total': 1211}), ({'plug_in': 506, 'charge_end': 796, 'unplug': 801, 'wh': 18131, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 300}, {'energy': 943, 'idle': 0, 'total': 943}), ({'plug_in': 412, 'charge_end': 659, 'unplug': 1059, 'wh': 41636, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 1458, 'idle': 1950, 'total': 3408}), ({'plug_in': 472, 'charge_end': 580, 'unplug': 980, 'wh': 58243, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 1690, 'idle': 1000, 'total': 2840}), ({'plug_in': 234, 'charge_end': 284, 'unplug': 309, 'wh': 13379, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 300}, {'energy': 603, 'idle': 50, 'total': 653})], [({'plug_in': 458, 'charge_end': 619, 'unplug': 1019, 'wh': 42887, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 500}, {'energy': 1502, 'idle': 3000, 'total': 4502}), ({'plug_in': 422, 'charge_end': 479, 'unplug': 679, 'wh': 52516, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 300}, {'energy': 1523, 'idle': 760, 'total': 2433}), ({'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': 447, 'charge_end': 641, 'unplug': 1041, 'wh': 10840, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 488, 'idle': 1000, 'total': 1638}), ({'plug_in': 230, 'charge_end': 296, 'unplug': 296, 'wh': 48898, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 200}, {'energy': 2201, 'idle': 0, 'total': 2351}), ({'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': 579, 'charge_end': 718, 'unplug': 723, 'wh': 50758, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2285, 'idle': 0, 'total': 2385}), ({'plug_in': 89, 'charge_end': 303, 'unplug': 703, 'wh': 15398, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 300}, {'energy': 693, 'idle': 1950, 'total': 2643})]]
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': 1325, 'idle': 0, 'total': 1475}{'energy': 1325, 'idle': 0, 'total': 1475}Passed
fee oracle 1{'energy': 438, 'idle': 50, 'total': 588}{'energy': 438, 'idle': 50, 'total': 588}Passed
fee oracle 2{'energy': 752, 'idle': 1900, 'total': 2802}{'energy': 752, 'idle': 1000, 'total': 1902}Failed
fee oracle 3{'energy': 83, 'idle': 1900, 'total': 2133}{'energy': 83, 'idle': 1000, 'total': 1233}Failed
fee oracle 4{'energy': 1645, 'idle': 0, 'total': 1745}{'energy': 1645, 'idle': 0, 'total': 1745}Passed
fee oracle 5{'energy': 1729, 'idle': 50, 'total': 1929}{'energy': 1729, 'idle': 50, 'total': 1929}Passed
fee oracle 6{'energy': 1326, 'idle': 0, 'total': 1426}{'energy': 1326, 'idle': 0, 'total': 1426}Passed
fee oracle 7{'energy': 24, 'idle': 3500, 'total': 3524}{'energy': 24, 'idle': 1000, 'total': 1024}Failed

SHA-256 / 14cf178d3a25aecd8ac2af59e6103f35e5dc9ebbff746003357736a3b81b73dc

2 / The unsuccessful fix

Exit 1
"""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': 131, 'charge_end': 273, 'unplug': 283, 'wh': 37842, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1325, 'idle': 0, 'total': 1475}), ({'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': 241, 'charge_end': 257, 'unplug': 457, 'wh': 25918, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 752, 'idle': 1000, 'total': 1902}), ({'plug_in': 407, 'charge_end': 459, 'unplug': 659, 'wh': 2348, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 83, 'idle': 1000, 'total': 1233}), ({'plug_in': 406, 'charge_end': 466, 'unplug': 476, 'wh': 46986, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1645, 'idle': 0, 'total': 1745}), ({'plug_in': 577, 'charge_end': 673, 'unplug': 698, 'wh': 33233, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1729, 'idle': 50, 'total': 1929}), ({'plug_in': 357, 'charge_end': 490, 'unplug': 490, 'wh': 37874, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1326, 'idle': 0, 'total': 1426}), ({'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': 567, 'charge_end': 630, 'unplug': 1030, 'wh': 36618, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1905, 'idle': 3000, 'total': 5055}), ({'plug_in': 240, 'charge_end': 417, 'unplug': 442, 'wh': 22897, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 1191, 'idle': 100, 'total': 1291}), ({'plug_in': 412, 'charge_end': 513, 'unplug': 913, 'wh': 37562, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 1954, 'idle': 1000, 'total': 3104}), ({'plug_in': 577, 'charge_end': 875, 'unplug': 890, 'wh': 36979, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1295, 'idle': 0, 'total': 1395}), ({'plug_in': 507, 'charge_end': 619, 'unplug': 624, 'wh': 58769, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2645, 'idle': 0, 'total': 2745}), ({'plug_in': 219, 'charge_end': 302, 'unplug': 502, 'wh': 7040, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 200}, {'energy': 247, 'idle': 1900, 'total': 2147}), ({'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': 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': 431, 'charge_end': 515, 'unplug': 520, 'wh': 37388, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1309, 'idle': 0, 'total': 1409}), ({'plug_in': 355, 'charge_end': 644, 'unplug': 659, 'wh': 31439, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 500}, {'energy': 912, 'idle': 0, 'total': 1062}), ({'plug_in': 361, 'charge_end': 432, 'unplug': 832, 'wh': 39144, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 2036, 'idle': 1000, 'total': 3186}), ({'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': 281, 'charge_end': 329, 'unplug': 529, 'wh': 43856, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1535, 'idle': 950, 'total': 2585}), ({'plug_in': 14, 'charge_end': 237, 'unplug': 637, 'wh': 4090, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 119, 'idle': 1000, 'total': 1269}), ({'plug_in': 525, 'charge_end': 752, 'unplug': 767, 'wh': 24814, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 300}, {'energy': 720, 'idle': 100, 'total': 970})], [({'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': 489, 'charge_end': 568, 'unplug': 768, 'wh': 1647, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 48, 'idle': 1000, 'total': 1198}), ({'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': 231, 'charge_end': 437, 'unplug': 442, 'wh': 31724, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1111, 'idle': 0, 'total': 1211}), ({'plug_in': 506, 'charge_end': 796, 'unplug': 801, 'wh': 18131, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 300}, {'energy': 943, 'idle': 0, 'total': 943}), ({'plug_in': 412, 'charge_end': 659, 'unplug': 1059, 'wh': 41636, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 1458, 'idle': 1950, 'total': 3408}), ({'plug_in': 472, 'charge_end': 580, 'unplug': 980, 'wh': 58243, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 1690, 'idle': 1000, 'total': 2840}), ({'plug_in': 234, 'charge_end': 284, 'unplug': 309, 'wh': 13379, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 300}, {'energy': 603, 'idle': 50, 'total': 653})], [({'plug_in': 458, 'charge_end': 619, 'unplug': 1019, 'wh': 42887, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 500}, {'energy': 1502, 'idle': 3000, 'total': 4502}), ({'plug_in': 422, 'charge_end': 479, 'unplug': 679, 'wh': 52516, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 300}, {'energy': 1523, 'idle': 760, 'total': 2433}), ({'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': 447, 'charge_end': 641, 'unplug': 1041, 'wh': 10840, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 488, 'idle': 1000, 'total': 1638}), ({'plug_in': 230, 'charge_end': 296, 'unplug': 296, 'wh': 48898, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 200}, {'energy': 2201, 'idle': 0, 'total': 2351}), ({'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': 579, 'charge_end': 718, 'unplug': 723, 'wh': 50758, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2285, 'idle': 0, 'total': 2385}), ({'plug_in': 89, 'charge_end': 303, 'unplug': 703, 'wh': 15398, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 300}, {'energy': 693, 'idle': 1950, 'total': 2643})]]
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': 1325, 'idle': 0, 'total': 1475}{'energy': 1325, 'idle': 0, 'total': 1475}Passed
fee oracle 1{'energy': 438, 'idle': 50, 'total': 588}{'energy': 438, 'idle': 50, 'total': 588}Passed
fee oracle 2{'energy': 752, 'idle': 1900, 'total': 2802}{'energy': 752, 'idle': 1000, 'total': 1902}Failed
fee oracle 3{'energy': 83, 'idle': 1900, 'total': 2133}{'energy': 83, 'idle': 1000, 'total': 1233}Failed
fee oracle 4{'energy': 1645, 'idle': 0, 'total': 1745}{'energy': 1645, 'idle': 0, 'total': 1745}Passed
fee oracle 5{'energy': 1729, 'idle': 50, 'total': 1929}{'energy': 1729, 'idle': 50, 'total': 1929}Passed
fee oracle 6{'energy': 1326, 'idle': 0, 'total': 1426}{'energy': 1326, 'idle': 0, 'total': 1426}Passed
fee oracle 7{'energy': 24, 'idle': 3500, 'total': 3524}{'energy': 24, 'idle': 1000, 'total': 1024}Failed

SHA-256 / 88493d22e6940f32f1b9c7c145bceb8a99123801ad5596d9fe47c784807ecc89

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': 131, 'charge_end': 273, 'unplug': 283, 'wh': 37842, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1325, 'idle': 0, 'total': 1475}), ({'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': 241, 'charge_end': 257, 'unplug': 457, 'wh': 25918, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 752, 'idle': 1000, 'total': 1902}), ({'plug_in': 407, 'charge_end': 459, 'unplug': 659, 'wh': 2348, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 83, 'idle': 1000, 'total': 1233}), ({'plug_in': 406, 'charge_end': 466, 'unplug': 476, 'wh': 46986, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1645, 'idle': 0, 'total': 1745}), ({'plug_in': 577, 'charge_end': 673, 'unplug': 698, 'wh': 33233, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1729, 'idle': 50, 'total': 1929}), ({'plug_in': 357, 'charge_end': 490, 'unplug': 490, 'wh': 37874, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1326, 'idle': 0, 'total': 1426}), ({'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': 567, 'charge_end': 630, 'unplug': 1030, 'wh': 36618, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 150, 'min_fee': 500}, {'energy': 1905, 'idle': 3000, 'total': 5055}), ({'plug_in': 240, 'charge_end': 417, 'unplug': 442, 'wh': 22897, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 1191, 'idle': 100, 'total': 1291}), ({'plug_in': 412, 'charge_end': 513, 'unplug': 913, 'wh': 37562, 'price_per_kwh': 52, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 300}, {'energy': 1954, 'idle': 1000, 'total': 3104}), ({'plug_in': 577, 'charge_end': 875, 'unplug': 890, 'wh': 36979, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1295, 'idle': 0, 'total': 1395}), ({'plug_in': 507, 'charge_end': 619, 'unplug': 624, 'wh': 58769, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2645, 'idle': 0, 'total': 2745}), ({'plug_in': 219, 'charge_end': 302, 'unplug': 502, 'wh': 7040, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 0, 'min_fee': 200}, {'energy': 247, 'idle': 1900, 'total': 2147}), ({'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': 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': 431, 'charge_end': 515, 'unplug': 520, 'wh': 37388, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1309, 'idle': 0, 'total': 1409}), ({'plug_in': 355, 'charge_end': 644, 'unplug': 659, 'wh': 31439, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 500}, {'energy': 912, 'idle': 0, 'total': 1062}), ({'plug_in': 361, 'charge_end': 432, 'unplug': 832, 'wh': 39144, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 500}, {'energy': 2036, 'idle': 1000, 'total': 3186}), ({'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': 281, 'charge_end': 329, 'unplug': 529, 'wh': 43856, 'price_per_kwh': 35, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 100, 'min_fee': 200}, {'energy': 1535, 'idle': 950, 'total': 2585}), ({'plug_in': 14, 'charge_end': 237, 'unplug': 637, 'wh': 4090, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 119, 'idle': 1000, 'total': 1269}), ({'plug_in': 525, 'charge_end': 752, 'unplug': 767, 'wh': 24814, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 300}, {'energy': 720, 'idle': 100, 'total': 970})], [({'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': 489, 'charge_end': 568, 'unplug': 768, 'wh': 1647, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 48, 'idle': 1000, 'total': 1198}), ({'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': 231, 'charge_end': 437, 'unplug': 442, 'wh': 31724, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 1000, 'session_fee': 100, 'min_fee': 300}, {'energy': 1111, 'idle': 0, 'total': 1211}), ({'plug_in': 506, 'charge_end': 796, 'unplug': 801, 'wh': 18131, 'price_per_kwh': 52, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 0, 'min_fee': 300}, {'energy': 943, 'idle': 0, 'total': 943}), ({'plug_in': 412, 'charge_end': 659, 'unplug': 1059, 'wh': 41636, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 200}, {'energy': 1458, 'idle': 1950, 'total': 3408}), ({'plug_in': 472, 'charge_end': 580, 'unplug': 980, 'wh': 58243, 'price_per_kwh': 29, 'idle_grace': 15, 'idle_rate': 40, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 1690, 'idle': 1000, 'total': 2840}), ({'plug_in': 234, 'charge_end': 284, 'unplug': 309, 'wh': 13379, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 300}, {'energy': 603, 'idle': 50, 'total': 653})], [({'plug_in': 458, 'charge_end': 619, 'unplug': 1019, 'wh': 42887, 'price_per_kwh': 35, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 500}, {'energy': 1502, 'idle': 3000, 'total': 4502}), ({'plug_in': 422, 'charge_end': 479, 'unplug': 679, 'wh': 52516, 'price_per_kwh': 29, 'idle_grace': 10, 'idle_rate': 40, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 300}, {'energy': 1523, 'idle': 760, 'total': 2433}), ({'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': 447, 'charge_end': 641, 'unplug': 1041, 'wh': 10840, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 50, 'idle_cap': 1000, 'session_fee': 150, 'min_fee': 200}, {'energy': 488, 'idle': 1000, 'total': 1638}), ({'plug_in': 230, 'charge_end': 296, 'unplug': 296, 'wh': 48898, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 2000, 'session_fee': 150, 'min_fee': 200}, {'energy': 2201, 'idle': 0, 'total': 2351}), ({'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': 579, 'charge_end': 718, 'unplug': 723, 'wh': 50758, 'price_per_kwh': 45, 'idle_grace': 10, 'idle_rate': 100, 'idle_cap': 2000, 'session_fee': 100, 'min_fee': 200}, {'energy': 2285, 'idle': 0, 'total': 2385}), ({'plug_in': 89, 'charge_end': 303, 'unplug': 703, 'wh': 15398, 'price_per_kwh': 45, 'idle_grace': 15, 'idle_rate': 50, 'idle_cap': 3000, 'session_fee': 0, 'min_fee': 300}, {'energy': 693, 'idle': 1950, 'total': 2643})]]
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': 1325, 'idle': 0, 'total': 1475}{'energy': 1325, 'idle': 0, 'total': 1475}Passed
fee oracle 1{'energy': 438, 'idle': 50, 'total': 588}{'energy': 438, 'idle': 50, 'total': 588}Passed
fee oracle 2{'energy': 752, 'idle': 1000, 'total': 1902}{'energy': 752, 'idle': 1000, 'total': 1902}Passed
fee oracle 3{'energy': 83, 'idle': 1000, 'total': 1233}{'energy': 83, 'idle': 1000, 'total': 1233}Passed
fee oracle 4{'energy': 1645, 'idle': 0, 'total': 1745}{'energy': 1645, 'idle': 0, 'total': 1745}Passed
fee oracle 5{'energy': 1729, 'idle': 50, 'total': 1929}{'energy': 1729, 'idle': 50, 'total': 1929}Passed
fee oracle 6{'energy': 1326, 'idle': 0, 'total': 1426}{'energy': 1326, 'idle': 0, 'total': 1426}Passed
fee oracle 7{'energy': 24, 'idle': 1000, 'total': 1024}{'energy': 24, 'idle': 1000, 'total': 1024}Passed

SHA-256 / 5eddcbd815c5413169af6b28bf0d48094ae66a7f2e088e9b02b1f94ffe5f3f39

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.789370+00:00.

Case digest / af74a21aa2498d5b284c7a22e3f2aa05afc24a412b33130816fa33041a85cc95