FAILURE MAP
← Case archive

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

A zero maximum age is treated as no age limit · case 01

With max_age 0, an hour-old rate is accepted.

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

ROOT CAUSE

The age check is guarded by 'if max_age', which is false for 0.

VERIFIED REPAIR

Only None disables the age limit; 0 accepts only same-instant ticks.

Unsuccessful approach: Testing 'is not None' but with >= rejects the same-instant tick that max_age 0 must accept.

Case contract

solve(ticks, trade_ts, max_age): ticks is the published rate feed [[ts, rate], ...] in publication order. Use the tick with the greatest ts <= trade_ts; among ticks with equal ts the later-published one is a correction and wins. No eligible tick returns 'ERR:no-rate'. If max_age is not None and trade_ts - ts > max_age the rate is 'ERR:stale' (max_age 0 accepts only a same-instant tick). Return [ts, rate].

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(ticks, trade_ts, max_age):
    best = None
    for ts, r in ticks:
        if ts <= trade_ts and (best is None or ts >= best[0]):
            best = [ts, r]
    if best is None: return 'ERR:no-rate'
    if max_age and trade_ts - best[0] > max_age: return 'ERR:stale'
    return best
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression zero-max-age 1', ([[3, '1.10']], 7, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[4, '1.2508'], [10, '1.2498']], 20, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('partial repair guard 2', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: correction wins', ([[1, '1.10'], [5, '1.20'], [5, '1.21'], [9, '1.30']], 7, 3), [5, '1.21']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale'),
  ('control: only future', ([[9, '1.30']], 7, None), 'ERR:no-rate'),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05'])],
 [('regression zero-max-age 1',
   ([[14, '1.1444'], [0, '1.1478'], [5, '1.1087'], [5, '1.1978'], [11, '1.2115'], [1, '1.2119']], 7, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[13, '1.1886'], [0, '1.0740'], [11, '1.0059']], 19, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[16, '1.0577'], [3, '1.1605'], [9, '1.0153'], [16, '1.0347'], [5, '1.1882']], 4, 1),
   [3, '1.1605']),
  ('partial repair guard 2', ([[10, '1.1254'], [1, '1.0516'], [3, '1.1640']], 2, 1), [1, '1.0516']),
  ('control: same instant zero age', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05']),
  ('control: age boundary', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate')],
 [('regression zero-max-age 1', ([[2, '1.1412'], [1, '1.0751'], [2, '1.0320']], 9, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[10, '1.2328'], [1, '1.0928'], [3, '1.1922'], [19, '1.2521'], [19, '1.2864']], 2, 0),
   'ERR:stale'),
  ('partial repair guard 1', ([[1, '1.2376'], [19, '1.2134'], [14, '1.2465']], 1, 0), [1, '1.2376']),
  ('partial repair guard 2', ([[3, '1.2016'], [20, '1.0619'], [10, '1.1904'], [10, '1.1149']], 6, 3), [3, '1.2016']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate'),
  ('control: out of order feed', ([[6, '1.26'], [2, '1.22'], [6, '1.19']], 6, 1), [6, '1.19']),
  ('control: correction wins', ([[1, '1.10'], [5, '1.20'], [5, '1.21'], [9, '1.30']], 7, 3), [5, '1.21']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale')],
 [('regression zero-max-age 1', ([[17, '1.1378']], 20, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[17, '1.1794'], [15, '1.0788'], [2, '1.2545']], 12, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[4, '1.2845'], [1, '1.0456'], [3, '1.1500'], [14, '1.1676']], 17, 3), [14, '1.1676']),
  ('partial repair guard 2', ([[14, '1.2739'], [20, '1.2257'], [0, '1.2886']], 16, 2), [14, '1.2739']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale'),
  ('control: only future', ([[9, '1.30']], 7, None), 'ERR:no-rate'),
  ('control: same instant zero age', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05'])],
 [('regression zero-max-age 1',
   ([[19, '1.2232'], [14, '1.2765'], [15, '1.2799'], [12, '1.1738'], [19, '1.2213'], [3, '1.1869']], 20, 0),
   'ERR:stale'),
  ('regression zero-max-age 2', ([[3, '1.1365'], [2, '1.0481'], [13, '1.1897']], 14, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[5, '1.0271'], [11, '1.2757'], [10, '1.0041'], [14, '1.1151'], [2, '1.2167']], 14, 0),
   [14, '1.1151']),
  ('partial repair guard 2', ([[13, '1.1719'], [0, '1.0347'], [20, '1.2239'], [9, '1.1422'], [3, '1.0957']], 1, 1),
   [0, '1.0347']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05']),
  ('control: age boundary', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate'),
  ('control: out of order feed', ([[6, '1.26'], [2, '1.22'], [6, '1.19']], 6, 1), [6, '1.19'])]]
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 zero-max-age 1[3, '1.10']ERR:staleFailed
regression zero-max-age 2[10, '1.2498']ERR:staleFailed
partial repair guard 1[7, '1.40'][7, '1.40']Passed
partial repair guard 2[4, '1.11'][4, '1.11']Passed
control: correction wins[5, '1.21'][5, '1.21']Passed
control: staleERR:staleERR:stalePassed
control: only futureERR:no-rateERR:no-ratePassed
control: unlimited age[0, '1.05'][0, '1.05']Passed

SHA-256 / 456afc82c3e3e94a03fac0e0ed8fe16f423528ae397bc900f69148bcc411577d

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(ticks, trade_ts, max_age):
    best = None
    for ts, r in ticks:
        if ts <= trade_ts and (best is None or ts >= best[0]):
            best = [ts, r]
    if best is None: return 'ERR:no-rate'
    if max_age is not None and trade_ts - best[0] >= max_age: return 'ERR:stale'
    return best
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression zero-max-age 1', ([[3, '1.10']], 7, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[4, '1.2508'], [10, '1.2498']], 20, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('partial repair guard 2', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: correction wins', ([[1, '1.10'], [5, '1.20'], [5, '1.21'], [9, '1.30']], 7, 3), [5, '1.21']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale'),
  ('control: only future', ([[9, '1.30']], 7, None), 'ERR:no-rate'),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05'])],
 [('regression zero-max-age 1',
   ([[14, '1.1444'], [0, '1.1478'], [5, '1.1087'], [5, '1.1978'], [11, '1.2115'], [1, '1.2119']], 7, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[13, '1.1886'], [0, '1.0740'], [11, '1.0059']], 19, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[16, '1.0577'], [3, '1.1605'], [9, '1.0153'], [16, '1.0347'], [5, '1.1882']], 4, 1),
   [3, '1.1605']),
  ('partial repair guard 2', ([[10, '1.1254'], [1, '1.0516'], [3, '1.1640']], 2, 1), [1, '1.0516']),
  ('control: same instant zero age', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05']),
  ('control: age boundary', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate')],
 [('regression zero-max-age 1', ([[2, '1.1412'], [1, '1.0751'], [2, '1.0320']], 9, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[10, '1.2328'], [1, '1.0928'], [3, '1.1922'], [19, '1.2521'], [19, '1.2864']], 2, 0),
   'ERR:stale'),
  ('partial repair guard 1', ([[1, '1.2376'], [19, '1.2134'], [14, '1.2465']], 1, 0), [1, '1.2376']),
  ('partial repair guard 2', ([[3, '1.2016'], [20, '1.0619'], [10, '1.1904'], [10, '1.1149']], 6, 3), [3, '1.2016']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate'),
  ('control: out of order feed', ([[6, '1.26'], [2, '1.22'], [6, '1.19']], 6, 1), [6, '1.19']),
  ('control: correction wins', ([[1, '1.10'], [5, '1.20'], [5, '1.21'], [9, '1.30']], 7, 3), [5, '1.21']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale')],
 [('regression zero-max-age 1', ([[17, '1.1378']], 20, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[17, '1.1794'], [15, '1.0788'], [2, '1.2545']], 12, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[4, '1.2845'], [1, '1.0456'], [3, '1.1500'], [14, '1.1676']], 17, 3), [14, '1.1676']),
  ('partial repair guard 2', ([[14, '1.2739'], [20, '1.2257'], [0, '1.2886']], 16, 2), [14, '1.2739']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale'),
  ('control: only future', ([[9, '1.30']], 7, None), 'ERR:no-rate'),
  ('control: same instant zero age', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05'])],
 [('regression zero-max-age 1',
   ([[19, '1.2232'], [14, '1.2765'], [15, '1.2799'], [12, '1.1738'], [19, '1.2213'], [3, '1.1869']], 20, 0),
   'ERR:stale'),
  ('regression zero-max-age 2', ([[3, '1.1365'], [2, '1.0481'], [13, '1.1897']], 14, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[5, '1.0271'], [11, '1.2757'], [10, '1.0041'], [14, '1.1151'], [2, '1.2167']], 14, 0),
   [14, '1.1151']),
  ('partial repair guard 2', ([[13, '1.1719'], [0, '1.0347'], [20, '1.2239'], [9, '1.1422'], [3, '1.0957']], 1, 1),
   [0, '1.0347']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05']),
  ('control: age boundary', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate'),
  ('control: out of order feed', ([[6, '1.26'], [2, '1.22'], [6, '1.19']], 6, 1), [6, '1.19'])]]
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 zero-max-age 1ERR:staleERR:stalePassed
regression zero-max-age 2ERR:staleERR:stalePassed
partial repair guard 1ERR:stale[7, '1.40']Failed
partial repair guard 2ERR:stale[4, '1.11']Failed
control: correction wins[5, '1.21'][5, '1.21']Passed
control: staleERR:staleERR:stalePassed
control: only futureERR:no-rateERR:no-ratePassed
control: unlimited age[0, '1.05'][0, '1.05']Passed

SHA-256 / 8c8213ff089b0e74bafc1403962164c16c3fdea8ff45204a35281ad9cc37d219

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(ticks, trade_ts, max_age):
    best = None
    for ts, r in ticks:
        if ts <= trade_ts and (best is None or ts >= best[0]):
            best = [ts, r]
    if best is None: return 'ERR:no-rate'
    if max_age is not None and trade_ts - best[0] > max_age: return 'ERR:stale'
    return best
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = [[('regression zero-max-age 1', ([[3, '1.10']], 7, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[4, '1.2508'], [10, '1.2498']], 20, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('partial repair guard 2', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: correction wins', ([[1, '1.10'], [5, '1.20'], [5, '1.21'], [9, '1.30']], 7, 3), [5, '1.21']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale'),
  ('control: only future', ([[9, '1.30']], 7, None), 'ERR:no-rate'),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05'])],
 [('regression zero-max-age 1',
   ([[14, '1.1444'], [0, '1.1478'], [5, '1.1087'], [5, '1.1978'], [11, '1.2115'], [1, '1.2119']], 7, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[13, '1.1886'], [0, '1.0740'], [11, '1.0059']], 19, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[16, '1.0577'], [3, '1.1605'], [9, '1.0153'], [16, '1.0347'], [5, '1.1882']], 4, 1),
   [3, '1.1605']),
  ('partial repair guard 2', ([[10, '1.1254'], [1, '1.0516'], [3, '1.1640']], 2, 1), [1, '1.0516']),
  ('control: same instant zero age', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05']),
  ('control: age boundary', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate')],
 [('regression zero-max-age 1', ([[2, '1.1412'], [1, '1.0751'], [2, '1.0320']], 9, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[10, '1.2328'], [1, '1.0928'], [3, '1.1922'], [19, '1.2521'], [19, '1.2864']], 2, 0),
   'ERR:stale'),
  ('partial repair guard 1', ([[1, '1.2376'], [19, '1.2134'], [14, '1.2465']], 1, 0), [1, '1.2376']),
  ('partial repair guard 2', ([[3, '1.2016'], [20, '1.0619'], [10, '1.1904'], [10, '1.1149']], 6, 3), [3, '1.2016']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate'),
  ('control: out of order feed', ([[6, '1.26'], [2, '1.22'], [6, '1.19']], 6, 1), [6, '1.19']),
  ('control: correction wins', ([[1, '1.10'], [5, '1.20'], [5, '1.21'], [9, '1.30']], 7, 3), [5, '1.21']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale')],
 [('regression zero-max-age 1', ([[17, '1.1378']], 20, 0), 'ERR:stale'),
  ('regression zero-max-age 2', ([[17, '1.1794'], [15, '1.0788'], [2, '1.2545']], 12, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[4, '1.2845'], [1, '1.0456'], [3, '1.1500'], [14, '1.1676']], 17, 3), [14, '1.1676']),
  ('partial repair guard 2', ([[14, '1.2739'], [20, '1.2257'], [0, '1.2886']], 16, 2), [14, '1.2739']),
  ('control: stale', ([[1, '1.10'], [9, '1.30']], 7, 3), 'ERR:stale'),
  ('control: only future', ([[9, '1.30']], 7, None), 'ERR:no-rate'),
  ('control: same instant zero age', ([[7, '1.40']], 7, 0), [7, '1.40']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05'])],
 [('regression zero-max-age 1',
   ([[19, '1.2232'], [14, '1.2765'], [15, '1.2799'], [12, '1.1738'], [19, '1.2213'], [3, '1.1869']], 20, 0),
   'ERR:stale'),
  ('regression zero-max-age 2', ([[3, '1.1365'], [2, '1.0481'], [13, '1.1897']], 14, 0), 'ERR:stale'),
  ('partial repair guard 1', ([[5, '1.0271'], [11, '1.2757'], [10, '1.0041'], [14, '1.1151'], [2, '1.2167']], 14, 0),
   [14, '1.1151']),
  ('partial repair guard 2', ([[13, '1.1719'], [0, '1.0347'], [20, '1.2239'], [9, '1.1422'], [3, '1.0957']], 1, 1),
   [0, '1.0347']),
  ('control: unlimited age', ([[0, '1.05']], 20, None), [0, '1.05']),
  ('control: age boundary', ([[4, '1.11'], [12, '1.50']], 8, 4), [4, '1.11']),
  ('control: empty feed', ([], 3, 5), 'ERR:no-rate'),
  ('control: out of order feed', ([[6, '1.26'], [2, '1.22'], [6, '1.19']], 6, 1), [6, '1.19'])]]
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 zero-max-age 1ERR:staleERR:stalePassed
regression zero-max-age 2ERR:staleERR:stalePassed
partial repair guard 1[7, '1.40'][7, '1.40']Passed
partial repair guard 2[4, '1.11'][4, '1.11']Passed
control: correction wins[5, '1.21'][5, '1.21']Passed
control: staleERR:staleERR:stalePassed
control: only futureERR:no-rateERR:no-ratePassed
control: unlimited age[0, '1.05'][0, '1.05']Passed

SHA-256 / 5b133a0533d88003688fb6ae5c3cd94e9ccc781f3d60ab7a72d0b4113edf92da

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.356255+00:00.

Case digest / 37d7995d8c40dc1cf7a9d4a22d09fdb1cee88316dd0040a24b683ccff09dcec9