FAILURE MAP
← Case archive

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

Reserve allocation: shortfall from wrong basis · case 01

The reported shortfall equals the quantity actually allocated, so fully covered demand shows a shortage.

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

ROOT CAUSE

The shortfall expression subtracts the remaining need from the original need, yielding the allocated amount.

VERIFIED REPAIR

Report the need still unallocated after both passes.

Unsuccessful approach: Subtracting total stock from need goes negative when stock exceeds demand.

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, need - 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]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['generated mix 7', [[['P0', 8, 20], ['P1', 8, 30], ['P2', 3, 10], ['P3', 5, 20]], 60], [[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0]], ['generated mix 15', [[['P0', 5, 48], ['P1', 3, 48], ['P2', 1, 20], ['P3', 5, 40]], 20], [[['P2', 20]], 0]], ['generated mix 23', [[['P0', 3, 40], ['P1', 2, 20], ['P2', 3, 10], ['P3', 5, 0]], 10], [[['P2', 10]], 0]]], [['generated mix 3', [[['P0', 1, 48], ['P1', 1, 48], ['P2', 1, 40], ['P3', 1, 20]], 40], [[['P2', 40]], 0]], ['generated mix 4', [[['P0', 3, 0], ['P1', 3, 20], ['P2', 5, 40], ['P3', 8, 30]], 20], [[['P1', 20]], 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 11', [[['P0', 5, 20], ['P1', 3, 40], ['P2', 3, 0], ['P3', 3, 20], ['P4', 3, 0], ['P5', 1, 20]], 20], [[['P5', 20]], 0]], ['generated mix 19', [[['P0', 5, 10], ['P1', 3, 40], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P3', 30]], 0]], ['generated mix 27', [[['P0', 8, 20], ['P1', 5, 48], ['P2', 5, 20]], 90], [[['P1', 48], ['P2', 20], ['P0', 20]], 2]]], [['generated mix 10', [[['P0', 3, 10], ['P1', 2, 10], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P1', 10], ['P0', 10], ['P3', 10]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 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 22', [[['P0', 3, 0], ['P1', 3, 40], ['P2', 3, 20]], 10], [[['P1', 10]], 0]], ['generated mix 30', [[['P0', 1, 20], ['P1', 5, 40], ['P2', 3, 48], ['P3', 2, 10], ['P4', 1, 48], ['P5', 2, 20]], 90], [[['P0', 20], ['P4', 48], ['P3', 10], ['P5', 12]], 0]], ['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 17', [[['P0', 3, 0]], 50], [[], 50]], ['generated mix 15', [[['P0', 5, 48], ['P1', 3, 48], ['P2', 1, 20], ['P3', 5, 40]], 20], [[['P2', 20]], 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 33', [[['P0', 3, 48]], 10], [[['P0', 10]], 0]], ['generated mix 41', [[['P0', 3, 0], ['P1', 3, 30], ['P2', 1, 48], ['P3', 3, 30], ['P4', 3, 20]], 20], [[['P4', 20]], 0]], ['generated mix 49', [[['P0', 3, 20], ['P1', 1, 0], ['P2', 8, 40], ['P3', 5, 20], ['P4', 5, 30], ['P5', 3, 40]], 25], [[['P0', 20], ['P5', 5]], 0]]], [['generated mix 24', [[['P0', 3, 20], ['P1', 3, 20], ['P2', 2, 20], ['P3', 5, 20], ['P4', 3, 30]], 10], [[['P2', 10]], 0]], ['generated mix 22', [[['P0', 3, 0], ['P1', 3, 40], ['P2', 3, 20]], 10], [[['P1', 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 fixtureActualExpectedOutcome
clean-out skip big[[['B', 20], ['C', 10]], 30][[['B', 20], ['C', 10]], 0]Failed
partial oldest[[['A', 30]], 30][[['A', 30]], 0]Failed
exact whole[[['A', 30]], 30][[['A', 30]], 0]Failed
equal qty pallets[[['A', 20], ['B', 20], ['C', 10]], 50][[['A', 20], ['B', 20], ['C', 10]], 0]Failed
shortfall[[['A', 10]], 10][[['A', 10]], 15]Failed
generated mix 7[[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 60][[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0]Failed
generated mix 15[[['P2', 20]], 20][[['P2', 20]], 0]Failed
generated mix 23[[['P2', 10]], 10][[['P2', 10]], 0]Failed

SHA-256 / bb1fb1bdb99c760204c403baeb326133f5d5cd8d6b3c7579310012c3d4709175

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 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, need - sum(q for _, _, q in pallets)]
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]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['generated mix 7', [[['P0', 8, 20], ['P1', 8, 30], ['P2', 3, 10], ['P3', 5, 20]], 60], [[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0]], ['generated mix 15', [[['P0', 5, 48], ['P1', 3, 48], ['P2', 1, 20], ['P3', 5, 40]], 20], [[['P2', 20]], 0]], ['generated mix 23', [[['P0', 3, 40], ['P1', 2, 20], ['P2', 3, 10], ['P3', 5, 0]], 10], [[['P2', 10]], 0]]], [['generated mix 3', [[['P0', 1, 48], ['P1', 1, 48], ['P2', 1, 40], ['P3', 1, 20]], 40], [[['P2', 40]], 0]], ['generated mix 4', [[['P0', 3, 0], ['P1', 3, 20], ['P2', 5, 40], ['P3', 8, 30]], 20], [[['P1', 20]], 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 11', [[['P0', 5, 20], ['P1', 3, 40], ['P2', 3, 0], ['P3', 3, 20], ['P4', 3, 0], ['P5', 1, 20]], 20], [[['P5', 20]], 0]], ['generated mix 19', [[['P0', 5, 10], ['P1', 3, 40], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P3', 30]], 0]], ['generated mix 27', [[['P0', 8, 20], ['P1', 5, 48], ['P2', 5, 20]], 90], [[['P1', 48], ['P2', 20], ['P0', 20]], 2]]], [['generated mix 10', [[['P0', 3, 10], ['P1', 2, 10], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P1', 10], ['P0', 10], ['P3', 10]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 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 22', [[['P0', 3, 0], ['P1', 3, 40], ['P2', 3, 20]], 10], [[['P1', 10]], 0]], ['generated mix 30', [[['P0', 1, 20], ['P1', 5, 40], ['P2', 3, 48], ['P3', 2, 10], ['P4', 1, 48], ['P5', 2, 20]], 90], [[['P0', 20], ['P4', 48], ['P3', 10], ['P5', 12]], 0]], ['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 17', [[['P0', 3, 0]], 50], [[], 50]], ['generated mix 15', [[['P0', 5, 48], ['P1', 3, 48], ['P2', 1, 20], ['P3', 5, 40]], 20], [[['P2', 20]], 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 33', [[['P0', 3, 48]], 10], [[['P0', 10]], 0]], ['generated mix 41', [[['P0', 3, 0], ['P1', 3, 30], ['P2', 1, 48], ['P3', 3, 30], ['P4', 3, 20]], 20], [[['P4', 20]], 0]], ['generated mix 49', [[['P0', 3, 20], ['P1', 1, 0], ['P2', 8, 40], ['P3', 5, 20], ['P4', 5, 30], ['P5', 3, 40]], 25], [[['P0', 20], ['P5', 5]], 0]]], [['generated mix 24', [[['P0', 3, 20], ['P1', 3, 20], ['P2', 2, 20], ['P3', 5, 20], ['P4', 3, 30]], 10], [[['P2', 10]], 0]], ['generated mix 22', [[['P0', 3, 0], ['P1', 3, 40], ['P2', 3, 20]], 10], [[['P1', 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 fixtureActualExpectedOutcome
clean-out skip big[[['B', 20], ['C', 10]], -50][[['B', 20], ['C', 10]], 0]Failed
partial oldest[[['A', 30]], -80][[['A', 30]], 0]Failed
exact whole[[['A', 30]], 0][[['A', 30]], 0]Passed
equal qty pallets[[['A', 20], ['B', 20], ['C', 10]], -30][[['A', 20], ['B', 20], ['C', 10]], 0]Failed
shortfall[[['A', 10]], 15][[['A', 10]], 15]Passed
generated mix 7[[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], -20][[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0]Failed
generated mix 15[[['P2', 20]], -136][[['P2', 20]], 0]Failed
generated mix 23[[['P2', 10]], -60][[['P2', 10]], 0]Failed

SHA-256 / f9cf45880be651b8ed823574607d4e3e21f5e7fef042463bb6eae7aa63fcd951

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]], ['partial oldest', [[['A', 1, 50], ['B', 2, 60]], 30], [[['A', 30]], 0]], ['exact whole', [[['A', 1, 30]], 30], [[['A', 30]], 0]], ['equal qty pallets', [[['A', 1, 20], ['B', 2, 20], ['C', 3, 40]], 50], [[['A', 20], ['B', 20], ['C', 10]], 0]], ['shortfall', [[['A', 1, 10]], 25], [[['A', 10]], 15]], ['generated mix 7', [[['P0', 8, 20], ['P1', 8, 30], ['P2', 3, 10], ['P3', 5, 20]], 60], [[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0]], ['generated mix 15', [[['P0', 5, 48], ['P1', 3, 48], ['P2', 1, 20], ['P3', 5, 40]], 20], [[['P2', 20]], 0]], ['generated mix 23', [[['P0', 3, 40], ['P1', 2, 20], ['P2', 3, 10], ['P3', 5, 0]], 10], [[['P2', 10]], 0]]], [['generated mix 3', [[['P0', 1, 48], ['P1', 1, 48], ['P2', 1, 40], ['P3', 1, 20]], 40], [[['P2', 40]], 0]], ['generated mix 4', [[['P0', 3, 0], ['P1', 3, 20], ['P2', 5, 40], ['P3', 8, 30]], 20], [[['P1', 20]], 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 11', [[['P0', 5, 20], ['P1', 3, 40], ['P2', 3, 0], ['P3', 3, 20], ['P4', 3, 0], ['P5', 1, 20]], 20], [[['P5', 20]], 0]], ['generated mix 19', [[['P0', 5, 10], ['P1', 3, 40], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P3', 30]], 0]], ['generated mix 27', [[['P0', 8, 20], ['P1', 5, 48], ['P2', 5, 20]], 90], [[['P1', 48], ['P2', 20], ['P0', 20]], 2]]], [['generated mix 10', [[['P0', 3, 10], ['P1', 2, 10], ['P2', 1, 30], ['P3', 3, 30]], 60], [[['P2', 30], ['P1', 10], ['P0', 10], ['P3', 10]], 0]], ['generated mix 9', [[['P0', 1, 20], ['P1', 2, 48], ['P2', 2, 20]], 20], [[['P0', 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 22', [[['P0', 3, 0], ['P1', 3, 40], ['P2', 3, 20]], 10], [[['P1', 10]], 0]], ['generated mix 30', [[['P0', 1, 20], ['P1', 5, 40], ['P2', 3, 48], ['P3', 2, 10], ['P4', 1, 48], ['P5', 2, 20]], 90], [[['P0', 20], ['P4', 48], ['P3', 10], ['P5', 12]], 0]], ['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 17', [[['P0', 3, 0]], 50], [[], 50]], ['generated mix 15', [[['P0', 5, 48], ['P1', 3, 48], ['P2', 1, 20], ['P3', 5, 40]], 20], [[['P2', 20]], 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 33', [[['P0', 3, 48]], 10], [[['P0', 10]], 0]], ['generated mix 41', [[['P0', 3, 0], ['P1', 3, 30], ['P2', 1, 48], ['P3', 3, 30], ['P4', 3, 20]], 20], [[['P4', 20]], 0]], ['generated mix 49', [[['P0', 3, 20], ['P1', 1, 0], ['P2', 8, 40], ['P3', 5, 20], ['P4', 5, 30], ['P5', 3, 40]], 25], [[['P0', 20], ['P5', 5]], 0]]], [['generated mix 24', [[['P0', 3, 20], ['P1', 3, 20], ['P2', 2, 20], ['P3', 5, 20], ['P4', 3, 30]], 10], [[['P2', 10]], 0]], ['generated mix 22', [[['P0', 3, 0], ['P1', 3, 40], ['P2', 3, 20]], 10], [[['P1', 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 fixtureActualExpectedOutcome
clean-out skip big[[['B', 20], ['C', 10]], 0][[['B', 20], ['C', 10]], 0]Passed
partial oldest[[['A', 30]], 0][[['A', 30]], 0]Passed
exact whole[[['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
shortfall[[['A', 10]], 15][[['A', 10]], 15]Passed
generated mix 7[[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0][[['P2', 10], ['P3', 20], ['P0', 20], ['P1', 10]], 0]Passed
generated mix 15[[['P2', 20]], 0][[['P2', 20]], 0]Passed
generated mix 23[[['P2', 10]], 0][[['P2', 10]], 0]Passed

SHA-256 / d4c9379b316303ab861094f5abdac945a6ed982eaabbc3970781dadc1cd90fd1

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

Case digest / 7e69c18f3ca73fa8db9881deeee2d20104803fea2b1756c14f8acada437aa7ba