{"abstract":"Points stay pending one day longer than the published hold period.","category":"Loyalty points ledgers","checks":7,"contract":"Events: [\"earn\",day,order,pts] starts pending; points post (become available) on day >= earn day + hold. [\"refund\",day,order] cancels a live earn if day < earn day + hold (\"cancelled\"), otherwise claws it back (\"clawed\"; available may go negative); unknown or already refunded orders are \"ignored\". [\"redeem\",day,pts] spends available (posted - spent) points or returns \"insufficient\". [\"query\",day] returns [pending, available]. Return results list.","evaluation_group":"w2-loyalty-points-ledgers-pending-points","failed_approach":"Posting when day - earn >= hold - 1 releases points a day early.","family":"w2-loyalty-points-ledgers-pending-points-posting-day-boundary","id":"FA-60486","implementations":{"attempt":{"sha256":"0403b14542a1d3910eae9aae0ef60e47e73d8d31c5ea8387cb63845662dbfb51","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    earns = {}\n    spent = 0\n    out = []\n    posted = lambda day: sum(e[1] for e in earns.values() if e[2] == 'live' and day - e[0] >= x['hold'] - 1)\n    pending = lambda day: sum(e[1] for e in earns.values() if e[2] == 'live' and day < e[0] + x['hold'])\n    for ev in x['events']:\n        k, day = ev[0], ev[1]\n        if k == 'earn':\n            earns[ev[2]] = [day, ev[3], 'live']\n            out.append('pending')\n        elif k == 'refund':\n            e = earns.get(ev[2])\n            if e is None or e[2] != 'live':\n                out.append('ignored')\n                continue\n            if day < e[0] + x['hold']:\n                e[2] = 'cancelled'\n            else:\n                e[2] = 'clawed'\n            out.append(e[2])\n        elif k == 'redeem':\n            if ev[2] > posted(day) - spent:\n                out.append('insufficient')\n                continue\n            spent += ev[2]\n            out.append('ok')\n        else:\n            out.append([pending(day), posted(day) - spent])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 32]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 41], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 41]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 23]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 31], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 151], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 12], ['query', 5], ['query', 12]]}, ['pending', [12, 0], [0, 12]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 26, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 33]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 42], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 42]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 24]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 32], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 152], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 13], ['query', 5], ['query', 12]]}, ['pending', [13, 0], [0, 13]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 27, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 34]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 43], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 43]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 25]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 33], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 153], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 14], ['query', 5], ['query', 12]]}, ['pending', [14, 0], [0, 14]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 28, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 35]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 44], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 44]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 26]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 34], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 154], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 15], ['query', 5], ['query', 12]]}, ['pending', [15, 0], [0, 15]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 29, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 36]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 45], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 45]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 27]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 35], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 155], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 16], ['query', 5], ['query', 12]]}, ['pending', [16, 0], [0, 16]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 25, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]]]\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":"f755cc4ad81f8451f994957005b41bcf0ba5ebf55f3cb1abf135b78099f03c71","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    earns = {}\n    spent = 0\n    out = []\n    posted = lambda day: sum(e[1] for e in earns.values() if e[2] == 'live' and day > e[0] + x['hold'])\n    pending = lambda day: sum(e[1] for e in earns.values() if e[2] == 'live' and day < e[0] + x['hold'])\n    for ev in x['events']:\n        k, day = ev[0], ev[1]\n        if k == 'earn':\n            earns[ev[2]] = [day, ev[3], 'live']\n            out.append('pending')\n        elif k == 'refund':\n            e = earns.get(ev[2])\n            if e is None or e[2] != 'live':\n                out.append('ignored')\n                continue\n            if day < e[0] + x['hold']:\n                e[2] = 'cancelled'\n            else:\n                e[2] = 'clawed'\n            out.append(e[2])\n        elif k == 'redeem':\n            if ev[2] > posted(day) - spent:\n                out.append('insufficient')\n                continue\n            spent += ev[2]\n            out.append('ok')\n        else:\n            out.append([pending(day), posted(day) - spent])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 32]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 41], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 41]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 23]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 31], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 151], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 12], ['query', 5], ['query', 12]]}, ['pending', [12, 0], [0, 12]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 26, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 33]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 42], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 42]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 24]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 32], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 152], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 13], ['query', 5], ['query', 12]]}, ['pending', [13, 0], [0, 13]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 27, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 34]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 43], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 43]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 25]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 33], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 153], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 14], ['query', 5], ['query', 12]]}, ['pending', [14, 0], [0, 14]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 28, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 35]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 44], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 44]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 26]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 34], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 154], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 15], ['query', 5], ['query', 12]]}, ['pending', [15, 0], [0, 15]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 29, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 36]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 45], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 45]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 27]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 35], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 155], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 16], ['query', 5], ['query', 12]]}, ['pending', [16, 0], [0, 16]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 25, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]]]\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":"2868ebaecdf43582bde2d467978660153522d1cd3c03b37fc6f50a0cfbab5da9","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(x):\n    earns = {}\n    spent = 0\n    out = []\n    posted = lambda day: sum(e[1] for e in earns.values() if e[2] == 'live' and day >= e[0] + x['hold'])\n    pending = lambda day: sum(e[1] for e in earns.values() if e[2] == 'live' and day < e[0] + x['hold'])\n    for ev in x['events']:\n        k, day = ev[0], ev[1]\n        if k == 'earn':\n            earns[ev[2]] = [day, ev[3], 'live']\n            out.append('pending')\n        elif k == 'refund':\n            e = earns.get(ev[2])\n            if e is None or e[2] != 'live':\n                out.append('ignored')\n                continue\n            if day < e[0] + x['hold']:\n                e[2] = 'cancelled'\n            else:\n                e[2] = 'clawed'\n            out.append(e[2])\n        elif k == 'redeem':\n            if ev[2] > posted(day) - spent:\n                out.append('insufficient')\n                continue\n            spent += ev[2]\n            out.append('ok')\n        else:\n            out.append([pending(day), posted(day) - spent])\n    return out\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 32]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 41], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 41]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 23]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 31], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 151], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 12], ['query', 5], ['query', 12]]}, ['pending', [12, 0], [0, 12]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 26, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 33]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 42], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 42]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 24]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 32], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 152], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 13], ['query', 5], ['query', 12]]}, ['pending', [13, 0], [0, 13]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 27, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 34]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 43], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 43]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 25]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 33], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 153], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 14], ['query', 5], ['query', 12]]}, ['pending', [14, 0], [0, 14]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 28, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 35]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 44], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 44]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 26]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 34], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 154], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 15], ['query', 5], ['query', 12]]}, ['pending', [15, 0], [0, 15]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 29, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]], [['posts after hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['query', 29], ['query', 30], ['query', 36]]}, ['pending', [100, 0], [0, 100], [0, 100]]], ['refund in hold', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 2, 'o2', 45], ['refund', 10, 'o1'], ['query', 40]]}, ['pending', 'pending', 'cancelled', [0, 45]]], ['refund after post', {'hold': 14, 'events': [['earn', 0, 'o1', 70], ['redeem', 20, 50], ['refund', 21, 'o1'], ['query', 27]]}, ['pending', 'ok', 'clawed', [0, -50]]], ['double refund', {'hold': 10, 'events': [['earn', 0, 'o1', 35], ['refund', 3, 'o1'], ['refund', 4, 'o1'], ['refund', 5, 'zz']]}, ['pending', 'cancelled', 'ignored', 'ignored']], ['redeem pending', {'hold': 30, 'events': [['earn', 0, 'o1', 100], ['earn', 25, 'o2', 100], ['redeem', 40, 155], ['redeem', 40, 100]]}, ['pending', 'pending', 'insufficient', 'ok']], ['same day earn query', {'hold': 7, 'events': [['earn', 5, 'o1', 16], ['query', 5], ['query', 12]]}, ['pending', [16, 0], [0, 16]]], ['refund near posting', {'hold': 30, 'events': [['earn', 0, 'o1', 60], ['refund', 25, 'o1'], ['query', 60]]}, ['pending', 'cancelled', [0, 0]]]]]\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-pending-points-posting-day-boundary","generated_at":"2026-09-29T14:46:46.017881+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":"Points post on day >= earn day + hold.","root_cause":"Posting requires the day to be strictly after earn day + hold.","sha256":"041e79f0ed2d16a0e67c637f6a09be772553a1e7c08abeff995e2c91fcac9ee7","title":"Pending points hold period: posting day boundary · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":40.229,"exit_code":1,"observations":[{"actual":["pending",[100,100],[0,100],[0,100]],"check":"posts after hold","expected":["pending",[100,0],[0,100],[0,100]],"passed":false},{"actual":["pending","pending","cancelled",[0,41]],"check":"refund in hold","expected":["pending","pending","cancelled",[0,41]],"passed":true},{"actual":["pending","ok","clawed",[0,-50]],"check":"refund after post","expected":["pending","ok","clawed",[0,-50]],"passed":true},{"actual":["pending","cancelled","ignored","ignored"],"check":"double refund","expected":["pending","cancelled","ignored","ignored"],"passed":true},{"actual":["pending","pending","insufficient","ok"],"check":"redeem pending","expected":["pending","pending","insufficient","ok"],"passed":true},{"actual":["pending",[12,0],[0,12]],"check":"same day earn query","expected":["pending",[12,0],[0,12]],"passed":true},{"actual":["pending","cancelled",[0,0]],"check":"refund near posting","expected":["pending","cancelled",[0,0]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"posts after hold\", \"actual\": [\"pending\", [100, 100], [0, 100], [0, 100]], \"expected\": [\"pending\", [100, 0], [0, 100], [0, 100]], \"passed\": false}, {\"check\": \"refund in hold\", \"actual\": [\"pending\", \"pending\", \"cancelled\", [0, 41]], \"expected\": [\"pending\", \"pending\", \"cancelled\", [0, 41]], \"passed\": true}, {\"check\": \"refund after post\", \"actual\": [\"pending\", \"ok\", \"clawed\", [0, -50]], \"expected\": [\"pending\", \"ok\", \"clawed\", [0, -50]], \"passed\": true}, {\"check\": \"double refund\", \"actual\": [\"pending\", \"cancelled\", \"ignored\", \"ignored\"], \"expected\": [\"pending\", \"cancelled\", \"ignored\", \"ignored\"], \"passed\": true}, {\"check\": \"redeem pending\", \"actual\": [\"pending\", \"pending\", \"insufficient\", \"ok\"], \"expected\": [\"pending\", \"pending\", \"insufficient\", \"ok\"], \"passed\": true}, {\"check\": \"same day earn query\", \"actual\": [\"pending\", [12, 0], [0, 12]], \"expected\": [\"pending\", [12, 0], [0, 12]], \"passed\": true}, {\"check\": \"refund near posting\", \"actual\": [\"pending\", \"cancelled\", [0, 0]], \"expected\": [\"pending\", \"cancelled\", [0, 0]], \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.529,"exit_code":1,"observations":[{"actual":["pending",[100,0],[0,0],[0,100]],"check":"posts after hold","expected":["pending",[100,0],[0,100],[0,100]],"passed":false},{"actual":["pending","pending","cancelled",[0,41]],"check":"refund in hold","expected":["pending","pending","cancelled",[0,41]],"passed":true},{"actual":["pending","ok","clawed",[0,-50]],"check":"refund after post","expected":["pending","ok","clawed",[0,-50]],"passed":true},{"actual":["pending","cancelled","ignored","ignored"],"check":"double refund","expected":["pending","cancelled","ignored","ignored"],"passed":true},{"actual":["pending","pending","insufficient","ok"],"check":"redeem pending","expected":["pending","pending","insufficient","ok"],"passed":true},{"actual":["pending",[12,0],[0,0]],"check":"same day earn query","expected":["pending",[12,0],[0,12]],"passed":false},{"actual":["pending","cancelled",[0,0]],"check":"refund near posting","expected":["pending","cancelled",[0,0]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"posts after hold\", \"actual\": [\"pending\", [100, 0], [0, 0], [0, 100]], \"expected\": [\"pending\", [100, 0], [0, 100], [0, 100]], \"passed\": false}, {\"check\": \"refund in hold\", \"actual\": [\"pending\", \"pending\", \"cancelled\", [0, 41]], \"expected\": [\"pending\", \"pending\", \"cancelled\", [0, 41]], \"passed\": true}, {\"check\": \"refund after post\", \"actual\": [\"pending\", \"ok\", \"clawed\", [0, -50]], \"expected\": [\"pending\", \"ok\", \"clawed\", [0, -50]], \"passed\": true}, {\"check\": \"double refund\", \"actual\": [\"pending\", \"cancelled\", \"ignored\", \"ignored\"], \"expected\": [\"pending\", \"cancelled\", \"ignored\", \"ignored\"], \"passed\": true}, {\"check\": \"redeem pending\", \"actual\": [\"pending\", \"pending\", \"insufficient\", \"ok\"], \"expected\": [\"pending\", \"pending\", \"insufficient\", \"ok\"], \"passed\": true}, {\"check\": \"same day earn query\", \"actual\": [\"pending\", [12, 0], [0, 0]], \"expected\": [\"pending\", [12, 0], [0, 12]], \"passed\": false}, {\"check\": \"refund near posting\", \"actual\": [\"pending\", \"cancelled\", [0, 0]], \"expected\": [\"pending\", \"cancelled\", [0, 0]], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":43.053,"exit_code":0,"observations":[{"actual":["pending",[100,0],[0,100],[0,100]],"check":"posts after hold","expected":["pending",[100,0],[0,100],[0,100]],"passed":true},{"actual":["pending","pending","cancelled",[0,41]],"check":"refund in hold","expected":["pending","pending","cancelled",[0,41]],"passed":true},{"actual":["pending","ok","clawed",[0,-50]],"check":"refund after post","expected":["pending","ok","clawed",[0,-50]],"passed":true},{"actual":["pending","cancelled","ignored","ignored"],"check":"double refund","expected":["pending","cancelled","ignored","ignored"],"passed":true},{"actual":["pending","pending","insufficient","ok"],"check":"redeem pending","expected":["pending","pending","insufficient","ok"],"passed":true},{"actual":["pending",[12,0],[0,12]],"check":"same day earn query","expected":["pending",[12,0],[0,12]],"passed":true},{"actual":["pending","cancelled",[0,0]],"check":"refund near posting","expected":["pending","cancelled",[0,0]],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"posts after hold\", \"actual\": [\"pending\", [100, 0], [0, 100], [0, 100]], \"expected\": [\"pending\", [100, 0], [0, 100], [0, 100]], \"passed\": true}, {\"check\": \"refund in hold\", \"actual\": [\"pending\", \"pending\", \"cancelled\", [0, 41]], \"expected\": [\"pending\", \"pending\", \"cancelled\", [0, 41]], \"passed\": true}, {\"check\": \"refund after post\", \"actual\": [\"pending\", \"ok\", \"clawed\", [0, -50]], \"expected\": [\"pending\", \"ok\", \"clawed\", [0, -50]], \"passed\": true}, {\"check\": \"double refund\", \"actual\": [\"pending\", \"cancelled\", \"ignored\", \"ignored\"], \"expected\": [\"pending\", \"cancelled\", \"ignored\", \"ignored\"], \"passed\": true}, {\"check\": \"redeem pending\", \"actual\": [\"pending\", \"pending\", \"insufficient\", \"ok\"], \"expected\": [\"pending\", \"pending\", \"insufficient\", \"ok\"], \"passed\": true}, {\"check\": \"same day earn query\", \"actual\": [\"pending\", [12, 0], [0, 12]], \"expected\": [\"pending\", [12, 0], [0, 12]], \"passed\": true}, {\"check\": \"refund near posting\", \"actual\": [\"pending\", \"cancelled\", [0, 0]], \"expected\": [\"pending\", \"cancelled\", [0, 0]], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}