FA-68351 / Toll and parking fee computation / Open access
Garage hourly fee with grace and daily maximum: the remainder of a multi-day stay is not capped · case 01
Garage hourly fee with grace and daily maximum returns a wrong result when the remainder of a multi-day stay is not capped.
ROOT CAUSE
The partial day after full days is billed hourly without the daily maximum.
VERIFIED REPAIR
Restore the partial day cap rule so that the step reads `min(x['daily_max'], -(-rem // 60) * x['hourly'])`.
Unsuccessful approach: Capping the whole stay hours once double counts the full days for multi-day stays.
Case contract
Input {entry, exit (absolute minutes), grace, hourly, daily_max, lost_ticket, lost_fee}; cents. Exit before entry is 'invalid'. A stay no longer than grace is free (grace is not deducted from longer stays). Otherwise each full 1440-minute block costs daily_max and the remainder costs hourly per started hour, capped at daily_max. A lost ticket pays the greater of the computed fee and lost_fee.
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):
if x['exit'] < x['entry']:
return 'invalid'
dur = x['exit'] - x['entry']
if dur <= x['grace']:
fee = 0
else:
days, rem = divmod(dur, 1440)
fee = days * x['daily_max'] + -(-rem // 60) * x['hourly']
if x['lost_ticket']:
fee = max(fee, x['lost_fee'])
return fee
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1945, 'exit': 6562, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 5500), ({'entry': 567, 'exit': 963, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1362, 'exit': 5675, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 731, 'exit': 2171, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1335, 'exit': 1738, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000)], [({'entry': 132, 'exit': 552, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 465, 'exit': 1605, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 53, 'exit': 593, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1903, 'exit': 4783, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 2049, 'exit': 2559, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2226, 'exit': 4482, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 918, 'exit': 3798, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1152, 'exit': 1160, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2128, 'exit': 3328, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 1705, 'exit': 3954, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800)], [({'entry': 2136, 'exit': 3576, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 359, 'exit': 377, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 358, 'exit': 898, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1365, 'exit': 3758, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 411, 'exit': 4074, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350)], [({'entry': 2534, 'exit': 2857, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 163, 'exit': 3043, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 2508, 'exit': 6945, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7800), ({'entry': 950, 'exit': 1518, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2204, 'exit': 4608, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)]]
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 | 5500 | 5500 | Passed |
| fee oracle 1 | 3150 | 2400 | Failed |
| fee oracle 2 | 1350 | 1350 | Passed |
| fee oracle 3 | 11200 | 6000 | Failed |
| fee oracle 4 | 2500 | 2500 | Passed |
| fee oracle 5 | 0 | 0 | Passed |
| fee oracle 6 | 2500 | 2500 | Passed |
| fee oracle 7 | 2100 | 2000 | Failed |
SHA-256 / c4539eefd002df26d8a66e5c78890d1df35d8b9052185bb0eb71a95d93f63c13
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if x['exit'] < x['entry']:
return 'invalid'
dur = x['exit'] - x['entry']
if dur <= x['grace']:
fee = 0
else:
days, rem = divmod(dur, 1440)
fee = days * x['daily_max'] + min(x['daily_max'], -(-dur // 60) * x['hourly'])
if x['lost_ticket']:
fee = max(fee, x['lost_fee'])
return fee
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1945, 'exit': 6562, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 5500), ({'entry': 567, 'exit': 963, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1362, 'exit': 5675, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 731, 'exit': 2171, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1335, 'exit': 1738, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000)], [({'entry': 132, 'exit': 552, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 465, 'exit': 1605, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 53, 'exit': 593, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1903, 'exit': 4783, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 2049, 'exit': 2559, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2226, 'exit': 4482, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 918, 'exit': 3798, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1152, 'exit': 1160, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2128, 'exit': 3328, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 1705, 'exit': 3954, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800)], [({'entry': 2136, 'exit': 3576, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 359, 'exit': 377, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 358, 'exit': 898, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1365, 'exit': 3758, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 411, 'exit': 4074, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350)], [({'entry': 2534, 'exit': 2857, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 163, 'exit': 3043, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 2508, 'exit': 6945, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7800), ({'entry': 950, 'exit': 1518, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2204, 'exit': 4608, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)]]
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 | 6000 | 5500 | Failed |
| fee oracle 1 | 2400 | 2400 | Passed |
| fee oracle 2 | 1350 | 1350 | Passed |
| fee oracle 3 | 6000 | 6000 | Passed |
| fee oracle 4 | 4000 | 2500 | Failed |
| fee oracle 5 | 0 | 0 | Passed |
| fee oracle 6 | 2500 | 2500 | Passed |
| fee oracle 7 | 2000 | 2000 | Passed |
SHA-256 / 1f8f995171a5f9328d8a81014581a4440f36039342febbbbddafc2863f1ea6eb
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if x['exit'] < x['entry']:
return 'invalid'
dur = x['exit'] - x['entry']
if dur <= x['grace']:
fee = 0
else:
days, rem = divmod(dur, 1440)
fee = days * x['daily_max'] + min(x['daily_max'], -(-rem // 60) * x['hourly'])
if x['lost_ticket']:
fee = max(fee, x['lost_fee'])
return fee
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'entry': 1945, 'exit': 6562, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 5500), ({'entry': 567, 'exit': 963, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 1362, 'exit': 5675, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 731, 'exit': 2171, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1335, 'exit': 1738, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000)], [({'entry': 132, 'exit': 552, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 465, 'exit': 1605, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 53, 'exit': 593, 'grace': 10, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 1903, 'exit': 4783, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 4000), ({'entry': 2049, 'exit': 2559, 'grace': 15, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 2400), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500)], [({'entry': 2226, 'exit': 4482, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 918, 'exit': 3798, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 4800), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1152, 'exit': 1160, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 2128, 'exit': 3328, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2400), ({'entry': 1705, 'exit': 3954, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800)], [({'entry': 2136, 'exit': 3576, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 2000), ({'entry': 359, 'exit': 377, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'entry': 358, 'exit': 898, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1365, 'exit': 3758, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 411, 'exit': 4074, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350)], [({'entry': 2534, 'exit': 2857, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 163, 'exit': 3043, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 4800), ({'entry': 2508, 'exit': 6945, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 7800), ({'entry': 950, 'exit': 1518, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2204, 'exit': 4608, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 4000), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0)]]
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 | 5500 | 5500 | Passed |
| fee oracle 1 | 2400 | 2400 | Passed |
| fee oracle 2 | 1350 | 1350 | Passed |
| fee oracle 3 | 6000 | 6000 | Passed |
| fee oracle 4 | 2500 | 2500 | Passed |
| fee oracle 5 | 0 | 0 | Passed |
| fee oracle 6 | 2500 | 2500 | Passed |
| fee oracle 7 | 2000 | 2000 | Passed |
SHA-256 / 289205c7e1ec8786d4b2bf96218057d237f504972415b2e9ea86a778b9279d78
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:01.487448+00:00.
Case digest / 8af27812578d7c37a1d9e32b798de54db8921d69ee1e643e9b21636b0cbdf08e