FAILURE MAP
← Case archive

FA-79491 / Barcode symbology encoding / Open access

Add-on width counts only the digit characters · case 01

Magazine labels with EAN-5 add-ons are laid out too narrow and the add-on is clipped.

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

ROOT CAUSE

The add-on width is taken as 7 modules per digit, ignoring the start pattern and separators.

VERIFIED REPAIR

Use 20 modules for EAN-2 and 47 for EAN-5.

Unsuccessful approach: Adding the start pattern still omits the two-module separators between add-on digits.

Case contract

Input {sym, modules, x_um, addon?}. Quiet zones in X: ean13 11 left / 7 right, upca 9/9, ean8 7/7, code128, code39 and itf14 10/10. Allowed X-dimensions in micrometres: EAN/UPC 264..660 inclusive, code128/code39 >= 190, itf14 >= 495. An EAN-2 (20 modules) or EAN-5 (47 modules) add-on is only allowed on EAN/UPC; it replaces the right quiet zone by a 7-module gap, the add-on and a 5-module trailing quiet zone. Return [total_um, left_quiet_um] or unknown/x-out-of-range/bad-addon.

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(spec):
    qz = {'ean13': (11, 7), 'upca': (9, 9), 'ean8': (7, 7), 'code128': (10, 10), 'code39': (10, 10), 'itf14': (10, 10)}
    xr = {'ean13': (264, 660), 'upca': (264, 660), 'ean8': (264, 660), 'code128': (190, None), 'code39': (190, None), 'itf14': (495, None)}
    sym = spec['sym']
    if sym not in qz:
        return 'unknown'
    lo, hi = xr[sym]
    x = spec['x_um']
    if x < lo or (hi is not None and x > hi):
        return 'x-out-of-range'
    left, right = qz[sym]
    addon = spec.get('addon', 0)
    if addon:
        if sym not in ('ean13', 'upca', 'ean8') or addon not in (2, 5):
            return 'bad-addon'
        right = 7 + (addon * 7) + 5
    total = left + spec['modules'] + right
    return [total * x, left * x]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[{'sym': 'ean13', 'modules': 101, 'x_um': 495, 'addon': 5}, [84645, 5445]], [{'sym': 'upca', 'modules': 95, 'x_um': 300, 'addon': 5}, [48900, 2700]], [{'sym': 'code39', 'modules': 200, 'x_um': 661}, [145420, 6610]], [{'sym': 'ean13', 'modules': 67, 'x_um': 330}, [28050, 3630]], [{'sym': 'qr', 'modules': 200, 'x_um': 250, 'addon': 2}, 'unknown'], [{'sym': 'ean8', 'modules': 101, 'x_um': 1100, 'addon': 5}, 'x-out-of-range'], [{'sym': 'code128', 'modules': 200, 'x_um': 1000, 'addon': 5}, 'bad-addon'], [{'sym': 'ean8', 'modules': 95, 'x_um': 264, 'addon': 2}, [35376, 1848]]], [[{'sym': 'ean8', 'modules': 95, 'x_um': 264, 'addon': 5}, [42504, 1848]], [{'sym': 'upca', 'modules': 101, 'x_um': 660, 'addon': 2}, [93720, 5940]], [{'sym': 'itf14', 'modules': 67, 'x_um': 1000}, [87000, 10000]], [{'sym': 'itf14', 'modules': 67, 'x_um': 250}, 'x-out-of-range'], [{'sym': 'code128', 'modules': 200, 'x_um': 660}, [145200, 6600]], [{'sym': 'ean13', 'modules': 95, 'x_um': 661}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 95, 'x_um': 190}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 101, 'x_um': 400, 'addon': 2}, [57600, 4400]]], [[{'sym': 'ean8', 'modules': 95, 'x_um': 300, 'addon': 2}, [40200, 2100]], [{'sym': 'ean13', 'modules': 101, 'x_um': 264, 'addon': 5}, [45144, 2904]], [{'sym': 'ean13', 'modules': 200, 'x_um': 190}, 'x-out-of-range'], [{'sym': 'code39', 'modules': 101, 'x_um': 400}, [48400, 4000]], [{'sym': 'itf14', 'modules': 95, 'x_um': 263, 'addon': 5}, 'x-out-of-range'], [{'sym': 'code39', 'modules': 101, 'x_um': 190, 'addon': 3}, 'bad-addon'], [{'sym': 'itf14', 'modules': 200, 'x_um': 263}, 'x-out-of-range'], [{'sym': 'ean8', 'modules': 67, 'x_um': 264, 'addon': 5}, [35112, 1848]]], [[{'sym': 'ean13', 'modules': 95, 'x_um': 264, 'addon': 2}, [36432, 2904]], [{'sym': 'upca', 'modules': 142, 'x_um': 264, 'addon': 5}, [55440, 2376]], [{'sym': 'code39', 'modules': 67, 'x_um': 330, 'addon': 2}, 'bad-addon'], [{'sym': 'ean13', 'modules': 101, 'x_um': 1100}, 'x-out-of-range'], [{'sym': 'itf14', 'modules': 95, 'x_um': 264, 'addon': 2}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 67, 'x_um': 661}, 'x-out-of-range'], [{'sym': 'itf14', 'modules': 67, 'x_um': 1100, 'addon': 3}, 'bad-addon'], [{'sym': 'ean13', 'modules': 67, 'x_um': 330, 'addon': 5}, [45210, 3630]]], [[{'sym': 'ean13', 'modules': 142, 'x_um': 264, 'addon': 5}, [55968, 2904]], [{'sym': 'ean13', 'modules': 142, 'x_um': 264, 'addon': 2}, [48840, 2904]], [{'sym': 'ean13', 'modules': 67, 'x_um': 330}, [28050, 3630]], [{'sym': 'ean13', 'modules': 101, 'x_um': 264}, [31416, 2904]], [{'sym': 'code128', 'modules': 101, 'x_um': 400}, [48400, 4000]], [{'sym': 'ean13', 'modules': 101, 'x_um': 660}, [78540, 7260]], [{'sym': 'upca', 'modules': 101, 'x_um': 1100}, 'x-out-of-range'], [{'sym': 'ean8', 'modules': 95, 'x_um': 330, 'addon': 2}, [44220, 2310]]]]
