FAILURE MAP
← Case archive

FA-60471 / Loyalty points ledgers / Open access

Refund points clawback: balance floor · case 01

Clawbacks push balances negative and no debt is tracked.

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

ROOT CAUSE

The whole clawback is taken from the balance regardless of available points.

VERIFIED REPAIR

Take at most the available balance and carry the shortfall as debt.

Unsuccessful approach: Flooring the balance but discarding the shortfall forgives the points.

Case contract

Input {earned, order_total, refunds:[cents], balance}. Cumulative refunds are capped at the order total. After each refund the cumulative clawback target is round-half-up(earned*cumulative refund/order total); the refund claws target minus already clawed. A clawback is taken from the balance only down to zero; the shortfall accumulates as debt. Return {claws, balance, debt}.

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):
    cum = 0
    clawed = 0
    bal = x['balance']
    debt = 0
    out = []
    for r in x['refunds']:
        cum = min(x['order_total'], cum + r)
        target = (2 * x['earned'] * cum + x['order_total']) // (2 * x['order_total'])
        c = target - clawed
        clawed = target
        take = c
        bal -= take
        debt += c - take
        out.append(c)
    return {'claws': out, 'balance': bal, 'debt': debt}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2501], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 51}, {'claws': [3, 4, 3], 'balance': 41, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3001], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 31}, {'claws': [100, 100], 'balance': 0, 'debt': 169}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 1}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 89}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 11}, {'claws': [2], 'balance': 9, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [2], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2502], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 52}, {'claws': [3, 4, 3], 'balance': 42, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3002], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 32}, {'claws': [100, 100], 'balance': 0, 'debt': 168}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 2}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 88}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 12}, {'claws': [2], 'balance': 10, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [3], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2503], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 53}, {'claws': [3, 4, 3], 'balance': 43, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3003], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 33}, {'claws': [100, 100], 'balance': 0, 'debt': 167}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 3}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 87}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 13}, {'claws': [2], 'balance': 11, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [4], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2504], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 54}, {'claws': [3, 4, 3], 'balance': 44, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3004], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 34}, {'claws': [100, 100], 'balance': 0, 'debt': 166}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 4}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 86}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 14}, {'claws': [2], 'balance': 12, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [5], 'balance': 5}, {'claws': [1], 'balance': 4, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2505], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 55}, {'claws': [3, 4, 3], 'balance': 45, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3005], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 35}, {'claws': [100, 100], 'balance': 0, 'debt': 165}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 5}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 85}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 15}, {'claws': [2], 'balance': 13, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [6], 'balance': 5}, {'claws': [1], 'balance': 4, 'debt': 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
two partial refunds{'balance': 937, 'claws': [31, 32], 'debt': 0}{'balance': 937, 'claws': [31, 32], 'debt': 0}Passed
rounding drift{'balance': 41, 'claws': [3, 4, 3], 'debt': 0}{'balance': 41, 'claws': [3, 4, 3], 'debt': 0}Passed
over refund{'balance': 420, 'claws': [60, 20], 'debt': 0}{'balance': 420, 'claws': [60, 20], 'debt': 0}Passed
spent points{'balance': -169, 'claws': [100, 100], 'debt': 0}{'balance': 0, 'claws': [100, 100], 'debt': 169}Failed
debt grows{'balance': -89, 'claws': [30, 30, 30], 'debt': 0}{'balance': 0, 'claws': [30, 30, 30], 'debt': 89}Failed
single half{'balance': 9, 'claws': [2], 'debt': 0}{'balance': 9, 'claws': [2], 'debt': 0}Passed
refund one of many{'balance': 5, 'claws': [0], 'debt': 0}{'balance': 5, 'claws': [0], 'debt': 0}Passed

SHA-256 / 95601150a91edb69e47ac5ded58d9b6f51247da76293d9755fd849dba843b94d

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    cum = 0
    clawed = 0
    bal = x['balance']
    debt = 0
    out = []
    for r in x['refunds']:
        cum = min(x['order_total'], cum + r)
        target = (2 * x['earned'] * cum + x['order_total']) // (2 * x['order_total'])
        c = target - clawed
        clawed = target
        take = min(c, bal)
        bal -= take
        debt += 0
        out.append(c)
    return {'claws': out, 'balance': bal, 'debt': debt}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2501], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 51}, {'claws': [3, 4, 3], 'balance': 41, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3001], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 31}, {'claws': [100, 100], 'balance': 0, 'debt': 169}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 1}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 89}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 11}, {'claws': [2], 'balance': 9, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [2], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2502], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 52}, {'claws': [3, 4, 3], 'balance': 42, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3002], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 32}, {'claws': [100, 100], 'balance': 0, 'debt': 168}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 2}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 88}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 12}, {'claws': [2], 'balance': 10, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [3], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2503], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 53}, {'claws': [3, 4, 3], 'balance': 43, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3003], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 33}, {'claws': [100, 100], 'balance': 0, 'debt': 167}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 3}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 87}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 13}, {'claws': [2], 'balance': 11, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [4], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2504], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 54}, {'claws': [3, 4, 3], 'balance': 44, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3004], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 34}, {'claws': [100, 100], 'balance': 0, 'debt': 166}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 4}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 86}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 14}, {'claws': [2], 'balance': 12, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [5], 'balance': 5}, {'claws': [1], 'balance': 4, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2505], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 55}, {'claws': [3, 4, 3], 'balance': 45, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3005], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 35}, {'claws': [100, 100], 'balance': 0, 'debt': 165}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 5}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 85}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 15}, {'claws': [2], 'balance': 13, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [6], 'balance': 5}, {'claws': [1], 'balance': 4, 'debt': 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
two partial refunds{'balance': 937, 'claws': [31, 32], 'debt': 0}{'balance': 937, 'claws': [31, 32], 'debt': 0}Passed
rounding drift{'balance': 41, 'claws': [3, 4, 3], 'debt': 0}{'balance': 41, 'claws': [3, 4, 3], 'debt': 0}Passed
over refund{'balance': 420, 'claws': [60, 20], 'debt': 0}{'balance': 420, 'claws': [60, 20], 'debt': 0}Passed
spent points{'balance': 0, 'claws': [100, 100], 'debt': 0}{'balance': 0, 'claws': [100, 100], 'debt': 169}Failed
debt grows{'balance': 0, 'claws': [30, 30, 30], 'debt': 0}{'balance': 0, 'claws': [30, 30, 30], 'debt': 89}Failed
single half{'balance': 9, 'claws': [2], 'debt': 0}{'balance': 9, 'claws': [2], 'debt': 0}Passed
refund one of many{'balance': 5, 'claws': [0], 'debt': 0}{'balance': 5, 'claws': [0], 'debt': 0}Passed

SHA-256 / e511bf859170188925cd02ba5000140442b0cb6c6af4098eeb3aa2925e1a00a1

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    cum = 0
    clawed = 0
    bal = x['balance']
    debt = 0
    out = []
    for r in x['refunds']:
        cum = min(x['order_total'], cum + r)
        target = (2 * x['earned'] * cum + x['order_total']) // (2 * x['order_total'])
        c = target - clawed
        clawed = target
        take = min(c, bal)
        bal -= take
        debt += c - take
        out.append(c)
    return {'claws': out, 'balance': bal, 'debt': debt}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2501], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 51}, {'claws': [3, 4, 3], 'balance': 41, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3001], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 31}, {'claws': [100, 100], 'balance': 0, 'debt': 169}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 1}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 89}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 11}, {'claws': [2], 'balance': 9, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [2], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2502], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 52}, {'claws': [3, 4, 3], 'balance': 42, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3002], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 32}, {'claws': [100, 100], 'balance': 0, 'debt': 168}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 2}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 88}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 12}, {'claws': [2], 'balance': 10, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [3], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2503], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 53}, {'claws': [3, 4, 3], 'balance': 43, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3003], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 33}, {'claws': [100, 100], 'balance': 0, 'debt': 167}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 3}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 87}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 13}, {'claws': [2], 'balance': 11, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [4], 'balance': 5}, {'claws': [0], 'balance': 5, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2504], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 54}, {'claws': [3, 4, 3], 'balance': 44, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3004], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 34}, {'claws': [100, 100], 'balance': 0, 'debt': 166}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 4}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 86}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 14}, {'claws': [2], 'balance': 12, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [5], 'balance': 5}, {'claws': [1], 'balance': 4, 'debt': 0}]], [['two partial refunds', {'earned': 125, 'order_total': 10000, 'refunds': [2500, 2505], 'balance': 1000}, {'claws': [31, 32], 'balance': 937, 'debt': 0}], ['rounding drift', {'earned': 10, 'order_total': 300, 'refunds': [100, 100, 100], 'balance': 55}, {'claws': [3, 4, 3], 'balance': 45, 'debt': 0}], ['over refund', {'earned': 80, 'order_total': 4000, 'refunds': [3000, 3005], 'balance': 500}, {'claws': [60, 20], 'balance': 420, 'debt': 0}], ['spent points', {'earned': 200, 'order_total': 2000, 'refunds': [1000, 1000], 'balance': 35}, {'claws': [100, 100], 'balance': 0, 'debt': 165}], ['debt grows', {'earned': 90, 'order_total': 900, 'refunds': [300, 300, 300], 'balance': 5}, {'claws': [30, 30, 30], 'balance': 0, 'debt': 85}], ['single half', {'earned': 3, 'order_total': 2, 'refunds': [1], 'balance': 15}, {'claws': [2], 'balance': 13, 'debt': 0}], ['refund one of many', {'earned': 999, 'order_total': 9990, 'refunds': [6], 'balance': 5}, {'claws': [1], 'balance': 4, 'debt': 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
two partial refunds{'balance': 937, 'claws': [31, 32], 'debt': 0}{'balance': 937, 'claws': [31, 32], 'debt': 0}Passed
rounding drift{'balance': 41, 'claws': [3, 4, 3], 'debt': 0}{'balance': 41, 'claws': [3, 4, 3], 'debt': 0}Passed
over refund{'balance': 420, 'claws': [60, 20], 'debt': 0}{'balance': 420, 'claws': [60, 20], 'debt': 0}Passed
spent points{'balance': 0, 'claws': [100, 100], 'debt': 169}{'balance': 0, 'claws': [100, 100], 'debt': 169}Passed
debt grows{'balance': 0, 'claws': [30, 30, 30], 'debt': 89}{'balance': 0, 'claws': [30, 30, 30], 'debt': 89}Passed
single half{'balance': 9, 'claws': [2], 'debt': 0}{'balance': 9, 'claws': [2], 'debt': 0}Passed
refund one of many{'balance': 5, 'claws': [0], 'debt': 0}{'balance': 5, 'claws': [0], 'debt': 0}Passed

SHA-256 / a35503a4c5cf2bb85d534cf4801183d2da562e84e17369c56a823ef028b36be0

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

Case digest / e0a21536a0f7021c4176ec07a2196fa25eb5e2c8bbcab2ad9dec3539d12a4447