FAILURE MAP
← Case archive

FA-62106 / Currency rounding and FX conversion / Open access

Net amounts are emitted with the raw Decimal exponent · case 01

A net of five dollars is written as '5' rather than '5.00'.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The summed Decimal is formatted without quantizing to the currency exponent.

VERIFIED REPAIR

Quantize each net to its currency exponent before formatting.

Unsuccessful approach: Quantizing every currency to two decimals mis-formats yen and dinar nets.

Case contract

solve(trades): each trade is [pay_ccy, pay_amount, recv_ccy, recv_amount] from our side. Net per currency = received - paid. Return [[ccy, net], ...] sorted by currency code, omitting currencies whose net is exactly zero; nets are plain strings at the currency exponent (JPY 0, KWD 3, else 2).

Why this case matters

Currency amounts must be rounded at the right stage and in the right unit, or ledgers, quotes and settlements drift by minor units.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN
N = 1
observations = []
def solve(trades):
    exps = {'JPY': 0, 'KWD': 3}
    net = {}
    for pay_c, pay_a, rec_c, rec_a in trades:
        net[pay_c] = net.get(pay_c, Decimal(0)) - Decimal(pay_a)
        net[rec_c] = net.get(rec_c, Decimal(0)) + Decimal(rec_a)
    out = []
    for c in sorted(net):
        v = net[c]
        if v == 0: continue
        out.append([c, format(v, 'f')])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression net-exponent 1', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('regression net-exponent 2',
   ([['GBP', '3755.04', 'GBP', '2258.67'], ['JPY', '4', 'GBP', '4532.21'], ['USD', '3940', 'EUR', '3321.70'],
     ['KWD', '2315', 'JPY', '2875']],),
   [['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]),
  ('partial repair guard 1', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('partial repair guard 2', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: empty', ([],), []),
  ('control: unsorted codes',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']])],
 [('regression net-exponent 1',
   ([['EUR', '4780', 'GBP', '4817.42'], ['EUR', '937.30', 'JPY', '1728'], ['GBP', '394', 'USD', '949']],),
   [['EUR', '-5717.30'], ['GBP', '4423.42'], ['JPY', '1728'], ['USD', '949.00']]),
  ('regression net-exponent 2',
   ([['GBP', '2181', 'KWD', '1051.460'], ['JPY', '550', 'EUR', '3789'], ['USD', '506.38', 'JPY', '1697'],
     ['KWD', '1052.629', 'EUR', '763.75']],),
   [['EUR', '4552.75'], ['GBP', '-2181.00'], ['JPY', '1147'], ['KWD', '-1.169'], ['USD', '-506.38']]),
  ('partial repair guard 1',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]),
  ('partial repair guard 2',
   ([['JPY', '1806', 'KWD', '4720.108'], ['USD', '3724.50', 'JPY', '222'], ['KWD', '4720.108', 'JPY', '1806']],),
   [['JPY', '222'], ['USD', '-3724.50']]),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('control: empty', ([],), []),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']])],
 [('regression net-exponent 1',
   ([['EUR', '4958.34', 'JPY', '456'], ['KWD', '149.894', 'EUR', '4865.00'], ['GBP', '4322.22', 'GBP', '4150.09'],
     ['USD', '4134', 'GBP', '151.91'], ['JPY', '456', 'EUR', '4958.34']],),
   [['EUR', '4865.00'], ['GBP', '-20.22'], ['KWD', '-149.894'], ['USD', '-4134.00']]),
  ('regression net-exponent 2', ([['USD', '313.17', 'GBP', '4250'], ['USD', '4617', 'JPY', '3628']],),
   [['GBP', '4250.00'], ['JPY', '3628'], ['USD', '-4930.17']]),
  ('partial repair guard 1',
   ([['GBP', '3755.04', 'GBP', '2258.67'], ['JPY', '4', 'GBP', '4532.21'], ['USD', '3940', 'EUR', '3321.70'],
     ['KWD', '2315', 'JPY', '2875']],),
   [['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]),
  ('partial repair guard 2',
   ([['USD', '3559.19', 'EUR', '1234.78'], ['USD', '3870', 'KWD', '4202'], ['USD', '3791.99', 'KWD', '3508.411'],
     ['USD', '3404.57', 'GBP', '663.83']],),
   [['EUR', '1234.78'], ['GBP', '663.83'], ['KWD', '7710.411'], ['USD', '-14625.75']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']])],
 [('regression net-exponent 1',
   ([['JPY', '1210', 'GBP', '400.13'], ['JPY', '1882', 'EUR', '1387'], ['JPY', '133', 'KWD', '4882'],
     ['GBP', '400.13', 'JPY', '1210']],),
   [['EUR', '1387.00'], ['JPY', '-2015'], ['KWD', '4882.000']]),
  ('regression net-exponent 2',
   ([['EUR', '2398.23', 'JPY', '1126'], ['JPY', '3068', 'JPY', '622'], ['KWD', '86.693', 'GBP', '3555'],
     ['KWD', '3551', 'JPY', '3728']],),
   [['EUR', '-2398.23'], ['GBP', '3555.00'], ['JPY', '2408'], ['KWD', '-3637.693']]),
  ('partial repair guard 1',
   ([['EUR', '4780', 'GBP', '4817.42'], ['EUR', '937.30', 'JPY', '1728'], ['GBP', '394', 'USD', '949']],),
   [['EUR', '-5717.30'], ['GBP', '4423.42'], ['JPY', '1728'], ['USD', '949.00']]),
  ('partial repair guard 2',
   ([['GBP', '2181', 'KWD', '1051.460'], ['JPY', '550', 'EUR', '3789'], ['USD', '506.38', 'JPY', '1697'],
     ['KWD', '1052.629', 'EUR', '763.75']],),
   [['EUR', '4552.75'], ['GBP', '-2181.00'], ['JPY', '1147'], ['KWD', '-1.169'], ['USD', '-506.38']]),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('control: empty', ([],), []),
  ('control: unsorted codes',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']])],
 [('regression net-exponent 1',
   ([['GBP', '3480.24', 'KWD', '2947.345'], ['GBP', '1426.56', 'USD', '1564'], ['KWD', '4552.575', 'GBP', '4813.80'],
     ['EUR', '2477.75', 'GBP', '2397.09']],),
   [['EUR', '-2477.75'], ['GBP', '2304.09'], ['KWD', '-1605.230'], ['USD', '1564.00']]),
  ('regression net-exponent 2',
   ([['USD', '1923', 'GBP', '3301'], ['JPY', '4033', 'JPY', '2447'], ['USD', '819.80', 'EUR', '4094.27'],
     ['USD', '2815.32', 'JPY', '479']],),
   [['EUR', '4094.27'], ['GBP', '3301.00'], ['JPY', '-1107'], ['USD', '-5558.12']]),
  ('partial repair guard 1',
   ([['EUR', '4958.34', 'JPY', '456'], ['KWD', '149.894', 'EUR', '4865.00'], ['GBP', '4322.22', 'GBP', '4150.09'],
     ['USD', '4134', 'GBP', '151.91'], ['JPY', '456', 'EUR', '4958.34']],),
   [['EUR', '4865.00'], ['GBP', '-20.22'], ['KWD', '-149.894'], ['USD', '-4134.00']]),
  ('partial repair guard 2', ([['USD', '313.17', 'GBP', '4250'], ['USD', '4617', 'JPY', '3628']],),
   [['GBP', '4250.00'], ['JPY', '3628'], ['USD', '-4930.17']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']])]]
for label, args, expected in cases[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression net-exponent 1[['GBP', '4'], ['USD', '-5']][['GBP', '4.00'], ['USD', '-5.00']]Failed
regression net-exponent 2[['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315'], ['USD', '-3940']][['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]Failed
partial repair guard 1[['KWD', '-0.250']][['KWD', '-0.250']]Passed
partial repair guard 2[['JPY', '16200'], ['USD', '-108.35']][['JPY', '16200'], ['USD', '-108.35']]Passed
control: fully offset[][]Passed
control: empty[][]Passed
control: unsorted codes[['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']][['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]Passed

SHA-256 / 7e27d28ff53d47e607085fbfb6ba4d024400ab774cf969beaa1517eb07fae48a

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN
N = 1
observations = []
def solve(trades):
    exps = {'JPY': 0, 'KWD': 3}
    net = {}
    for pay_c, pay_a, rec_c, rec_a in trades:
        net[pay_c] = net.get(pay_c, Decimal(0)) - Decimal(pay_a)
        net[rec_c] = net.get(rec_c, Decimal(0)) + Decimal(rec_a)
    out = []
    for c in sorted(net):
        v = net[c]
        if v == 0: continue
        out.append([c, format(v.quantize(Decimal('0.01')), 'f')])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression net-exponent 1', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('regression net-exponent 2',
   ([['GBP', '3755.04', 'GBP', '2258.67'], ['JPY', '4', 'GBP', '4532.21'], ['USD', '3940', 'EUR', '3321.70'],
     ['KWD', '2315', 'JPY', '2875']],),
   [['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]),
  ('partial repair guard 1', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('partial repair guard 2', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: empty', ([],), []),
  ('control: unsorted codes',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']])],
 [('regression net-exponent 1',
   ([['EUR', '4780', 'GBP', '4817.42'], ['EUR', '937.30', 'JPY', '1728'], ['GBP', '394', 'USD', '949']],),
   [['EUR', '-5717.30'], ['GBP', '4423.42'], ['JPY', '1728'], ['USD', '949.00']]),
  ('regression net-exponent 2',
   ([['GBP', '2181', 'KWD', '1051.460'], ['JPY', '550', 'EUR', '3789'], ['USD', '506.38', 'JPY', '1697'],
     ['KWD', '1052.629', 'EUR', '763.75']],),
   [['EUR', '4552.75'], ['GBP', '-2181.00'], ['JPY', '1147'], ['KWD', '-1.169'], ['USD', '-506.38']]),
  ('partial repair guard 1',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]),
  ('partial repair guard 2',
   ([['JPY', '1806', 'KWD', '4720.108'], ['USD', '3724.50', 'JPY', '222'], ['KWD', '4720.108', 'JPY', '1806']],),
   [['JPY', '222'], ['USD', '-3724.50']]),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('control: empty', ([],), []),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']])],
 [('regression net-exponent 1',
   ([['EUR', '4958.34', 'JPY', '456'], ['KWD', '149.894', 'EUR', '4865.00'], ['GBP', '4322.22', 'GBP', '4150.09'],
     ['USD', '4134', 'GBP', '151.91'], ['JPY', '456', 'EUR', '4958.34']],),
   [['EUR', '4865.00'], ['GBP', '-20.22'], ['KWD', '-149.894'], ['USD', '-4134.00']]),
  ('regression net-exponent 2', ([['USD', '313.17', 'GBP', '4250'], ['USD', '4617', 'JPY', '3628']],),
   [['GBP', '4250.00'], ['JPY', '3628'], ['USD', '-4930.17']]),
  ('partial repair guard 1',
   ([['GBP', '3755.04', 'GBP', '2258.67'], ['JPY', '4', 'GBP', '4532.21'], ['USD', '3940', 'EUR', '3321.70'],
     ['KWD', '2315', 'JPY', '2875']],),
   [['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]),
  ('partial repair guard 2',
   ([['USD', '3559.19', 'EUR', '1234.78'], ['USD', '3870', 'KWD', '4202'], ['USD', '3791.99', 'KWD', '3508.411'],
     ['USD', '3404.57', 'GBP', '663.83']],),
   [['EUR', '1234.78'], ['GBP', '663.83'], ['KWD', '7710.411'], ['USD', '-14625.75']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']])],
 [('regression net-exponent 1',
   ([['JPY', '1210', 'GBP', '400.13'], ['JPY', '1882', 'EUR', '1387'], ['JPY', '133', 'KWD', '4882'],
     ['GBP', '400.13', 'JPY', '1210']],),
   [['EUR', '1387.00'], ['JPY', '-2015'], ['KWD', '4882.000']]),
  ('regression net-exponent 2',
   ([['EUR', '2398.23', 'JPY', '1126'], ['JPY', '3068', 'JPY', '622'], ['KWD', '86.693', 'GBP', '3555'],
     ['KWD', '3551', 'JPY', '3728']],),
   [['EUR', '-2398.23'], ['GBP', '3555.00'], ['JPY', '2408'], ['KWD', '-3637.693']]),
  ('partial repair guard 1',
   ([['EUR', '4780', 'GBP', '4817.42'], ['EUR', '937.30', 'JPY', '1728'], ['GBP', '394', 'USD', '949']],),
   [['EUR', '-5717.30'], ['GBP', '4423.42'], ['JPY', '1728'], ['USD', '949.00']]),
  ('partial repair guard 2',
   ([['GBP', '2181', 'KWD', '1051.460'], ['JPY', '550', 'EUR', '3789'], ['USD', '506.38', 'JPY', '1697'],
     ['KWD', '1052.629', 'EUR', '763.75']],),
   [['EUR', '4552.75'], ['GBP', '-2181.00'], ['JPY', '1147'], ['KWD', '-1.169'], ['USD', '-506.38']]),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('control: empty', ([],), []),
  ('control: unsorted codes',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']])],
 [('regression net-exponent 1',
   ([['GBP', '3480.24', 'KWD', '2947.345'], ['GBP', '1426.56', 'USD', '1564'], ['KWD', '4552.575', 'GBP', '4813.80'],
     ['EUR', '2477.75', 'GBP', '2397.09']],),
   [['EUR', '-2477.75'], ['GBP', '2304.09'], ['KWD', '-1605.230'], ['USD', '1564.00']]),
  ('regression net-exponent 2',
   ([['USD', '1923', 'GBP', '3301'], ['JPY', '4033', 'JPY', '2447'], ['USD', '819.80', 'EUR', '4094.27'],
     ['USD', '2815.32', 'JPY', '479']],),
   [['EUR', '4094.27'], ['GBP', '3301.00'], ['JPY', '-1107'], ['USD', '-5558.12']]),
  ('partial repair guard 1',
   ([['EUR', '4958.34', 'JPY', '456'], ['KWD', '149.894', 'EUR', '4865.00'], ['GBP', '4322.22', 'GBP', '4150.09'],
     ['USD', '4134', 'GBP', '151.91'], ['JPY', '456', 'EUR', '4958.34']],),
   [['EUR', '4865.00'], ['GBP', '-20.22'], ['KWD', '-149.894'], ['USD', '-4134.00']]),
  ('partial repair guard 2', ([['USD', '313.17', 'GBP', '4250'], ['USD', '4617', 'JPY', '3628']],),
   [['GBP', '4250.00'], ['JPY', '3628'], ['USD', '-4930.17']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']])]]
for label, args, expected in cases[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression net-exponent 1[['GBP', '4.00'], ['USD', '-5.00']][['GBP', '4.00'], ['USD', '-5.00']]Passed
regression net-exponent 2[['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871.00'], ['KWD', '-2315.00'], ['USD', '-3940.00']][['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]Failed
partial repair guard 1[['KWD', '-0.25']][['KWD', '-0.250']]Failed
partial repair guard 2[['JPY', '16200.00'], ['USD', '-108.35']][['JPY', '16200'], ['USD', '-108.35']]Failed
control: fully offset[][]Passed
control: empty[][]Passed
control: unsorted codes[['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.31']][['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]Failed

SHA-256 / 025facf7059ef4e383c9148fd99298a07fe9751bad07e5a320432fa8752b25a2

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
from decimal import Decimal, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_FLOOR, ROUND_CEILING, ROUND_DOWN, ROUND_UP, ROUND_HALF_DOWN
N = 1
observations = []
def solve(trades):
    exps = {'JPY': 0, 'KWD': 3}
    net = {}
    for pay_c, pay_a, rec_c, rec_a in trades:
        net[pay_c] = net.get(pay_c, Decimal(0)) - Decimal(pay_a)
        net[rec_c] = net.get(rec_c, Decimal(0)) + Decimal(rec_a)
    out = []
    for c in sorted(net):
        v = net[c]
        if v == 0: continue
        out.append([c, format(v.quantize(Decimal(1).scaleb(-exps.get(c, 2))), 'f')])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression net-exponent 1', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('regression net-exponent 2',
   ([['GBP', '3755.04', 'GBP', '2258.67'], ['JPY', '4', 'GBP', '4532.21'], ['USD', '3940', 'EUR', '3321.70'],
     ['KWD', '2315', 'JPY', '2875']],),
   [['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]),
  ('partial repair guard 1', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('partial repair guard 2', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: empty', ([],), []),
  ('control: unsorted codes',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']])],
 [('regression net-exponent 1',
   ([['EUR', '4780', 'GBP', '4817.42'], ['EUR', '937.30', 'JPY', '1728'], ['GBP', '394', 'USD', '949']],),
   [['EUR', '-5717.30'], ['GBP', '4423.42'], ['JPY', '1728'], ['USD', '949.00']]),
  ('regression net-exponent 2',
   ([['GBP', '2181', 'KWD', '1051.460'], ['JPY', '550', 'EUR', '3789'], ['USD', '506.38', 'JPY', '1697'],
     ['KWD', '1052.629', 'EUR', '763.75']],),
   [['EUR', '4552.75'], ['GBP', '-2181.00'], ['JPY', '1147'], ['KWD', '-1.169'], ['USD', '-506.38']]),
  ('partial repair guard 1',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]),
  ('partial repair guard 2',
   ([['JPY', '1806', 'KWD', '4720.108'], ['USD', '3724.50', 'JPY', '222'], ['KWD', '4720.108', 'JPY', '1806']],),
   [['JPY', '222'], ['USD', '-3724.50']]),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('control: empty', ([],), []),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']])],
 [('regression net-exponent 1',
   ([['EUR', '4958.34', 'JPY', '456'], ['KWD', '149.894', 'EUR', '4865.00'], ['GBP', '4322.22', 'GBP', '4150.09'],
     ['USD', '4134', 'GBP', '151.91'], ['JPY', '456', 'EUR', '4958.34']],),
   [['EUR', '4865.00'], ['GBP', '-20.22'], ['KWD', '-149.894'], ['USD', '-4134.00']]),
  ('regression net-exponent 2', ([['USD', '313.17', 'GBP', '4250'], ['USD', '4617', 'JPY', '3628']],),
   [['GBP', '4250.00'], ['JPY', '3628'], ['USD', '-4930.17']]),
  ('partial repair guard 1',
   ([['GBP', '3755.04', 'GBP', '2258.67'], ['JPY', '4', 'GBP', '4532.21'], ['USD', '3940', 'EUR', '3321.70'],
     ['KWD', '2315', 'JPY', '2875']],),
   [['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]),
  ('partial repair guard 2',
   ([['USD', '3559.19', 'EUR', '1234.78'], ['USD', '3870', 'KWD', '4202'], ['USD', '3791.99', 'KWD', '3508.411'],
     ['USD', '3404.57', 'GBP', '663.83']],),
   [['EUR', '1234.78'], ['GBP', '663.83'], ['KWD', '7710.411'], ['USD', '-14625.75']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']])],
 [('regression net-exponent 1',
   ([['JPY', '1210', 'GBP', '400.13'], ['JPY', '1882', 'EUR', '1387'], ['JPY', '133', 'KWD', '4882'],
     ['GBP', '400.13', 'JPY', '1210']],),
   [['EUR', '1387.00'], ['JPY', '-2015'], ['KWD', '4882.000']]),
  ('regression net-exponent 2',
   ([['EUR', '2398.23', 'JPY', '1126'], ['JPY', '3068', 'JPY', '622'], ['KWD', '86.693', 'GBP', '3555'],
     ['KWD', '3551', 'JPY', '3728']],),
   [['EUR', '-2398.23'], ['GBP', '3555.00'], ['JPY', '2408'], ['KWD', '-3637.693']]),
  ('partial repair guard 1',
   ([['EUR', '4780', 'GBP', '4817.42'], ['EUR', '937.30', 'JPY', '1728'], ['GBP', '394', 'USD', '949']],),
   [['EUR', '-5717.30'], ['GBP', '4423.42'], ['JPY', '1728'], ['USD', '949.00']]),
  ('partial repair guard 2',
   ([['GBP', '2181', 'KWD', '1051.460'], ['JPY', '550', 'EUR', '3789'], ['USD', '506.38', 'JPY', '1697'],
     ['KWD', '1052.629', 'EUR', '763.75']],),
   [['EUR', '4552.75'], ['GBP', '-2181.00'], ['JPY', '1147'], ['KWD', '-1.169'], ['USD', '-506.38']]),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']]),
  ('control: empty', ([],), []),
  ('control: unsorted codes',
   ([['USD', '1.00', 'EUR', '0.92'], ['GBP', '0.79', 'USD', '1.00'], ['KWD', '0.307', 'CHF', '0.88']],),
   [['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']])],
 [('regression net-exponent 1',
   ([['GBP', '3480.24', 'KWD', '2947.345'], ['GBP', '1426.56', 'USD', '1564'], ['KWD', '4552.575', 'GBP', '4813.80'],
     ['EUR', '2477.75', 'GBP', '2397.09']],),
   [['EUR', '-2477.75'], ['GBP', '2304.09'], ['KWD', '-1605.230'], ['USD', '1564.00']]),
  ('regression net-exponent 2',
   ([['USD', '1923', 'GBP', '3301'], ['JPY', '4033', 'JPY', '2447'], ['USD', '819.80', 'EUR', '4094.27'],
     ['USD', '2815.32', 'JPY', '479']],),
   [['EUR', '4094.27'], ['GBP', '3301.00'], ['JPY', '-1107'], ['USD', '-5558.12']]),
  ('partial repair guard 1',
   ([['EUR', '4958.34', 'JPY', '456'], ['KWD', '149.894', 'EUR', '4865.00'], ['GBP', '4322.22', 'GBP', '4150.09'],
     ['USD', '4134', 'GBP', '151.91'], ['JPY', '456', 'EUR', '4958.34']],),
   [['EUR', '4865.00'], ['GBP', '-20.22'], ['KWD', '-149.894'], ['USD', '-4134.00']]),
  ('partial repair guard 2', ([['USD', '313.17', 'GBP', '4250'], ['USD', '4617', 'JPY', '3628']],),
   [['GBP', '4250.00'], ['JPY', '3628'], ['USD', '-4930.17']]),
  ('control: chained trades', ([['USD', '108.35', 'EUR', '100.00'], ['EUR', '100.00', 'JPY', '16200']],),
   [['JPY', '16200'], ['USD', '-108.35']]),
  ('control: short amounts', ([['USD', '5', 'GBP', '4']],), [['GBP', '4.00'], ['USD', '-5.00']]),
  ('control: fully offset', ([['USD', '10.00', 'EUR', '9.20'], ['EUR', '9.20', 'USD', '10.00']],), []),
  ('control: same currency swap', ([['KWD', '1.250', 'KWD', '1.000']],), [['KWD', '-0.250']])]]
for label, args, expected in cases[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression net-exponent 1[['GBP', '4.00'], ['USD', '-5.00']][['GBP', '4.00'], ['USD', '-5.00']]Passed
regression net-exponent 2[['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']][['EUR', '3321.70'], ['GBP', '3035.84'], ['JPY', '2871'], ['KWD', '-2315.000'], ['USD', '-3940.00']]Passed
partial repair guard 1[['KWD', '-0.250']][['KWD', '-0.250']]Passed
partial repair guard 2[['JPY', '16200'], ['USD', '-108.35']][['JPY', '16200'], ['USD', '-108.35']]Passed
control: fully offset[][]Passed
control: empty[][]Passed
control: unsorted codes[['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']][['CHF', '0.88'], ['EUR', '0.92'], ['GBP', '-0.79'], ['KWD', '-0.307']]Passed

SHA-256 / 217260206e6a62b2aa2aa7cc045ac6158e7ba8f34c575af68f60395f04fcf952

Verification & scope

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.

Observations recorded using Python 3.12.14 at 2026-09-29T14:47:01.462110+00:00.

Case digest / 6f2edb95bbb155de3c9311bd8c6e7282fe5845307bfc97a9a25a893a8cafc053