FAILURE MAP
← Case archive

FA-95261 / Warehouse slotting and bin packing / Open access

UOM breakdown: disallowed units picked · case 01

Tasks ask for pallets or inners at locations that cannot present them.

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

ROOT CAUSE

The location allowed-unit list is ignored.

VERIFIED REPAIR

Skip units not allowed at the pick location.

Unsuccessful approach: Assuming cases are always allowed still picks cases from each-only locations.

Case contract

qty eaches; pack [eaches per inner, per case, per pallet] with 0 meaning the level does not exist; allowed unit codes for the pick location. Greedy from largest allowed defined unit: PAL, CS, IP, EA. Return [[unit, count]] for nonzero counts in that order, then ["UNPICKABLE", eaches] if a remainder cannot be expressed.

Why this case matters

Pick tasks are expressed in the largest unit a location can present.

1 / The failure

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

N = 1
observations = []
def solve(qty, pack, allowed):
    levels = [('PAL', pack[2]), ('CS', pack[1]), ('IP', pack[0]), ('EA', 1)]
    rem = qty
    out = []
    for unit, size in levels:
        if size <= 0:
            continue
        n = rem // size
        if n:
            out.append([unit, n])
            rem -= n * size
    if rem:
        out.append(['UNPICKABLE', rem])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['pallet not allowed', [500, [6, 24, 240], ['CS', 'EA']], [['CS', 20], ['EA', 20]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 8', [1000, [0, 48, 0], ['CS', 'IP']], [['CS', 20], ['UNPICKABLE', 40]]]], [['generated mix 9', [250, [6, 48, 480], ['PAL', 'CS']], [['CS', 5], ['UNPICKABLE', 10]]], ['generated mix 31', [500, [0, 48, 960], ['EA']], [['EA', 500]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['generated mix 10', [13, [6, 12, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 1], ['EA', 1]]], ['generated mix 18', [50, [0, 24, 240], ['CS']], [['CS', 2], ['UNPICKABLE', 2]]]], [['generated mix 24', [50, [4, 12, 0], ['IP', 'EA']], [['IP', 12], ['EA', 2]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['generated mix 20', [0, [6, 12, 0], ['PAL', 'CS', 'IP']], []], ['generated mix 29', [500, [4, 12, 0], ['CS', 'IP', 'EA']], [['CS', 41], ['IP', 2]]], ['generated mix 37', [500, [0, 48, 960], ['CS', 'EA']], [['CS', 10], ['EA', 20]]]], [['generated mix 49', [24, [0, 48, 0], ['PAL', 'CS', 'IP']], [['UNPICKABLE', 24]]], ['generated mix 30', [13, [4, 12, 240], ['PAL', 'IP', 'EA']], [['IP', 3], ['EA', 1]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['pallet not allowed', [500, [6, 24, 240], ['CS', 'EA']], [['CS', 20], ['EA', 20]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['generated mix 32', [25, [4, 24, 240], ['PAL', 'CS', 'EA']], [['CS', 1], ['EA', 1]]], ['generated mix 40', [3, [4, 48, 480], ['IP']], [['UNPICKABLE', 3]]]], [['generated mix 67', [5, [4, 24, 0], ['PAL', 'CS', 'IP']], [['IP', 1], ['UNPICKABLE', 1]]], ['generated mix 72', [25, [4, 12, 120], ['PAL', 'EA']], [['EA', 25]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 42', [120, [0, 12, 120], ['PAL', 'IP', 'EA']], [['PAL', 1]]], ['generated mix 50', [120, [6, 24, 0], ['PAL', 'CS', 'EA']], [['CS', 5]]]]]
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
no each picking[['CS', 2], ['EA', 2]][['CS', 2], ['UNPICKABLE', 2]]Failed
inner only[['CS', 1], ['EA', 1]][['IP', 3], ['UNPICKABLE', 1]]Failed
full breakdown[['PAL', 1], ['IP', 1], ['EA', 5]][['PAL', 1], ['IP', 1], ['EA', 5]]Passed
undefined inner[['CS', 1], ['EA', 1]][['EA', 13]]Failed
pallet not allowed[['PAL', 2], ['IP', 3], ['EA', 2]][['CS', 20], ['EA', 20]]Failed
case and each[['CS', 2], ['EA', 2]][['CS', 2], ['EA', 2]]Passed
zero qty[][]Passed
generated mix 8[['CS', 20], ['EA', 40]][['CS', 20], ['UNPICKABLE', 40]]Failed

