FAILURE MAP
← Case archive

FA-72371 / Check-digit algorithms / Open access

ISIN generation doubles with validation parity · case 01

Computed ISIN check digits disagree with issued identifiers.

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

ROOT CAUSE

The generator doubles digits at odd offsets (validation parity) even though the check digit is absent from the payload.

VERIFIED REPAIR

When generating from the payload, double the rightmost expanded payload digit (even offsets).

Unsuccessful approach: Counting doubling positions from the left is only correct when the expanded payload has an odd length.

Case contract

Input a 12-character ISIN: two uppercase ASCII letters (country), nine uppercase alphanumerics, one check digit; anything else is "malformed". Letters expand to two digits (A=10 .. Z=35), then Luhn doubling starts at the rightmost digit of the expanded 11-character payload. Return [computed check digit, whether it matches].

Why this case matters

Securities settlement systems reject ISINs whose check digit does not match before routing trades.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(s):
    if len(s) != 12 or not s.isascii() or not s[:2].isalpha() or not s[:2].isupper():
        return 'malformed'
    if not s[2:11].isalnum() or s[2:11] != s[2:11].upper() or not s[11].isdigit():
        return 'malformed'
    digits = ''
    for ch in s[:11]:
        digits += ch if ch.isdigit() else str(ord(ch) - 55)
    total = 0
    for i, ch in enumerate(reversed(digits)):
        d = int(ch)
        if i % 2 == 1:
            d *= 2
            if d > 9:
                d -= 9
        total += d
    check = (10 - total % 10) % 10
    return [check, check == int(s[11])]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["US4V5PGS4IX8"]', ['US4V5PGS4IX8'], [0, False]], ['regression ["DEC85GG2TSS1"]', ['DEC85GG2TSS1'], [4, False]], ['partial-repair ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['partial-repair ["XS0K4JDSXBN1"]', ['XS0K4JDSXBN1'], [4, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']], [['regression ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['regression ["FRLWNIYHPT37"]', ['FRLWNIYHPT37'], [5, False]], ['partial-repair ["AU0000XVGZA3"]', ['AU0000XVGZA3'], [3, True]], ['partial-repair ["DE000BAY0017"]', ['DE000BAY0017'], [7, True]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["XS2021832634"]', ['XS2021832634'], [4, True]]], [['regression ["NL5BVKR8BB60"]', ['NL5BVKR8BB60'], [3, False]], ['regression ["AUKWRNHD2XR3"]', ['AUKWRNHD2XR3'], [8, False]], ['partial-repair ["CA0000ABCDE0"]', ['CA0000ABCDE0'], [9, False]], ['partial-repair ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']], [['regression ["IE9141151847"]', ['IE9141151847'], [0, False]], ['regression ["LU7763909076"]', ['LU7763909076'], [8, False]], ['partial-repair ["CA3CKMM2IAN8"]', ['CA3CKMM2IAN8'], [0, False]], ['partial-repair ["AU0000XVGZA3"]', ['AU0000XVGZA3'], [3, True]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["XS2021832634"]', ['XS2021832634'], [4, True]]], [['regression ["BM9170095145"]', ['BM9170095145'], [7, False]], ['regression ["US0378331005"]', ['US0378331005'], [5, True]], ['partial-repair ["US38259P5089"]', ['US38259P5089'], [9, True]], ['partial-repair ["CA0000ABCDE0"]', ['CA0000ABCDE0'], [9, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']]]
for label, args, expected in fixtures[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 ["US4V5PGS4IX8"][7, False][0, False]Failed
regression ["DEC85GG2TSS1"][3, False][4, False]Failed
partial-repair ["CHXVXSVIT016"][9, False][1, False]Failed
partial-repair ["XS0K4JDSXBN1"][6, False][4, False]Failed
control ["GBOV8F5J6090"][7, False][7, False]Passed
control ["US6754047769"][8, False][8, False]Passed
control ["US037833100"]malformedmalformedPassed
control ["us0378331005"]malformedmalformedPassed

SHA-256 / 781864c2438dc0eb9c3a1130a0694c4e5f404b9957ef7af90d917ceb14e79291

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(s):
    if len(s) != 12 or not s.isascii() or not s[:2].isalpha() or not s[:2].isupper():
        return 'malformed'
    if not s[2:11].isalnum() or s[2:11] != s[2:11].upper() or not s[11].isdigit():
        return 'malformed'
    digits = ''
    for ch in s[:11]:
        digits += ch if ch.isdigit() else str(ord(ch) - 55)
    total = 0
    for i, ch in enumerate(reversed(digits)):
        d = int(ch)
        if (len(digits) - 1 - i) % 2 == 0:
            d *= 2
            if d > 9:
                d -= 9
        total += d
    check = (10 - total % 10) % 10
    return [check, check == int(s[11])]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["US4V5PGS4IX8"]', ['US4V5PGS4IX8'], [0, False]], ['regression ["DEC85GG2TSS1"]', ['DEC85GG2TSS1'], [4, False]], ['partial-repair ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['partial-repair ["XS0K4JDSXBN1"]', ['XS0K4JDSXBN1'], [4, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']], [['regression ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['regression ["FRLWNIYHPT37"]', ['FRLWNIYHPT37'], [5, False]], ['partial-repair ["AU0000XVGZA3"]', ['AU0000XVGZA3'], [3, True]], ['partial-repair ["DE000BAY0017"]', ['DE000BAY0017'], [7, True]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["XS2021832634"]', ['XS2021832634'], [4, True]]], [['regression ["NL5BVKR8BB60"]', ['NL5BVKR8BB60'], [3, False]], ['regression ["AUKWRNHD2XR3"]', ['AUKWRNHD2XR3'], [8, False]], ['partial-repair ["CA0000ABCDE0"]', ['CA0000ABCDE0'], [9, False]], ['partial-repair ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']], [['regression ["IE9141151847"]', ['IE9141151847'], [0, False]], ['regression ["LU7763909076"]', ['LU7763909076'], [8, False]], ['partial-repair ["CA3CKMM2IAN8"]', ['CA3CKMM2IAN8'], [0, False]], ['partial-repair ["AU0000XVGZA3"]', ['AU0000XVGZA3'], [3, True]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["XS2021832634"]', ['XS2021832634'], [4, True]]], [['regression ["BM9170095145"]', ['BM9170095145'], [7, False]], ['regression ["US0378331005"]', ['US0378331005'], [5, True]], ['partial-repair ["US38259P5089"]', ['US38259P5089'], [9, True]], ['partial-repair ["CA0000ABCDE0"]', ['CA0000ABCDE0'], [9, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']]]
for label, args, expected in fixtures[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 ["US4V5PGS4IX8"][0, False][0, False]Passed
regression ["DEC85GG2TSS1"][4, False][4, False]Passed
partial-repair ["CHXVXSVIT016"][9, False][1, False]Failed
partial-repair ["XS0K4JDSXBN1"][6, False][4, False]Failed
control ["GBOV8F5J6090"][7, False][7, False]Passed
control ["US6754047769"][8, False][8, False]Passed
control ["US037833100"]malformedmalformedPassed
control ["us0378331005"]malformedmalformedPassed

SHA-256 / 9c2fdd9d37cb663e4a4b6824de28e1158a285306d45a96d7308caafc10b64737

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(s):
    if len(s) != 12 or not s.isascii() or not s[:2].isalpha() or not s[:2].isupper():
        return 'malformed'
    if not s[2:11].isalnum() or s[2:11] != s[2:11].upper() or not s[11].isdigit():
        return 'malformed'
    digits = ''
    for ch in s[:11]:
        digits += ch if ch.isdigit() else str(ord(ch) - 55)
    total = 0
    for i, ch in enumerate(reversed(digits)):
        d = int(ch)
        if i % 2 == 0:
            d *= 2
            if d > 9:
                d -= 9
        total += d
    check = (10 - total % 10) % 10
    return [check, check == int(s[11])]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["US4V5PGS4IX8"]', ['US4V5PGS4IX8'], [0, False]], ['regression ["DEC85GG2TSS1"]', ['DEC85GG2TSS1'], [4, False]], ['partial-repair ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['partial-repair ["XS0K4JDSXBN1"]', ['XS0K4JDSXBN1'], [4, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']], [['regression ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['regression ["FRLWNIYHPT37"]', ['FRLWNIYHPT37'], [5, False]], ['partial-repair ["AU0000XVGZA3"]', ['AU0000XVGZA3'], [3, True]], ['partial-repair ["DE000BAY0017"]', ['DE000BAY0017'], [7, True]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["XS2021832634"]', ['XS2021832634'], [4, True]]], [['regression ["NL5BVKR8BB60"]', ['NL5BVKR8BB60'], [3, False]], ['regression ["AUKWRNHD2XR3"]', ['AUKWRNHD2XR3'], [8, False]], ['partial-repair ["CA0000ABCDE0"]', ['CA0000ABCDE0'], [9, False]], ['partial-repair ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']], [['regression ["IE9141151847"]', ['IE9141151847'], [0, False]], ['regression ["LU7763909076"]', ['LU7763909076'], [8, False]], ['partial-repair ["CA3CKMM2IAN8"]', ['CA3CKMM2IAN8'], [0, False]], ['partial-repair ["AU0000XVGZA3"]', ['AU0000XVGZA3'], [3, True]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["XS2021832634"]', ['XS2021832634'], [4, True]]], [['regression ["BM9170095145"]', ['BM9170095145'], [7, False]], ['regression ["US0378331005"]', ['US0378331005'], [5, True]], ['partial-repair ["US38259P5089"]', ['US38259P5089'], [9, True]], ['partial-repair ["CA0000ABCDE0"]', ['CA0000ABCDE0'], [9, False]], ['control ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US6754047769"]', ['US6754047769'], [8, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed']]]
for label, args, expected in fixtures[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 ["US4V5PGS4IX8"][0, False][0, False]Passed
regression ["DEC85GG2TSS1"][4, False][4, False]Passed
partial-repair ["CHXVXSVIT016"][1, False][1, False]Passed
partial-repair ["XS0K4JDSXBN1"][4, False][4, False]Passed
control ["GBOV8F5J6090"][7, False][7, False]Passed
control ["US6754047769"][8, False][8, False]Passed
control ["US037833100"]malformedmalformedPassed
control ["us0378331005"]malformedmalformedPassed

SHA-256 / 8b5177b5decdee4843d67f6a4823b91da0b81f179723abd6e33acfe04086fe55

Verification & scope

A deterministic, bounded teaching model of the named scheme under the stated contract; not a certified validator. 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:48:37.933135+00:00.

Case digest / 4f871a9e7d9bef1e359d1d1f2b88eaec457a963030b2057ab58809de800d1ed5