FAILURE MAP
← Case archive

FA-72651 / Check-digit algorithms / Open access

UPC-E expansion treats m6 = 2 as a product digit · case 01

Codes ending in compressed digit 2 expand into the wrong manufacturer number.

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

ROOT CAUSE

Only m6 in 0-1 uses the manufacturer rule; 2 falls through to the 5-9 rule.

VERIFIED REPAIR

Apply the m1 m2 m6 0000 m3 m4 m5 rule for m6 in 0, 1 and 2.

Unsuccessful approach: Extending the rule to 0-3 fixes 2 but steals the 3 case.

Case contract

Expand an 8-digit UPC-E (number system 0 or 1, six compressed digits m1..m6, check digit) to UPC-A. By m6: 0-2 -> m1 m2 m6 0000 m3 m4 m5; 3 -> m1 m2 m3 00000 m4 m5; 4 -> m1 m2 m3 m4 00000 m5; 5-9 -> m1..m5 0000 m6. The UPC-A check (weights 3,1 from the left over the 11 digits) must equal the given check digit; return the 12-digit UPC-A string, or None for malformed or mismatching input.

Why this case matters

Point-of-sale systems normalise zero-suppressed UPC-E labels into UPC-A keys for price lookup.

1 / The failure

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

N = 1
observations = []
def solve(s):
    if len(s) != 8 or not s.isascii() or not s.isdigit() or s[0] not in '01':
        return None
    ns, m, chk = s[0], s[1:7], s[7]
    last = m[5]
    if last in '01':
        body = m[0:2] + last + '0000' + m[2:5]
    elif last == '3':
        body = m[0:3] + '00000' + m[3:5]
    elif last == '4':
        body = m[0:4] + '00000' + m[4]
    else:
        body = m[0:5] + '0000' + last
    a = ns + body
    total = sum(int(ch) * (3 if i % 2 == 0 else 1) for i, ch in enumerate(a))
    check = (10 - total % 10) % 10
    if str(check) != chk:
        return None
    return a + chk
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["13813703"]', ['13813703'], '138000001373'], ['control ["06109613"]', ['06109613'], '061100000963'], ['control ["10054749"]', ['10054749'], '100540000079'], ['control ["08190253"]', ['08190253'], '081902000053']], [['regression ["14586929"]', ['14586929'], '145200008699'], ['regression ["08548229"]', ['08548229'], '085200004829'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["15067371"]', ['15067371'], '150673000071'], ['control ["00140485"]', ['00140485'], '001404000085'], ['control ["04896098"]', ['04896098'], '048960000098'], ['control ["14227004"]', ['14227004'], '142000002704']], [['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["07813340"]', ['07813340'], '078130000030'], ['control ["16526754"]', ['16526754'], '165267000054'], ['control ["28109420"]', ['28109420'], None], ['control ["32492194"]', ['32492194'], None]], [['regression ["14586929"]', ['14586929'], '145200008699'], ['regression ["08548229"]', ['08548229'], '085200004829'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["97987994"]', ['97987994'], None], ['control ["04252614"]', ['04252614'], '042100005264'], ['control ["01234565"]', ['01234565'], '012345000065'], ['control ["23456781"]', ['23456781'], None]], [['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["0425261a"]', ['0425261a'], None], ['control ["04252615"]', ['04252615'], None], ['control ["12345670"]', ['12345670'], '123456000070'], ['control ["00000000"]', ['00000000'], '000000000000']]]
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 ["08548229"]None085200004829Failed
regression ["14586929"]None145200008699Failed
partial-repair ["03909633"]039000000963039000000963Passed
partial-repair ["04793431"]047900000341047900000341Passed
control ["13813703"]138000001373138000001373Passed
control ["06109613"]061100000963061100000963Passed
control ["10054749"]100540000079100540000079Passed
control ["08190253"]081902000053081902000053Passed

SHA-256 / 5215ac04fcb557be29d086c2ad68998b2c64a6fcec3475eec87f12260750a36e

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) != 8 or not s.isascii() or not s.isdigit() or s[0] not in '01':
        return None
    ns, m, chk = s[0], s[1:7], s[7]
    last = m[5]
    if last in '0123':
        body = m[0:2] + last + '0000' + m[2:5]
    elif last == '3':
        body = m[0:3] + '00000' + m[3:5]
    elif last == '4':
        body = m[0:4] + '00000' + m[4]
    else:
        body = m[0:5] + '0000' + last
    a = ns + body
    total = sum(int(ch) * (3 if i % 2 == 0 else 1) for i, ch in enumerate(a))
    check = (10 - total % 10) % 10
    if str(check) != chk:
        return None
    return a + chk
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["13813703"]', ['13813703'], '138000001373'], ['control ["06109613"]', ['06109613'], '061100000963'], ['control ["10054749"]', ['10054749'], '100540000079'], ['control ["08190253"]', ['08190253'], '081902000053']], [['regression ["14586929"]', ['14586929'], '145200008699'], ['regression ["08548229"]', ['08548229'], '085200004829'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["15067371"]', ['15067371'], '150673000071'], ['control ["00140485"]', ['00140485'], '001404000085'], ['control ["04896098"]', ['04896098'], '048960000098'], ['control ["14227004"]', ['14227004'], '142000002704']], [['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["07813340"]', ['07813340'], '078130000030'], ['control ["16526754"]', ['16526754'], '165267000054'], ['control ["28109420"]', ['28109420'], None], ['control ["32492194"]', ['32492194'], None]], [['regression ["14586929"]', ['14586929'], '145200008699'], ['regression ["08548229"]', ['08548229'], '085200004829'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["97987994"]', ['97987994'], None], ['control ["04252614"]', ['04252614'], '042100005264'], ['control ["01234565"]', ['01234565'], '012345000065'], ['control ["23456781"]', ['23456781'], None]], [['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["0425261a"]', ['0425261a'], None], ['control ["04252615"]', ['04252615'], None], ['control ["12345670"]', ['12345670'], '123456000070'], ['control ["00000000"]', ['00000000'], '000000000000']]]
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 ["08548229"]085200004829085200004829Passed
regression ["14586929"]145200008699145200008699Passed
partial-repair ["03909633"]None039000000963Failed
partial-repair ["04793431"]None047900000341Failed
control ["13813703"]138000001373138000001373Passed
control ["06109613"]061100000963061100000963Passed
control ["10054749"]100540000079100540000079Passed
control ["08190253"]081902000053081902000053Passed

SHA-256 / 50cf48f35d37632604b5fce9c716d05271ecaa654f04ea032fc8f025c6112def

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) != 8 or not s.isascii() or not s.isdigit() or s[0] not in '01':
        return None
    ns, m, chk = s[0], s[1:7], s[7]
    last = m[5]
    if last in '012':
        body = m[0:2] + last + '0000' + m[2:5]
    elif last == '3':
        body = m[0:3] + '00000' + m[3:5]
    elif last == '4':
        body = m[0:4] + '00000' + m[4]
    else:
        body = m[0:5] + '0000' + last
    a = ns + body
    total = sum(int(ch) * (3 if i % 2 == 0 else 1) for i, ch in enumerate(a))
    check = (10 - total % 10) % 10
    if str(check) != chk:
        return None
    return a + chk
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["13813703"]', ['13813703'], '138000001373'], ['control ["06109613"]', ['06109613'], '061100000963'], ['control ["10054749"]', ['10054749'], '100540000079'], ['control ["08190253"]', ['08190253'], '081902000053']], [['regression ["14586929"]', ['14586929'], '145200008699'], ['regression ["08548229"]', ['08548229'], '085200004829'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["15067371"]', ['15067371'], '150673000071'], ['control ["00140485"]', ['00140485'], '001404000085'], ['control ["04896098"]', ['04896098'], '048960000098'], ['control ["14227004"]', ['14227004'], '142000002704']], [['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["07813340"]', ['07813340'], '078130000030'], ['control ["16526754"]', ['16526754'], '165267000054'], ['control ["28109420"]', ['28109420'], None], ['control ["32492194"]', ['32492194'], None]], [['regression ["14586929"]', ['14586929'], '145200008699'], ['regression ["08548229"]', ['08548229'], '085200004829'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["97987994"]', ['97987994'], None], ['control ["04252614"]', ['04252614'], '042100005264'], ['control ["01234565"]', ['01234565'], '012345000065'], ['control ["23456781"]', ['23456781'], None]], [['regression ["08548229"]', ['08548229'], '085200004829'], ['regression ["14586929"]', ['14586929'], '145200008699'], ['partial-repair ["03909633"]', ['03909633'], '039000000963'], ['partial-repair ["04793431"]', ['04793431'], '047900000341'], ['control ["0425261a"]', ['0425261a'], None], ['control ["04252615"]', ['04252615'], None], ['control ["12345670"]', ['12345670'], '123456000070'], ['control ["00000000"]', ['00000000'], '000000000000']]]
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 ["08548229"]085200004829085200004829Passed
regression ["14586929"]145200008699145200008699Passed
partial-repair ["03909633"]039000000963039000000963Passed
partial-repair ["04793431"]047900000341047900000341Passed
control ["13813703"]138000001373138000001373Passed
control ["06109613"]061100000963061100000963Passed
control ["10054749"]100540000079100540000079Passed
control ["08190253"]081902000053081902000053Passed

SHA-256 / cbff61943dc75cc55ed9318ddfd80bd4660f092cd4cdc3e6cdd836b278e27a6a

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

Case digest / 6bfcb7bef1c4855e43a4aa72373db2c5324c4b93d47a878d67b843991aac746e