SHA-256 / 9b72d30b497746970f2b5e62547156557ecc2312266e8f2b49694a7754da6f14

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(qty, pack, allowed):
    levels = [('PAL', pack[2]), ('CS', pack[1]), ('IP', pack[0]), ('EA', 1)]
    rem = qty
    out = []
    for unit, size in levels:
        if size <= 0 or (unit not in allowed and unit != 'CS'):
            continue
        n = rem // size
        if n:
            out.append([unit, n])
            rem -= n * size
    if rem:
        out.append(['UNPICKABLE', rem])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['pallet not allowed', [500, [6, 24, 240], ['CS', 'EA']], [['CS', 20], ['EA', 20]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 8', [1000, [0, 48, 0], ['CS', 'IP']], [['CS', 20], ['UNPICKABLE', 40]]]], [['generated mix 9', [250, [6, 48, 480], ['PAL', 'CS']], [['CS', 5], ['UNPICKABLE', 10]]], ['generated mix 31', [500, [0, 48, 960], ['EA']], [['EA', 500]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['generated mix 10', [13, [6, 12, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 1], ['EA', 1]]], ['generated mix 18', [50, [0, 24, 240], ['CS']], [['CS', 2], ['UNPICKABLE', 2]]]], [['generated mix 24', [50, [4, 12, 0], ['IP', 'EA']], [['IP', 12], ['EA', 2]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['generated mix 20', [0, [6, 12, 0], ['PAL', 'CS', 'IP']], []], ['generated mix 29', [500, [4, 12, 0], ['CS', 'IP', 'EA']], [['CS', 41], ['IP', 2]]], ['generated mix 37', [500, [0, 48, 960], ['CS', 'EA']], [['CS', 10], ['EA', 20]]]], [['generated mix 49', [24, [0, 48, 0], ['PAL', 'CS', 'IP']], [['UNPICKABLE', 24]]], ['generated mix 30', [13, [4, 12, 240], ['PAL', 'IP', 'EA']], [['IP', 3], ['EA', 1]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['pallet not allowed', [500, [6, 24, 240], ['CS', 'EA']], [['CS', 20], ['EA', 20]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['generated mix 32', [25, [4, 24, 240], ['PAL', 'CS', 'EA']], [['CS', 1], ['EA', 1]]], ['generated mix 40', [3, [4, 48, 480], ['IP']], [['UNPICKABLE', 3]]]], [['generated mix 67', [5, [4, 24, 0], ['PAL', 'CS', 'IP']], [['IP', 1], ['UNPICKABLE', 1]]], ['generated mix 72', [25, [4, 12, 120], ['PAL', 'EA']], [['EA', 25]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 42', [120, [0, 12, 120], ['PAL', 'IP', 'EA']], [['PAL', 1]]], ['generated mix 50', [120, [6, 24, 0], ['PAL', 'CS', 'EA']], [['CS', 5]]]]]
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
no each picking[['CS', 2], ['UNPICKABLE', 2]][['CS', 2], ['UNPICKABLE', 2]]Passed
inner only[['CS', 1], ['UNPICKABLE', 1]][['IP', 3], ['UNPICKABLE', 1]]Failed
full breakdown[['PAL', 1], ['IP', 1], ['EA', 5]][['PAL', 1], ['IP', 1], ['EA', 5]]Passed
undefined inner[['CS', 1], ['EA', 1]][['EA', 13]]Failed
pallet not allowed[['CS', 20], ['EA', 20]][['CS', 20], ['EA', 20]]Passed
case and each[['CS', 2], ['EA', 2]][['CS', 2], ['EA', 2]]Passed
zero qty[][]Passed
generated mix 8[['CS', 20], ['UNPICKABLE', 40]][['CS', 20], ['UNPICKABLE', 40]]Passed

