{"abstract":"Large lira amounts convert to a EUR intermediate that is off by a few thousandths.","category":"Currency rounding and FX conversion","checks":6,"contract":"solve(amount, frm, to): stipulated legacy-currency triangulation. Fixed rates are units per 1 EUR (DEM 1.95583, FRF 6.55957, ITL 1936.27, ESP 166.386, IEP 0.787564, NLG 2.20371, BEF 40.3399, PTE 200.482, ATS 13.7603, FIM 5.94573). Exponents: ITL, ESP, BEF, PTE 0; others and EUR 2. Legacy to legacy: divide by the source rate, round the EUR intermediate half-up to 3 decimals, multiply by the target rate, round half-up to the target exponent. Legacy to EUR: divide and round half-up to 2 decimals. EUR to legacy: multiply and round half-up to the target exponent. Same currency: round the amount half-up to its exponent. Inverse rates are never used. Unknown codes return 'ERR:currency'.","evaluation_group":"w2-currency_rounding_and_fx_conversion-legacy-euro-triangulation","failed_approach":"Rounding the inverse to ten decimals reduces but does not remove the error for large amounts.","family":"w2-currency_rounding_and_fx_conversion-legacy-euro-triangulation-inverse-rate","id":"FA-61921","implementations":{"attempt":{"sha256":"e9e230f2689ca966f37bc3e290e4e2912bcc89b00aa56fbff52b317249867351","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nfrom decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN\nN = 1\nobservations = []\ndef solve(amount, frm, to):\n    rates = {'DEM': '1.95583', 'FRF': '6.55957', 'ITL': '1936.27', 'ESP': '166.386', 'IEP': '0.787564', 'NLG': '2.20371', 'BEF': '40.3399', 'PTE': '200.482', 'ATS': '13.7603', 'FIM': '5.94573', 'EUR': '1'}\n    zero = ('ITL', 'ESP', 'BEF', 'PTE')\n    if frm not in rates or to not in rates: return 'ERR:currency'\n    def q(v, c):\n        return v.quantize(Decimal(1) if c in zero else Decimal('0.01'), rounding=ROUND_HALF_UP)\n    x = Decimal(amount)\n    if frm == to: return format(q(x, to), 'f')\n    if frm == 'EUR':\n        eur = x\n    elif to == 'EUR':\n        return format(q(x / Decimal(rates[frm]), 'EUR'), 'f')\n    else:\n        eur = (x * (Decimal(1) / Decimal(rates[frm])).quantize(Decimal('1e-10'))).quantize(Decimal('0.001'), rounding=ROUND_HALF_UP)\n    return format(q(eur * Decimal(rates[to]), to), 'f')\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression inverse-rate 1', ('987654321', 'ITL', 'DEM'), '997631.50'),\n  ('regression inverse-rate 2', ('123456789', 'ESP', 'FRF'), '4867136.96'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38'),\n  ('control: lira to euro', ('1000000', 'ITL', 'EUR'), '516.46'),\n  ('control: euro to lira', ('10', 'EUR', 'ITL'), '19363'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101')],\n [('regression inverse-rate 1', ('99999999', 'PTE', 'NLG'), '1099205.90'),\n  ('regression inverse-rate 2', ('123456', 'ESP', 'IEP'), '584.36'),\n  ('partial repair guard 2', ('2701255', 'ESP', 'DEM'), '31752.65'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101'),\n  ('control: unknown', ('5', 'XEU', 'DEM'), 'ERR:currency'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1'),\n  ('control: schilling to markka', ('987.65', 'ATS', 'FIM'), '426.75')],\n [('regression inverse-rate 1', ('2542824', 'FRF', 'ESP'), '64499703'),\n  ('regression inverse-rate 2', ('204024', 'ESP', 'PTE'), '245833'),\n  ('partial repair guard 1', ('2898066', 'FRF', 'ATS'), '6079401.18'),\n  ('partial repair guard 2', ('1936907', 'ESP', 'FRF'), '76360.26'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1'),\n  ('control: schilling to markka', ('987.65', 'ATS', 'FIM'), '426.75'),\n  ('control: franc to franc', ('12.345', 'BEF', 'FRF'), '2.01'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38')],\n [('regression inverse-rate 1', ('2732281.35', 'DEM', 'FRF'), '9163675.15'),\n  ('regression inverse-rate 2', ('1991579.94', 'NLG', 'DEM'), '1767560.97'),\n  ('partial repair guard 1', ('3124364', 'BEF', 'FRF'), '508044.99'),\n  ('partial repair guard 2', ('3838340.18', 'IEP', 'ATS'), '67063390.89'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38'),\n  ('control: lira to euro', ('1000000', 'ITL', 'EUR'), '516.46'),\n  ('control: euro to lira', ('10', 'EUR', 'ITL'), '19363'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101')],\n [('regression inverse-rate 1', ('4401171', 'FIM', 'DEM'), '1447751.96'),\n  ('regression inverse-rate 2', ('2414493', 'DEM', 'PTE'), '247497168'),\n  ('partial repair guard 1', ('3438237', 'IEP', 'FRF'), '28636855.27'),\n  ('partial repair guard 2', ('987654321', 'ITL', 'DEM'), '997631.50'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101'),\n  ('control: unknown', ('5', 'XEU', 'DEM'), 'ERR:currency'),\n  ('control: peseta to punt', ('123456', 'ESP', 'IEP'), '584.36'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1')]]\nfor label, args, expected in cases[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":"8979be4c2040c93433cd401b72e49ca296ff428a17fb6d3629aaaf49f6faf1a1","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nfrom decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN\nN = 1\nobservations = []\ndef solve(amount, frm, to):\n    rates = {'DEM': '1.95583', 'FRF': '6.55957', 'ITL': '1936.27', 'ESP': '166.386', 'IEP': '0.787564', 'NLG': '2.20371', 'BEF': '40.3399', 'PTE': '200.482', 'ATS': '13.7603', 'FIM': '5.94573', 'EUR': '1'}\n    zero = ('ITL', 'ESP', 'BEF', 'PTE')\n    if frm not in rates or to not in rates: return 'ERR:currency'\n    def q(v, c):\n        return v.quantize(Decimal(1) if c in zero else Decimal('0.01'), rounding=ROUND_HALF_UP)\n    x = Decimal(amount)\n    if frm == to: return format(q(x, to), 'f')\n    if frm == 'EUR':\n        eur = x\n    elif to == 'EUR':\n        return format(q(x / Decimal(rates[frm]), 'EUR'), 'f')\n    else:\n        eur = (x * (Decimal(1) / Decimal(rates[frm])).quantize(Decimal('1e-6'))).quantize(Decimal('0.001'), rounding=ROUND_HALF_UP)\n    return format(q(eur * Decimal(rates[to]), to), 'f')\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression inverse-rate 1', ('987654321', 'ITL', 'DEM'), '997631.50'),\n  ('regression inverse-rate 2', ('123456789', 'ESP', 'FRF'), '4867136.96'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38'),\n  ('control: lira to euro', ('1000000', 'ITL', 'EUR'), '516.46'),\n  ('control: euro to lira', ('10', 'EUR', 'ITL'), '19363'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101')],\n [('regression inverse-rate 1', ('99999999', 'PTE', 'NLG'), '1099205.90'),\n  ('regression inverse-rate 2', ('123456', 'ESP', 'IEP'), '584.36'),\n  ('partial repair guard 2', ('2701255', 'ESP', 'DEM'), '31752.65'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101'),\n  ('control: unknown', ('5', 'XEU', 'DEM'), 'ERR:currency'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1'),\n  ('control: schilling to markka', ('987.65', 'ATS', 'FIM'), '426.75')],\n [('regression inverse-rate 1', ('2542824', 'FRF', 'ESP'), '64499703'),\n  ('regression inverse-rate 2', ('204024', 'ESP', 'PTE'), '245833'),\n  ('partial repair guard 1', ('2898066', 'FRF', 'ATS'), '6079401.18'),\n  ('partial repair guard 2', ('1936907', 'ESP', 'FRF'), '76360.26'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1'),\n  ('control: schilling to markka', ('987.65', 'ATS', 'FIM'), '426.75'),\n  ('control: franc to franc', ('12.345', 'BEF', 'FRF'), '2.01'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38')],\n [('regression inverse-rate 1', ('2732281.35', 'DEM', 'FRF'), '9163675.15'),\n  ('regression inverse-rate 2', ('1991579.94', 'NLG', 'DEM'), '1767560.97'),\n  ('partial repair guard 1', ('3124364', 'BEF', 'FRF'), '508044.99'),\n  ('partial repair guard 2', ('3838340.18', 'IEP', 'ATS'), '67063390.89'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38'),\n  ('control: lira to euro', ('1000000', 'ITL', 'EUR'), '516.46'),\n  ('control: euro to lira', ('10', 'EUR', 'ITL'), '19363'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101')],\n [('regression inverse-rate 1', ('4401171', 'FIM', 'DEM'), '1447751.96'),\n  ('regression inverse-rate 2', ('2414493', 'DEM', 'PTE'), '247497168'),\n  ('partial repair guard 1', ('3438237', 'IEP', 'FRF'), '28636855.27'),\n  ('partial repair guard 2', ('987654321', 'ITL', 'DEM'), '997631.50'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101'),\n  ('control: unknown', ('5', 'XEU', 'DEM'), 'ERR:currency'),\n  ('control: peseta to punt', ('123456', 'ESP', 'IEP'), '584.36'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1')]]\nfor label, args, expected in cases[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":"d6c369a5768e2271bd62a82e45e100573d89e7e597ddf58192afa0d5102c4941","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nfrom decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN\nN = 1\nobservations = []\ndef solve(amount, frm, to):\n    rates = {'DEM': '1.95583', 'FRF': '6.55957', 'ITL': '1936.27', 'ESP': '166.386', 'IEP': '0.787564', 'NLG': '2.20371', 'BEF': '40.3399', 'PTE': '200.482', 'ATS': '13.7603', 'FIM': '5.94573', 'EUR': '1'}\n    zero = ('ITL', 'ESP', 'BEF', 'PTE')\n    if frm not in rates or to not in rates: return 'ERR:currency'\n    def q(v, c):\n        return v.quantize(Decimal(1) if c in zero else Decimal('0.01'), rounding=ROUND_HALF_UP)\n    x = Decimal(amount)\n    if frm == to: return format(q(x, to), 'f')\n    if frm == 'EUR':\n        eur = x\n    elif to == 'EUR':\n        return format(q(x / Decimal(rates[frm]), 'EUR'), 'f')\n    else:\n        eur = (x / Decimal(rates[frm])).quantize(Decimal('0.001'), rounding=ROUND_HALF_UP)\n    return format(q(eur * Decimal(rates[to]), to), 'f')\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\ncases = [[('regression inverse-rate 1', ('987654321', 'ITL', 'DEM'), '997631.50'),\n  ('regression inverse-rate 2', ('123456789', 'ESP', 'FRF'), '4867136.96'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38'),\n  ('control: lira to euro', ('1000000', 'ITL', 'EUR'), '516.46'),\n  ('control: euro to lira', ('10', 'EUR', 'ITL'), '19363'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101')],\n [('regression inverse-rate 1', ('99999999', 'PTE', 'NLG'), '1099205.90'),\n  ('regression inverse-rate 2', ('123456', 'ESP', 'IEP'), '584.36'),\n  ('partial repair guard 2', ('2701255', 'ESP', 'DEM'), '31752.65'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101'),\n  ('control: unknown', ('5', 'XEU', 'DEM'), 'ERR:currency'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1'),\n  ('control: schilling to markka', ('987.65', 'ATS', 'FIM'), '426.75')],\n [('regression inverse-rate 1', ('2542824', 'FRF', 'ESP'), '64499703'),\n  ('regression inverse-rate 2', ('204024', 'ESP', 'PTE'), '245833'),\n  ('partial repair guard 1', ('2898066', 'FRF', 'ATS'), '6079401.18'),\n  ('partial repair guard 2', ('1936907', 'ESP', 'FRF'), '76360.26'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1'),\n  ('control: schilling to markka', ('987.65', 'ATS', 'FIM'), '426.75'),\n  ('control: franc to franc', ('12.345', 'BEF', 'FRF'), '2.01'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38')],\n [('regression inverse-rate 1', ('2732281.35', 'DEM', 'FRF'), '9163675.15'),\n  ('regression inverse-rate 2', ('1991579.94', 'NLG', 'DEM'), '1767560.97'),\n  ('partial repair guard 1', ('3124364', 'BEF', 'FRF'), '508044.99'),\n  ('partial repair guard 2', ('3838340.18', 'IEP', 'ATS'), '67063390.89'),\n  ('control: mark to franc', ('100', 'DEM', 'FRF'), '335.38'),\n  ('control: lira to euro', ('1000000', 'ITL', 'EUR'), '516.46'),\n  ('control: euro to lira', ('10', 'EUR', 'ITL'), '19363'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101')],\n [('regression inverse-rate 1', ('4401171', 'FIM', 'DEM'), '1447751.96'),\n  ('regression inverse-rate 2', ('2414493', 'DEM', 'PTE'), '247497168'),\n  ('partial repair guard 1', ('3438237', 'IEP', 'FRF'), '28636855.27'),\n  ('partial repair guard 2', ('987654321', 'ITL', 'DEM'), '997631.50'),\n  ('control: same currency rounding', ('100.5', 'ITL', 'ITL'), '101'),\n  ('control: unknown', ('5', 'XEU', 'DEM'), 'ERR:currency'),\n  ('control: peseta to punt', ('123456', 'ESP', 'IEP'), '584.36'),\n  ('control: guilder to escudo', ('0.01', 'NLG', 'PTE'), '1')]]\nfor label, args, expected in cases[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, bounded teaching model with a stipulated toy contract; it makes no claim of conformance to any real regulation, standard, or institution's rules. 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-currency_rounding_and_fx_conversion-legacy-euro-triangulation-inverse-rate","generated_at":"2026-09-29T14:46:59.753866+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Currency amounts must be rounded at the right stage and in the right unit, or ledgers, quotes and settlements drift by minor units.","repair":"Always divide by the published units-per-EUR rate; inverse rates are not permitted.","root_cause":"The source leg multiplies by 1/rate rounded to six decimals instead of dividing by the fixed rate.","sha256":"429d52eae16078ab069ed35ee8a0d7792fe26327c01577baed467680b812fb9c","title":"Triangulation multiplies by a pre-rounded inverse of the legacy rate · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":43.241,"exit_code":1,"observations":[{"actual":"997631.51","check":"regression inverse-rate 1","expected":"997631.50","passed":false},{"actual":"4867136.92","check":"regression inverse-rate 2","expected":"4867136.96","passed":false},{"actual":"335.38","check":"control: mark to franc","expected":"335.38","passed":true},{"actual":"516.46","check":"control: lira to euro","expected":"516.46","passed":true},{"actual":"19363","check":"control: euro to lira","expected":"19363","passed":true},{"actual":"101","check":"control: same currency rounding","expected":"101","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression inverse-rate 1\", \"actual\": \"997631.51\", \"expected\": \"997631.50\", \"passed\": false}, {\"check\": \"regression inverse-rate 2\", \"actual\": \"4867136.92\", \"expected\": \"4867136.96\", \"passed\": false}, {\"check\": \"control: mark to franc\", \"actual\": \"335.38\", \"expected\": \"335.38\", \"passed\": true}, {\"check\": \"control: lira to euro\", \"actual\": \"516.46\", \"expected\": \"516.46\", \"passed\": true}, {\"check\": \"control: euro to lira\", \"actual\": \"19363\", \"expected\": \"19363\", \"passed\": true}, {\"check\": \"control: same currency rounding\", \"actual\": \"101\", \"expected\": \"101\", \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":44.501,"exit_code":1,"observations":[{"actual":"996748.92","check":"regression inverse-rate 1","expected":"997631.50","passed":false},{"actual":"4867038.93","check":"regression inverse-rate 2","expected":"4867136.96","passed":false},{"actual":"335.38","check":"control: mark to franc","expected":"335.38","passed":true},{"actual":"516.46","check":"control: lira to euro","expected":"516.46","passed":true},{"actual":"19363","check":"control: euro to lira","expected":"19363","passed":true},{"actual":"101","check":"control: same currency rounding","expected":"101","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression inverse-rate 1\", \"actual\": \"996748.92\", \"expected\": \"997631.50\", \"passed\": false}, {\"check\": \"regression inverse-rate 2\", \"actual\": \"4867038.93\", \"expected\": \"4867136.96\", \"passed\": false}, {\"check\": \"control: mark to franc\", \"actual\": \"335.38\", \"expected\": \"335.38\", \"passed\": true}, {\"check\": \"control: lira to euro\", \"actual\": \"516.46\", \"expected\": \"516.46\", \"passed\": true}, {\"check\": \"control: euro to lira\", \"actual\": \"19363\", \"expected\": \"19363\", \"passed\": true}, {\"check\": \"control: same currency rounding\", \"actual\": \"101\", \"expected\": \"101\", \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":44.689,"exit_code":0,"observations":[{"actual":"997631.50","check":"regression inverse-rate 1","expected":"997631.50","passed":true},{"actual":"4867136.96","check":"regression inverse-rate 2","expected":"4867136.96","passed":true},{"actual":"335.38","check":"control: mark to franc","expected":"335.38","passed":true},{"actual":"516.46","check":"control: lira to euro","expected":"516.46","passed":true},{"actual":"19363","check":"control: euro to lira","expected":"19363","passed":true},{"actual":"101","check":"control: same currency rounding","expected":"101","passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"regression inverse-rate 1\", \"actual\": \"997631.50\", \"expected\": \"997631.50\", \"passed\": true}, {\"check\": \"regression inverse-rate 2\", \"actual\": \"4867136.96\", \"expected\": \"4867136.96\", \"passed\": true}, {\"check\": \"control: mark to franc\", \"actual\": \"335.38\", \"expected\": \"335.38\", \"passed\": true}, {\"check\": \"control: lira to euro\", \"actual\": \"516.46\", \"expected\": \"516.46\", \"passed\": true}, {\"check\": \"control: euro to lira\", \"actual\": \"19363\", \"expected\": \"19363\", \"passed\": true}, {\"check\": \"control: same currency rounding\", \"actual\": \"101\", \"expected\": \"101\", \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}