FA-66466 / Airline fare rule evaluation / Open access
Change fee absorbed by the downgrade residual · case 01
Downgrades collect nothing even though the contract always collects the fee.
ROOT CAUSE
The fee is added inside the fare-difference clamp, so a negative difference cancels it.
VERIFIED REPAIR
Collect the fee separately from the clamped fare difference.
Unsuccessful approach: Deducting the fee from the credit instead still fails to collect it.
Case contract
Input {'paid','new_fare','fee','fee_pct','fee_rule' FLAT|HIGHER,'residual' CREDIT|FORFEIT,'waiver_h','hours_since_ticket'}. Fee waived when hours_since_ticket <= waiver_h; FLAT fee = fee; HIGHER = max(fee, fee_pct% of the original paid fare). Collect = max(0, new-paid) + fee; residual credit = max(0, paid-new) only when residual is CREDIT (the fee is never netted against credit). Return [collect, credit] rounded 2.
Why this case matters
Voluntary change pricing combines a fare difference, a penalty with a higher-of rule, a free-change window and residual value handling.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
paid, new = x['paid'], x['new_fare']
if x['hours_since_ticket'] <= x['waiver_h']:
fee = 0.0
elif x['fee_rule'] == 'FLAT':
fee = x['fee']
else:
fee = max(x['fee'], x['fee_pct'] * paid / 100)
collect = max(0.0, new - paid + fee)
credit = max(0.0, paid - new) if x['residual'] == 'CREDIT' else 0.0
return [round(collect, 2), round(credit, 2)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1101.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [291.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 51}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 421.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 310.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 0.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 945.21, 'new_fare': 746.1, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 397}, [141.78, 0.0]], ['sampled case 2', {'paid': 616.49, 'new_fare': 852.38, 'fee': 150.0, 'fee_pct': 10, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [385.89, 0.0]], ['sampled case 3', {'paid': 832.44, 'new_fare': 589.1, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [0.0, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1102.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [292.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 52}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 422.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 320.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 10.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 187.06, 'new_fare': 196.65, 'fee': 150.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [9.59, 0.0]], ['sampled case 2', {'paid': 1518.15, 'new_fare': 1549.03, 'fee': 150.0, 'fee_pct': 20, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [30.88, 0.0]], ['sampled case 3', {'paid': 1212.02, 'new_fare': 1432.47, 'fee': 100.0, 'fee_pct': 5, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 49}, [320.45, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1103.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [293.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 53}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 423.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 330.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 20.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 1440.92, 'new_fare': 1296.99, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [0.0, 143.93]], ['sampled case 2', {'paid': 1622.18, 'new_fare': 873.9, 'fee': 150.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [243.33, 0.0]], ['sampled case 3', {'paid': 1642.66, 'new_fare': 1568.49, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 48}, [0.0, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1104.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [294.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 54}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 424.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 340.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 30.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 1227.57, 'new_fare': 1031.14, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [245.51, 0.0]], ['sampled case 2', {'paid': 762.01, 'new_fare': 1039.32, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [277.31, 0.0]], ['sampled case 3', {'paid': 1675.54, 'new_fare': 1027.22, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [0.0, 648.32]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1105.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [295.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 55}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 425.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 350.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 40.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 938.24, 'new_fare': 955.89, 'fee': 100.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'waiver_h': 48, 'hours_since_ticket': 57.2}, [117.65, 0.0]], ['sampled case 2', {'paid': 1989.4, 'new_fare': 2128.3, 'fee': 150.0, 'fee_pct': 10, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 12.8}, [138.9, 0.0]], ['sampled case 3', {'paid': 1315.4, 'new_fare': 1527.5, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [212.1, 0.0]]]]
for label, args, expected in fixtures[N-1]:
check(label, 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 |
|---|---|---|---|
| upgrade HIGHER rule | [291.0, 0.0] | [291.0, 0.0] | Passed |
| downgrade with credit | [0.0, 150.0] | [75.0, 150.0] | Failed |
| downgrade forfeit | [0.0, 0.0] | [75.0, 0.0] | Failed |
| exactly 24h after ticketing | [20.0, 0.0] | [20.0, 0.0] | Passed |
| cheap fare minimum fee | [75.0, 0.0] | [75.0, 0.0] | Passed |
| pct fee exceeds flat | [0.0, 300.0] | [150.0, 300.0] | Failed |
| fee larger than residual | [35.0, 40.0] | [75.0, 40.0] | Failed |
| sampled case 1 | [0.0, 0.0] | [141.78, 0.0] | Failed |
| sampled case 2 | [385.89, 0.0] | [385.89, 0.0] | Passed |
| sampled case 3 | [0.0, 0.0] | [0.0, 0.0] | Passed |
SHA-256 / ee04e7e8f9f290a77f08fd2a039dab7dd2cbe0745099cf38b5ee3c20453fc13c
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
paid, new = x['paid'], x['new_fare']
if x['hours_since_ticket'] <= x['waiver_h']:
fee = 0.0
elif x['fee_rule'] == 'FLAT':
fee = x['fee']
else:
fee = max(x['fee'], x['fee_pct'] * paid / 100)
collect = max(0.0, new - paid) + fee
credit = max(0.0, paid - new - fee) if x['residual'] == 'CREDIT' else 0.0
return [round(collect, 2), round(credit, 2)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1101.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [291.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 51}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 421.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 310.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 0.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 945.21, 'new_fare': 746.1, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 397}, [141.78, 0.0]], ['sampled case 2', {'paid': 616.49, 'new_fare': 852.38, 'fee': 150.0, 'fee_pct': 10, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [385.89, 0.0]], ['sampled case 3', {'paid': 832.44, 'new_fare': 589.1, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [0.0, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1102.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [292.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 52}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 422.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 320.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 10.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 187.06, 'new_fare': 196.65, 'fee': 150.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [9.59, 0.0]], ['sampled case 2', {'paid': 1518.15, 'new_fare': 1549.03, 'fee': 150.0, 'fee_pct': 20, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [30.88, 0.0]], ['sampled case 3', {'paid': 1212.02, 'new_fare': 1432.47, 'fee': 100.0, 'fee_pct': 5, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 49}, [320.45, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1103.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [293.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 53}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 423.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 330.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 20.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 1440.92, 'new_fare': 1296.99, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [0.0, 143.93]], ['sampled case 2', {'paid': 1622.18, 'new_fare': 873.9, 'fee': 150.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [243.33, 0.0]], ['sampled case 3', {'paid': 1642.66, 'new_fare': 1568.49, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 48}, [0.0, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1104.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [294.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 54}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 424.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 340.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 30.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 1227.57, 'new_fare': 1031.14, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [245.51, 0.0]], ['sampled case 2', {'paid': 762.01, 'new_fare': 1039.32, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [277.31, 0.0]], ['sampled case 3', {'paid': 1675.54, 'new_fare': 1027.22, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [0.0, 648.32]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1105.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [295.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 55}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 425.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 350.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 40.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 938.24, 'new_fare': 955.89, 'fee': 100.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'waiver_h': 48, 'hours_since_ticket': 57.2}, [117.65, 0.0]], ['sampled case 2', {'paid': 1989.4, 'new_fare': 2128.3, 'fee': 150.0, 'fee_pct': 10, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 12.8}, [138.9, 0.0]], ['sampled case 3', {'paid': 1315.4, 'new_fare': 1527.5, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [212.1, 0.0]]]]
for label, args, expected in fixtures[N-1]:
check(label, 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 |
|---|---|---|---|
| upgrade HIGHER rule | [291.0, 0.0] | [291.0, 0.0] | Passed |
| downgrade with credit | [75.0, 75.0] | [75.0, 150.0] | Failed |
| downgrade forfeit | [75.0, 0.0] | [75.0, 0.0] | Passed |
| exactly 24h after ticketing | [20.0, 0.0] | [20.0, 0.0] | Passed |
| cheap fare minimum fee | [75.0, 0.0] | [75.0, 0.0] | Passed |
| pct fee exceeds flat | [150.0, 150.0] | [150.0, 300.0] | Failed |
| fee larger than residual | [75.0, 0.0] | [75.0, 40.0] | Failed |
| sampled case 1 | [141.78, 0.0] | [141.78, 0.0] | Passed |
| sampled case 2 | [385.89, 0.0] | [385.89, 0.0] | Passed |
| sampled case 3 | [0.0, 0.0] | [0.0, 0.0] | Passed |
SHA-256 / a912c11e6c7a31058410eea69d2c251bb8f1c0709585fe05c6cdfe21d0be378a
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
paid, new = x['paid'], x['new_fare']
if x['hours_since_ticket'] <= x['waiver_h']:
fee = 0.0
elif x['fee_rule'] == 'FLAT':
fee = x['fee']
else:
fee = max(x['fee'], x['fee_pct'] * paid / 100)
collect = max(0.0, new - paid) + fee
credit = max(0.0, paid - new) if x['residual'] == 'CREDIT' else 0.0
return [round(collect, 2), round(credit, 2)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1101.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [291.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 51}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 421.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 310.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 0.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 945.21, 'new_fare': 746.1, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 397}, [141.78, 0.0]], ['sampled case 2', {'paid': 616.49, 'new_fare': 852.38, 'fee': 150.0, 'fee_pct': 10, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [385.89, 0.0]], ['sampled case 3', {'paid': 832.44, 'new_fare': 589.1, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [0.0, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1102.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [292.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 52}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 422.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 320.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 10.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 187.06, 'new_fare': 196.65, 'fee': 150.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [9.59, 0.0]], ['sampled case 2', {'paid': 1518.15, 'new_fare': 1549.03, 'fee': 150.0, 'fee_pct': 20, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [30.88, 0.0]], ['sampled case 3', {'paid': 1212.02, 'new_fare': 1432.47, 'fee': 100.0, 'fee_pct': 5, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 49}, [320.45, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1103.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [293.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 53}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 423.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 330.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 20.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 1440.92, 'new_fare': 1296.99, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [0.0, 143.93]], ['sampled case 2', {'paid': 1622.18, 'new_fare': 873.9, 'fee': 150.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [243.33, 0.0]], ['sampled case 3', {'paid': 1642.66, 'new_fare': 1568.49, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 48}, [0.0, 0.0]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1104.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [294.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 54}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 424.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 340.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 30.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 1227.57, 'new_fare': 1031.14, 'fee': 75.0, 'fee_pct': 20, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 48}, [245.51, 0.0]], ['sampled case 2', {'paid': 762.01, 'new_fare': 1039.32, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [277.31, 0.0]], ['sampled case 3', {'paid': 1675.54, 'new_fare': 1027.22, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'waiver_h': 24, 'hours_since_ticket': 24}, [0.0, 648.32]]], [['upgrade HIGHER rule', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 900.0, 'new_fare': 1105.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 100}, [295.0, 0.0]], ['downgrade with credit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 450.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 55}, [75.0, 150.0]], ['downgrade forfeit', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 600.0, 'new_fare': 425.0, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'hours_since_ticket': 72}, [75.0, 0.0]], ['exactly 24h after ticketing', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 520.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 24}, [20.0, 0.0]], ['cheap fare minimum fee', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 350.0, 'new_fare': 310.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 30}, [75.0, 40.0]], ['pct fee exceeds flat', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 1500.0, 'new_fare': 1200.0, 'fee_rule': 'HIGHER', 'residual': 'CREDIT', 'hours_since_ticket': 200}, [150.0, 300.0]], ['fee larger than residual', {'waiver_h': 24, 'fee': 75.0, 'fee_pct': 10, 'paid': 500.0, 'new_fare': 460.0, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'hours_since_ticket': 48}, [75.0, 40.0]], ['sampled case 1', {'paid': 938.24, 'new_fare': 955.89, 'fee': 100.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'CREDIT', 'waiver_h': 48, 'hours_since_ticket': 57.2}, [117.65, 0.0]], ['sampled case 2', {'paid': 1989.4, 'new_fare': 2128.3, 'fee': 150.0, 'fee_pct': 10, 'fee_rule': 'HIGHER', 'residual': 'FORFEIT', 'waiver_h': 24, 'hours_since_ticket': 12.8}, [138.9, 0.0]], ['sampled case 3', {'paid': 1315.4, 'new_fare': 1527.5, 'fee': 50.0, 'fee_pct': 15, 'fee_rule': 'FLAT', 'residual': 'FORFEIT', 'waiver_h': 48, 'hours_since_ticket': 24}, [212.1, 0.0]]]]
for label, args, expected in fixtures[N-1]:
check(label, 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 |
|---|---|---|---|
| upgrade HIGHER rule | [291.0, 0.0] | [291.0, 0.0] | Passed |
| downgrade with credit | [75.0, 150.0] | [75.0, 150.0] | Passed |
| downgrade forfeit | [75.0, 0.0] | [75.0, 0.0] | Passed |
| exactly 24h after ticketing | [20.0, 0.0] | [20.0, 0.0] | Passed |
| cheap fare minimum fee | [75.0, 0.0] | [75.0, 0.0] | Passed |
| pct fee exceeds flat | [150.0, 300.0] | [150.0, 300.0] | Passed |
| fee larger than residual | [75.0, 40.0] | [75.0, 40.0] | Passed |
| sampled case 1 | [141.78, 0.0] | [141.78, 0.0] | Passed |
| sampled case 2 | [385.89, 0.0] | [385.89, 0.0] | Passed |
| sampled case 3 | [0.0, 0.0] | [0.0, 0.0] | Passed |
SHA-256 / 62966235379743b4049403fd2564a334b52d40c96eae5386430cd1cd4ca5a9a8
Verification & scope
A stipulated toy fare-rule contract with invented constants; it is not an ATPCO or carrier tariff implementation and makes no claim of industry-standard conformance. 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:47:44.080061+00:00.
Case digest / e77622edb080f35686d5fef896d7ef8e1f67871f6947cc50ec830f67f61f93b6