FAILURE MAP
← Case archive

FA-79446 / Barcode symbology encoding / Open access

Set C accepts pairs containing spaces · case 01

A space-padded quantity is encoded as a digit pair value because int() ignores whitespace.

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

ROOT CAUSE

Only the length parity is checked before converting pairs with int().

VERIFIED REPAIR

Require even length and ASCII digits only.

Unsuccessful approach: Checking isdigit without the parity lets an odd final digit become a single-digit pair.

Case contract

Turn planned Code 128 segments into symbol values (without the checksum). Segments are [set, text], ["FNC1"] or ["SHIFT", char]. The first set segment emits its start (A 103, B 104, C 105); later set changes emit Code A 101, Code B 100 or Code C 99. Set A encodes 32..95 as ord-32 and 0..31 as ord+64; set B encodes 32..127 as ord-32; set C encodes even-length ASCII digit text as pair values. FNC1 is 102 and needs a prior start; SHIFT (98) is only valid in A or B and encodes one character in the other of A/B. Errors: no-start, bad-shift, bad-c, unencodable.

Why this case matters

Retail, logistics, pharmacy and document workflows depend on encoders that produce exactly the module pattern, code-set switches, separators and quiet zones scanners expect; one misplaced module or separator makes a label unreadable or, worse, scan as different data.

1 / The failure

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

N = 1
observations = []
def solve(segs):
    out = []
    cur = None
    starts = {'A': 103, 'B': 104, 'C': 105}
    switch = {'A': 101, 'B': 100, 'C': 99}
    def val(s, ch):
        o = ord(ch)
        if s == 'A':
            if 32 <= o <= 95:
                return o - 32
            if 0 <= o <= 31:
                return o + 64
            return None
        if 32 <= o <= 127:
            return o - 32
        return None
    for seg in segs:
        kind = seg[0]
        if kind == 'FNC1':
            if cur is None:
                return {'error': 'no-start'}
            out.append(102)
            continue
        if kind == 'SHIFT':
            if cur not in ('A', 'B'):
                return {'error': 'bad-shift'}
            other = 'B' if cur == 'A' else 'A'
            v = val(other, seg[1])
            if v is None:
                return {'error': 'unencodable', 'char': seg[1]}
            out += [98, v]
            continue
        s, text = seg
        if cur is None:
            out.append(starts[s])
        elif s != cur:
            out.append(switch[s])
        cur = s
        if s == 'C':
            if len(text) % 2:
                return {'error': 'bad-c'}
            out += [int(text[j:j + 2]) for j in range(0, len(text), 2)]
        else:
            for ch in text:
                v = val(s, ch)
                if v is None:
                    return {'error': 'unencodable', 'char': ch}
                out.append(v)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['B', 'Lot 7'], ['C', '12'], ['C', ' 1']], {'error': 'bad-c'}], [[['B', 'Q'], ['B', '{x}'], ['C', '123']], {'error': 'bad-c'}], [[['C', '12'], ['A', 'HELLO']], [105, 12, 101, 40, 37, 44, 44, 47]], [[['B', 'ab'], ['A', '\x00Q'], ['SHIFT', '\t'], ['FNC1']], {'error': 'unencodable', 'char': '\t'}], [[['B', 'Lot 7'], ['A', '\x00Q'], ['FNC1'], ['C', '4711']], [104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11]], [[['A', 'X\x1d1']], [103, 56, 93, 17]], [[['A', 'HELLO'], ['A', 'AB'], ['A', 'X\x1d1']], [103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17]], [[['B', '{x}'], ['A', 'X\x1d1'], ['C', ' 1'], ['SHIFT', '\x1d']], {'error': 'bad-c'}]], [[[['C', ' 1'], ['FNC1']], {'error': 'bad-c'}], [[['A', '\t'], ['C', '0099'], ['A', 'HELLO'], ['C', '123']], {'error': 'bad-c'}], [[['A', '\x00Q'], ['B', '{x}'], ['A', 'X\x1d1'], ['SHIFT', 'z']], [103, 64, 49, 100, 91, 88, 93, 101, 56, 93, 17, 98, 90]], [[['A', 'AB'], ['B', 'Q'], ['B', 'z~']], [103, 33, 34, 100, 49, 90, 94]], [[['A', 'AB'], ['FNC1']], [103, 33, 34, 102]], [[['B', 'z~'], ['SHIFT', 'z'], ['FNC1']], {'error': 'unencodable', 'char': 'z'}], [[['B', '{x}'], ['A', '_^']], [104, 91, 88, 93, 101, 63, 62]], [[['C', ' 1'], ['A', '\x00Q'], ['FNC1'], ['B', '{x}']], {'error': 'bad-c'}]], [[[['C', ' 1']], {'error': 'bad-c'}], [[['C', '123'], ['A', 'AB'], ['A', '\t'], ['A', '\x00Q']], {'error': 'bad-c'}], [[['FNC1'], ['C', '0099'], ['B', 'Lot 7'], ['C', '4711'], ['C', '12']], {'error': 'no-start'}], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['C', '0099']], [105, 0, 99]], [[['A', 'AB']], [103, 33, 34]], [[['A', 'X\x1d1']], [103, 56, 93, 17]], [[['B', '{x}'], ['C', ' 1']], {'error': 'bad-c'}]], [[[['C', ' 1'], ['C', '0099']], {'error': 'bad-c'}], [[['B', '{x}'], ['C', '123'], ['C', '0099']], {'error': 'bad-c'}], [[['B', 'z~']], [104, 90, 94]], [[['C', '4711']], [105, 47, 11]], [[['A', 'HELLO'], ['A', '_^'], ['A', '_^']], [103, 40, 37, 44, 44, 47, 63, 62, 63, 62]], [[['A', '\t']], [103, 73]], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['B', 'Lot 7'], ['C', ' 1'], ['A', 'AB'], ['B', 'ab']], {'error': 'bad-c'}]], [[[['B', 'ab'], ['C', ' 1']], {'error': 'bad-c'}], [[['C', '0099'], ['C', '123']], {'error': 'bad-c'}], [[['FNC1'], ['A', 'HELLO']], {'error': 'no-start'}], [[['C', '4711'], ['B', 'Q'], ['B', '{x}']], [105, 47, 11, 100, 49, 91, 88, 93]], [[['B', '{x}'], ['B', 'Q']], [104, 91, 88, 93, 49]], [[['A', 'AB']], [103, 33, 34]], [[['FNC1'], ['A', 'X\x1d1']], {'error': 'no-start'}], [[['C', ' 1'], ['A', '_^'], ['SHIFT', '\x1d']], {'error': 'bad-c'}]]]
