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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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