FA-61956 / Currency rounding and FX conversion / Open access
The rounding difference is subtracted from the plug line · case 01
Converted lines sum to a value two differences away from the control total.
ROOT CAUSE
The plug applies conv[i] -= diff instead of adding the signed difference.
THE FAILURE
The plug applies conv[i] -= diff instead of adding the signed difference.
Unsuccessful approach: Adding the absolute difference only works when the rounded lines under-shoot the total.
Case contract
solve(lines, rate, exp): lines are source-currency decimal strings (credits negative), rate a decimal string, exp the target exponent. The converted total is round_half_even(sum(lines)*rate) at exp. Each line is converted and rounded half-even individually; the difference between the converted total and the sum of converted lines is posted in full to the line with the largest absolute source amount (earliest on ties). Return the converted lines as plain strings; zero lines are unsigned. An empty invoice returns [].
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(lines, rate, exp):
r = Decimal(rate)
qt = Decimal(1).scaleb(-exp)
def q(v): return v.quantize(qt, rounding=ROUND_HALF_EVEN)
src = [Decimal(l) for l in lines]
if not src: return []
conv = [q(v * r) for v in src]
total = q(sum(src, Decimal(0)) * r)
diff = total - sum(conv, Decimal(0))
i = max(range(len(conv)), key=lambda k: (abs(src[k]), -k))
conv[i] -= diff
return [format(abs(c) if c == 0 else c, 'f') for c in conv]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression plug-sign 1', (['10.01', '10.01', '10.01'], '0.5', 2), ['5.02', '5.00', '5.00']),
('regression plug-sign 2', (['135.46', '1241.19', '543.10'], '121.0106', 2), ['16392.10', '150197.14', '65720.86']),
('partial repair guard 2', (['2340.71', '566.48', '2486.21', '1232.14'], '11.46450', 3),
['26835.070', '6494.410', '28503.154', '14125.869']),
('control: credit and debit', (['-3.33', '3.33'], '1.5', 2), ['-5.00', '5.00']),
('control: tiny credit', (['100.00', '-0.01'], '0.3', 2), ['30.00', '0.00']),
('control: empty invoice', ([], '1.1', 2), []),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150'])],
[('regression plug-sign 1', (['2009.44', '2296.55', '1393.27', '1770.57', '2944.58'], '81.6625', 2),
['164095.89', '187542.01', '113777.91', '144589.17', '240461.78']),
('regression plug-sign 2', (['1729.48', '-260.26', '1061.77', '2756.95'], '151.6104', 2),
['262207.15', '-39458.12', '160975.37', '417982.30']),
('partial repair guard 1', (['474.23', '2013.40'], '2.07137', 2), ['982.31', '4170.49']),
('partial repair guard 2', (['426.74', '2140.94'], '102.7874', 2), ['43863.50', '220061.65']),
('control: empty invoice', ([], '1.1', 2), []),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150']),
('control: dinar target', (['1.25', '2.50'], '0.3071', 3), ['0.384', '0.768']),
('control: single line', (['123.45'], '0.9215', 2), ['113.76'])],
[('regression plug-sign 1', (['607.45', '-205.45', '116.41', '195.72', '309.63'], '1991.467', 2),
['1209716.64', '-409146.90', '231826.67', '389769.92', '616617.93']),
('regression plug-sign 2', (['2340.71', '566.48', '2486.21', '1232.14'], '11.46450', 3),
['26835.070', '6494.410', '28503.154', '14125.869']),
('partial repair guard 1', (['866.33', '-73.41', '796.96', '969.42'], '561.952', 2),
['486835.88', '-41252.90', '447853.27', '544767.50']),
('partial repair guard 2', (['1337.60', '1422.94', '1036.77', '2321.08'], '12.49239', 2),
['16709.82', '17775.92', '12951.74', '28995.83']),
('control: single line', (['123.45'], '0.9215', 2), ['113.76']),
('control: largest is credit', (['-50.05', '20.03', '20.03'], '1.0833', 2), ['-54.22', '21.70', '21.70']),
('control: three equal lines', (['10.01', '10.01', '10.01'], '0.5', 2), ['5.02', '5.00', '5.00']),
('control: credit and debit', (['-3.33', '3.33'], '1.5', 2), ['-5.00', '5.00'])],
[('regression plug-sign 1', (['2564.41', '147.72', '2843.10'], '11.81884', 3), ['30308.351', '1745.879', '33602.145']),
('regression plug-sign 2', (['2885.93', '241.41'], '10.35728', 0), ['29891', '2500']),
('partial repair guard 1', (['1936.34', '641.20', '-204.60', '2626.29', '2966.22'], '145.7597', 2),
['282240.34', '93461.12', '-29822.43', '382807.24', '432355.33']),
('partial repair guard 2', (['1035.43', '-191.27', '803.79', '-53.39', '961.52'], '25.8497', 3),
['26765.554', '-4944.272', '20777.730', '-1380.115', '24855.004']),
('control: credit and debit', (['-3.33', '3.33'], '1.5', 2), ['-5.00', '5.00']),
('control: tiny credit', (['100.00', '-0.01'], '0.3', 2), ['30.00', '0.00']),
('control: empty invoice', ([], '1.1', 2), []),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150'])],
[('regression plug-sign 1', (['474.23', '2013.40'], '2.07137', 2), ['982.31', '4170.49']),
('regression plug-sign 2', (['1616.46', '-55.89', '2559.69'], '35.6985', 3), ['57705.197', '-1995.189', '91377.094']),
('partial repair guard 1', (['1446.45', '-213.92', '1311.94', '997.39'], '1.64995', 0),
['2386', '-353', '2165', '1646']),
('partial repair guard 2', (['2819.33', '273.60', '2697.59'], '1443.082', 2),
['4068524.37', '394827.24', '3892843.57']),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150']),
('control: dinar target', (['1.25', '2.50'], '0.3071', 3), ['0.384', '0.768']),
('control: single line', (['123.45'], '0.9215', 2), ['113.76']),
('control: largest is credit', (['-50.05', '20.03', '20.03'], '1.0833', 2), ['-54.22', '21.70', '21.70'])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression plug-sign 1 | ['4.98', '5.00', '5.00'] | ['5.02', '5.00', '5.00'] | Failed |
| regression plug-sign 2 | ['16392.10', '150197.16', '65720.86'] | ['16392.10', '150197.14', '65720.86'] | Failed |
| partial repair guard 2 | ['26835.070', '6494.410', '28503.156', '14125.869'] | ['26835.070', '6494.410', '28503.154', '14125.869'] | Failed |
| control: credit and debit | ['-5.00', '5.00'] | ['-5.00', '5.00'] | Passed |
| control: tiny credit | ['30.00', '0.00'] | ['30.00', '0.00'] | Passed |
| control: empty invoice | [] | [] | Passed |
| control: yen target | ['3026', '758', '150'] | ['3026', '758', '150'] | Passed |
SHA-256 / ea4610fd4cb1fe0bf19e53e91d781481399c172e93443c2ad532f91e38008886
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(lines, rate, exp):
r = Decimal(rate)
qt = Decimal(1).scaleb(-exp)
def q(v): return v.quantize(qt, rounding=ROUND_HALF_EVEN)
src = [Decimal(l) for l in lines]
if not src: return []
conv = [q(v * r) for v in src]
total = q(sum(src, Decimal(0)) * r)
diff = total - sum(conv, Decimal(0))
i = max(range(len(conv)), key=lambda k: (abs(src[k]), -k))
conv[i] += abs(diff)
return [format(abs(c) if c == 0 else c, 'f') for c in conv]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression plug-sign 1', (['10.01', '10.01', '10.01'], '0.5', 2), ['5.02', '5.00', '5.00']),
('regression plug-sign 2', (['135.46', '1241.19', '543.10'], '121.0106', 2), ['16392.10', '150197.14', '65720.86']),
('partial repair guard 2', (['2340.71', '566.48', '2486.21', '1232.14'], '11.46450', 3),
['26835.070', '6494.410', '28503.154', '14125.869']),
('control: credit and debit', (['-3.33', '3.33'], '1.5', 2), ['-5.00', '5.00']),
('control: tiny credit', (['100.00', '-0.01'], '0.3', 2), ['30.00', '0.00']),
('control: empty invoice', ([], '1.1', 2), []),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150'])],
[('regression plug-sign 1', (['2009.44', '2296.55', '1393.27', '1770.57', '2944.58'], '81.6625', 2),
['164095.89', '187542.01', '113777.91', '144589.17', '240461.78']),
('regression plug-sign 2', (['1729.48', '-260.26', '1061.77', '2756.95'], '151.6104', 2),
['262207.15', '-39458.12', '160975.37', '417982.30']),
('partial repair guard 1', (['474.23', '2013.40'], '2.07137', 2), ['982.31', '4170.49']),
('partial repair guard 2', (['426.74', '2140.94'], '102.7874', 2), ['43863.50', '220061.65']),
('control: empty invoice', ([], '1.1', 2), []),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150']),
('control: dinar target', (['1.25', '2.50'], '0.3071', 3), ['0.384', '0.768']),
('control: single line', (['123.45'], '0.9215', 2), ['113.76'])],
[('regression plug-sign 1', (['607.45', '-205.45', '116.41', '195.72', '309.63'], '1991.467', 2),
['1209716.64', '-409146.90', '231826.67', '389769.92', '616617.93']),
('regression plug-sign 2', (['2340.71', '566.48', '2486.21', '1232.14'], '11.46450', 3),
['26835.070', '6494.410', '28503.154', '14125.869']),
('partial repair guard 1', (['866.33', '-73.41', '796.96', '969.42'], '561.952', 2),
['486835.88', '-41252.90', '447853.27', '544767.50']),
('partial repair guard 2', (['1337.60', '1422.94', '1036.77', '2321.08'], '12.49239', 2),
['16709.82', '17775.92', '12951.74', '28995.83']),
('control: single line', (['123.45'], '0.9215', 2), ['113.76']),
('control: largest is credit', (['-50.05', '20.03', '20.03'], '1.0833', 2), ['-54.22', '21.70', '21.70']),
('control: three equal lines', (['10.01', '10.01', '10.01'], '0.5', 2), ['5.02', '5.00', '5.00']),
('control: credit and debit', (['-3.33', '3.33'], '1.5', 2), ['-5.00', '5.00'])],
[('regression plug-sign 1', (['2564.41', '147.72', '2843.10'], '11.81884', 3), ['30308.351', '1745.879', '33602.145']),
('regression plug-sign 2', (['2885.93', '241.41'], '10.35728', 0), ['29891', '2500']),
('partial repair guard 1', (['1936.34', '641.20', '-204.60', '2626.29', '2966.22'], '145.7597', 2),
['282240.34', '93461.12', '-29822.43', '382807.24', '432355.33']),
('partial repair guard 2', (['1035.43', '-191.27', '803.79', '-53.39', '961.52'], '25.8497', 3),
['26765.554', '-4944.272', '20777.730', '-1380.115', '24855.004']),
('control: credit and debit', (['-3.33', '3.33'], '1.5', 2), ['-5.00', '5.00']),
('control: tiny credit', (['100.00', '-0.01'], '0.3', 2), ['30.00', '0.00']),
('control: empty invoice', ([], '1.1', 2), []),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150'])],
[('regression plug-sign 1', (['474.23', '2013.40'], '2.07137', 2), ['982.31', '4170.49']),
('regression plug-sign 2', (['1616.46', '-55.89', '2559.69'], '35.6985', 3), ['57705.197', '-1995.189', '91377.094']),
('partial repair guard 1', (['1446.45', '-213.92', '1311.94', '997.39'], '1.64995', 0),
['2386', '-353', '2165', '1646']),
('partial repair guard 2', (['2819.33', '273.60', '2697.59'], '1443.082', 2),
['4068524.37', '394827.24', '3892843.57']),
('control: yen target', (['19.99', '5.01', '0.99'], '151.37', 0), ['3026', '758', '150']),
('control: dinar target', (['1.25', '2.50'], '0.3071', 3), ['0.384', '0.768']),
('control: single line', (['123.45'], '0.9215', 2), ['113.76']),
('control: largest is credit', (['-50.05', '20.03', '20.03'], '1.0833', 2), ['-54.22', '21.70', '21.70'])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression plug-sign 1 | ['5.02', '5.00', '5.00'] | ['5.02', '5.00', '5.00'] | Passed |
| regression plug-sign 2 | ['16392.10', '150197.16', '65720.86'] | ['16392.10', '150197.14', '65720.86'] | Failed |
| partial repair guard 2 | ['26835.070', '6494.410', '28503.156', '14125.869'] | ['26835.070', '6494.410', '28503.154', '14125.869'] | Failed |
| control: credit and debit | ['-5.00', '5.00'] | ['-5.00', '5.00'] | Passed |
| control: tiny credit | ['30.00', '0.00'] | ['30.00', '0.00'] | Passed |
| control: empty invoice | [] | [] | Passed |
| control: yen target | ['3026', '758', '150'] | ['3026', '758', '150'] | Passed |
SHA-256 / 565c66a5837c909d4517612e82cea176f00ad7cab020f11560cca4046bcd05be
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗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:00.042131+00:00.
Case digest / 656656dd628e42f0fc39ca5c0bb8abc82a9813155bfc764c8339dba50ac8f82e