labels = ["regression: set C text validation", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("%s %d" % (labels[i % len(labels)], i), 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: set C text validation 0[104, 44, 79, 84, 0, 23, 99, 12, 1]{'error': 'bad-c'}Failed
repair trap 1{'error': 'bad-c'}{'error': 'bad-c'}Passed
combined fault 2[105, 12, 101, 40, 37, 44, 44, 47][105, 12, 101, 40, 37, 44, 44, 47]Passed
control 3{'char': '\t', 'error': 'unencodable'}{'char': '\t', 'error': 'unencodable'}Passed
control 4[104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11][104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11]Passed
boundary 5[103, 56, 93, 17][103, 56, 93, 17]Passed
boundary 6[103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17][103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17]Passed
control 7{'error': 'bad-shift'}{'error': 'bad-c'}Failed

SHA-256 / ce74fb8d8fbd6ed60c92d6911de93271339f540eca8474e2c2d648f79d5188d9

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(segs):
    out = []
    cur = None
    starts = {'A': 103, 'B': 104, 'C': 105}
    switch = {'A': 101, 'B': 100, 'C': 99}
    def val(s, ch):
        o = ord(ch)
        if s == 'A':
            if 32 <= o <= 95:
                return o - 32
            if 0 <= o <= 31:
                return o + 64
            return None
        if 32 <= o <= 127:
            return o - 32
        return None
    for seg in segs:
        kind = seg[0]
        if kind == 'FNC1':
            if cur is None:
                return {'error': 'no-start'}
            out.append(102)
            continue
        if kind == 'SHIFT':
            if cur not in ('A', 'B'):
                return {'error': 'bad-shift'}
            other = 'B' if cur == 'A' else 'A'
            v = val(other, seg[1])
            if v is None:
                return {'error': 'unencodable', 'char': seg[1]}
            out += [98, v]
            continue
        s, text = seg
        if cur is None:
            out.append(starts[s])
        elif s != cur:
            out.append(switch[s])
        cur = s
        if s == 'C':
            if not text.isdigit():
                return {'error': 'bad-c'}
            out += [int(text[j:j + 2]) for j in range(0, len(text), 2)]
        else:
            for ch in text:
                v = val(s, ch)
                if v is None:
                    return {'error': 'unencodable', 'char': ch}
                out.append(v)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['B', 'Lot 7'], ['C', '12'], ['C', ' 1']], {'error': 'bad-c'}], [[['B', 'Q'], ['B', '{x}'], ['C', '123']], {'error': 'bad-c'}], [[['C', '12'], ['A', 'HELLO']], [105, 12, 101, 40, 37, 44, 44, 47]], [[['B', 'ab'], ['A', '\x00Q'], ['SHIFT', '\t'], ['FNC1']], {'error': 'unencodable', 'char': '\t'}], [[['B', 'Lot 7'], ['A', '\x00Q'], ['FNC1'], ['C', '4711']], [104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11]], [[['A', 'X\x1d1']], [103, 56, 93, 17]], [[['A', 'HELLO'], ['A', 'AB'], ['A', 'X\x1d1']], [103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17]], [[['B', '{x}'], ['A', 'X\x1d1'], ['C', ' 1'], ['SHIFT', '\x1d']], {'error': 'bad-c'}]], [[[['C', ' 1'], ['FNC1']], {'error': 'bad-c'}], [[['A', '\t'], ['C', '0099'], ['A', 'HELLO'], ['C', '123']], {'error': 'bad-c'}], [[['A', '\x00Q'], ['B', '{x}'], ['A', 'X\x1d1'], ['SHIFT', 'z']], [103, 64, 49, 100, 91, 88, 93, 101, 56, 93, 17, 98, 90]], [[['A', 'AB'], ['B', 'Q'], ['B', 'z~']], [103, 33, 34, 100, 49, 90, 94]], [[['A', 'AB'], ['FNC1']], [103, 33, 34, 102]], [[['B', 'z~'], ['SHIFT', 'z'], ['FNC1']], {'error': 'unencodable', 'char': 'z'}], [[['B', '{x}'], ['A', '_^']], [104, 91, 88, 93, 101, 63, 62]], [[['C', ' 1'], ['A', '\x00Q'], ['FNC1'], ['B', '{x}']], {'error': 'bad-c'}]], [[[['C', ' 1']], {'error': 'bad-c'}], [[['C', '123'], ['A', 'AB'], ['A', '\t'], ['A', '\x00Q']], {'error': 'bad-c'}], [[['FNC1'], ['C', '0099'], ['B', 'Lot 7'], ['C', '4711'], ['C', '12']], {'error': 'no-start'}], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['C', '0099']], [105, 0, 99]], [[['A', 'AB']], [103, 33, 34]], [[['A', 'X\x1d1']], [103, 56, 93, 17]], [[['B', '{x}'], ['C', ' 1']], {'error': 'bad-c'}]], [[[['C', ' 1'], ['C', '0099']], {'error': 'bad-c'}], [[['B', '{x}'], ['C', '123'], ['C', '0099']], {'error': 'bad-c'}], [[['B', 'z~']], [104, 90, 94]], [[['C', '4711']], [105, 47, 11]], [[['A', 'HELLO'], ['A', '_^'], ['A', '_^']], [103, 40, 37, 44, 44, 47, 63, 62, 63, 62]], [[['A', '\t']], [103, 73]], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['B', 'Lot 7'], ['C', ' 1'], ['A', 'AB'], ['B', 'ab']], {'error': 'bad-c'}]], [[[['B', 'ab'], ['C', ' 1']], {'error': 'bad-c'}], [[['C', '0099'], ['C', '123']], {'error': 'bad-c'}], [[['FNC1'], ['A', 'HELLO']], {'error': 'no-start'}], [[['C', '4711'], ['B', 'Q'], ['B', '{x}']], [105, 47, 11, 100, 49, 91, 88, 93]], [[['B', '{x}'], ['B', 'Q']], [104, 91, 88, 93, 49]], [[['A', 'AB']], [103, 33, 34]], [[['FNC1'], ['A', 'X\x1d1']], {'error': 'no-start'}], [[['C', ' 1'], ['A', '_^'], ['SHIFT', '\x1d']], {'error': 'bad-c'}]]]
