FAILURE MAP
← Case archive

FA-72366 / Check-digit algorithms / Open access

ISIN letters expand from one instead of ten · case 01

ISINs containing letters get the wrong computed check digit.

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

ROOT CAUSE

Letters are expanded with ord(ch) - 64 (A=1), not the ISIN value A=10 .. Z=35.

VERIFIED REPAIR

Expand each letter to ord(ch) - 55 so A becomes "10" and Z becomes "35".

Unsuccessful approach: Expanding with ord(ch) - 65 (A=0) is still off by ten for every letter.

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) - 64)
    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 ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed']], [['regression ["JPFWKDL124I1"]', ['JPFWKDL124I1'], [1, True]], ['regression ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['partial-repair ["FRLWNIYHPT37"]', ['FRLWNIYHPT37'], [5, False]], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["US000000000A"]', ['US000000000A'], 'malformed'], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed']], [['regression ["XS0K4JDSXBN1"]', ['XS0K4JDSXBN1'], [4, False]], ['regression ["AUKWRNHD2XR3"]', ['AUKWRNHD2XR3'], [8, False]], ['partial-repair ["NL5BVKR8BB60"]', ['NL5BVKR8BB60'], [3, False]], ['partial-repair ["CA3CKMM2IAN8"]', ['CA3CKMM2IAN8'], [0, False]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["US000000000A"]', ['US000000000A'], 'malformed']], [['regression ["US6754047769"]', ['US6754047769'], [8, False]], ['regression ["IE9141151847"]', ['IE9141151847'], [0, False]], ['partial-repair ["LU7763909076"]', ['LU7763909076'], [8, False]], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed']], [['regression ["KY3791880781"]', ['KY3791880781'], [4, False]], ['regression ["BM9170095145"]', ['BM9170095145'], [7, False]], ['partial-repair ["US0378331005"]', ['US0378331005'], [5, True]], ['control ["US000000000A"]', ['US000000000A'], 'malformed'], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], '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"][9, False][0, False]Failed
regression ["GBOV8F5J6090"][1, False][7, False]Failed
control ["US037833100"]malformedmalformedPassed
control ["us0378331005"]malformedmalformedPassed
control ["US03783310a5"]malformedmalformedPassed
control ["12Q037833100"]malformedmalformedPassed
control ["1S0378331005"]malformedmalformedPassed
control ["U10378331005"]malformedmalformedPassed

SHA-256 / a5689026595c6cc5b3250e4c57945d5ff1db3bab97bffdc9322c119072d69443

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) - 65)
    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 ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed']], [['regression ["JPFWKDL124I1"]', ['JPFWKDL124I1'], [1, True]], ['regression ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['partial-repair ["FRLWNIYHPT37"]', ['FRLWNIYHPT37'], [5, False]], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["US000000000A"]', ['US000000000A'], 'malformed'], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed']], [['regression ["XS0K4JDSXBN1"]', ['XS0K4JDSXBN1'], [4, False]], ['regression ["AUKWRNHD2XR3"]', ['AUKWRNHD2XR3'], [8, False]], ['partial-repair ["NL5BVKR8BB60"]', ['NL5BVKR8BB60'], [3, False]], ['partial-repair ["CA3CKMM2IAN8"]', ['CA3CKMM2IAN8'], [0, False]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["US000000000A"]', ['US000000000A'], 'malformed']], [['regression ["US6754047769"]', ['US6754047769'], [8, False]], ['regression ["IE9141151847"]', ['IE9141151847'], [0, False]], ['partial-repair ["LU7763909076"]', ['LU7763909076'], [8, False]], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed']], [['regression ["KY3791880781"]', ['KY3791880781'], [4, False]], ['regression ["BM9170095145"]', ['BM9170095145'], [7, False]], ['partial-repair ["US0378331005"]', ['US0378331005'], [5, True]], ['control ["US000000000A"]', ['US000000000A'], 'malformed'], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], '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"][2, False][0, False]Failed
regression ["GBOV8F5J6090"][1, False][7, False]Failed
control ["US037833100"]malformedmalformedPassed
control ["us0378331005"]malformedmalformedPassed
control ["US03783310a5"]malformedmalformedPassed
control ["12Q037833100"]malformedmalformedPassed
control ["1S0378331005"]malformedmalformedPassed
control ["U10378331005"]malformedmalformedPassed

SHA-256 / 481de792fa70b649fea355362cf96a9086041dce6afed7392d35c15f16aee041

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 ["GBOV8F5J6090"]', ['GBOV8F5J6090'], [7, False]], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed']], [['regression ["JPFWKDL124I1"]', ['JPFWKDL124I1'], [1, True]], ['regression ["CHXVXSVIT016"]', ['CHXVXSVIT016'], [1, False]], ['partial-repair ["FRLWNIYHPT37"]', ['FRLWNIYHPT37'], [5, False]], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["US000000000A"]', ['US000000000A'], 'malformed'], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed']], [['regression ["XS0K4JDSXBN1"]', ['XS0K4JDSXBN1'], [4, False]], ['regression ["AUKWRNHD2XR3"]', ['AUKWRNHD2XR3'], [8, False]], ['partial-repair ["NL5BVKR8BB60"]', ['NL5BVKR8BB60'], [3, False]], ['partial-repair ["CA3CKMM2IAN8"]', ['CA3CKMM2IAN8'], [0, False]], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed'], ['control ["US000000000A"]', ['US000000000A'], 'malformed']], [['regression ["US6754047769"]', ['US6754047769'], [8, False]], ['regression ["IE9141151847"]', ['IE9141151847'], [0, False]], ['partial-repair ["LU7763909076"]', ['LU7763909076'], [8, False]], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], 'malformed'], ['control ["1S0378331005"]', ['1S0378331005'], 'malformed'], ['control ["U10378331005"]', ['U10378331005'], 'malformed']], [['regression ["KY3791880781"]', ['KY3791880781'], [4, False]], ['regression ["BM9170095145"]', ['BM9170095145'], [7, False]], ['partial-repair ["US0378331005"]', ['US0378331005'], [5, True]], ['control ["US000000000A"]', ['US000000000A'], 'malformed'], ['control ["US037833100"]', ['US037833100'], 'malformed'], ['control ["us0378331005"]', ['us0378331005'], 'malformed'], ['control ["US03783310a5"]', ['US03783310a5'], 'malformed'], ['control ["12Q037833100"]', ['12Q037833100'], '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 ["GBOV8F5J6090"][7, False][7, False]Passed
control ["US037833100"]malformedmalformedPassed
control ["us0378331005"]malformedmalformedPassed
control ["US03783310a5"]malformedmalformedPassed
control ["12Q037833100"]malformedmalformedPassed
control ["1S0378331005"]malformedmalformedPassed
control ["U10378331005"]malformedmalformedPassed

SHA-256 / 0d7f8131ac0e4f0fed99fe7cc3c783ee16963cb3edb5396acabb38e0125627f2

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

Case digest / aecbdc0f6704027c138712cf02a71f53a769a68c403710efcde1e5192e918631