FA-68366 / Toll and parking fee computation / Open access
Garage hourly fee with grace and daily maximum: zero-length stays are rejected as invalid · case 01
Garage hourly fee with grace and daily maximum returns a wrong result when zero-length stays are rejected as invalid.
ROOT CAUSE
An exit in the same minute as entry is reported invalid instead of free.
VERIFIED REPAIR
Restore the invalid timestamp check rule so that the step reads `if x['exit'] < x['entry']:`.
Unsuccessful approach: Allowing exits up to grace minutes before entry bills clock-skewed tickets as free 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'] + 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': 631, 'exit': 638, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 2581, 'exit': 2580, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, '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': 1676, 'exit': 1676, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 2473, 'exit': 2473, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 360, 'exit': 346, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid')], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, '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': 1465, 'exit': 1462, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 406, 'exit': 561, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 900), ({'entry': 87, 'exit': 85, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1952, 'exit': 1952, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 89, 'exit': 365, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500)], [({'entry': 717, 'exit': 699, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 2276, 'exit': 2276, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'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': 5, 'exit': 5, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 0), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1064, 'exit': 1058, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid')], [({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2683, 'exit': 5878, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 169, 'exit': 161, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 2896, 'exit': 7216, 'grace': 10, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4500), ({'entry': 2250, 'exit': 2230, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1281, 'exit': 1281, 'grace': 20, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, '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': 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': 1799, 'exit': 1789, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1549, 'exit': 4829, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4500), ({'entry': 1393, 'exit': 1446, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 426, 'exit': 438, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 2821, 'exit': 2816, 'grace': 10, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 'invalid'), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
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 | 3000 | 3000 | Passed |
| fee oracle 1 | invalid | invalid | Passed |
| fee oracle 2 | 0 | 0 | Passed |
| fee oracle 3 | 2600 | 2600 | Passed |
| fee oracle 4 | invalid | 2500 | Failed |
| fee oracle 5 | invalid | 2500 | Failed |
| fee oracle 6 | invalid | 0 | Failed |
| fee oracle 7 | invalid | invalid | Passed |
SHA-256 / 8efe271f74099aa2b757d46f8b2f332b16ac8dcff8ba290197d3db99a52ca066
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'] - x['grace']:
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': 631, 'exit': 638, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 2581, 'exit': 2580, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, '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': 1676, 'exit': 1676, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 2473, 'exit': 2473, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 360, 'exit': 346, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid')], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, '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': 1465, 'exit': 1462, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 406, 'exit': 561, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 900), ({'entry': 87, 'exit': 85, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1952, 'exit': 1952, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 89, 'exit': 365, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500)], [({'entry': 717, 'exit': 699, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 2276, 'exit': 2276, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'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': 5, 'exit': 5, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 0), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1064, 'exit': 1058, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid')], [({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2683, 'exit': 5878, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 169, 'exit': 161, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 2896, 'exit': 7216, 'grace': 10, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4500), ({'entry': 2250, 'exit': 2230, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1281, 'exit': 1281, 'grace': 20, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, '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': 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': 1799, 'exit': 1789, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1549, 'exit': 4829, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4500), ({'entry': 1393, 'exit': 1446, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 426, 'exit': 438, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 2821, 'exit': 2816, 'grace': 10, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 'invalid'), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
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 | 3000 | 3000 | Passed |
| fee oracle 1 | 0 | invalid | Failed |
| fee oracle 2 | 0 | 0 | Passed |
| fee oracle 3 | 2600 | 2600 | Passed |
| fee oracle 4 | 2500 | 2500 | Passed |
| fee oracle 5 | 2500 | 2500 | Passed |
| fee oracle 6 | 0 | 0 | Passed |
| fee oracle 7 | 0 | invalid | Failed |
SHA-256 / 31b9840a782af8b0449921214273488f67bd18f8556d818ab6ff06829546f3c1
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': 631, 'exit': 638, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 2581, 'exit': 2580, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, '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': 1676, 'exit': 1676, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 2473, 'exit': 2473, 'grace': 15, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 360, 'exit': 346, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid')], [({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, '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': 1465, 'exit': 1462, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 406, 'exit': 561, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 900), ({'entry': 87, 'exit': 85, 'grace': 20, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1952, 'exit': 1952, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 89, 'exit': 365, 'grace': 10, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500)], [({'entry': 717, 'exit': 699, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 2276, 'exit': 2276, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 0), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600), ({'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': 5, 'exit': 5, 'grace': 0, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 0), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 1064, 'exit': 1058, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid')], [({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 2683, 'exit': 5878, 'grace': 15, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 169, 'exit': 161, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 'invalid'), ({'entry': 2896, 'exit': 7216, 'grace': 10, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4500), ({'entry': 2250, 'exit': 2230, 'grace': 20, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1281, 'exit': 1281, 'grace': 20, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 3000}, 3000), ({'entry': 500, 'exit': 500, 'grace': 0, 'hourly': 300, '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': 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': 1799, 'exit': 1789, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 'invalid'), ({'entry': 1549, 'exit': 4829, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4500), ({'entry': 1393, 'exit': 1446, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 426, 'exit': 438, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 2821, 'exit': 2816, 'grace': 10, 'hourly': 200, 'daily_max': 2400, 'lost_ticket': True, 'lost_fee': 2500}, 'invalid'), ({'entry': 0, 'exit': 1560, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2600)]]
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 | 3000 | 3000 | Passed |
| fee oracle 1 | invalid | invalid | Passed |
| fee oracle 2 | 0 | 0 | Passed |
| fee oracle 3 | 2600 | 2600 | Passed |
| fee oracle 4 | 2500 | 2500 | Passed |
| fee oracle 5 | 2500 | 2500 | Passed |
| fee oracle 6 | 0 | 0 | Passed |
| fee oracle 7 | invalid | invalid | Passed |
SHA-256 / 876246072a8beda9f3db0655e20f50cae10efe2d40488947e4c2c572d554c294
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.553828+00:00.
Case digest / 2c512b78af6437eb4cec5e26dcf863d5894b023a987095c2dc6e2fba7aa1b23d