labels = ["regression: set C text validation", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("%s %d" % (labels[i % len(labels)], i), 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: set C text validation 0{'error': 'bad-c'}{'error': 'bad-c'}Passed
repair trap 1[104, 49, 91, 88, 93, 99, 12, 3]{'error': 'bad-c'}Failed
combined fault 2[105, 12, 101, 40, 37, 44, 44, 47][105, 12, 101, 40, 37, 44, 44, 47]Passed
control 3{'char': '\t', 'error': 'unencodable'}{'char': '\t', 'error': 'unencodable'}Passed
control 4[104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11][104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11]Passed
boundary 5[103, 56, 93, 17][103, 56, 93, 17]Passed
boundary 6[103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17][103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17]Passed
control 7{'error': 'bad-c'}{'error': 'bad-c'}Passed

SHA-256 / 2a82d253fbc1a8160560df6dc8a1eed35262a04c5dc60d465fc07849d258f757

3 / The verified repair

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

N = 1
observations = []
def solve(segs):
    out = []
    cur = None
    starts = {'A': 103, 'B': 104, 'C': 105}
    switch = {'A': 101, 'B': 100, 'C': 99}
    def val(s, ch):
        o = ord(ch)
        if s == 'A':
            if 32 <= o <= 95:
                return o - 32
            if 0 <= o <= 31:
                return o + 64
            return None
        if 32 <= o <= 127:
            return o - 32
        return None
    for seg in segs:
        kind = seg[0]
        if kind == 'FNC1':
            if cur is None:
                return {'error': 'no-start'}
            out.append(102)
            continue
        if kind == 'SHIFT':
            if cur not in ('A', 'B'):
                return {'error': 'bad-shift'}
            other = 'B' if cur == 'A' else 'A'
            v = val(other, seg[1])
            if v is None:
                return {'error': 'unencodable', 'char': seg[1]}
            out += [98, v]
            continue
        s, text = seg
        if cur is None:
            out.append(starts[s])
        elif s != cur:
            out.append(switch[s])
        cur = s
        if s == 'C':
            if len(text) % 2 or not all(c in '0123456789' for c in text):
                return {'error': 'bad-c'}
            out += [int(text[j:j + 2]) for j in range(0, len(text), 2)]
        else:
            for ch in text:
                v = val(s, ch)
                if v is None:
                    return {'error': 'unencodable', 'char': ch}
                out.append(v)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['B', 'Lot 7'], ['C', '12'], ['C', ' 1']], {'error': 'bad-c'}], [[['B', 'Q'], ['B', '{x}'], ['C', '123']], {'error': 'bad-c'}], [[['C', '12'], ['A', 'HELLO']], [105, 12, 101, 40, 37, 44, 44, 47]], [[['B', 'ab'], ['A', '\x00Q'], ['SHIFT', '\t'], ['FNC1']], {'error': 'unencodable', 'char': '\t'}], [[['B', 'Lot 7'], ['A', '\x00Q'], ['FNC1'], ['C', '4711']], [104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11]], [[['A', 'X\x1d1']], [103, 56, 93, 17]], [[['A', 'HELLO'], ['A', 'AB'], ['A', 'X\x1d1']], [103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17]], [[['B', '{x}'], ['A', 'X\x1d1'], ['C', ' 1'], ['SHIFT', '\x1d']], {'error': 'bad-c'}]], [[[['C', ' 1'], ['FNC1']], {'error': 'bad-c'}], [[['A', '\t'], ['C', '0099'], ['A', 'HELLO'], ['C', '123']], {'error': 'bad-c'}], [[['A', '\x00Q'], ['B', '{x}'], ['A', 'X\x1d1'], ['SHIFT', 'z']], [103, 64, 49, 100, 91, 88, 93, 101, 56, 93, 17, 98, 90]], [[['A', 'AB'], ['B', 'Q'], ['B', 'z~']], [103, 33, 34, 100, 49, 90, 94]], [[['A', 'AB'], ['FNC1']], [103, 33, 34, 102]], [[['B', 'z~'], ['SHIFT', 'z'], ['FNC1']], {'error': 'unencodable', 'char': 'z'}], [[['B', '{x}'], ['A', '_^']], [104, 91, 88, 93, 101, 63, 62]], [[['C', ' 1'], ['A', '\x00Q'], ['FNC1'], ['B', '{x}']], {'error': 'bad-c'}]], [[[['C', ' 1']], {'error': 'bad-c'}], [[['C', '123'], ['A', 'AB'], ['A', '\t'], ['A', '\x00Q']], {'error': 'bad-c'}], [[['FNC1'], ['C', '0099'], ['B', 'Lot 7'], ['C', '4711'], ['C', '12']], {'error': 'no-start'}], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['C', '0099']], [105, 0, 99]], [[['A', 'AB']], [103, 33, 34]], [[['A', 'X\x1d1']], [103, 56, 93, 17]], [[['B', '{x}'], ['C', ' 1']], {'error': 'bad-c'}]], [[[['C', ' 1'], ['C', '0099']], {'error': 'bad-c'}], [[['B', '{x}'], ['C', '123'], ['C', '0099']], {'error': 'bad-c'}], [[['B', 'z~']], [104, 90, 94]], [[['C', '4711']], [105, 47, 11]], [[['A', 'HELLO'], ['A', '_^'], ['A', '_^']], [103, 40, 37, 44, 44, 47, 63, 62, 63, 62]], [[['A', '\t']], [103, 73]], [[['B', 'Lot 7']], [104, 44, 79, 84, 0, 23]], [[['B', 'Lot 7'], ['C', ' 1'], ['A', 'AB'], ['B', 'ab']], {'error': 'bad-c'}]], [[[['B', 'ab'], ['C', ' 1']], {'error': 'bad-c'}], [[['C', '0099'], ['C', '123']], {'error': 'bad-c'}], [[['FNC1'], ['A', 'HELLO']], {'error': 'no-start'}], [[['C', '4711'], ['B', 'Q'], ['B', '{x}']], [105, 47, 11, 100, 49, 91, 88, 93]], [[['B', '{x}'], ['B', 'Q']], [104, 91, 88, 93, 49]], [[['A', 'AB']], [103, 33, 34]], [[['FNC1'], ['A', 'X\x1d1']], {'error': 'no-start'}], [[['C', ' 1'], ['A', '_^'], ['SHIFT', '\x1d']], {'error': 'bad-c'}]]]