SHA-256 / d346a04c47e0d42e743e1b5f37fc318f88302d07bbbec68cb677f2820ca06c43

3 / The verified repair

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

N = 1
observations = []
def solve(qty, pack, allowed):
    levels = [('PAL', pack[2]), ('CS', pack[1]), ('IP', pack[0]), ('EA', 1)]
    rem = qty
    out = []
    for unit, size in levels:
        if unit not in allowed or size <= 0:
            continue
        n = rem // size
        if n:
            out.append([unit, n])
            rem -= n * size
    if rem:
        out.append(['UNPICKABLE', rem])
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['pallet not allowed', [500, [6, 24, 240], ['CS', 'EA']], [['CS', 20], ['EA', 20]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 8', [1000, [0, 48, 0], ['CS', 'IP']], [['CS', 20], ['UNPICKABLE', 40]]]], [['generated mix 9', [250, [6, 48, 480], ['PAL', 'CS']], [['CS', 5], ['UNPICKABLE', 10]]], ['generated mix 31', [500, [0, 48, 960], ['EA']], [['EA', 500]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['generated mix 10', [13, [6, 12, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 1], ['EA', 1]]], ['generated mix 18', [50, [0, 24, 240], ['CS']], [['CS', 2], ['UNPICKABLE', 2]]]], [['generated mix 24', [50, [4, 12, 0], ['IP', 'EA']], [['IP', 12], ['EA', 2]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['generated mix 20', [0, [6, 12, 0], ['PAL', 'CS', 'IP']], []], ['generated mix 29', [500, [4, 12, 0], ['CS', 'IP', 'EA']], [['CS', 41], ['IP', 2]]], ['generated mix 37', [500, [0, 48, 960], ['CS', 'EA']], [['CS', 10], ['EA', 20]]]], [['generated mix 49', [24, [0, 48, 0], ['PAL', 'CS', 'IP']], [['UNPICKABLE', 24]]], ['generated mix 30', [13, [4, 12, 240], ['PAL', 'IP', 'EA']], [['IP', 3], ['EA', 1]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['pallet not allowed', [500, [6, 24, 240], ['CS', 'EA']], [['CS', 20], ['EA', 20]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['generated mix 32', [25, [4, 24, 240], ['PAL', 'CS', 'EA']], [['CS', 1], ['EA', 1]]], ['generated mix 40', [3, [4, 48, 480], ['IP']], [['UNPICKABLE', 3]]]], [['generated mix 67', [5, [4, 24, 0], ['PAL', 'CS', 'IP']], [['IP', 1], ['UNPICKABLE', 1]]], ['generated mix 72', [25, [4, 12, 120], ['PAL', 'EA']], [['EA', 25]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 42', [120, [0, 12, 120], ['PAL', 'IP', 'EA']], [['PAL', 1]]], ['generated mix 50', [120, [6, 24, 0], ['PAL', 'CS', 'EA']], [['CS', 5]]]]]
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
no each picking[['CS', 2], ['UNPICKABLE', 2]][['CS', 2], ['UNPICKABLE', 2]]Passed
inner only[['IP', 3], ['UNPICKABLE', 1]][['IP', 3], ['UNPICKABLE', 1]]Passed
full breakdown[['PAL', 1], ['IP', 1], ['EA', 5]][['PAL', 1], ['IP', 1], ['EA', 5]]Passed
undefined inner[['EA', 13]][['EA', 13]]Passed
pallet not allowed[['CS', 20], ['EA', 20]][['CS', 20], ['EA', 20]]Passed
case and each[['CS', 2], ['EA', 2]][['CS', 2], ['EA', 2]]Passed
zero qty[][]Passed
generated mix 8[['CS', 20], ['UNPICKABLE', 40]][['CS', 20], ['UNPICKABLE', 40]]Passed

SHA-256 / 630b1aab4ff2d1cc5854297729ab487a8ad93b0183e0f5c977e1abcd514624a0

Verification & scope

Greedy stipulated conversion with integer pack sizes. 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:52:12.062117+00:00.

Case digest / 4ea14c57f29eac69b795a8afecbbf8697bd44c5f556af9e15d0d8e63db26f562