FA-68346 / Toll and parking fee computation / Open access
Garage hourly fee with grace and daily maximum: partial hours are not charged · case 01
Garage hourly fee with grace and daily maximum returns a wrong result when partial hours are not charged.
ROOT CAUSE
Floor division bills only completed hours, so a 61 minute stay pays for one hour.
VERIFIED REPAIR
Restore the started hour rounding rule so that the step reads `-(-rem // 60) * x['hourly']`.
Unsuccessful approach: Adding one hour to the floor charges an extra hour for stays of exactly whole hours.
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': 2558, 'exit': 3256, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 2210, 'exit': 2538, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 319, 'exit': 350, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 1650, 'exit': 2045, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'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': 2110, 'exit': 2118, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 0)], [({'entry': 396, 'exit': 561, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 900), ({'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': 625, 'exit': 633, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 889, 'exit': 910, 'grace': 0, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 450), ({'entry': 2241, 'exit': 6561, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 436, 'exit': 417, 'grace': 15, 'hourly': 200, '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': 561, 'exit': 4971, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4900), ({'entry': 353, 'exit': 551, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 1031, 'exit': 1034, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1182, 'exit': 5502, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 963, 'exit': 1120, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'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': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 810, 'exit': 1530, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 866, 'exit': 1216, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 2379, 'exit': 2409, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 256, 'exit': 551, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1000), ({'entry': 33, 'exit': 4353, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 6000)], [({'entry': 2094, 'exit': 2098, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 567, 'exit': 1020, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 2252, 'exit': 2411, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1169, 'exit': 1186, 'grace': 10, 'hourly': 450, 'daily_max': 2400, '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': 2558, 'exit': 2796, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500), ({'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)]]
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 | 2000 | 2000 | Passed |
| fee oracle 1 | 1500 | 1800 | Failed |
| fee oracle 2 | 1350 | 1350 | Passed |
| fee oracle 3 | 0 | 300 | Failed |
| fee oracle 4 | 1800 | 2100 | Failed |
| fee oracle 5 | 2500 | 2500 | Passed |
| fee oracle 6 | 2600 | 2600 | Passed |
| fee oracle 7 | 0 | 0 | Passed |
SHA-256 / 05537cab40446bb3ae2bc1c272fcf7fbe6fa9062ddf2a69045c9899aec9cf6ff
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'], (rem // 60 + 1) * 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': 2558, 'exit': 3256, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 2210, 'exit': 2538, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 319, 'exit': 350, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 1650, 'exit': 2045, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'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': 2110, 'exit': 2118, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 0)], [({'entry': 396, 'exit': 561, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 900), ({'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': 625, 'exit': 633, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 889, 'exit': 910, 'grace': 0, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 450), ({'entry': 2241, 'exit': 6561, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 436, 'exit': 417, 'grace': 15, 'hourly': 200, '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': 561, 'exit': 4971, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4900), ({'entry': 353, 'exit': 551, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 1031, 'exit': 1034, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1182, 'exit': 5502, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 963, 'exit': 1120, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'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': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 810, 'exit': 1530, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 866, 'exit': 1216, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 2379, 'exit': 2409, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 256, 'exit': 551, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1000), ({'entry': 33, 'exit': 4353, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 6000)], [({'entry': 2094, 'exit': 2098, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 567, 'exit': 1020, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 2252, 'exit': 2411, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1169, 'exit': 1186, 'grace': 10, 'hourly': 450, 'daily_max': 2400, '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': 2558, 'exit': 2796, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500), ({'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)]]
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 | 2000 | 2000 | Passed |
| fee oracle 1 | 1800 | 1800 | Passed |
| fee oracle 2 | 1800 | 1350 | Failed |
| fee oracle 3 | 300 | 300 | Passed |
| fee oracle 4 | 2100 | 2100 | Passed |
| fee oracle 5 | 2500 | 2500 | Passed |
| fee oracle 6 | 2900 | 2600 | Failed |
| fee oracle 7 | 0 | 0 | Passed |
SHA-256 / 6e393e052c296de2e2e7dc3b78317376ad7850f8430009fe412e9fe35f935a9e
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': 2558, 'exit': 3256, 'grace': 10, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 2000), ({'entry': 2210, 'exit': 2538, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 319, 'exit': 350, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 300), ({'entry': 1650, 'exit': 2045, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 2100), ({'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': 2110, 'exit': 2118, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 0)], [({'entry': 396, 'exit': 561, 'grace': 20, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 900), ({'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': 625, 'exit': 633, 'grace': 0, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 889, 'exit': 910, 'grace': 0, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 450), ({'entry': 2241, 'exit': 6561, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 6000), ({'entry': 436, 'exit': 417, 'grace': 15, 'hourly': 200, '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': 561, 'exit': 4971, 'grace': 0, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 4900), ({'entry': 353, 'exit': 551, 'grace': 20, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1800), ({'entry': 1031, 'exit': 1034, 'grace': 20, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 1182, 'exit': 5502, 'grace': 10, 'hourly': 300, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 2500}, 7200), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 963, 'exit': 1120, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'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': 500, 'exit': 500, 'grace': 0, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 2500), ({'entry': 810, 'exit': 1530, 'grace': 15, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 866, 'exit': 1216, 'grace': 10, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 1800), ({'entry': 2379, 'exit': 2409, 'grace': 0, 'hourly': 300, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 300), ({'entry': 100, 'exit': 115, 'grace': 15, 'hourly': 300, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 0), ({'entry': 60, 'exit': 240, 'grace': 15, 'hourly': 450, 'daily_max': 2400, 'lost_ticket': False, 'lost_fee': 3000}, 1350), ({'entry': 256, 'exit': 551, 'grace': 15, 'hourly': 200, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1000), ({'entry': 33, 'exit': 4353, 'grace': 20, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': True, 'lost_fee': 2500}, 6000)], [({'entry': 2094, 'exit': 2098, 'grace': 0, 'hourly': 450, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 2500}, 450), ({'entry': 567, 'exit': 1020, 'grace': 10, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 2500}, 1500), ({'entry': 2252, 'exit': 2411, 'grace': 0, 'hourly': 200, 'daily_max': 2000, 'lost_ticket': False, 'lost_fee': 3000}, 600), ({'entry': 1169, 'exit': 1186, 'grace': 10, 'hourly': 450, 'daily_max': 2400, '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': 2558, 'exit': 2796, 'grace': 15, 'hourly': 450, 'daily_max': 1500, 'lost_ticket': False, 'lost_fee': 3000}, 1500), ({'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)]]
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 | 2000 | 2000 | Passed |
| fee oracle 1 | 1800 | 1800 | Passed |
| fee oracle 2 | 1350 | 1350 | Passed |
| fee oracle 3 | 300 | 300 | Passed |
| fee oracle 4 | 2100 | 2100 | Passed |
| fee oracle 5 | 2500 | 2500 | Passed |
| fee oracle 6 | 2600 | 2600 | Passed |
| fee oracle 7 | 0 | 0 | Passed |
SHA-256 / ecb5029ee15a683c057303c9ceb2db988c5ac694711e756b3a6e8b3f054f7be3
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.395536+00:00.
Case digest / daac160c7f895132648fe1de2450faf959f90538421936cc611f403acaa48c5b