FA-60596 / Loyalty points ledgers / Open access
Breakage-based revenue recognition: recognition ceiling · case 01
Redemptions beyond the expected level recognize more revenue than was deferred and the liability turns negative.
ROOT CAUSE
The redeemed count is not capped at expected redemptions.
VERIFIED REPAIR
Cap the redemption ratio at 100% of expected.
Unsuccessful approach: Capping at issued points still exceeds expected redemptions.
Case contract
Input {issued, redeemed, value_mc (millicents per point), breakage_bp}. Deferred revenue = floor(issued*value_mc/1000) cents. Expected redemptions = floor(issued*(10000-breakage_bp)/10000); if zero return {"error"}. Recognized = floor(deferred*min(redeemed, expected)/expected); liability = deferred - recognized. Return {deferred, expected, recognized, liability}.
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):
deferred = x['issued'] * x['value_mc'] // 1000
expected = x['issued'] * (10000 - x['breakage_bp']) // 10000
if expected <= 0:
return {'error': 'no expected redemptions'}
used = x['redeemed']
recognized = deferred * used // expected
return {'deferred': deferred, 'expected': expected, 'recognized': recognized, 'liability': deferred - recognized}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['mid program', {'issued': 100000, 'redeemed': 30001, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37501, 'liability': 62499}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1001}, {'deferred': 40000, 'expected': 44995, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1112, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1112, 'liability': 1387}], ['no breakage', {'issued': 700, 'redeemed': 351, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 351, 'liability': 349}], ['all breakage', {'issued': 700, 'redeemed': 1, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 4, 'breakage_bp': 3000}, {'deferred': 399, 'expected': 69999, 'recognized': 70, 'liability': 329}]], [['mid program', {'issued': 100000, 'redeemed': 30002, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37502, 'liability': 62498}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1002}, {'deferred': 40000, 'expected': 44990, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1113, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1113, 'liability': 1386}], ['no breakage', {'issued': 700, 'redeemed': 352, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 352, 'liability': 348}], ['all breakage', {'issued': 700, 'redeemed': 2, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 5, 'breakage_bp': 3000}, {'deferred': 499, 'expected': 69999, 'recognized': 88, 'liability': 411}]], [['mid program', {'issued': 100000, 'redeemed': 30003, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37503, 'liability': 62497}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1003}, {'deferred': 40000, 'expected': 44985, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1114, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1114, 'liability': 1385}], ['no breakage', {'issued': 700, 'redeemed': 353, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 353, 'liability': 347}], ['all breakage', {'issued': 700, 'redeemed': 3, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 6, 'breakage_bp': 3000}, {'deferred': 599, 'expected': 69999, 'recognized': 105, 'liability': 494}]], [['mid program', {'issued': 100000, 'redeemed': 30004, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37505, 'liability': 62495}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1004}, {'deferred': 40000, 'expected': 44980, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1115, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1115, 'liability': 1384}], ['no breakage', {'issued': 700, 'redeemed': 354, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 354, 'liability': 346}], ['all breakage', {'issued': 700, 'redeemed': 4, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 7, 'breakage_bp': 3000}, {'deferred': 699, 'expected': 69999, 'recognized': 123, 'liability': 576}]], [['mid program', {'issued': 100000, 'redeemed': 30005, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37506, 'liability': 62494}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1005}, {'deferred': 40000, 'expected': 44975, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1116, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1116, 'liability': 1383}], ['no breakage', {'issued': 700, 'redeemed': 355, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 355, 'liability': 345}], ['all breakage', {'issued': 700, 'redeemed': 5, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 8, 'breakage_bp': 3000}, {'deferred': 799, 'expected': 69999, 'recognized': 140, 'liability': 659}]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| mid program | {'deferred': 100000, 'expected': 80000, 'liability': 62499, 'recognized': 37501} | {'deferred': 100000, 'expected': 80000, 'liability': 62499, 'recognized': 37501} | Passed |
| fully redeemed | {'deferred': 40000, 'expected': 44995, 'liability': -4, 'recognized': 40004} | {'deferred': 40000, 'expected': 44995, 'liability': 0, 'recognized': 40000} | Failed |
| over redeemed | {'deferred': 1200, 'expected': 850, 'liability': -141, 'recognized': 1341} | {'deferred': 1200, 'expected': 850, 'liability': 0, 'recognized': 1200} | Failed |
| fractional value | {'deferred': 2499, 'expected': 2499, 'liability': 1387, 'recognized': 1112} | {'deferred': 2499, 'expected': 2499, 'liability': 1387, 'recognized': 1112} | Passed |
| no breakage | {'deferred': 700, 'expected': 700, 'liability': 349, 'recognized': 351} | {'deferred': 700, 'expected': 700, 'liability': 349, 'recognized': 351} | Passed |
| all breakage | {'error': 'no expected redemptions'} | {'error': 'no expected redemptions'} | Passed |
| tiny value | {'deferred': 399, 'expected': 69999, 'liability': 329, 'recognized': 70} | {'deferred': 399, 'expected': 69999, 'liability': 329, 'recognized': 70} | Passed |
SHA-256 / 59209a967dd14c9ccaca79c100e3f6054a10b8dcca4759d6201dbe3758deab40
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
deferred = x['issued'] * x['value_mc'] // 1000
expected = x['issued'] * (10000 - x['breakage_bp']) // 10000
if expected <= 0:
return {'error': 'no expected redemptions'}
used = min(x['redeemed'], x['issued'])
recognized = deferred * used // expected
return {'deferred': deferred, 'expected': expected, 'recognized': recognized, 'liability': deferred - recognized}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['mid program', {'issued': 100000, 'redeemed': 30001, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37501, 'liability': 62499}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1001}, {'deferred': 40000, 'expected': 44995, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1112, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1112, 'liability': 1387}], ['no breakage', {'issued': 700, 'redeemed': 351, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 351, 'liability': 349}], ['all breakage', {'issued': 700, 'redeemed': 1, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 4, 'breakage_bp': 3000}, {'deferred': 399, 'expected': 69999, 'recognized': 70, 'liability': 329}]], [['mid program', {'issued': 100000, 'redeemed': 30002, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37502, 'liability': 62498}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1002}, {'deferred': 40000, 'expected': 44990, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1113, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1113, 'liability': 1386}], ['no breakage', {'issued': 700, 'redeemed': 352, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 352, 'liability': 348}], ['all breakage', {'issued': 700, 'redeemed': 2, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 5, 'breakage_bp': 3000}, {'deferred': 499, 'expected': 69999, 'recognized': 88, 'liability': 411}]], [['mid program', {'issued': 100000, 'redeemed': 30003, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37503, 'liability': 62497}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1003}, {'deferred': 40000, 'expected': 44985, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1114, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1114, 'liability': 1385}], ['no breakage', {'issued': 700, 'redeemed': 353, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 353, 'liability': 347}], ['all breakage', {'issued': 700, 'redeemed': 3, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 6, 'breakage_bp': 3000}, {'deferred': 599, 'expected': 69999, 'recognized': 105, 'liability': 494}]], [['mid program', {'issued': 100000, 'redeemed': 30004, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37505, 'liability': 62495}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1004}, {'deferred': 40000, 'expected': 44980, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1115, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1115, 'liability': 1384}], ['no breakage', {'issued': 700, 'redeemed': 354, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 354, 'liability': 346}], ['all breakage', {'issued': 700, 'redeemed': 4, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 7, 'breakage_bp': 3000}, {'deferred': 699, 'expected': 69999, 'recognized': 123, 'liability': 576}]], [['mid program', {'issued': 100000, 'redeemed': 30005, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37506, 'liability': 62494}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1005}, {'deferred': 40000, 'expected': 44975, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1116, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1116, 'liability': 1383}], ['no breakage', {'issued': 700, 'redeemed': 355, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 355, 'liability': 345}], ['all breakage', {'issued': 700, 'redeemed': 5, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 8, 'breakage_bp': 3000}, {'deferred': 799, 'expected': 69999, 'recognized': 140, 'liability': 659}]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| mid program | {'deferred': 100000, 'expected': 80000, 'liability': 62499, 'recognized': 37501} | {'deferred': 100000, 'expected': 80000, 'liability': 62499, 'recognized': 37501} | Passed |
| fully redeemed | {'deferred': 40000, 'expected': 44995, 'liability': -4, 'recognized': 40004} | {'deferred': 40000, 'expected': 44995, 'liability': 0, 'recognized': 40000} | Failed |
| over redeemed | {'deferred': 1200, 'expected': 850, 'liability': -141, 'recognized': 1341} | {'deferred': 1200, 'expected': 850, 'liability': 0, 'recognized': 1200} | Failed |
| fractional value | {'deferred': 2499, 'expected': 2499, 'liability': 1387, 'recognized': 1112} | {'deferred': 2499, 'expected': 2499, 'liability': 1387, 'recognized': 1112} | Passed |
| no breakage | {'deferred': 700, 'expected': 700, 'liability': 349, 'recognized': 351} | {'deferred': 700, 'expected': 700, 'liability': 349, 'recognized': 351} | Passed |
| all breakage | {'error': 'no expected redemptions'} | {'error': 'no expected redemptions'} | Passed |
| tiny value | {'deferred': 399, 'expected': 69999, 'liability': 329, 'recognized': 70} | {'deferred': 399, 'expected': 69999, 'liability': 329, 'recognized': 70} | Passed |
SHA-256 / 4f9fde378bf109fd2376e6979b12284300668618820d8f121b43dc719df4971a
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
deferred = x['issued'] * x['value_mc'] // 1000
expected = x['issued'] * (10000 - x['breakage_bp']) // 10000
if expected <= 0:
return {'error': 'no expected redemptions'}
used = min(x['redeemed'], expected)
recognized = deferred * used // expected
return {'deferred': deferred, 'expected': expected, 'recognized': recognized, 'liability': deferred - recognized}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['mid program', {'issued': 100000, 'redeemed': 30001, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37501, 'liability': 62499}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1001}, {'deferred': 40000, 'expected': 44995, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1112, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1112, 'liability': 1387}], ['no breakage', {'issued': 700, 'redeemed': 351, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 351, 'liability': 349}], ['all breakage', {'issued': 700, 'redeemed': 1, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 4, 'breakage_bp': 3000}, {'deferred': 399, 'expected': 69999, 'recognized': 70, 'liability': 329}]], [['mid program', {'issued': 100000, 'redeemed': 30002, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37502, 'liability': 62498}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1002}, {'deferred': 40000, 'expected': 44990, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1113, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1113, 'liability': 1386}], ['no breakage', {'issued': 700, 'redeemed': 352, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 352, 'liability': 348}], ['all breakage', {'issued': 700, 'redeemed': 2, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 5, 'breakage_bp': 3000}, {'deferred': 499, 'expected': 69999, 'recognized': 88, 'liability': 411}]], [['mid program', {'issued': 100000, 'redeemed': 30003, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37503, 'liability': 62497}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1003}, {'deferred': 40000, 'expected': 44985, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1114, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1114, 'liability': 1385}], ['no breakage', {'issued': 700, 'redeemed': 353, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 353, 'liability': 347}], ['all breakage', {'issued': 700, 'redeemed': 3, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 6, 'breakage_bp': 3000}, {'deferred': 599, 'expected': 69999, 'recognized': 105, 'liability': 494}]], [['mid program', {'issued': 100000, 'redeemed': 30004, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37505, 'liability': 62495}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1004}, {'deferred': 40000, 'expected': 44980, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1115, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1115, 'liability': 1384}], ['no breakage', {'issued': 700, 'redeemed': 354, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 354, 'liability': 346}], ['all breakage', {'issued': 700, 'redeemed': 4, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 7, 'breakage_bp': 3000}, {'deferred': 699, 'expected': 69999, 'recognized': 123, 'liability': 576}]], [['mid program', {'issued': 100000, 'redeemed': 30005, 'value_mc': 1000, 'breakage_bp': 2000}, {'deferred': 100000, 'expected': 80000, 'recognized': 37506, 'liability': 62494}], ['fully redeemed', {'issued': 50000, 'redeemed': 45000, 'value_mc': 800, 'breakage_bp': 1005}, {'deferred': 40000, 'expected': 44975, 'recognized': 40000, 'liability': 0}], ['over redeemed', {'issued': 1000, 'redeemed': 950, 'value_mc': 1200, 'breakage_bp': 1500}, {'deferred': 1200, 'expected': 850, 'recognized': 1200, 'liability': 0}], ['fractional value', {'issued': 3333, 'redeemed': 1116, 'value_mc': 750, 'breakage_bp': 2500}, {'deferred': 2499, 'expected': 2499, 'recognized': 1116, 'liability': 1383}], ['no breakage', {'issued': 700, 'redeemed': 355, 'value_mc': 1000, 'breakage_bp': 0}, {'deferred': 700, 'expected': 700, 'recognized': 355, 'liability': 345}], ['all breakage', {'issued': 700, 'redeemed': 5, 'value_mc': 1000, 'breakage_bp': 10000}, {'error': 'no expected redemptions'}], ['tiny value', {'issued': 99999, 'redeemed': 12345, 'value_mc': 8, 'breakage_bp': 3000}, {'deferred': 799, 'expected': 69999, 'recognized': 140, 'liability': 659}]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| mid program | {'deferred': 100000, 'expected': 80000, 'liability': 62499, 'recognized': 37501} | {'deferred': 100000, 'expected': 80000, 'liability': 62499, 'recognized': 37501} | Passed |
| fully redeemed | {'deferred': 40000, 'expected': 44995, 'liability': 0, 'recognized': 40000} | {'deferred': 40000, 'expected': 44995, 'liability': 0, 'recognized': 40000} | Passed |
| over redeemed | {'deferred': 1200, 'expected': 850, 'liability': 0, 'recognized': 1200} | {'deferred': 1200, 'expected': 850, 'liability': 0, 'recognized': 1200} | Passed |
| fractional value | {'deferred': 2499, 'expected': 2499, 'liability': 1387, 'recognized': 1112} | {'deferred': 2499, 'expected': 2499, 'liability': 1387, 'recognized': 1112} | Passed |
| no breakage | {'deferred': 700, 'expected': 700, 'liability': 349, 'recognized': 351} | {'deferred': 700, 'expected': 700, 'liability': 349, 'recognized': 351} | Passed |
| all breakage | {'error': 'no expected redemptions'} | {'error': 'no expected redemptions'} | Passed |
| tiny value | {'deferred': 399, 'expected': 69999, 'liability': 329, 'recognized': 70} | {'deferred': 399, 'expected': 69999, 'liability': 329, 'recognized': 70} | Passed |
SHA-256 / 706960ac1820d2a9bad824de1f32ae415e5461d59821348a885a754271cc68cb
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:47.090766+00:00.
Case digest / c635a2f631c095eea4ad02c92c427b2d47f6d64ffdd38a543c2bae9f4ccafcb4