labels = ["regression: set C text validation", "repair trap", "combined fault", "control", "control", "boundary", "boundary", "control"]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("%s %d" % (labels[i % len(labels)], i), 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: set C text validation 0{'error': 'bad-c'}{'error': 'bad-c'}Passed
repair trap 1{'error': 'bad-c'}{'error': 'bad-c'}Passed
combined fault 2[105, 12, 101, 40, 37, 44, 44, 47][105, 12, 101, 40, 37, 44, 44, 47]Passed
control 3{'char': '\t', 'error': 'unencodable'}{'char': '\t', 'error': 'unencodable'}Passed
control 4[104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11][104, 44, 79, 84, 0, 23, 101, 64, 49, 102, 99, 47, 11]Passed
boundary 5[103, 56, 93, 17][103, 56, 93, 17]Passed
boundary 6[103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17][103, 40, 37, 44, 44, 47, 33, 34, 56, 93, 17]Passed
control 7{'error': 'bad-c'}{'error': 'bad-c'}Passed

SHA-256 / 9e1a1e4c172cfad6937b365c254d7593b4eecd5af8fee3ef0fefee441143e08a

Verification & scope

A deterministic bounded teaching model with a stipulated contract; it makes no claim of conformance to any published specification. 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:49:44.476151+00:00.

Case digest / 86d258fc733df7852c120684e43827d5f4eb1fc5690bfe518f336c089643b04b