{"abstract":"A member with exactly the 500-point minimum cannot redeem.","category":"Loyalty points ledgers","checks":8,"contract":"Input {balance, order_cents, request_pts, max_pct, cpp (cents per point)}. Balance below 500 returns {\"error\":\"below minimum\"}. Points are used in blocks of 100: used = min(request floored to a block, balance floored to a block, cap) where cap = floor(order*max_pct/100 / cpp) floored to a block. Cash due = order - used*cpp. Return {points_used, cash_due}.","evaluation_group":"w2-loyalty-points-ledgers-redemption-blocks","failed_approach":"Checking the requested points instead of the balance lets small balances through.","family":"w2-loyalty-points-ledgers-redemption-blocks-minimum-balance-boundary","id":"FA-60411","implementations":{"attempt":{"sha256":"7aca55faecb23354e4e89855771b8585447baf55d688a271cf6e091dd0b6ecac","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    bal = x['balance']\n    order = x['order_cents']\n    if x['request_pts'] < 500:\n        return {'error': 'below minimum'}\n    blk = 100\n    cap_cents = order * x['max_pct'] // 100\n    cap = cap_cents // x['cpp'] // blk * blk\n    use = min(x['request_pts'] // blk * blk, bal // blk * blk, cap)\n    return {'points_used': use, 'cash_due': order - use * x['cpp']}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['normal', {'balance': 2750, 'order_cents': 4001, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2201}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5001, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1291, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 51, 'cpp': 2}, {'points_used': 1200, 'cash_due': 2600}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1285, 'max_pct': 90, 'cpp': 1}, {'points_used': 1200, 'cash_due': 8800}], ['small balance big request', {'balance': 451, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4002, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2202}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5002, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 2}, {'points_used': 500, 'cash_due': 8999}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1292, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 52, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1295, 'max_pct': 90, 'cpp': 1}, {'points_used': 1200, 'cash_due': 8800}], ['small balance big request', {'balance': 452, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4003, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2203}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5003, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1293, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 53, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1305, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 453, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4004, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2204}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5004, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 2}, {'points_used': 500, 'cash_due': 8999}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1294, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 54, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1315, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 454, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4005, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2205}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5005, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1295, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 55, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1325, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 455, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"fb701156358696738ff8941c5da50dcc42cf5d944067fb6f523dece8bbbeaaa9","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    bal = x['balance']\n    order = x['order_cents']\n    if bal <= 500:\n        return {'error': 'below minimum'}\n    blk = 100\n    cap_cents = order * x['max_pct'] // 100\n    cap = cap_cents // x['cpp'] // blk * blk\n    use = min(x['request_pts'] // blk * blk, bal // blk * blk, cap)\n    return {'points_used': use, 'cash_due': order - use * x['cpp']}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['normal', {'balance': 2750, 'order_cents': 4001, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2201}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5001, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1291, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 51, 'cpp': 2}, {'points_used': 1200, 'cash_due': 2600}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1285, 'max_pct': 90, 'cpp': 1}, {'points_used': 1200, 'cash_due': 8800}], ['small balance big request', {'balance': 451, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4002, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2202}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5002, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 2}, {'points_used': 500, 'cash_due': 8999}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1292, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 52, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1295, 'max_pct': 90, 'cpp': 1}, {'points_used': 1200, 'cash_due': 8800}], ['small balance big request', {'balance': 452, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4003, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2203}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5003, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1293, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 53, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1305, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 453, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4004, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2204}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5004, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 2}, {'points_used': 500, 'cash_due': 8999}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1294, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 54, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1315, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 454, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4005, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2205}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5005, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1295, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 55, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1325, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 455, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"d1143619211eda229af8eb9c724af7bb86a96061694de4d2607d44c24f357b9e","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    bal = x['balance']\n    order = x['order_cents']\n    if bal < 500:\n        return {'error': 'below minimum'}\n    blk = 100\n    cap_cents = order * x['max_pct'] // 100\n    cap = cap_cents // x['cpp'] // blk * blk\n    use = min(x['request_pts'] // blk * blk, bal // blk * blk, cap)\n    return {'points_used': use, 'cash_due': order - use * x['cpp']}\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['normal', {'balance': 2750, 'order_cents': 4001, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2201}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5001, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1291, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 51, 'cpp': 2}, {'points_used': 1200, 'cash_due': 2600}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1285, 'max_pct': 90, 'cpp': 1}, {'points_used': 1200, 'cash_due': 8800}], ['small balance big request', {'balance': 451, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4002, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2202}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5002, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 2}, {'points_used': 500, 'cash_due': 8999}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1292, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 52, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1295, 'max_pct': 90, 'cpp': 1}, {'points_used': 1200, 'cash_due': 8800}], ['small balance big request', {'balance': 452, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4003, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2203}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5003, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1293, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 53, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1305, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 453, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4004, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2204}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5004, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 2}, {'points_used': 500, 'cash_due': 8999}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1294, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 54, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1315, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 454, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]], [['normal', {'balance': 2750, 'order_cents': 4005, 'request_pts': 1850, 'max_pct': 50, 'cpp': 1}, {'points_used': 1800, 'cash_due': 2205}], ['cap binds', {'balance': 9000, 'order_cents': 3000, 'request_pts': 5005, 'max_pct': 40, 'cpp': 1}, {'points_used': 1200, 'cash_due': 1800}], ['minimum balance edge', {'balance': 500, 'order_cents': 9999, 'request_pts': 500, 'max_pct': 100, 'cpp': 3}, {'points_used': 500, 'cash_due': 8499}], ['below minimum', {'balance': 499, 'order_cents': 9999, 'request_pts': 400, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}], ['balance binds', {'balance': 1295, 'order_cents': 50000, 'request_pts': 3000, 'max_pct': 60, 'cpp': 1}, {'points_used': 1200, 'cash_due': 48800}], ['two cents per point', {'balance': 5000, 'order_cents': 5000, 'request_pts': 4000, 'max_pct': 55, 'cpp': 2}, {'points_used': 1300, 'cash_due': 2400}], ['odd request', {'balance': 3000, 'order_cents': 10000, 'request_pts': 1325, 'max_pct': 90, 'cpp': 1}, {'points_used': 1300, 'cash_due': 8700}], ['small balance big request', {'balance': 455, 'order_cents': 9000, 'request_pts': 600, 'max_pct': 100, 'cpp': 1}, {'error': 'below minimum'}]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, solve(args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"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.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-loyalty-points-ledgers-redemption-blocks-minimum-balance-boundary","generated_at":"2026-09-29T14:46:45.362973+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Member point balances, statements and the program liability depend on this ledger rule.","repair":"Reject only balances below 500 points.","root_cause":"The minimum-balance test rejects balances equal to the minimum.","sha256":"a29efeeacbee5c0da970cbf091c80614b0d8218e71bb67f6212370761064d2cc","title":"Points redemption at checkout: minimum balance boundary · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":43.134,"exit_code":1,"observations":[{"actual":{"cash_due":2201,"points_used":1800},"check":"normal","expected":{"cash_due":2201,"points_used":1800},"passed":true},{"actual":{"cash_due":1800,"points_used":1200},"check":"cap binds","expected":{"cash_due":1800,"points_used":1200},"passed":true},{"actual":{"cash_due":8499,"points_used":500},"check":"minimum balance edge","expected":{"cash_due":8499,"points_used":500},"passed":true},{"actual":{"error":"below minimum"},"check":"below minimum","expected":{"error":"below minimum"},"passed":true},{"actual":{"cash_due":48800,"points_used":1200},"check":"balance binds","expected":{"cash_due":48800,"points_used":1200},"passed":true},{"actual":{"cash_due":2600,"points_used":1200},"check":"two cents per point","expected":{"cash_due":2600,"points_used":1200},"passed":true},{"actual":{"cash_due":8800,"points_used":1200},"check":"odd request","expected":{"cash_due":8800,"points_used":1200},"passed":true},{"actual":{"cash_due":8600,"points_used":400},"check":"small balance big request","expected":{"error":"below minimum"},"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"normal\", \"actual\": {\"points_used\": 1800, \"cash_due\": 2201}, \"expected\": {\"points_used\": 1800, \"cash_due\": 2201}, \"passed\": true}, {\"check\": \"cap binds\", \"actual\": {\"points_used\": 1200, \"cash_due\": 1800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 1800}, \"passed\": true}, {\"check\": \"minimum balance edge\", \"actual\": {\"points_used\": 500, \"cash_due\": 8499}, \"expected\": {\"points_used\": 500, \"cash_due\": 8499}, \"passed\": true}, {\"check\": \"below minimum\", \"actual\": {\"error\": \"below minimum\"}, \"expected\": {\"error\": \"below minimum\"}, \"passed\": true}, {\"check\": \"balance binds\", \"actual\": {\"points_used\": 1200, \"cash_due\": 48800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 48800}, \"passed\": true}, {\"check\": \"two cents per point\", \"actual\": {\"points_used\": 1200, \"cash_due\": 2600}, \"expected\": {\"points_used\": 1200, \"cash_due\": 2600}, \"passed\": true}, {\"check\": \"odd request\", \"actual\": {\"points_used\": 1200, \"cash_due\": 8800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 8800}, \"passed\": true}, {\"check\": \"small balance big request\", \"actual\": {\"points_used\": 400, \"cash_due\": 8600}, \"expected\": {\"error\": \"below minimum\"}, \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":41.743,"exit_code":1,"observations":[{"actual":{"cash_due":2201,"points_used":1800},"check":"normal","expected":{"cash_due":2201,"points_used":1800},"passed":true},{"actual":{"cash_due":1800,"points_used":1200},"check":"cap binds","expected":{"cash_due":1800,"points_used":1200},"passed":true},{"actual":{"error":"below minimum"},"check":"minimum balance edge","expected":{"cash_due":8499,"points_used":500},"passed":false},{"actual":{"error":"below minimum"},"check":"below minimum","expected":{"error":"below minimum"},"passed":true},{"actual":{"cash_due":48800,"points_used":1200},"check":"balance binds","expected":{"cash_due":48800,"points_used":1200},"passed":true},{"actual":{"cash_due":2600,"points_used":1200},"check":"two cents per point","expected":{"cash_due":2600,"points_used":1200},"passed":true},{"actual":{"cash_due":8800,"points_used":1200},"check":"odd request","expected":{"cash_due":8800,"points_used":1200},"passed":true},{"actual":{"error":"below minimum"},"check":"small balance big request","expected":{"error":"below minimum"},"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"normal\", \"actual\": {\"points_used\": 1800, \"cash_due\": 2201}, \"expected\": {\"points_used\": 1800, \"cash_due\": 2201}, \"passed\": true}, {\"check\": \"cap binds\", \"actual\": {\"points_used\": 1200, \"cash_due\": 1800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 1800}, \"passed\": true}, {\"check\": \"minimum balance edge\", \"actual\": {\"error\": \"below minimum\"}, \"expected\": {\"points_used\": 500, \"cash_due\": 8499}, \"passed\": false}, {\"check\": \"below minimum\", \"actual\": {\"error\": \"below minimum\"}, \"expected\": {\"error\": \"below minimum\"}, \"passed\": true}, {\"check\": \"balance binds\", \"actual\": {\"points_used\": 1200, \"cash_due\": 48800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 48800}, \"passed\": true}, {\"check\": \"two cents per point\", \"actual\": {\"points_used\": 1200, \"cash_due\": 2600}, \"expected\": {\"points_used\": 1200, \"cash_due\": 2600}, \"passed\": true}, {\"check\": \"odd request\", \"actual\": {\"points_used\": 1200, \"cash_due\": 8800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 8800}, \"passed\": true}, {\"check\": \"small balance big request\", \"actual\": {\"error\": \"below minimum\"}, \"expected\": {\"error\": \"below minimum\"}, \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":42.836,"exit_code":0,"observations":[{"actual":{"cash_due":2201,"points_used":1800},"check":"normal","expected":{"cash_due":2201,"points_used":1800},"passed":true},{"actual":{"cash_due":1800,"points_used":1200},"check":"cap binds","expected":{"cash_due":1800,"points_used":1200},"passed":true},{"actual":{"cash_due":8499,"points_used":500},"check":"minimum balance edge","expected":{"cash_due":8499,"points_used":500},"passed":true},{"actual":{"error":"below minimum"},"check":"below minimum","expected":{"error":"below minimum"},"passed":true},{"actual":{"cash_due":48800,"points_used":1200},"check":"balance binds","expected":{"cash_due":48800,"points_used":1200},"passed":true},{"actual":{"cash_due":2600,"points_used":1200},"check":"two cents per point","expected":{"cash_due":2600,"points_used":1200},"passed":true},{"actual":{"cash_due":8800,"points_used":1200},"check":"odd request","expected":{"cash_due":8800,"points_used":1200},"passed":true},{"actual":{"error":"below minimum"},"check":"small balance big request","expected":{"error":"below minimum"},"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"normal\", \"actual\": {\"points_used\": 1800, \"cash_due\": 2201}, \"expected\": {\"points_used\": 1800, \"cash_due\": 2201}, \"passed\": true}, {\"check\": \"cap binds\", \"actual\": {\"points_used\": 1200, \"cash_due\": 1800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 1800}, \"passed\": true}, {\"check\": \"minimum balance edge\", \"actual\": {\"points_used\": 500, \"cash_due\": 8499}, \"expected\": {\"points_used\": 500, \"cash_due\": 8499}, \"passed\": true}, {\"check\": \"below minimum\", \"actual\": {\"error\": \"below minimum\"}, \"expected\": {\"error\": \"below minimum\"}, \"passed\": true}, {\"check\": \"balance binds\", \"actual\": {\"points_used\": 1200, \"cash_due\": 48800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 48800}, \"passed\": true}, {\"check\": \"two cents per point\", \"actual\": {\"points_used\": 1200, \"cash_due\": 2600}, \"expected\": {\"points_used\": 1200, \"cash_due\": 2600}, \"passed\": true}, {\"check\": \"odd request\", \"actual\": {\"points_used\": 1200, \"cash_due\": 8800}, \"expected\": {\"points_used\": 1200, \"cash_due\": 8800}, \"passed\": true}, {\"check\": \"small balance big request\", \"actual\": {\"error\": \"below minimum\"}, \"expected\": {\"error\": \"below minimum\"}, \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}