FA-95256 / Warehouse slotting and bin packing / Open access
UOM breakdown: eaches consumed first · case 01
Whole cases are picked as loose eaches whenever each picking is allowed.
ROOT CAUSE
The unit hierarchy is iterated smallest unit first.
VERIFIED REPAIR
Iterate units from pallet down to each.
Unsuccessful approach: Trying inners before cases breaks full cases into inner packs.
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 = [('EA', 1), ('IP', pack[0]), ('CS', pack[1]), ('PAL', pack[2])]
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 = [[['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['generated mix 4', [500, [4, 12, 120], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 4], ['CS', 1], ['IP', 2]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['generated mix 7', [3, [4, 48, 480], ['PAL', 'CS', 'IP']], [['UNPICKABLE', 3]]], ['generated mix 15', [250, [4, 24, 480], ['PAL', 'IP', 'EA']], [['IP', 62], ['EA', 2]]]], [['generated mix 12', [500, [6, 24, 0], ['CS', 'IP', 'EA']], [['CS', 20], ['IP', 3], ['EA', 2]]], ['generated mix 28', [50, [4, 48, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 1], ['EA', 2]]], ['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 9', [250, [6, 48, 480], ['PAL', 'CS']], [['CS', 5], ['UNPICKABLE', 10]]], ['generated mix 18', [50, [0, 24, 240], ['CS']], [['CS', 2], ['UNPICKABLE', 2]]]], [['generated mix 25', [50, [6, 24, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 2], ['EA', 2]]], ['generated mix 60', [500, [4, 48, 0], ['PAL', 'CS', 'IP']], [['CS', 10], ['IP', 5]]], ['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]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['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 36', [25, [4, 48, 0], ['PAL', 'CS', 'IP', 'EA']], [['IP', 6], ['EA', 1]]], ['generated mix 80', [50, [4, 12, 240], ['PAL', 'CS', 'IP', 'EA']], [['CS', 4], ['EA', 2]]], ['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 31', [500, [0, 48, 960], ['EA']], [['EA', 500]]], ['generated mix 40', [3, [4, 48, 480], ['IP']], [['UNPICKABLE', 3]]]], [['generated mix 48', [50, [6, 48, 0], ['CS', 'IP']], [['CS', 1], ['UNPICKABLE', 2]]], ['generated mix 12', [500, [6, 24, 0], ['CS', 'IP', 'EA']], [['CS', 20], ['IP', 3], ['EA', 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]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 43', [120, [6, 24, 240], ['PAL', 'CS', 'EA']], [['CS', 5]]], ['generated mix 52', [50, [4, 48, 0], ['EA']], [['EA', 50]]]]]
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 |
|---|---|---|---|
| full breakdown | [['EA', 251]] | [['PAL', 1], ['IP', 1], ['EA', 5]] | Failed |
| generated mix 4 | [['EA', 500]] | [['PAL', 4], ['CS', 1], ['IP', 2]] | Failed |
| case and each | [['EA', 50]] | [['CS', 2], ['EA', 2]] | Failed |
| undefined inner | [['EA', 13]] | [['EA', 13]] | Passed |
| inner only | [['IP', 3], ['UNPICKABLE', 1]] | [['IP', 3], ['UNPICKABLE', 1]] | Passed |
| no each picking | [['IP', 8], ['UNPICKABLE', 2]] | [['CS', 2], ['UNPICKABLE', 2]] | Failed |
| generated mix 7 | [['UNPICKABLE', 3]] | [['UNPICKABLE', 3]] | Passed |
| generated mix 15 | [['EA', 250]] | [['IP', 62], ['EA', 2]] | Failed |
SHA-256 / a6f5f2ed42d4e54412564eecb28a609fdc13c9da6c1b841e8da379305f730728
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]), ('IP', pack[0]), ('CS', pack[1]), ('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 = [[['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['generated mix 4', [500, [4, 12, 120], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 4], ['CS', 1], ['IP', 2]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['generated mix 7', [3, [4, 48, 480], ['PAL', 'CS', 'IP']], [['UNPICKABLE', 3]]], ['generated mix 15', [250, [4, 24, 480], ['PAL', 'IP', 'EA']], [['IP', 62], ['EA', 2]]]], [['generated mix 12', [500, [6, 24, 0], ['CS', 'IP', 'EA']], [['CS', 20], ['IP', 3], ['EA', 2]]], ['generated mix 28', [50, [4, 48, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 1], ['EA', 2]]], ['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 9', [250, [6, 48, 480], ['PAL', 'CS']], [['CS', 5], ['UNPICKABLE', 10]]], ['generated mix 18', [50, [0, 24, 240], ['CS']], [['CS', 2], ['UNPICKABLE', 2]]]], [['generated mix 25', [50, [6, 24, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 2], ['EA', 2]]], ['generated mix 60', [500, [4, 48, 0], ['PAL', 'CS', 'IP']], [['CS', 10], ['IP', 5]]], ['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]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['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 36', [25, [4, 48, 0], ['PAL', 'CS', 'IP', 'EA']], [['IP', 6], ['EA', 1]]], ['generated mix 80', [50, [4, 12, 240], ['PAL', 'CS', 'IP', 'EA']], [['CS', 4], ['EA', 2]]], ['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 31', [500, [0, 48, 960], ['EA']], [['EA', 500]]], ['generated mix 40', [3, [4, 48, 480], ['IP']], [['UNPICKABLE', 3]]]], [['generated mix 48', [50, [6, 48, 0], ['CS', 'IP']], [['CS', 1], ['UNPICKABLE', 2]]], ['generated mix 12', [500, [6, 24, 0], ['CS', 'IP', 'EA']], [['CS', 20], ['IP', 3], ['EA', 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]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 43', [120, [6, 24, 240], ['PAL', 'CS', 'EA']], [['CS', 5]]], ['generated mix 52', [50, [4, 48, 0], ['EA']], [['EA', 50]]]]]
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 |
|---|---|---|---|
| full breakdown | [['PAL', 1], ['IP', 1], ['EA', 5]] | [['PAL', 1], ['IP', 1], ['EA', 5]] | Passed |
| generated mix 4 | [['PAL', 4], ['IP', 5]] | [['PAL', 4], ['CS', 1], ['IP', 2]] | Failed |
| case and each | [['CS', 2], ['EA', 2]] | [['CS', 2], ['EA', 2]] | Passed |
| undefined inner | [['EA', 13]] | [['EA', 13]] | Passed |
| inner only | [['IP', 3], ['UNPICKABLE', 1]] | [['IP', 3], ['UNPICKABLE', 1]] | Passed |
| no each picking | [['IP', 8], ['UNPICKABLE', 2]] | [['CS', 2], ['UNPICKABLE', 2]] | Failed |
| generated mix 7 | [['UNPICKABLE', 3]] | [['UNPICKABLE', 3]] | Passed |
| generated mix 15 | [['IP', 62], ['EA', 2]] | [['IP', 62], ['EA', 2]] | Passed |
SHA-256 / fcb37366c6d3843035efc9a6460993fefbc6e5dec9042280dd13c4fb26cfd1d9
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 = [[['full breakdown', [251, [6, 24, 240], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 1], ['IP', 1], ['EA', 5]]], ['generated mix 4', [500, [4, 12, 120], ['PAL', 'CS', 'IP', 'EA']], [['PAL', 4], ['CS', 1], ['IP', 2]]], ['case and each', [50, [6, 24, 0], ['CS', 'EA']], [['CS', 2], ['EA', 2]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['inner only', [13, [4, 12, 0], ['IP']], [['IP', 3], ['UNPICKABLE', 1]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['generated mix 7', [3, [4, 48, 480], ['PAL', 'CS', 'IP']], [['UNPICKABLE', 3]]], ['generated mix 15', [250, [4, 24, 480], ['PAL', 'IP', 'EA']], [['IP', 62], ['EA', 2]]]], [['generated mix 12', [500, [6, 24, 0], ['CS', 'IP', 'EA']], [['CS', 20], ['IP', 3], ['EA', 2]]], ['generated mix 28', [50, [4, 48, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 1], ['EA', 2]]], ['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 9', [250, [6, 48, 480], ['PAL', 'CS']], [['CS', 5], ['UNPICKABLE', 10]]], ['generated mix 18', [50, [0, 24, 240], ['CS']], [['CS', 2], ['UNPICKABLE', 2]]]], [['generated mix 25', [50, [6, 24, 0], ['PAL', 'CS', 'IP', 'EA']], [['CS', 2], ['EA', 2]]], ['generated mix 60', [500, [4, 48, 0], ['PAL', 'CS', 'IP']], [['CS', 10], ['IP', 5]]], ['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]]], ['undefined inner', [13, [0, 12, 0], ['IP', 'EA']], [['EA', 13]]], ['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 36', [25, [4, 48, 0], ['PAL', 'CS', 'IP', 'EA']], [['IP', 6], ['EA', 1]]], ['generated mix 80', [50, [4, 12, 240], ['PAL', 'CS', 'IP', 'EA']], [['CS', 4], ['EA', 2]]], ['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 31', [500, [0, 48, 960], ['EA']], [['EA', 500]]], ['generated mix 40', [3, [4, 48, 480], ['IP']], [['UNPICKABLE', 3]]]], [['generated mix 48', [50, [6, 48, 0], ['CS', 'IP']], [['CS', 1], ['UNPICKABLE', 2]]], ['generated mix 12', [500, [6, 24, 0], ['CS', 'IP', 'EA']], [['CS', 20], ['IP', 3], ['EA', 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]]], ['no each picking', [50, [6, 24, 0], ['CS', 'IP']], [['CS', 2], ['UNPICKABLE', 2]]], ['zero qty', [0, [6, 24, 240], ['EA']], []], ['generated mix 43', [120, [6, 24, 240], ['PAL', 'CS', 'EA']], [['CS', 5]]], ['generated mix 52', [50, [4, 48, 0], ['EA']], [['EA', 50]]]]]
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 |
|---|---|---|---|
| full breakdown | [['PAL', 1], ['IP', 1], ['EA', 5]] | [['PAL', 1], ['IP', 1], ['EA', 5]] | Passed |
| generated mix 4 | [['PAL', 4], ['CS', 1], ['IP', 2]] | [['PAL', 4], ['CS', 1], ['IP', 2]] | Passed |
| case and each | [['CS', 2], ['EA', 2]] | [['CS', 2], ['EA', 2]] | Passed |
| undefined inner | [['EA', 13]] | [['EA', 13]] | Passed |
| inner only | [['IP', 3], ['UNPICKABLE', 1]] | [['IP', 3], ['UNPICKABLE', 1]] | Passed |
| no each picking | [['CS', 2], ['UNPICKABLE', 2]] | [['CS', 2], ['UNPICKABLE', 2]] | Passed |
| generated mix 7 | [['UNPICKABLE', 3]] | [['UNPICKABLE', 3]] | Passed |
| generated mix 15 | [['IP', 62], ['EA', 2]] | [['IP', 62], ['EA', 2]] | Passed |
SHA-256 / 19b5223dba8f9017d06e9753453f1cd71394a3a75e37c5d97d756894cb23b666
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.030493+00:00.
Case digest / c34a64817b6ca59ef7cb050316722a6520a2af91681901e1369f9004ef1deee6