FAILURE MAP
← Case archive

FA-60741 / Loyalty points ledgers / Open access

Tier multiplier in force at transaction time: historical tier lookup · case 01

Transactions made before an upgrade are re-earned at the new, higher multiplier.

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

ROOT CAUSE

Every transaction uses the most recent tier in the history instead of the tier in force on its day.

VERIFIED REPAIR

Use the latest tier effective on or before the transaction day.

Unsuccessful approach: Comparing effective days with the last transaction day applies one tier to the whole batch.

Case contract

Input {tier_history:[[effective_day,tier]] (any order), txns:[[day,base]], mult:{tier:pct}}. Each transaction earns floor(base*pct/100) using the tier with the latest effective_day <= transaction day ("member" before any entry). Unknown tier names earn at 100%. Return {points, total}.

Why this case matters

Member point balances, statements and the program liability depend on this ledger rule.

1 / The failure

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

N = 1
observations = []
def solve(x):
    hist = sorted(x['tier_history'])
    out = []
    for day, base in x['txns']:
        tier = 'member'
        for eff, t in hist:
            tier = t
        pct = x['mult'].get(tier, 100)
        out.append(base * pct // 100)
    return {'points': out, 'total': sum(out)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1001], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1251, 1500], 'total': 3751}], ['effective day', {'tier_history': [[100, 'silver'], [201, 'gold']], 'txns': [[100, 400], [201, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 101], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [151, 200], 'total': 351}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 334]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [334], 'total': 334}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 11]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 11], 'total': 88}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 201]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 251], 'total': 551}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 91]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [113], 'total': 113}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1002], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1252, 1500], 'total': 3752}], ['effective day', {'tier_history': [[100, 'silver'], [202, 'gold']], 'txns': [[100, 400], [202, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 102], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [153, 200], 'total': 353}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 335]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [335], 'total': 335}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 12]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 12], 'total': 89}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 202]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 252], 'total': 552}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 92]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [115], 'total': 115}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1003], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1253, 1500], 'total': 3753}], ['effective day', {'tier_history': [[100, 'silver'], [203, 'gold']], 'txns': [[100, 400], [203, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 103], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [154, 200], 'total': 354}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 336]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [336], 'total': 336}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 13]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 13], 'total': 90}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 203]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 253], 'total': 553}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 93]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [116], 'total': 116}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1004], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1255, 1500], 'total': 3755}], ['effective day', {'tier_history': [[100, 'silver'], [204, 'gold']], 'txns': [[100, 400], [204, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 104], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [156, 200], 'total': 356}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 337]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [337], 'total': 337}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 14]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 14], 'total': 91}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 204]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 255], 'total': 555}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 94]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [117], 'total': 117}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1005], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1256, 1500], 'total': 3756}], ['effective day', {'tier_history': [[100, 'silver'], [205, 'gold']], 'txns': [[100, 400], [205, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 105], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [157, 200], 'total': 357}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 338]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [338], 'total': 338}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 15]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 15], 'total': 92}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 205]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 256], 'total': 556}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 95]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [118], 'total': 118}]]]
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
tier changes midyear{'points': [1500, 1501, 1500], 'total': 4501}{'points': [1000, 1251, 1500], 'total': 3751}Failed
effective day{'points': [600, 600], 'total': 1200}{'points': [500, 600], 'total': 1100}Failed
unsorted history{'points': [202, 200], 'total': 402}{'points': [151, 200], 'total': 351}Failed
legacy tier{'points': [334], 'total': 334}{'points': [334], 'total': 334}Passed
before any tier{'points': [115, 16], 'total': 131}{'points': [77, 11], 'total': 88}Failed
downgrade{'points': [250, 251], 'total': 501}{'points': [300, 251], 'total': 551}Failed
late earns{'points': [182], 'total': 182}{'points': [113], 'total': 113}Failed

SHA-256 / 740274c23b22335a0183e3aad99591c586b23427b56280646e2f930406d1af09

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    hist = sorted(x['tier_history'])
    out = []
    for day, base in x['txns']:
        tier = 'member'
        for eff, t in hist:
            if eff <= x['txns'][-1][0]:
                tier = t
            else:
                break
        pct = x['mult'].get(tier, 100)
        out.append(base * pct // 100)
    return {'points': out, 'total': sum(out)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1001], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1251, 1500], 'total': 3751}], ['effective day', {'tier_history': [[100, 'silver'], [201, 'gold']], 'txns': [[100, 400], [201, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 101], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [151, 200], 'total': 351}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 334]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [334], 'total': 334}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 11]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 11], 'total': 88}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 201]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 251], 'total': 551}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 91]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [113], 'total': 113}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1002], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1252, 1500], 'total': 3752}], ['effective day', {'tier_history': [[100, 'silver'], [202, 'gold']], 'txns': [[100, 400], [202, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 102], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [153, 200], 'total': 353}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 335]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [335], 'total': 335}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 12]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 12], 'total': 89}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 202]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 252], 'total': 552}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 92]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [115], 'total': 115}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1003], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1253, 1500], 'total': 3753}], ['effective day', {'tier_history': [[100, 'silver'], [203, 'gold']], 'txns': [[100, 400], [203, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 103], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [154, 200], 'total': 354}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 336]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [336], 'total': 336}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 13]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 13], 'total': 90}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 203]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 253], 'total': 553}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 93]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [116], 'total': 116}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1004], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1255, 1500], 'total': 3755}], ['effective day', {'tier_history': [[100, 'silver'], [204, 'gold']], 'txns': [[100, 400], [204, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 104], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [156, 200], 'total': 356}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 337]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [337], 'total': 337}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 14]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 14], 'total': 91}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 204]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 255], 'total': 555}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 94]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [117], 'total': 117}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1005], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1256, 1500], 'total': 3756}], ['effective day', {'tier_history': [[100, 'silver'], [205, 'gold']], 'txns': [[100, 400], [205, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 105], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [157, 200], 'total': 357}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 338]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [338], 'total': 338}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 15]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 15], 'total': 92}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 205]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 256], 'total': 556}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 95]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [118], 'total': 118}]]]
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
tier changes midyear{'points': [1500, 1501, 1500], 'total': 4501}{'points': [1000, 1251, 1500], 'total': 3751}Failed
effective day{'points': [600, 600], 'total': 1200}{'points': [500, 600], 'total': 1100}Failed
unsorted history{'points': [202, 200], 'total': 402}{'points': [151, 200], 'total': 351}Failed
legacy tier{'points': [334], 'total': 334}{'points': [334], 'total': 334}Passed
before any tier{'points': [77, 11], 'total': 88}{'points': [77, 11], 'total': 88}Passed
downgrade{'points': [250, 251], 'total': 501}{'points': [300, 251], 'total': 551}Failed
late earns{'points': [113], 'total': 113}{'points': [113], 'total': 113}Passed

