FAILURE MAP
← Case archive

FA-68381 / Toll and parking fee computation / Open access

Tiered parking rate table: additional blocks are counted from time zero · case 01

Tiered parking rate table returns a wrong result when additional blocks are counted from time zero.

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

ROOT CAUSE

Only completed blocks beyond the last tier are charged.

VERIFIED REPAIR

Restore the additional block count rule so that the step reads `-(-(m - last_upto) // blk)`.

Unsuccessful approach: Counting blocks on the absolute clock mis-aligns blocks when the last tier is not a multiple of the block length.

Case contract

Input {minutes, tiers: [[upto minutes, cumulative price]] in any order, extra_per: [block minutes, cents], max}. A stay of 0 minutes is free. Tiers are applied in ascending upto order and a stay of exactly upto minutes belongs to that tier (price capped at max). Beyond the last tier each started block after its upto adds the block price; the whole fee is capped at max.

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):
    m = x['minutes']
    tiers = sorted(x['tiers'])
    if m <= 0:
        return 0
    for upto, price in tiers:
        if m <= upto:
            return min(price, x['max'])
    last_upto, last_price = tiers[-1]
    blk, add = x['extra_per']
    extra = (m - last_upto) // blk
    return min(last_price + extra * add, x['max'])
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 675, 'tiers': [[60, 300], [120, 1200], [240, 1350]], 'extra_per': [60, 50], 'max': 4000}, 1750), ({'minutes': 301, 'tiers': [[300, 200]], 'extra_per': [15, 50], 'max': 4000}, 250), ({'minutes': 391, 'tiers': [[60, 200], [120, 750], [270, 950]], 'extra_per': [20, 150], 'max': 2500}, 2000), ({'minutes': 38, 'tiers': [[210, 100], [270, 500]], 'extra_per': [15, 100], 'max': 4000}, 100), ({'minutes': 435, 'tiers': [[30, 800], [150, 1800], [60, 850], [90, 1650]], 'extra_per': [20, 50], 'max': 4000}, 2550), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000)], [({'minutes': 31, 'tiers': [[30, 500], [210, 1450], [360, 1950]], 'extra_per': [30, 150], 'max': 2500}, 1450), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000), ({'minutes': 271, 'tiers': [[180, 700], [210, 1600], [270, 1950]], 'extra_per': [20, 150], 'max': 2500}, 2100), ({'minutes': 222, 'tiers': [[180, 2000], [120, 300]], 'extra_per': [60, 100], 'max': 2500}, 2100), ({'minutes': 1000, 'tiers': [[90, 400], [180, 700]], 'extra_per': [45, 150], 'max': 2500}, 2500), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 618, 'tiers': [[330, 950], [270, 500], [360, 1000]], 'extra_per': [60, 100], 'max': 1500}, 1500), ({'minutes': 643, 'tiers': [[330, 650], [120, 350], [240, 400]], 'extra_per': [60, 50], 'max': 2500}, 950)], [({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 211, 'tiers': [[210, 1300]], 'extra_per': [60, 100], 'max': 2500}, 1400), ({'minutes': 61, 'tiers': [[30, 400], [60, 1250]], 'extra_per': [30, 150], 'max': 1500}, 1400), ({'minutes': 175, 'tiers': [[30, 250]], 'extra_per': [60, 50], 'max': 4000}, 400), ({'minutes': 61, 'tiers': [[60, 350], [210, 2000], [150, 1950]], 'extra_per': [20, 150], 'max': 4000}, 1950), ({'minutes': 468, 'tiers': [[30, 750], [90, 1050], [240, 1150]], 'extra_per': [15, 50], 'max': 2500}, 1950), ({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000)], [({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 348, 'tiers': [[150, 1400]], 'extra_per': [60, 50], 'max': 4000}, 1600), ({'minutes': 198, 'tiers': [[90, 450], [180, 600], [300, 1250]], 'extra_per': [30, 50], 'max': 2500}, 1250), ({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 113, 'tiers': [[30, 900], [90, 1750]], 'extra_per': [30, 100], 'max': 4000}, 1850), ({'minutes': 271, 'tiers': [[270, 1150]], 'extra_per': [60, 150], 'max': 2500}, 1300), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000), ({'minutes': 191, 'tiers': [[360, 1700], [330, 1100], [210, 1000]], 'extra_per': [60, 50], 'max': 4000}, 1000)], [({'minutes': 181, 'tiers': [[90, 1150], [180, 1200]], 'extra_per': [60, 50], 'max': 1500}, 1250), ({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 361, 'tiers': [[30, 250], [90, 300], [360, 1650]], 'extra_per': [30, 50], 'max': 4000}, 1700), ({'minutes': 271, 'tiers': [[60, 450], [270, 1600]], 'extra_per': [60, 150], 'max': 2500}, 1750), ({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 394, 'tiers': [[30, 100], [150, 1600]], 'extra_per': [60, 100], 'max': 4000}, 2100), ({'minutes': 375, 'tiers': [[30, 350], [300, 2000], [60, 850], [210, 1350]], 'extra_per': [20, 150], 'max': 4000}, 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 fixtureActualExpectedOutcome
fee oracle 000Passed
fee oracle 117001750Failed
fee oracle 2200250Failed
fee oracle 318502000Failed
fee oracle 4100100Passed
fee oracle 525002550Failed
fee oracle 6300300Passed
fee oracle 78001000Failed

SHA-256 / c47f9438d5b7230730c32b203b587aaccad606c5af11dc145316477a34812026

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    m = x['minutes']
    tiers = sorted(x['tiers'])
    if m <= 0:
        return 0
    for upto, price in tiers:
        if m <= upto:
            return min(price, x['max'])
    last_upto, last_price = tiers[-1]
    blk, add = x['extra_per']
    extra = -(-m // blk) - -(-last_upto // blk)
    return min(last_price + extra * add, x['max'])
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 675, 'tiers': [[60, 300], [120, 1200], [240, 1350]], 'extra_per': [60, 50], 'max': 4000}, 1750), ({'minutes': 301, 'tiers': [[300, 200]], 'extra_per': [15, 50], 'max': 4000}, 250), ({'minutes': 391, 'tiers': [[60, 200], [120, 750], [270, 950]], 'extra_per': [20, 150], 'max': 2500}, 2000), ({'minutes': 38, 'tiers': [[210, 100], [270, 500]], 'extra_per': [15, 100], 'max': 4000}, 100), ({'minutes': 435, 'tiers': [[30, 800], [150, 1800], [60, 850], [90, 1650]], 'extra_per': [20, 50], 'max': 4000}, 2550), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000)], [({'minutes': 31, 'tiers': [[30, 500], [210, 1450], [360, 1950]], 'extra_per': [30, 150], 'max': 2500}, 1450), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000), ({'minutes': 271, 'tiers': [[180, 700], [210, 1600], [270, 1950]], 'extra_per': [20, 150], 'max': 2500}, 2100), ({'minutes': 222, 'tiers': [[180, 2000], [120, 300]], 'extra_per': [60, 100], 'max': 2500}, 2100), ({'minutes': 1000, 'tiers': [[90, 400], [180, 700]], 'extra_per': [45, 150], 'max': 2500}, 2500), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 618, 'tiers': [[330, 950], [270, 500], [360, 1000]], 'extra_per': [60, 100], 'max': 1500}, 1500), ({'minutes': 643, 'tiers': [[330, 650], [120, 350], [240, 400]], 'extra_per': [60, 50], 'max': 2500}, 950)], [({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 211, 'tiers': [[210, 1300]], 'extra_per': [60, 100], 'max': 2500}, 1400), ({'minutes': 61, 'tiers': [[30, 400], [60, 1250]], 'extra_per': [30, 150], 'max': 1500}, 1400), ({'minutes': 175, 'tiers': [[30, 250]], 'extra_per': [60, 50], 'max': 4000}, 400), ({'minutes': 61, 'tiers': [[60, 350], [210, 2000], [150, 1950]], 'extra_per': [20, 150], 'max': 4000}, 1950), ({'minutes': 468, 'tiers': [[30, 750], [90, 1050], [240, 1150]], 'extra_per': [15, 50], 'max': 2500}, 1950), ({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000)], [({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 348, 'tiers': [[150, 1400]], 'extra_per': [60, 50], 'max': 4000}, 1600), ({'minutes': 198, 'tiers': [[90, 450], [180, 600], [300, 1250]], 'extra_per': [30, 50], 'max': 2500}, 1250), ({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 113, 'tiers': [[30, 900], [90, 1750]], 'extra_per': [30, 100], 'max': 4000}, 1850), ({'minutes': 271, 'tiers': [[270, 1150]], 'extra_per': [60, 150], 'max': 2500}, 1300), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000), ({'minutes': 191, 'tiers': [[360, 1700], [330, 1100], [210, 1000]], 'extra_per': [60, 50], 'max': 4000}, 1000)], [({'minutes': 181, 'tiers': [[90, 1150], [180, 1200]], 'extra_per': [60, 50], 'max': 1500}, 1250), ({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 361, 'tiers': [[30, 250], [90, 300], [360, 1650]], 'extra_per': [30, 50], 'max': 4000}, 1700), ({'minutes': 271, 'tiers': [[60, 450], [270, 1600]], 'extra_per': [60, 150], 'max': 2500}, 1750), ({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 394, 'tiers': [[30, 100], [150, 1600]], 'extra_per': [60, 100], 'max': 4000}, 2100), ({'minutes': 375, 'tiers': [[30, 350], [300, 2000], [60, 850], [210, 1350]], 'extra_per': [20, 150], 'max': 4000}, 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 fixtureActualExpectedOutcome
fee oracle 000Passed
fee oracle 117501750Passed
fee oracle 2250250Passed
fee oracle 318502000Failed
fee oracle 4100100Passed
fee oracle 525002550Failed
fee oracle 6300300Passed
fee oracle 710001000Passed

SHA-256 / 00545a2d013ab9c733039a979be0f9b3ee43a59a4d4ca74a068cb1d9e12c5366

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    m = x['minutes']
    tiers = sorted(x['tiers'])
    if m <= 0:
        return 0
    for upto, price in tiers:
        if m <= upto:
            return min(price, x['max'])
    last_upto, last_price = tiers[-1]
    blk, add = x['extra_per']
    extra = -(-(m - last_upto) // blk)
    return min(last_price + extra * add, x['max'])
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 675, 'tiers': [[60, 300], [120, 1200], [240, 1350]], 'extra_per': [60, 50], 'max': 4000}, 1750), ({'minutes': 301, 'tiers': [[300, 200]], 'extra_per': [15, 50], 'max': 4000}, 250), ({'minutes': 391, 'tiers': [[60, 200], [120, 750], [270, 950]], 'extra_per': [20, 150], 'max': 2500}, 2000), ({'minutes': 38, 'tiers': [[210, 100], [270, 500]], 'extra_per': [15, 100], 'max': 4000}, 100), ({'minutes': 435, 'tiers': [[30, 800], [150, 1800], [60, 850], [90, 1650]], 'extra_per': [20, 50], 'max': 4000}, 2550), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000)], [({'minutes': 31, 'tiers': [[30, 500], [210, 1450], [360, 1950]], 'extra_per': [30, 150], 'max': 2500}, 1450), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000), ({'minutes': 271, 'tiers': [[180, 700], [210, 1600], [270, 1950]], 'extra_per': [20, 150], 'max': 2500}, 2100), ({'minutes': 222, 'tiers': [[180, 2000], [120, 300]], 'extra_per': [60, 100], 'max': 2500}, 2100), ({'minutes': 1000, 'tiers': [[90, 400], [180, 700]], 'extra_per': [45, 150], 'max': 2500}, 2500), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 618, 'tiers': [[330, 950], [270, 500], [360, 1000]], 'extra_per': [60, 100], 'max': 1500}, 1500), ({'minutes': 643, 'tiers': [[330, 650], [120, 350], [240, 400]], 'extra_per': [60, 50], 'max': 2500}, 950)], [({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 211, 'tiers': [[210, 1300]], 'extra_per': [60, 100], 'max': 2500}, 1400), ({'minutes': 61, 'tiers': [[30, 400], [60, 1250]], 'extra_per': [30, 150], 'max': 1500}, 1400), ({'minutes': 175, 'tiers': [[30, 250]], 'extra_per': [60, 50], 'max': 4000}, 400), ({'minutes': 61, 'tiers': [[60, 350], [210, 2000], [150, 1950]], 'extra_per': [20, 150], 'max': 4000}, 1950), ({'minutes': 468, 'tiers': [[30, 750], [90, 1050], [240, 1150]], 'extra_per': [15, 50], 'max': 2500}, 1950), ({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000)], [({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 348, 'tiers': [[150, 1400]], 'extra_per': [60, 50], 'max': 4000}, 1600), ({'minutes': 198, 'tiers': [[90, 450], [180, 600], [300, 1250]], 'extra_per': [30, 50], 'max': 2500}, 1250), ({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 113, 'tiers': [[30, 900], [90, 1750]], 'extra_per': [30, 100], 'max': 4000}, 1850), ({'minutes': 271, 'tiers': [[270, 1150]], 'extra_per': [60, 150], 'max': 2500}, 1300), ({'minutes': 250, 'tiers': [[240, 800], [60, 300], [120, 500]], 'extra_per': [60, 200], 'max': 2000}, 1000), ({'minutes': 191, 'tiers': [[360, 1700], [330, 1100], [210, 1000]], 'extra_per': [60, 50], 'max': 4000}, 1000)], [({'minutes': 181, 'tiers': [[90, 1150], [180, 1200]], 'extra_per': [60, 50], 'max': 1500}, 1250), ({'minutes': 1, 'tiers': [[30, 150], [60, 300]], 'extra_per': [30, 100], 'max': 1500}, 150), ({'minutes': 60, 'tiers': [[60, 300], [120, 500], [240, 800]], 'extra_per': [60, 200], 'max': 2000}, 300), ({'minutes': 361, 'tiers': [[30, 250], [90, 300], [360, 1650]], 'extra_per': [30, 50], 'max': 4000}, 1700), ({'minutes': 271, 'tiers': [[60, 450], [270, 1600]], 'extra_per': [60, 150], 'max': 2500}, 1750), ({'minutes': 0, 'tiers': [[60, 300]], 'extra_per': [30, 100], 'max': 1500}, 0), ({'minutes': 394, 'tiers': [[30, 100], [150, 1600]], 'extra_per': [60, 100], 'max': 4000}, 2100), ({'minutes': 375, 'tiers': [[30, 350], [300, 2000], [60, 850], [210, 1350]], 'extra_per': [20, 150], 'max': 4000}, 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 fixtureActualExpectedOutcome
fee oracle 000Passed
fee oracle 117501750Passed
fee oracle 2250250Passed
fee oracle 320002000Passed
fee oracle 4100100Passed
fee oracle 525502550Passed
fee oracle 6300300Passed
fee oracle 710001000Passed

SHA-256 / 2b4c247813599d61bfa0f9ef13781a6660d0dc5d6eee468a008ba15b0271aefa

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.676294+00:00.

Case digest / 14e12cf9082c519bcf466e618bea3781281d6bd7cd6bb94e056978f3a4a3ae12