FA-62141 / Currency rounding and FX conversion / Open access
The minus sign is placed between the currency symbol and the digits · case 01
Refunds render as '$-1.50' instead of '-$1.50'.
ROOT CAUSE
The sign is concatenated after the prefix symbol.
VERIFIED REPAIR
Emit the sign before the prefix.
Unsuccessful approach: Emitting the sign only for prefix styles drops it from suffix-style euro amounts.
Case contract
solve(minor, ccy): format integer minor units. Styles: USD '$' prefix, ',' groups, '.' decimal, 2 digits; EUR ' €' suffix, '.' groups, ',' decimal, 2; JPY '¥' prefix, ',' groups, 0 digits (no decimal separator); CHF 'CHF ' prefix, "'" groups, '.', 2; KWD 'KD ' prefix, ',', '.', 3. Group the whole part in threes from the right; the fraction is zero-padded to the exponent. A negative amount places '-' before everything. Unknown codes return 'ERR:currency'.
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
N = 1
observations = []
def solve(minor, ccy):
spec = {'USD': ('$', '', ',', '.', 2), 'EUR': ('', ' €', '.', ',', 2), 'JPY': ('¥', '', ',', '.', 0), 'CHF': ('CHF ', '', "'", '.', 2), 'KWD': ('KD ', '', ',', '.', 3)}
if ccy not in spec: return 'ERR:currency'
pre, suf, grp, dec, e = spec[ccy]
neg = minor < 0
major, frac = divmod(abs(minor), 10 ** e)
digits = str(major)
groups = []
while len(digits) > 3:
groups.insert(0, digits[-3:])
digits = digits[:-3]
groups.insert(0, digits)
body = grp.join(groups)
if e: body += dec + str(frac).zfill(e)
return pre + ('-' if neg else '') + body + suf
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression sign-placement 1', (-150, 'USD'), '-$1.50'), ('regression sign-placement 2', (-1000, 'JPY'), '-¥1,000'),
('partial repair guard 1', (-50, 'EUR'), '-0,50 €'), ('partial repair guard 2', (-1000000, 'EUR'), '-10.000,00 €'),
('control: dollars', (123450, 'USD'), '$1,234.50'), ('control: yen', (1234567, 'JPY'), '¥1,234,567'),
('control: franc', (12345678, 'CHF'), "CHF 123'456.78"), ('control: dinar', (1005, 'KWD'), 'KD 1.005')],
[('regression sign-placement 1', (-100000, 'USD'), '-$1,000.00'),
('regression sign-placement 2', (-50, 'KWD'), '-KD 0.050'),
('partial repair guard 1', (-123456, 'EUR'), '-1.234,56 €'), ('partial repair guard 2', (-105, 'EUR'), '-1,05 €'),
('control: yen', (1234567, 'JPY'), '¥1,234,567'), ('control: franc', (12345678, 'CHF'), "CHF 123'456.78"),
('control: dinar', (1005, 'KWD'), 'KD 1.005'), ('control: unknown', (5, 'GBP'), 'ERR:currency')],
[('regression sign-placement 1', (-105, 'KWD'), '-KD 0.105'), ('regression sign-placement 2', (-999, 'JPY'), '-¥999'),
('partial repair guard 1', (-1000, 'EUR'), '-10,00 €'), ('partial repair guard 2', (-99999, 'EUR'), '-999,99 €'),
('control: unknown', (5, 'GBP'), 'ERR:currency'), ('control: million euros', (100000000, 'EUR'), '1.000.000,00 €'),
('control: zero yen', (0, 'JPY'), '¥0'), ('control: small dollars', (105, 'USD'), '$1.05')],
[('regression sign-placement 1', (-105, 'JPY'), '-¥105'),
('regression sign-placement 2', (-987654321, 'USD'), '-$9,876,543.21'),
('partial repair guard 1', (-987654321, 'EUR'), '-9.876.543,21 €'),
('partial repair guard 2', (-999, 'EUR'), '-9,99 €'), ('control: small dollars', (105, 'USD'), '$1.05'),
('control: negative yen', (-1000, 'JPY'), '-¥1,000'), ('control: dollars', (123450, 'USD'), '$1,234.50'),
('control: negative dollars', (-150, 'USD'), '-$1.50')],
[('regression sign-placement 1', (-50, 'JPY'), '-¥50'),
('regression sign-placement 2', (-1000000, 'CHF'), "-CHF 10'000.00"),
('partial repair guard 1', (-100000, 'EUR'), '-1.000,00 €'), ('partial repair guard 2', (-5, 'EUR'), '-0,05 €'),
('control: negative dollars', (-150, 'USD'), '-$1.50'), ('control: negative euro cents', (-50, 'EUR'), '-0,50 €'),
('control: yen', (1234567, 'JPY'), '¥1,234,567'), ('control: franc', (12345678, 'CHF'), "CHF 123'456.78")]]
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 sign-placement 1 | $-1.50 | -$1.50 | Failed |
| regression sign-placement 2 | ¥-1,000 | -¥1,000 | Failed |
| partial repair guard 1 | -0,50 € | -0,50 € | Passed |
| partial repair guard 2 | -10.000,00 € | -10.000,00 € | Passed |
| control: dollars | $1,234.50 | $1,234.50 | Passed |
| control: yen | ¥1,234,567 | ¥1,234,567 | Passed |
| control: franc | CHF 123'456.78 | CHF 123'456.78 | Passed |
| control: dinar | KD 1.005 | KD 1.005 | Passed |
SHA-256 / 6d2e7e06788cf9a4555775bb589b9a9b3ab570331b5ba54e16012bac75632fef
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(minor, ccy):
spec = {'USD': ('$', '', ',', '.', 2), 'EUR': ('', ' €', '.', ',', 2), 'JPY': ('¥', '', ',', '.', 0), 'CHF': ('CHF ', '', "'", '.', 2), 'KWD': ('KD ', '', ',', '.', 3)}
if ccy not in spec: return 'ERR:currency'
pre, suf, grp, dec, e = spec[ccy]
neg = minor < 0
major, frac = divmod(abs(minor), 10 ** e)
digits = str(major)
groups = []
while len(digits) > 3:
groups.insert(0, digits[-3:])
digits = digits[:-3]
groups.insert(0, digits)
body = grp.join(groups)
if e: body += dec + str(frac).zfill(e)
return ('-' if neg and pre else '') + pre + body + suf
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression sign-placement 1', (-150, 'USD'), '-$1.50'), ('regression sign-placement 2', (-1000, 'JPY'), '-¥1,000'),
('partial repair guard 1', (-50, 'EUR'), '-0,50 €'), ('partial repair guard 2', (-1000000, 'EUR'), '-10.000,00 €'),
('control: dollars', (123450, 'USD'), '$1,234.50'), ('control: yen', (1234567, 'JPY'), '¥1,234,567'),
('control: franc', (12345678, 'CHF'), "CHF 123'456.78"), ('control: dinar', (1005, 'KWD'), 'KD 1.005')],
[('regression sign-placement 1', (-100000, 'USD'), '-$1,000.00'),
('regression sign-placement 2', (-50, 'KWD'), '-KD 0.050'),
('partial repair guard 1', (-123456, 'EUR'), '-1.234,56 €'), ('partial repair guard 2', (-105, 'EUR'), '-1,05 €'),
('control: yen', (1234567, 'JPY'), '¥1,234,567'), ('control: franc', (12345678, 'CHF'), "CHF 123'456.78"),
('control: dinar', (1005, 'KWD'), 'KD 1.005'), ('control: unknown', (5, 'GBP'), 'ERR:currency')],
[('regression sign-placement 1', (-105, 'KWD'), '-KD 0.105'), ('regression sign-placement 2', (-999, 'JPY'), '-¥999'),
('partial repair guard 1', (-1000, 'EUR'), '-10,00 €'), ('partial repair guard 2', (-99999, 'EUR'), '-999,99 €'),
('control: unknown', (5, 'GBP'), 'ERR:currency'), ('control: million euros', (100000000, 'EUR'), '1.000.000,00 €'),
('control: zero yen', (0, 'JPY'), '¥0'), ('control: small dollars', (105, 'USD'), '$1.05')],
[('regression sign-placement 1', (-105, 'JPY'), '-¥105'),
('regression sign-placement 2', (-987654321, 'USD'), '-$9,876,543.21'),
('partial repair guard 1', (-987654321, 'EUR'), '-9.876.543,21 €'),
('partial repair guard 2', (-999, 'EUR'), '-9,99 €'), ('control: small dollars', (105, 'USD'), '$1.05'),
('control: negative yen', (-1000, 'JPY'), '-¥1,000'), ('control: dollars', (123450, 'USD'), '$1,234.50'),
('control: negative dollars', (-150, 'USD'), '-$1.50')],
[('regression sign-placement 1', (-50, 'JPY'), '-¥50'),
('regression sign-placement 2', (-1000000, 'CHF'), "-CHF 10'000.00"),
('partial repair guard 1', (-100000, 'EUR'), '-1.000,00 €'), ('partial repair guard 2', (-5, 'EUR'), '-0,05 €'),
('control: negative dollars', (-150, 'USD'), '-$1.50'), ('control: negative euro cents', (-50, 'EUR'), '-0,50 €'),
('control: yen', (1234567, 'JPY'), '¥1,234,567'), ('control: franc', (12345678, 'CHF'), "CHF 123'456.78")]]
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 sign-placement 1 | -$1.50 | -$1.50 | Passed |
| regression sign-placement 2 | -¥1,000 | -¥1,000 | Passed |
| partial repair guard 1 | 0,50 € | -0,50 € | Failed |
| partial repair guard 2 | 10.000,00 € | -10.000,00 € | Failed |
| control: dollars | $1,234.50 | $1,234.50 | Passed |
| control: yen | ¥1,234,567 | ¥1,234,567 | Passed |
| control: franc | CHF 123'456.78 | CHF 123'456.78 | Passed |
| control: dinar | KD 1.005 | KD 1.005 | Passed |
SHA-256 / e6b8dcdce50d7480c9477744b4034126b58582d02f398ea12b53ba4754ba8ba8
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(minor, ccy):
spec = {'USD': ('$', '', ',', '.', 2), 'EUR': ('', ' €', '.', ',', 2), 'JPY': ('¥', '', ',', '.', 0), 'CHF': ('CHF ', '', "'", '.', 2), 'KWD': ('KD ', '', ',', '.', 3)}
if ccy not in spec: return 'ERR:currency'
pre, suf, grp, dec, e = spec[ccy]
neg = minor < 0
major, frac = divmod(abs(minor), 10 ** e)
digits = str(major)
groups = []
while len(digits) > 3:
groups.insert(0, digits[-3:])
digits = digits[:-3]
groups.insert(0, digits)
body = grp.join(groups)
if e: body += dec + str(frac).zfill(e)
return ('-' if neg else '') + pre + body + suf
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression sign-placement 1', (-150, 'USD'), '-$1.50'), ('regression sign-placement 2', (-1000, 'JPY'), '-¥1,000'),
('partial repair guard 1', (-50, 'EUR'), '-0,50 €'), ('partial repair guard 2', (-1000000, 'EUR'), '-10.000,00 €'),
('control: dollars', (123450, 'USD'), '$1,234.50'), ('control: yen', (1234567, 'JPY'), '¥1,234,567'),
('control: franc', (12345678, 'CHF'), "CHF 123'456.78"), ('control: dinar', (1005, 'KWD'), 'KD 1.005')],
[('regression sign-placement 1', (-100000, 'USD'), '-$1,000.00'),
('regression sign-placement 2', (-50, 'KWD'), '-KD 0.050'),
('partial repair guard 1', (-123456, 'EUR'), '-1.234,56 €'), ('partial repair guard 2', (-105, 'EUR'), '-1,05 €'),
('control: yen', (1234567, 'JPY'), '¥1,234,567'), ('control: franc', (12345678, 'CHF'), "CHF 123'456.78"),
('control: dinar', (1005, 'KWD'), 'KD 1.005'), ('control: unknown', (5, 'GBP'), 'ERR:currency')],
[('regression sign-placement 1', (-105, 'KWD'), '-KD 0.105'), ('regression sign-placement 2', (-999, 'JPY'), '-¥999'),
('partial repair guard 1', (-1000, 'EUR'), '-10,00 €'), ('partial repair guard 2', (-99999, 'EUR'), '-999,99 €'),
('control: unknown', (5, 'GBP'), 'ERR:currency'), ('control: million euros', (100000000, 'EUR'), '1.000.000,00 €'),
('control: zero yen', (0, 'JPY'), '¥0'), ('control: small dollars', (105, 'USD'), '$1.05')],
[('regression sign-placement 1', (-105, 'JPY'), '-¥105'),
('regression sign-placement 2', (-987654321, 'USD'), '-$9,876,543.21'),
('partial repair guard 1', (-987654321, 'EUR'), '-9.876.543,21 €'),
('partial repair guard 2', (-999, 'EUR'), '-9,99 €'), ('control: small dollars', (105, 'USD'), '$1.05'),
('control: negative yen', (-1000, 'JPY'), '-¥1,000'), ('control: dollars', (123450, 'USD'), '$1,234.50'),
('control: negative dollars', (-150, 'USD'), '-$1.50')],
[('regression sign-placement 1', (-50, 'JPY'), '-¥50'),
('regression sign-placement 2', (-1000000, 'CHF'), "-CHF 10'000.00"),
('partial repair guard 1', (-100000, 'EUR'), '-1.000,00 €'), ('partial repair guard 2', (-5, 'EUR'), '-0,05 €'),
('control: negative dollars', (-150, 'USD'), '-$1.50'), ('control: negative euro cents', (-50, 'EUR'), '-0,50 €'),
('control: yen', (1234567, 'JPY'), '¥1,234,567'), ('control: franc', (12345678, 'CHF'), "CHF 123'456.78")]]
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 sign-placement 1 | -$1.50 | -$1.50 | Passed |
| regression sign-placement 2 | -¥1,000 | -¥1,000 | Passed |
| partial repair guard 1 | -0,50 € | -0,50 € | Passed |
| partial repair guard 2 | -10.000,00 € | -10.000,00 € | Passed |
| control: dollars | $1,234.50 | $1,234.50 | Passed |
| control: yen | ¥1,234,567 | ¥1,234,567 | Passed |
| control: franc | CHF 123'456.78 | CHF 123'456.78 | Passed |
| control: dinar | KD 1.005 | KD 1.005 | Passed |
SHA-256 / 24d452b066414d4d056d4907009f694f4c3144e3443526447ca353d7481650b9
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.826966+00:00.
Case digest / efe10d411d7e10d2590616b7bbdca77450bd416f889f720ddb16cb1f80e0449a