FAILURE MAP
← Case archive

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.

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

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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