FA-72556 / Check-digit algorithms / Open access
ORCID complements the remainder against eleven · case 01
Every generated check character is off by one.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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"] | malformed | malformed | Passed |
| control ["0000-00021825-0097"] | malformed | malformed | Passed |
| control ["0000-0002-1825-009"] | malformed | malformed | Passed |
| control ["000-00002-1825-0097"] | malformed | malformed | Passed |
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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"] | malformed | malformed | Passed |
| control ["0000-00021825-0097"] | malformed | malformed | Passed |
| control ["0000-0002-1825-009"] | malformed | malformed | Passed |
| control ["000-00002-1825-0097"] | malformed | malformed | Passed |
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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"] | malformed | malformed | Passed |
| control ["0000-00021825-0097"] | malformed | malformed | Passed |
| control ["0000-0002-1825-009"] | malformed | malformed | Passed |
| control ["000-00002-1825-0097"] | malformed | malformed | Passed |
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