FA-62066 / Currency rounding and FX conversion / Open access
The percentage fee is floored instead of rounded up · case 01
A 1% fee on 1001 minor units is 10 instead of 11.
ROOT CAUSE
Integer division amount*bps//10000 truncates the fee.
THE FAILURE
Integer division amount*bps//10000 truncates the fee.
Unsuccessful approach: Rounding the fee to nearest with float division still under-charges fractions below one half.
Case contract
solve(amount, rate, src_exp, dst_exp, fee_bps, min_fee): amount and min_fee are source minor units, fee_bps a non-negative integer. fee = max(min_fee, ceil(amount*fee_bps/10000)) in source minor units, deducted before conversion. A fee greater than or equal to the amount returns 'ERR:amount-below-fee'; a non-positive amount or negative bps returns 'ERR:input'. The net amount is converted exactly (net * rate * 10**(dst_exp - src_exp)) and rounded half-even. Return [fee, converted].
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(amount, rate, src_exp, dst_exp, fee_bps, min_fee):
if fee_bps < 0 or amount <= 0: return 'ERR:input'
conv = lambda m: Decimal(m) * Decimal(rate) * Decimal(10) ** (dst_exp - src_exp)
rq = lambda d: int(d.quantize(Decimal(1), rounding=ROUND_HALF_EVEN))
pct = amount * fee_bps // 10000
fee = max(min_fee, pct)
if fee >= amount: return 'ERR:amount-below-fee'
return [fee, rq(conv(amount - fee))]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fee-ceiling 1', (1001, '1', 2, 2, 100, 0), [11, 990]),
('regression fee-ceiling 2', (1003, '1', 2, 2, 100, 0), [11, 992]),
('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
[('regression fee-ceiling 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
('regression fee-ceiling 2', (197637, '16116.34', 0, 2, 333, 100), [6582, 307910733870]),
('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')],
[('regression fee-ceiling 1', (22226, '179.9447', 0, 2, 150, 100), [334, 393934937]),
('regression fee-ceiling 2', (50411, '12342.04', 3, 3, 333, 1), [1679, 601452293]),
('partial repair guard 2', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee'),
('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990])],
[('regression fee-ceiling 1', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
('regression fee-ceiling 2', (269350, '9.84392', 0, 3, 333, 0), [8970, 2563159890]),
('partial repair guard 2', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
[('regression fee-ceiling 1', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
('regression fee-ceiling 2', (90216, '1.62136', 0, 2, 1000, 250), [9022, 13164470]),
('partial repair guard 1', (234309, '91.3439', 3, 3, 333, 100), [7803, 20689941]),
('partial repair guard 2', (462525, '13331.53', 0, 0, 1000, 50), [46253, 5549542656]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
('control: large percentage fee', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')]]
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 fee-ceiling 1 | [10, 991] | [11, 990] | Failed |
| regression fee-ceiling 2 | [10, 993] | [11, 992] | Failed |
| control: yen payout | [150, 14910] | [150, 14910] | Passed |
| control: fee equals amount | ERR:amount-below-fee | ERR:amount-below-fee | Passed |
| control: minimum fee applies | [100, 61113] | [100, 61113] | Passed |
| control: zero bps | [0, 842] | [0, 842] | Passed |
SHA-256 / 43330627406d1d069de6528f0ac2a219675b89b9f4438101d255df3404ee2804
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(amount, rate, src_exp, dst_exp, fee_bps, min_fee):
if fee_bps < 0 or amount <= 0: return 'ERR:input'
conv = lambda m: Decimal(m) * Decimal(rate) * Decimal(10) ** (dst_exp - src_exp)
rq = lambda d: int(d.quantize(Decimal(1), rounding=ROUND_HALF_EVEN))
pct = round(amount * fee_bps / 10000)
fee = max(min_fee, pct)
if fee >= amount: return 'ERR:amount-below-fee'
return [fee, rq(conv(amount - fee))]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression fee-ceiling 1', (1001, '1', 2, 2, 100, 0), [11, 990]),
('regression fee-ceiling 2', (1003, '1', 2, 2, 100, 0), [11, 992]),
('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
[('regression fee-ceiling 1', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
('regression fee-ceiling 2', (197637, '16116.34', 0, 2, 333, 100), [6582, 307910733870]),
('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')],
[('regression fee-ceiling 1', (22226, '179.9447', 0, 2, 150, 100), [334, 393934937]),
('regression fee-ceiling 2', (50411, '12342.04', 3, 3, 333, 1), [1679, 601452293]),
('partial repair guard 2', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee'),
('control: yen payout', (10000, '151.37', 2, 0, 150, 50), [150, 14910]),
('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990])],
[('regression fee-ceiling 1', (268603, '16.66106', 2, 0, 150, 50), [4030, 44081]),
('regression fee-ceiling 2', (269350, '9.84392', 0, 3, 333, 0), [8970, 2563159890]),
('partial repair guard 2', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
('control: fee rounds up', (1001, '1', 2, 2, 100, 0), [11, 990]),
('control: fee equals amount', (500, '0.9', 2, 2, 10, 500), 'ERR:amount-below-fee'),
('control: minimum fee applies', (20000, '0.3071', 2, 3, 25, 100), [100, 61113]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842])],
[('regression fee-ceiling 1', (84375, '129.7381', 0, 0, 99, 250), [836, 10838191]),
('regression fee-ceiling 2', (90216, '1.62136', 0, 2, 1000, 250), [9022, 13164470]),
('partial repair guard 1', (234309, '91.3439', 3, 3, 333, 100), [7803, 20689941]),
('partial repair guard 2', (462525, '13331.53', 0, 0, 1000, 50), [46253, 5549542656]),
('control: zero bps', (777, '1.0833', 2, 2, 0, 0), [0, 842]),
('control: large percentage fee', (123456, '0.92', 2, 2, 250, 199), [3087, 110739]),
('control: invalid amount', (0, '1.1', 2, 2, 10, 0), 'ERR:input'),
('control: minimum exceeds amount', (99, '1.2', 2, 2, 5, 150), 'ERR:amount-below-fee')]]
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 fee-ceiling 1 | [10, 991] | [11, 990] | Failed |
| regression fee-ceiling 2 | [10, 993] | [11, 992] | Failed |
| control: yen payout | [150, 14910] | [150, 14910] | Passed |
| control: fee equals amount | ERR:amount-below-fee | ERR:amount-below-fee | Passed |
| control: minimum fee applies | [100, 61113] | [100, 61113] | Passed |
| control: zero bps | [0, 842] | [0, 842] | Passed |
SHA-256 / d1adb7c550a70856b47e8f24a1fd018080481eea9cbed10214375553b4acea3b
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 6 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:01.127071+00:00.
Case digest / 3ce81392c642850b9fc5d1bda7a7897a2c7bcf9fe74fc0824d72476d3497ddcb