FAILURE MAP
← Case archive

FA-72556 / Check-digit algorithms / Open access

ORCID complements the remainder against eleven · case 01

Every generated check character is off by one.

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

ROOT CAUSE

The check is (11 - total % 11) % 11; MOD 11-2 uses 12 because of the final doubling.

VERIFIED REPAIR

Compute (12 - total % 11) % 11.

Unsuccessful approach: Dropping the outer modulus yields 12 or 11 for remainders 0 and 1.

Case contract

ORCID identifier check (ISO 7064 MOD 11-2). Input is 16 characters, either plain or as four hyphen-separated groups of four (other hyphen layouts "malformed"); fifteen digits then a digit or uppercase X. Fold total = (total + digit) * 2 over the fifteen digits; the check value is (12 - total % 11) % 11 with 10 written X. Return [check character, whether it matches].

Why this case matters

Research information systems verify ORCID iDs before linking publications to authors.

1 / The failure

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

N = 1
observations = []
def solve(s):
    if '-' in s and [len(g) for g in s.split('-')] != [4, 4, 4, 4]:
        return 'malformed'
    t = s.replace('-', '')
    if len(t) != 16 or not t.isascii() or not t[:15].isdigit() or not (t[15].isdigit() or t[15] == 'X'):
        return 'malformed'
    total = 0
    for ch in t[:15]:
        total = (total + int(ch)) * 2
    r = (11 - total % 11) % 11
    check = 'X' if r == 10 else str(r)
    return [check, check == t[15]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["0000-2284-2705-0317"]', ['0000-2284-2705-0317'], ['6', False]], ['regression ["0000-6830-1348-0503"]', ['0000-6830-1348-0503'], ['5', False]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['partial-repair ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-4451-8984-5952"]', ['0000-4451-8984-5952'], ['7', False]], ['regression ["0000-8150-6101-2864"]', ['0000-8150-6101-2864'], ['3', False]], ['partial-repair ["0000-0001-5109-3700"]', ['0000-0001-5109-3700'], ['0', True]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['regression ["0000-6263-5457-6118"]', ['0000-6263-5457-6118'], ['7', False]], ['partial-repair ["8604828079008568"]', ['8604828079008568'], ['1', False]], ['partial-repair ["0000-0001-5109-3700"]', ['0000-0001-5109-3700'], ['0', True]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['regression ["0000-5390-9620-5628"]', ['0000-5390-9620-5628'], ['4', False]], ['partial-repair ["8604828079008568"]', ['8604828079008568'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed'], ['control ["0000-0002-1694-233x"]', ['0000-0002-1694-233x'], 'malformed']], [['regression ["0000-9157-2825-059X"]', ['0000-9157-2825-059X'], ['4', False]], ['regression ["0000-9861-4470-6996"]', ['0000-9861-4470-6996'], ['8', False]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['partial-repair ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], '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 ["0000-2284-2705-0317"]['5', False]['6', False]Failed
regression ["0000-6830-1348-0503"]['4', False]['5', False]Failed
partial-repair ["0000-8999-3438-1875"]['X', False]['0', False]Failed
partial-repair ["0000-9095-7746-214X"]['0', False]['1', False]Failed
control ["00000-002-1825-0097"]malformedmalformedPassed
control ["0000-00021825-0097"]malformedmalformedPassed
control ["0000-0002-1825-009"]malformedmalformedPassed
control ["000-00002-1825-0097"]malformedmalformedPassed

SHA-256 / 6a8e2f09aa5273139106d096704db5def113176344fe7297528afdebe059bedf

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(s):
    if '-' in s and [len(g) for g in s.split('-')] != [4, 4, 4, 4]:
        return 'malformed'
    t = s.replace('-', '')
    if len(t) != 16 or not t.isascii() or not t[:15].isdigit() or not (t[15].isdigit() or t[15] == 'X'):
        return 'malformed'
    total = 0
    for ch in t[:15]:
        total = (total + int(ch)) * 2
    r = 12 - total % 11
    check = 'X' if r == 10 else str(r)
    return [check, check == t[15]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["0000-2284-2705-0317"]', ['0000-2284-2705-0317'], ['6', False]], ['regression ["0000-6830-1348-0503"]', ['0000-6830-1348-0503'], ['5', False]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['partial-repair ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-4451-8984-5952"]', ['0000-4451-8984-5952'], ['7', False]], ['regression ["0000-8150-6101-2864"]', ['0000-8150-6101-2864'], ['3', False]], ['partial-repair ["0000-0001-5109-3700"]', ['0000-0001-5109-3700'], ['0', True]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['regression ["0000-6263-5457-6118"]', ['0000-6263-5457-6118'], ['7', False]], ['partial-repair ["8604828079008568"]', ['8604828079008568'], ['1', False]], ['partial-repair ["0000-0001-5109-3700"]', ['0000-0001-5109-3700'], ['0', True]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['regression ["0000-5390-9620-5628"]', ['0000-5390-9620-5628'], ['4', False]], ['partial-repair ["8604828079008568"]', ['8604828079008568'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed'], ['control ["0000-0002-1694-233x"]', ['0000-0002-1694-233x'], 'malformed']], [['regression ["0000-9157-2825-059X"]', ['0000-9157-2825-059X'], ['4', False]], ['regression ["0000-9861-4470-6996"]', ['0000-9861-4470-6996'], ['8', False]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['partial-repair ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], '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 ["0000-2284-2705-0317"]['6', False]['6', False]Passed
regression ["0000-6830-1348-0503"]['5', False]['5', False]Passed
partial-repair ["0000-8999-3438-1875"]['11', False]['0', False]Failed
partial-repair ["0000-9095-7746-214X"]['12', False]['1', False]Failed
control ["00000-002-1825-0097"]malformedmalformedPassed
control ["0000-00021825-0097"]malformedmalformedPassed
control ["0000-0002-1825-009"]malformedmalformedPassed
control ["000-00002-1825-0097"]malformedmalformedPassed

SHA-256 / 98e7753a7e6133b28f8ab405e764ad957aa35ef5c15bc1ce827c6bbdd785b6de

3 / The verified repair

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

N = 1
observations = []
def solve(s):
    if '-' in s and [len(g) for g in s.split('-')] != [4, 4, 4, 4]:
        return 'malformed'
    t = s.replace('-', '')
    if len(t) != 16 or not t.isascii() or not t[:15].isdigit() or not (t[15].isdigit() or t[15] == 'X'):
        return 'malformed'
    total = 0
    for ch in t[:15]:
        total = (total + int(ch)) * 2
    r = (12 - total % 11) % 11
    check = 'X' if r == 10 else str(r)
    return [check, check == t[15]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["0000-2284-2705-0317"]', ['0000-2284-2705-0317'], ['6', False]], ['regression ["0000-6830-1348-0503"]', ['0000-6830-1348-0503'], ['5', False]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['partial-repair ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-4451-8984-5952"]', ['0000-4451-8984-5952'], ['7', False]], ['regression ["0000-8150-6101-2864"]', ['0000-8150-6101-2864'], ['3', False]], ['partial-repair ["0000-0001-5109-3700"]', ['0000-0001-5109-3700'], ['0', True]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['regression ["0000-6263-5457-6118"]', ['0000-6263-5457-6118'], ['7', False]], ['partial-repair ["8604828079008568"]', ['8604828079008568'], ['1', False]], ['partial-repair ["0000-0001-5109-3700"]', ['0000-0001-5109-3700'], ['0', True]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed']], [['regression ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['regression ["0000-5390-9620-5628"]', ['0000-5390-9620-5628'], ['4', False]], ['partial-repair ["8604828079008568"]', ['8604828079008568'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], 'malformed'], ['control ["0000-0002-1694-233x"]', ['0000-0002-1694-233x'], 'malformed']], [['regression ["0000-9157-2825-059X"]', ['0000-9157-2825-059X'], ['4', False]], ['regression ["0000-9861-4470-6996"]', ['0000-9861-4470-6996'], ['8', False]], ['partial-repair ["0000-8999-3438-1875"]', ['0000-8999-3438-1875'], ['0', False]], ['partial-repair ["0000-9095-7746-214X"]', ['0000-9095-7746-214X'], ['1', False]], ['control ["00000-002-1825-0097"]', ['00000-002-1825-0097'], 'malformed'], ['control ["0000-00021825-0097"]', ['0000-00021825-0097'], 'malformed'], ['control ["0000-0002-1825-009"]', ['0000-0002-1825-009'], 'malformed'], ['control ["000-00002-1825-0097"]', ['000-00002-1825-0097'], '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 ["0000-2284-2705-0317"]['6', False]['6', False]Passed
regression ["0000-6830-1348-0503"]['5', False]['5', False]Passed
partial-repair ["0000-8999-3438-1875"]['0', False]['0', False]Passed
partial-repair ["0000-9095-7746-214X"]['1', False]['1', False]Passed
control ["00000-002-1825-0097"]malformedmalformedPassed
control ["0000-00021825-0097"]malformedmalformedPassed
control ["0000-0002-1825-009"]malformedmalformedPassed
control ["000-00002-1825-0097"]malformedmalformedPassed

SHA-256 / d92bf9e50307c5f9bd13e30ff2f316c7fa74bebcdbec47618c9a39c5e77ec895

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

Case digest / fa63306a8112bb8d6178ab1b88e4ac00b23da466b8a0f9d2bc858e4d9ae9d202