FA-95096 / Warehouse slotting and bin packing / Open access
Reserve allocation: exact-fit pallet not cleaned out · case 01
A pallet holding exactly the remaining need is picked partially instead of moved whole.
ROOT CAUSE
The whole-pallet test requires quantity strictly below the remaining need.
VERIFIED REPAIR
Take a whole pallet when its quantity is at most the remaining need.
Unsuccessful approach: Stopping pass 1 at the first oversized pallet skips later pallets that would clean out.
Case contract
pallets [[license_plate, received_day, qty]]; need units. Order pallets by received_day then plate. Pass 1 takes whole pallets (qty > 0) whose qty fits the remaining need, oldest first, skipping ones that are too large. Pass 2 takes partial quantity from remaining pallets oldest first. Return [[[plate, qty] in pick order], shortfall].
Why this case matters
Reserve allocation decides which pallets feed replenishment and order picks.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(pallets, need):
order = sorted(pallets, key=lambda p: (p[1], p[0]))
rem = need
alloc = []
taken = set()
for lp, day, q in order:
if 0 < q < rem:
alloc.append([lp, q])
taken.add(lp)
rem -= q
for lp, day, q in order:
if rem == 0:
break
if lp in taken:
continue
t = min(q, rem)
if t > 0:
alloc.append([lp, t])
rem -= t
return [alloc, rem]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['generated mix 1', [[['P0', 8, 40], ['P1', 5, 48], ['P2', 2, 48]], 40], [[['P0', 40]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 20]], 0]]], [['generated mix 23', [[['P0', 3, 40], ['P1', 2, 20], ['P2', 3, 10], ['P3', 5, 0]], 10], [[['P2', 10]], 0]], ['generated mix 19', [[['P0', 5, 10], ['P1', 3, 40], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P3', 30]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 20]], 0]], ['generated mix 17', [[['P0', 3, 0]], 50], [[], 50]], ['generated mix 27', [[['P0', 8, 20], ['P1', 5, 48], ['P2', 5, 20]], 90], [[['P1', 48], ['P2', 20], ['P0', 20]], 2]]], [['generated mix 56', [[['P0', 3, 20], ['P1', 2, 40]], 40], [[['P1', 40]], 0]], ['generated mix 40', [[['P0', 5, 0], ['P1', 3, 48], ['P2', 2, 40], ['P3', 3, 20], ['P4', 5, 40], ['P5', 3, 30]], 20], [[['P3', 20]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 20', [[['P0', 2, 0], ['P1', 3, 48], ['P2', 2, 30]], 60], [[['P2', 30], ['P1', 30]], 0]], ['generated mix 28', [[['P0', 3, 40]], 90], [[['P0', 40]], 50]], ['generated mix 36', [[['P0', 5, 40], ['P1', 2, 10], ['P2', 1, 40], ['P3', 8, 10]], 90], [[['P2', 40], ['P1', 10], ['P0', 40]], 0]]], [['generated mix 3', [[['P0', 1, 48], ['P1', 1, 48], ['P2', 1, 40], ['P3', 1, 20]], 40], [[['P2', 40]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['generated mix 34', [[['P0', 3, 40], ['P1', 3, 0], ['P2', 3, 0], ['P3', 1, 0]], 0], [[], 0]], ['generated mix 42', [[['P0', 5, 20], ['P1', 3, 30], ['P2', 2, 0]], 90], [[['P1', 30], ['P0', 20]], 40]]], [['generated mix 38', [[['P0', 3, 40], ['P1', 3, 20], ['P2', 2, 20], ['P3', 5, 10], ['P4', 2, 20]], 60], [[['P2', 20], ['P4', 20], ['P1', 20]], 0]], ['generated mix 16', [[['P0', 8, 0], ['P1', 2, 0], ['P2', 5, 0], ['P3', 3, 40], ['P4', 2, 20], ['P5', 3, 10]], 30], [[['P4', 20], ['P5', 10]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 44', [[['P0', 3, 20]], 10], [[['P0', 10]], 0]], ['generated mix 52', [[['P0', 3, 30], ['P1', 3, 10], ['P2', 3, 0], ['P3', 8, 10], ['P4', 3, 20]], 30], [[['P0', 30]], 0]], ['generated mix 60', [[['P0', 3, 20], ['P1', 5, 20], ['P2', 3, 20], ['P3', 3, 30]], 30], [[['P0', 20], ['P2', 10]], 0]]]]
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 |
|---|---|---|---|
| clean-out skip big | [[['B', 20], ['A', 10]], 0] | [[['B', 20], ['C', 10]], 0] | Failed |
| generated mix 1 | [[['P2', 40]], 0] | [[['P0', 40]], 0] | Failed |
| exact whole | [[['A', 30]], 0] | [[['A', 30]], 0] | Passed |
| shortfall | [[['A', 10]], 15] | [[['A', 10]], 15] | Passed |
| zero need | [[], 0] | [[], 0] | Passed |
| partial oldest | [[['A', 30]], 0] | [[['A', 30]], 0] | Passed |
| equal qty pallets | [[['A', 20], ['B', 20], ['C', 10]], 0] | [[['A', 20], ['B', 20], ['C', 10]], 0] | Passed |
| generated mix 9 | [[['P0', 20]], 0] | [[['P0', 20]], 0] | Passed |
SHA-256 / bf54560f8b1e164f1d3362fec1e04b0eaa078fb0f81db986ffb3bd470ee41106
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(pallets, need):
order = sorted(pallets, key=lambda p: (p[1], p[0]))
rem = need
alloc = []
taken = set()
for lp, day, q in order:
if q > rem:
break
if 0 < q <= rem:
alloc.append([lp, q])
taken.add(lp)
rem -= q
for lp, day, q in order:
if rem == 0:
break
if lp in taken:
continue
t = min(q, rem)
if t > 0:
alloc.append([lp, t])
rem -= t
return [alloc, rem]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['generated mix 1', [[['P0', 8, 40], ['P1', 5, 48], ['P2', 2, 48]], 40], [[['P0', 40]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 20]], 0]]], [['generated mix 23', [[['P0', 3, 40], ['P1', 2, 20], ['P2', 3, 10], ['P3', 5, 0]], 10], [[['P2', 10]], 0]], ['generated mix 19', [[['P0', 5, 10], ['P1', 3, 40], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P3', 30]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 20]], 0]], ['generated mix 17', [[['P0', 3, 0]], 50], [[], 50]], ['generated mix 27', [[['P0', 8, 20], ['P1', 5, 48], ['P2', 5, 20]], 90], [[['P1', 48], ['P2', 20], ['P0', 20]], 2]]], [['generated mix 56', [[['P0', 3, 20], ['P1', 2, 40]], 40], [[['P1', 40]], 0]], ['generated mix 40', [[['P0', 5, 0], ['P1', 3, 48], ['P2', 2, 40], ['P3', 3, 20], ['P4', 5, 40], ['P5', 3, 30]], 20], [[['P3', 20]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 20', [[['P0', 2, 0], ['P1', 3, 48], ['P2', 2, 30]], 60], [[['P2', 30], ['P1', 30]], 0]], ['generated mix 28', [[['P0', 3, 40]], 90], [[['P0', 40]], 50]], ['generated mix 36', [[['P0', 5, 40], ['P1', 2, 10], ['P2', 1, 40], ['P3', 8, 10]], 90], [[['P2', 40], ['P1', 10], ['P0', 40]], 0]]], [['generated mix 3', [[['P0', 1, 48], ['P1', 1, 48], ['P2', 1, 40], ['P3', 1, 20]], 40], [[['P2', 40]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['generated mix 34', [[['P0', 3, 40], ['P1', 3, 0], ['P2', 3, 0], ['P3', 1, 0]], 0], [[], 0]], ['generated mix 42', [[['P0', 5, 20], ['P1', 3, 30], ['P2', 2, 0]], 90], [[['P1', 30], ['P0', 20]], 40]]], [['generated mix 38', [[['P0', 3, 40], ['P1', 3, 20], ['P2', 2, 20], ['P3', 5, 10], ['P4', 2, 20]], 60], [[['P2', 20], ['P4', 20], ['P1', 20]], 0]], ['generated mix 16', [[['P0', 8, 0], ['P1', 2, 0], ['P2', 5, 0], ['P3', 3, 40], ['P4', 2, 20], ['P5', 3, 10]], 30], [[['P4', 20], ['P5', 10]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 44', [[['P0', 3, 20]], 10], [[['P0', 10]], 0]], ['generated mix 52', [[['P0', 3, 30], ['P1', 3, 10], ['P2', 3, 0], ['P3', 8, 10], ['P4', 3, 20]], 30], [[['P0', 30]], 0]], ['generated mix 60', [[['P0', 3, 20], ['P1', 5, 20], ['P2', 3, 20], ['P3', 3, 30]], 30], [[['P0', 20], ['P2', 10]], 0]]]]
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 |
|---|---|---|---|
| clean-out skip big | [[['A', 30]], 0] | [[['B', 20], ['C', 10]], 0] | Failed |
| generated mix 1 | [[['P2', 40]], 0] | [[['P0', 40]], 0] | Failed |
| exact whole | [[['A', 30]], 0] | [[['A', 30]], 0] | Passed |
| shortfall | [[['A', 10]], 15] | [[['A', 10]], 15] | Passed |
| zero need | [[], 0] | [[], 0] | Passed |
| partial oldest | [[['A', 30]], 0] | [[['A', 30]], 0] | Passed |
| equal qty pallets | [[['A', 20], ['B', 20], ['C', 10]], 0] | [[['A', 20], ['B', 20], ['C', 10]], 0] | Passed |
| generated mix 9 | [[['P0', 20]], 0] | [[['P0', 20]], 0] | Passed |
SHA-256 / 6975c765f0f5460e94a50c25e18d96be2f627c8fd439cab72a3584e280f3311c
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(pallets, need):
order = sorted(pallets, key=lambda p: (p[1], p[0]))
rem = need
alloc = []
taken = set()
for lp, day, q in order:
if 0 < q <= rem:
alloc.append([lp, q])
taken.add(lp)
rem -= q
for lp, day, q in order:
if rem == 0:
break
if lp in taken:
continue
t = min(q, rem)
if t > 0:
alloc.append([lp, t])
rem -= t
return [alloc, rem]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['generated mix 1', [[['P0', 8, 40], ['P1', 5, 48], ['P2', 2, 48]], 40], [[['P0', 40]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 20]], 0]]], [['generated mix 23', [[['P0', 3, 40], ['P1', 2, 20], ['P2', 3, 10], ['P3', 5, 0]], 10], [[['P2', 10]], 0]], ['generated mix 19', [[['P0', 5, 10], ['P1', 3, 40], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P3', 30]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 20]], 0]], ['generated mix 17', [[['P0', 3, 0]], 50], [[], 50]], ['generated mix 27', [[['P0', 8, 20], ['P1', 5, 48], ['P2', 5, 20]], 90], [[['P1', 48], ['P2', 20], ['P0', 20]], 2]]], [['generated mix 56', [[['P0', 3, 20], ['P1', 2, 40]], 40], [[['P1', 40]], 0]], ['generated mix 40', [[['P0', 5, 0], ['P1', 3, 48], ['P2', 2, 40], ['P3', 3, 20], ['P4', 5, 40], ['P5', 3, 30]], 20], [[['P3', 20]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 20', [[['P0', 2, 0], ['P1', 3, 48], ['P2', 2, 30]], 60], [[['P2', 30], ['P1', 30]], 0]], ['generated mix 28', [[['P0', 3, 40]], 90], [[['P0', 40]], 50]], ['generated mix 36', [[['P0', 5, 40], ['P1', 2, 10], ['P2', 1, 40], ['P3', 8, 10]], 90], [[['P2', 40], ['P1', 10], ['P0', 40]], 0]]], [['generated mix 3', [[['P0', 1, 48], ['P1', 1, 48], ['P2', 1, 40], ['P3', 1, 20]], 40], [[['P2', 40]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['zero need', [[['A', 1, 10]], 0], [[], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['generated mix 34', [[['P0', 3, 40], ['P1', 3, 0], ['P2', 3, 0], ['P3', 1, 0]], 0], [[], 0]], ['generated mix 42', [[['P0', 5, 20], ['P1', 3, 30], ['P2', 2, 0]], 90], [[['P1', 30], ['P0', 20]], 40]]], [['generated mix 38', [[['P0', 3, 40], ['P1', 3, 20], ['P2', 2, 20], ['P3', 5, 10], ['P4', 2, 20]], 60], [[['P2', 20], ['P4', 20], ['P1', 20]], 0]], ['generated mix 16', [[['P0', 8, 0], ['P1', 2, 0], ['P2', 5, 0], ['P3', 3, 40], ['P4', 2, 20], ['P5', 3, 10]], 30], [[['P4', 20], ['P5', 10]], 0]], ['clean-out skip big', [[['A', 1, 50], ['B', 2, 20], ['C', 3, 10]], 30], [[['B', 20], ['C', 10]], 0]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['generated mix 44', [[['P0', 3, 20]], 10], [[['P0', 10]], 0]], ['generated mix 52', [[['P0', 3, 30], ['P1', 3, 10], ['P2', 3, 0], ['P3', 8, 10], ['P4', 3, 20]], 30], [[['P0', 30]], 0]], ['generated mix 60', [[['P0', 3, 20], ['P1', 5, 20], ['P2', 3, 20], ['P3', 3, 30]], 30], [[['P0', 20], ['P2', 10]], 0]]]]
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 |
|---|---|---|---|
| clean-out skip big | [[['B', 20], ['C', 10]], 0] | [[['B', 20], ['C', 10]], 0] | Passed |
| generated mix 1 | [[['P0', 40]], 0] | [[['P0', 40]], 0] | Passed |
| exact whole | [[['A', 30]], 0] | [[['A', 30]], 0] | Passed |
| shortfall | [[['A', 10]], 15] | [[['A', 10]], 15] | Passed |
| zero need | [[], 0] | [[], 0] | Passed |
| partial oldest | [[['A', 30]], 0] | [[['A', 30]], 0] | Passed |
| equal qty pallets | [[['A', 20], ['B', 20], ['C', 10]], 0] | [[['A', 20], ['B', 20], ['C', 10]], 0] | Passed |
| generated mix 9 | [[['P0', 20]], 0] | [[['P0', 20]], 0] | Passed |
SHA-256 / b1a2d40c353bd64ed1ff86190d629489af3fdb3dffbfeeb1a9e096b162f1e723
Verification & scope
Stipulated clean-out policy; no lot, expiry, or location travel considerations. 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:10.532305+00:00.
Case digest / 879c83658954d445e6ec6682d7971eae47783e96f1219eed267baa540f3c5a29