{"abstract":"Swiss card payments are rounded to 5 centimes.","category":"Ride-hailing fare and surge pricing","checks":7,"contract":"Convert a fare to the payment currency with the directed rate fx[FROM+TO] = [num, den] (half up), then, for cash payments only, round half up to the payment currency cash step (CHF 5 centimes, SEK 100 ore, others 1). Card and wallet payments are not cash-rounded. Return the amount in minor units of the payment currency.","evaluation_group":"w2-ride-hailing-fare-surge-cash-rounding-fx","failed_approach":"Excluding only cards still rounds wallet payments.","family":"w2-ride-hailing-fare-surge-cash-rounding-fx-cash-only-rounding","id":"FA-85711","implementations":{"attempt":{"sha256":"2b9fc175b1ed36950c5d475095f6a7dbd6f97191e805843a0abd2fb65ed5fd9f","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(fare_cents, fare_ccy, pay_ccy, method, fx, cash_step):\n    amt = fare_cents\n    if pay_ccy != fare_ccy:\n        num, den = fx[fare_ccy + pay_ccy]\n        amt = (amt * num * 2 + den) // (2 * den)\n    if method != 'card':\n        step = cash_step.get(pay_ccy, 1)\n        amt = (amt * 2 + step) // (2 * step) * step\n    return amt\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('regression: cash-only rounding',\n   [4478, 'CHF', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   4478),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'EUR', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14154),\n  ('normal control 1',\n   [1003, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 2',\n   [1999, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1880),\n  ('normal control 3',\n   [2502, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2350),\n  ('normal control 4',\n   [1234, 'CHF', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1283)],\n [('regression: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('partial repair probe: cash-only rounding',\n   [2928, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2928),\n  ('second regression',\n   [1003, 'EUR', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   943),\n  ('normal control 1',\n   [1234, 'SEK', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1200),\n  ('normal control 2',\n   [2502, 'EUR', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('normal control 3',\n   [1003, 'SEK', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 4',\n   [517, 'SEK', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   500)],\n [('regression: cash-only rounding',\n   [1003, 'EUR', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   943),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'SEK', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1234),\n  ('normal control 1',\n   [1796, 'SEK', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   162),\n  ('normal control 2',\n   [1003, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 3',\n   [2502, 'CHF', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2500),\n  ('normal control 4',\n   [1234, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   111)],\n [('regression: cash-only rounding',\n   [2502, 'SEK', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('partial repair probe: cash-only rounding',\n   [1003, 'SEK', 'SEK', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1003),\n  ('second regression',\n   [2502, 'EUR', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2352),\n  ('normal control 1',\n   [1234, 'EUR', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14200),\n  ('normal control 2',\n   [2502, 'EUR', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('normal control 3',\n   [2502, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2350),\n  ('normal control 4',\n   [4790, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   4505)],\n [('regression: cash-only rounding',\n   [1999, 'SEK', 'SEK', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'EUR', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14154),\n  ('normal control 1',\n   [1999, 'CHF', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2079),\n  ('normal control 2',\n   [1234, 'EUR', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1160),\n  ('normal control 3',\n   [1234, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1160),\n  ('normal control 4',\n   [1003, 'EUR', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1003)]]\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":"2fbf824623ed896a12ab19c77a840a444ff0f15ca35d0a33c16d755432d00990","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(fare_cents, fare_ccy, pay_ccy, method, fx, cash_step):\n    amt = fare_cents\n    if pay_ccy != fare_ccy:\n        num, den = fx[fare_ccy + pay_ccy]\n        amt = (amt * num * 2 + den) // (2 * den)\n    if True:\n        step = cash_step.get(pay_ccy, 1)\n        amt = (amt * 2 + step) // (2 * step) * step\n    return amt\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('regression: cash-only rounding',\n   [4478, 'CHF', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   4478),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'EUR', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14154),\n  ('normal control 1',\n   [1003, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 2',\n   [1999, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1880),\n  ('normal control 3',\n   [2502, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2350),\n  ('normal control 4',\n   [1234, 'CHF', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1283)],\n [('regression: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('partial repair probe: cash-only rounding',\n   [2928, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2928),\n  ('second regression',\n   [1003, 'EUR', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   943),\n  ('normal control 1',\n   [1234, 'SEK', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1200),\n  ('normal control 2',\n   [2502, 'EUR', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('normal control 3',\n   [1003, 'SEK', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 4',\n   [517, 'SEK', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   500)],\n [('regression: cash-only rounding',\n   [1003, 'EUR', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   943),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'SEK', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1234),\n  ('normal control 1',\n   [1796, 'SEK', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   162),\n  ('normal control 2',\n   [1003, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 3',\n   [2502, 'CHF', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2500),\n  ('normal control 4',\n   [1234, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   111)],\n [('regression: cash-only rounding',\n   [2502, 'SEK', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('partial repair probe: cash-only rounding',\n   [1003, 'SEK', 'SEK', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1003),\n  ('second regression',\n   [2502, 'EUR', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2352),\n  ('normal control 1',\n   [1234, 'EUR', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14200),\n  ('normal control 2',\n   [2502, 'EUR', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('normal control 3',\n   [2502, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2350),\n  ('normal control 4',\n   [4790, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   4505)],\n [('regression: cash-only rounding',\n   [1999, 'SEK', 'SEK', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'EUR', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14154),\n  ('normal control 1',\n   [1999, 'CHF', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2079),\n  ('normal control 2',\n   [1234, 'EUR', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1160),\n  ('normal control 3',\n   [1234, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1160),\n  ('normal control 4',\n   [1003, 'EUR', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1003)]]\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":"86bf9dfcc4cd1722e808a17de9cc4dc3554500945fb23a43a426d17f228358bc","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(fare_cents, fare_ccy, pay_ccy, method, fx, cash_step):\n    amt = fare_cents\n    if pay_ccy != fare_ccy:\n        num, den = fx[fare_ccy + pay_ccy]\n        amt = (amt * num * 2 + den) // (2 * den)\n    if method == 'cash':\n        step = cash_step.get(pay_ccy, 1)\n        amt = (amt * 2 + step) // (2 * step) * step\n    return amt\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('regression: cash-only rounding',\n   [4478, 'CHF', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   4478),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'EUR', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14154),\n  ('normal control 1',\n   [1003, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 2',\n   [1999, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1880),\n  ('normal control 3',\n   [2502, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2350),\n  ('normal control 4',\n   [1234, 'CHF', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1283)],\n [('regression: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('partial repair probe: cash-only rounding',\n   [2928, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2928),\n  ('second regression',\n   [1003, 'EUR', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   943),\n  ('normal control 1',\n   [1234, 'SEK', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1200),\n  ('normal control 2',\n   [2502, 'EUR', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('normal control 3',\n   [1003, 'SEK', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 4',\n   [517, 'SEK', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   500)],\n [('regression: cash-only rounding',\n   [1003, 'EUR', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   943),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'SEK', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1234),\n  ('normal control 1',\n   [1796, 'SEK', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   162),\n  ('normal control 2',\n   [1003, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   90),\n  ('normal control 3',\n   [2502, 'CHF', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2500),\n  ('normal control 4',\n   [1234, 'SEK', 'EUR', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   111)],\n [('regression: cash-only rounding',\n   [2502, 'SEK', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('partial repair probe: cash-only rounding',\n   [1003, 'SEK', 'SEK', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1003),\n  ('second regression',\n   [2502, 'EUR', 'CHF', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2352),\n  ('normal control 1',\n   [1234, 'EUR', 'SEK', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14200),\n  ('normal control 2',\n   [2502, 'EUR', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2502),\n  ('normal control 3',\n   [2502, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2350),\n  ('normal control 4',\n   [4790, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   4505)],\n [('regression: cash-only rounding',\n   [1999, 'SEK', 'SEK', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('partial repair probe: cash-only rounding',\n   [1999, 'CHF', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1999),\n  ('second regression',\n   [1234, 'EUR', 'SEK', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   14154),\n  ('normal control 1',\n   [1999, 'CHF', 'EUR', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   2079),\n  ('normal control 2',\n   [1234, 'EUR', 'CHF', 'wallet',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1160),\n  ('normal control 3',\n   [1234, 'EUR', 'CHF', 'cash',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1160),\n  ('normal control 4',\n   [1003, 'EUR', 'EUR', 'card',\n    {'CHFEUR': [104, 100], 'EURCHF': [94, 100], 'EURSEK': [1147, 100], 'SEKEUR': [9, 100]},\n    {'CHF': 5, 'SEK': 100}],\n   1003)]]\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":"A deterministic toy pricing contract stipulated for this example; it does not reproduce the pricing of any real ride-hailing operator or regulator. 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-ride-hailing-fare-surge-cash-rounding-fx-cash-only-rounding","generated_at":"2026-09-29T14:50:42.920413+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Ride-hailing prices are computed per trip at scale; ordering, unit and boundary slips become systematic over- or under-charging.","repair":"Round only cash payments.","root_cause":"Cash rounding runs for every payment method.","sha256":"0f99afd37cbc90bcc90678bf362dddd502d27ccf7e886bb52796c3fb761e997c","title":"Card payments rounded to the cash step · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":40.233,"exit_code":1,"observations":[{"actual":4478,"check":"regression: cash-only rounding","expected":4478,"passed":true},{"actual":2000,"check":"partial repair probe: cash-only rounding","expected":1999,"passed":false},{"actual":14154,"check":"second regression","expected":14154,"passed":true},{"actual":90,"check":"normal control 1","expected":90,"passed":true},{"actual":1880,"check":"normal control 2","expected":1880,"passed":true},{"actual":2350,"check":"normal control 3","expected":2350,"passed":true},{"actual":1283,"check":"normal control 4","expected":1283,"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: cash-only rounding\", \"actual\": 4478, \"expected\": 4478, \"passed\": true}, {\"check\": \"partial repair probe: cash-only rounding\", \"actual\": 2000, \"expected\": 1999, \"passed\": false}, {\"check\": \"second regression\", \"actual\": 14154, \"expected\": 14154, \"passed\": true}, {\"check\": \"normal control 1\", \"actual\": 90, \"expected\": 90, \"passed\": true}, {\"check\": \"normal control 2\", \"actual\": 1880, \"expected\": 1880, \"passed\": true}, {\"check\": \"normal control 3\", \"actual\": 2350, \"expected\": 2350, \"passed\": true}, {\"check\": \"normal control 4\", \"actual\": 1283, \"expected\": 1283, \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.756,"exit_code":1,"observations":[{"actual":4480,"check":"regression: cash-only rounding","expected":4478,"passed":false},{"actual":2000,"check":"partial repair probe: cash-only rounding","expected":1999,"passed":false},{"actual":14200,"check":"second regression","expected":14154,"passed":false},{"actual":90,"check":"normal control 1","expected":90,"passed":true},{"actual":1880,"check":"normal control 2","expected":1880,"passed":true},{"actual":2350,"check":"normal control 3","expected":2350,"passed":true},{"actual":1283,"check":"normal control 4","expected":1283,"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: cash-only rounding\", \"actual\": 4480, \"expected\": 4478, \"passed\": false}, {\"check\": \"partial repair probe: cash-only rounding\", \"actual\": 2000, \"expected\": 1999, \"passed\": false}, {\"check\": \"second regression\", \"actual\": 14200, \"expected\": 14154, \"passed\": false}, {\"check\": \"normal control 1\", \"actual\": 90, \"expected\": 90, \"passed\": true}, {\"check\": \"normal control 2\", \"actual\": 1880, \"expected\": 1880, \"passed\": true}, {\"check\": \"normal control 3\", \"actual\": 2350, \"expected\": 2350, \"passed\": true}, {\"check\": \"normal control 4\", \"actual\": 1283, \"expected\": 1283, \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":40.706,"exit_code":0,"observations":[{"actual":4478,"check":"regression: cash-only rounding","expected":4478,"passed":true},{"actual":1999,"check":"partial repair probe: cash-only rounding","expected":1999,"passed":true},{"actual":14154,"check":"second regression","expected":14154,"passed":true},{"actual":90,"check":"normal control 1","expected":90,"passed":true},{"actual":1880,"check":"normal control 2","expected":1880,"passed":true},{"actual":2350,"check":"normal control 3","expected":2350,"passed":true},{"actual":1283,"check":"normal control 4","expected":1283,"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression: cash-only rounding\", \"actual\": 4478, \"expected\": 4478, \"passed\": true}, {\"check\": \"partial repair probe: cash-only rounding\", \"actual\": 1999, \"expected\": 1999, \"passed\": true}, {\"check\": \"second regression\", \"actual\": 14154, \"expected\": 14154, \"passed\": true}, {\"check\": \"normal control 1\", \"actual\": 90, \"expected\": 90, \"passed\": true}, {\"check\": \"normal control 2\", \"actual\": 1880, \"expected\": 1880, \"passed\": true}, {\"check\": \"normal control 3\", \"actual\": 2350, \"expected\": 2350, \"passed\": true}, {\"check\": \"normal control 4\", \"actual\": 1283, \"expected\": 1283, \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}