labels = ["regression: add-on symbol width", "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: add-on symbol width 0[78705, 5445][84645, 5445]Failed
repair trap 1[45300, 2700][48900, 2700]Failed
combined fault 2[145420, 6610][145420, 6610]Passed
control 3[28050, 3630][28050, 3630]Passed
control 4unknownunknownPassed
boundary 5x-out-of-rangex-out-of-rangePassed
boundary 6bad-addonbad-addonPassed
control 7[33792, 1848][35376, 1848]Failed

SHA-256 / 2035eb8cee1f064586040884956a492c6137d76de34930e544b4507a028fe583

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(spec):
    qz = {'ean13': (11, 7), 'upca': (9, 9), 'ean8': (7, 7), 'code128': (10, 10), 'code39': (10, 10), 'itf14': (10, 10)}
    xr = {'ean13': (264, 660), 'upca': (264, 660), 'ean8': (264, 660), 'code128': (190, None), 'code39': (190, None), 'itf14': (495, None)}
    sym = spec['sym']
    if sym not in qz:
        return 'unknown'
    lo, hi = xr[sym]
    x = spec['x_um']
    if x < lo or (hi is not None and x > hi):
        return 'x-out-of-range'
    left, right = qz[sym]
    addon = spec.get('addon', 0)
    if addon:
        if sym not in ('ean13', 'upca', 'ean8') or addon not in (2, 5):
            return 'bad-addon'
        right = 7 + (4 + addon * 7) + 5
    total = left + spec['modules'] + right
    return [total * x, left * x]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[{'sym': 'ean13', 'modules': 101, 'x_um': 495, 'addon': 5}, [84645, 5445]], [{'sym': 'upca', 'modules': 95, 'x_um': 300, 'addon': 5}, [48900, 2700]], [{'sym': 'code39', 'modules': 200, 'x_um': 661}, [145420, 6610]], [{'sym': 'ean13', 'modules': 67, 'x_um': 330}, [28050, 3630]], [{'sym': 'qr', 'modules': 200, 'x_um': 250, 'addon': 2}, 'unknown'], [{'sym': 'ean8', 'modules': 101, 'x_um': 1100, 'addon': 5}, 'x-out-of-range'], [{'sym': 'code128', 'modules': 200, 'x_um': 1000, 'addon': 5}, 'bad-addon'], [{'sym': 'ean8', 'modules': 95, 'x_um': 264, 'addon': 2}, [35376, 1848]]], [[{'sym': 'ean8', 'modules': 95, 'x_um': 264, 'addon': 5}, [42504, 1848]], [{'sym': 'upca', 'modules': 101, 'x_um': 660, 'addon': 2}, [93720, 5940]], [{'sym': 'itf14', 'modules': 67, 'x_um': 1000}, [87000, 10000]], [{'sym': 'itf14', 'modules': 67, 'x_um': 250}, 'x-out-of-range'], [{'sym': 'code128', 'modules': 200, 'x_um': 660}, [145200, 6600]], [{'sym': 'ean13', 'modules': 95, 'x_um': 661}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 95, 'x_um': 190}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 101, 'x_um': 400, 'addon': 2}, [57600, 4400]]], [[{'sym': 'ean8', 'modules': 95, 'x_um': 300, 'addon': 2}, [40200, 2100]], [{'sym': 'ean13', 'modules': 101, 'x_um': 264, 'addon': 5}, [45144, 2904]], [{'sym': 'ean13', 'modules': 200, 'x_um': 190}, 'x-out-of-range'], [{'sym': 'code39', 'modules': 101, 'x_um': 400}, [48400, 4000]], [{'sym': 'itf14', 'modules': 95, 'x_um': 263, 'addon': 5}, 'x-out-of-range'], [{'sym': 'code39', 'modules': 101, 'x_um': 190, 'addon': 3}, 'bad-addon'], [{'sym': 'itf14', 'modules': 200, 'x_um': 263}, 'x-out-of-range'], [{'sym': 'ean8', 'modules': 67, 'x_um': 264, 'addon': 5}, [35112, 1848]]], [[{'sym': 'ean13', 'modules': 95, 'x_um': 264, 'addon': 2}, [36432, 2904]], [{'sym': 'upca', 'modules': 142, 'x_um': 264, 'addon': 5}, [55440, 2376]], [{'sym': 'code39', 'modules': 67, 'x_um': 330, 'addon': 2}, 'bad-addon'], [{'sym': 'ean13', 'modules': 101, 'x_um': 1100}, 'x-out-of-range'], [{'sym': 'itf14', 'modules': 95, 'x_um': 264, 'addon': 2}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 67, 'x_um': 661}, 'x-out-of-range'], [{'sym': 'itf14', 'modules': 67, 'x_um': 1100, 'addon': 3}, 'bad-addon'], [{'sym': 'ean13', 'modules': 67, 'x_um': 330, 'addon': 5}, [45210, 3630]]], [[{'sym': 'ean13', 'modules': 142, 'x_um': 264, 'addon': 5}, [55968, 2904]], [{'sym': 'ean13', 'modules': 142, 'x_um': 264, 'addon': 2}, [48840, 2904]], [{'sym': 'ean13', 'modules': 67, 'x_um': 330}, [28050, 3630]], [{'sym': 'ean13', 'modules': 101, 'x_um': 264}, [31416, 2904]], [{'sym': 'code128', 'modules': 101, 'x_um': 400}, [48400, 4000]], [{'sym': 'ean13', 'modules': 101, 'x_um': 660}, [78540, 7260]], [{'sym': 'upca', 'modules': 101, 'x_um': 1100}, 'x-out-of-range'], [{'sym': 'ean8', 'modules': 95, 'x_um': 330, 'addon': 2}, [44220, 2310]]]]