SHA-256 / 191c887f1ac27476477c6c31b64552fb8b8175928d6e8afecdda099900d16769

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    hist = sorted(x['tier_history'])
    out = []
    for day, base in x['txns']:
        tier = 'member'
        for eff, t in hist:
            if eff <= day:
                tier = t
            else:
                break
        pct = x['mult'].get(tier, 100)
        out.append(base * pct // 100)
    return {'points': out, 'total': sum(out)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1001], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1251, 1500], 'total': 3751}], ['effective day', {'tier_history': [[100, 'silver'], [201, 'gold']], 'txns': [[100, 400], [201, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 101], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [151, 200], 'total': 351}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 334]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [334], 'total': 334}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 11]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 11], 'total': 88}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 201]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 251], 'total': 551}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 91]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [113], 'total': 113}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1002], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1252, 1500], 'total': 3752}], ['effective day', {'tier_history': [[100, 'silver'], [202, 'gold']], 'txns': [[100, 400], [202, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 102], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [153, 200], 'total': 353}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 335]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [335], 'total': 335}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 12]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 12], 'total': 89}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 202]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 252], 'total': 552}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 92]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [115], 'total': 115}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1003], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1253, 1500], 'total': 3753}], ['effective day', {'tier_history': [[100, 'silver'], [203, 'gold']], 'txns': [[100, 400], [203, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 103], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [154, 200], 'total': 354}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 336]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [336], 'total': 336}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 13]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 13], 'total': 90}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 203]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 253], 'total': 553}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 93]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [116], 'total': 116}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1004], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1255, 1500], 'total': 3755}], ['effective day', {'tier_history': [[100, 'silver'], [204, 'gold']], 'txns': [[100, 400], [204, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 104], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [156, 200], 'total': 356}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 337]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [337], 'total': 337}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 14]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 14], 'total': 91}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 204]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 255], 'total': 555}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 94]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [117], 'total': 117}]], [['tier changes midyear', {'tier_history': [[100, 'silver'], [200, 'gold']], 'txns': [[50, 1000], [150, 1005], [250, 1000]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [1000, 1256, 1500], 'total': 3756}], ['effective day', {'tier_history': [[100, 'silver'], [205, 'gold']], 'txns': [[100, 400], [205, 400]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [500, 600], 'total': 1100}], ['unsorted history', {'tier_history': [[300, 'platinum'], [100, 'gold']], 'txns': [[150, 105], [350, 100]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [157, 200], 'total': 357}], ['legacy tier', {'tier_history': [[10, 'diamond']], 'txns': [[20, 338]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [338], 'total': 338}], ['before any tier', {'tier_history': [[500, 'gold']], 'txns': [[1, 77], [499, 15]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [77, 15], 'total': 92}], ['downgrade', {'tier_history': [[10, 'gold'], [60, 'silver']], 'txns': [[59, 200], [61, 205]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [300, 256], 'total': 556}], ['late earns', {'tier_history': [[0, 'silver'], [30, 'platinum']], 'txns': [[15, 95]], 'mult': {'member': 100, 'silver': 125, 'gold': 150, 'platinum': 200}}, {'points': [118], 'total': 118}]]]
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
tier changes midyear{'points': [1000, 1251, 1500], 'total': 3751}{'points': [1000, 1251, 1500], 'total': 3751}Passed
effective day{'points': [500, 600], 'total': 1100}{'points': [500, 600], 'total': 1100}Passed
unsorted history{'points': [151, 200], 'total': 351}{'points': [151, 200], 'total': 351}Passed
legacy tier{'points': [334], 'total': 334}{'points': [334], 'total': 334}Passed
before any tier{'points': [77, 11], 'total': 88}{'points': [77, 11], 'total': 88}Passed
downgrade{'points': [300, 251], 'total': 551}{'points': [300, 251], 'total': 551}Passed
late earns{'points': [113], 'total': 113}{'points': [113], 'total': 113}Passed

SHA-256 / a6aa004133bf274de7fb5e95d2650e5d09e58efe89ca92bbd37e211aad14dda3

Verification & scope

Stipulated bounded loyalty-program model with explicit toy rules; not any real program terms. 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:46:48.523366+00:00.

Case digest / 173f6d2f63d87d9abde9231efb96d4e2324436af2120e81e17bbd51803f96f46