labels = ["regression: add-on symbol width", "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: add-on symbol width 0[80685, 5445][84645, 5445]Failed
repair trap 1[46500, 2700][48900, 2700]Failed
combined fault 2[145420, 6610][145420, 6610]Passed
control 3[28050, 3630][28050, 3630]Passed
control 4unknownunknownPassed
boundary 5x-out-of-rangex-out-of-rangePassed
boundary 6bad-addonbad-addonPassed
control 7[34848, 1848][35376, 1848]Failed

SHA-256 / 390a1134296d180ff44adc4d1947d358c2603189bdd01fc3572b5b4450baffb9

3 / The verified repair

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

N = 1
observations = []
def solve(spec):
    qz = {'ean13': (11, 7), 'upca': (9, 9), 'ean8': (7, 7), 'code128': (10, 10), 'code39': (10, 10), 'itf14': (10, 10)}
    xr = {'ean13': (264, 660), 'upca': (264, 660), 'ean8': (264, 660), 'code128': (190, None), 'code39': (190, None), 'itf14': (495, None)}
    sym = spec['sym']
    if sym not in qz:
        return 'unknown'
    lo, hi = xr[sym]
    x = spec['x_um']
    if x < lo or (hi is not None and x > hi):
        return 'x-out-of-range'
    left, right = qz[sym]
    addon = spec.get('addon', 0)
    if addon:
        if sym not in ('ean13', 'upca', 'ean8') or addon not in (2, 5):
            return 'bad-addon'
        right = 7 + (20 if addon == 2 else 47) + 5
    total = left + spec['modules'] + right
    return [total * x, left * x]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[{'sym': 'ean13', 'modules': 101, 'x_um': 495, 'addon': 5}, [84645, 5445]], [{'sym': 'upca', 'modules': 95, 'x_um': 300, 'addon': 5}, [48900, 2700]], [{'sym': 'code39', 'modules': 200, 'x_um': 661}, [145420, 6610]], [{'sym': 'ean13', 'modules': 67, 'x_um': 330}, [28050, 3630]], [{'sym': 'qr', 'modules': 200, 'x_um': 250, 'addon': 2}, 'unknown'], [{'sym': 'ean8', 'modules': 101, 'x_um': 1100, 'addon': 5}, 'x-out-of-range'], [{'sym': 'code128', 'modules': 200, 'x_um': 1000, 'addon': 5}, 'bad-addon'], [{'sym': 'ean8', 'modules': 95, 'x_um': 264, 'addon': 2}, [35376, 1848]]], [[{'sym': 'ean8', 'modules': 95, 'x_um': 264, 'addon': 5}, [42504, 1848]], [{'sym': 'upca', 'modules': 101, 'x_um': 660, 'addon': 2}, [93720, 5940]], [{'sym': 'itf14', 'modules': 67, 'x_um': 1000}, [87000, 10000]], [{'sym': 'itf14', 'modules': 67, 'x_um': 250}, 'x-out-of-range'], [{'sym': 'code128', 'modules': 200, 'x_um': 660}, [145200, 6600]], [{'sym': 'ean13', 'modules': 95, 'x_um': 661}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 95, 'x_um': 190}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 101, 'x_um': 400, 'addon': 2}, [57600, 4400]]], [[{'sym': 'ean8', 'modules': 95, 'x_um': 300, 'addon': 2}, [40200, 2100]], [{'sym': 'ean13', 'modules': 101, 'x_um': 264, 'addon': 5}, [45144, 2904]], [{'sym': 'ean13', 'modules': 200, 'x_um': 190}, 'x-out-of-range'], [{'sym': 'code39', 'modules': 101, 'x_um': 400}, [48400, 4000]], [{'sym': 'itf14', 'modules': 95, 'x_um': 263, 'addon': 5}, 'x-out-of-range'], [{'sym': 'code39', 'modules': 101, 'x_um': 190, 'addon': 3}, 'bad-addon'], [{'sym': 'itf14', 'modules': 200, 'x_um': 263}, 'x-out-of-range'], [{'sym': 'ean8', 'modules': 67, 'x_um': 264, 'addon': 5}, [35112, 1848]]], [[{'sym': 'ean13', 'modules': 95, 'x_um': 264, 'addon': 2}, [36432, 2904]], [{'sym': 'upca', 'modules': 142, 'x_um': 264, 'addon': 5}, [55440, 2376]], [{'sym': 'code39', 'modules': 67, 'x_um': 330, 'addon': 2}, 'bad-addon'], [{'sym': 'ean13', 'modules': 101, 'x_um': 1100}, 'x-out-of-range'], [{'sym': 'itf14', 'modules': 95, 'x_um': 264, 'addon': 2}, 'x-out-of-range'], [{'sym': 'ean13', 'modules': 67, 'x_um': 661}, 'x-out-of-range'], [{'sym': 'itf14', 'modules': 67, 'x_um': 1100, 'addon': 3}, 'bad-addon'], [{'sym': 'ean13', 'modules': 67, 'x_um': 330, 'addon': 5}, [45210, 3630]]], [[{'sym': 'ean13', 'modules': 142, 'x_um': 264, 'addon': 5}, [55968, 2904]], [{'sym': 'ean13', 'modules': 142, 'x_um': 264, 'addon': 2}, [48840, 2904]], [{'sym': 'ean13', 'modules': 67, 'x_um': 330}, [28050, 3630]], [{'sym': 'ean13', 'modules': 101, 'x_um': 264}, [31416, 2904]], [{'sym': 'code128', 'modules': 101, 'x_um': 400}, [48400, 4000]], [{'sym': 'ean13', 'modules': 101, 'x_um': 660}, [78540, 7260]], [{'sym': 'upca', 'modules': 101, 'x_um': 1100}, 'x-out-of-range'], [{'sym': 'ean8', 'modules': 95, 'x_um': 330, 'addon': 2}, [44220, 2310]]]]
labels = ["regression: add-on symbol width", "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: add-on symbol width 0[84645, 5445][84645, 5445]Passed
repair trap 1[48900, 2700][48900, 2700]Passed
combined fault 2[145420, 6610][145420, 6610]Passed
control 3[28050, 3630][28050, 3630]Passed
control 4unknownunknownPassed
boundary 5x-out-of-rangex-out-of-rangePassed
boundary 6bad-addonbad-addonPassed
control 7[35376, 1848][35376, 1848]Passed

SHA-256 / 345e22dcbc2dbe88689a1c81e9d473997705ee85583ebac842dae4ac4419e759

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

Case digest / aa1aacb0592e59b59f072cf0e290477e9674f81c60518fdfed14806769e8503b