FAILURE MAP
← Case archive

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

Replenishment: partial reserve case requested · case 01

A task requests more units than exist as full cases in reserve, forcing a case to be broken in reserve.

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

ROOT CAUSE

The reserve limit uses the raw unit count instead of full cases available.

VERIFIED REPAIR

Cap quantity at the number of full cases in reserve times the case pack.

Unsuccessful approach: Dividing reserve by case pack without multiplying back compares cases against units.

Case contract

faces [[loc, on_hand, min, max, case_pack, reserve_units]], min >= 1. Replenish when on_hand <= min. Quantity is the largest number of full cases that keeps on_hand <= max, limited to full cases available in reserve. A stocked-out face whose max leaves no room for a full case still gets one case if reserve has one. Zero-quantity tasks are dropped. Tasks are ordered by on_hand/min ascending, then loc.

Why this case matters

Min/max replenishment keeps forward pick faces stocked from reserve.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
N = 1
observations = []
def solve(faces):
    tasks = []
    for loc, oh, mn, mx, cp, reserve in faces:
        if oh > mn:
            continue
        avail = reserve
        qty = (mx - oh) // cp * cp
        qty = min(qty, avail)
        if qty == 0 and oh == 0 and avail >= cp:
            qty = cp
        if qty == 0:
            continue
        tasks.append((Fraction(oh, mn), loc, qty))
    tasks.sort()
    return [[loc, qty] for _, loc, qty in tasks]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 8', [[['F0', 0, 12, 15, 6, 0], ['F1', 1, 10, 22, 6, 12]]], [['F1', 12]]], ['generated mix 16', [[['F0', 6, 6, 36, 1, 0], ['F1', 1, 10, 22, 1, 3], ['F2', 5, 4, 16, 6, 24], ['F3', 7, 6, 36, 6, 24]]], [['F1', 3]]]], [['generated mix 44', [[['F0', 4, 4, 4, 6, 3], ['F1', 11, 10, 10, 1, 48], ['F2', 11, 12, 24, 4, 48], ['F3', 3, 6, 9, 4, 3]]], [['F2', 12]]], ['generated mix 4', [[['F0', 1, 12, 42, 12, 24]]], [['F0', 24]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['generated mix 10', [[['F0', 0, 4, 4, 12, 12], ['F1', 5, 6, 12, 12, 24]]], [['F0', 12]]], ['generated mix 18', [[['F0', 5, 6, 9, 6, 24], ['F1', 1, 12, 15, 4, 3], ['F2', 3, 12, 15, 12, 0], ['F3', 7, 6, 30, 6, 24]]], []], ['generated mix 26', [[['F0', 7, 6, 6, 12, 48], ['F1', 0, 4, 28, 6, 12], ['F2', 0, 6, 30, 6, 0], ['F3', 1, 6, 6, 1, 3]]], [['F1', 12], ['F3', 3]]]], [['generated mix 66', [[['F0', 12, 12, 42, 1, 48], ['F1', 0, 12, 15, 6, 3], ['F2', 1, 4, 28, 12, 12]]], [['F2', 12], ['F0', 30]]], ['generated mix 10', [[['F0', 0, 4, 4, 12, 12], ['F1', 5, 6, 12, 12, 24]]], [['F0', 12]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 21', [[['F0', 0, 4, 16, 1, 24], ['F1', 11, 10, 22, 6, 12], ['F2', 0, 6, 18, 4, 24], ['F3', 3, 4, 34, 6, 48], ['F4', 12, 12, 24, 12, 100]]], [['F0', 16], ['F2', 16], ['F3', 30], ['F4', 12]]], ['generated mix 29', [[['F0', 1, 12, 36, 1, 100], ['F1', 0, 4, 16, 1, 100], ['F2', 3, 12, 18, 4, 24], ['F3', 7, 6, 6, 1, 48]]], [['F1', 16], ['F0', 35], ['F2', 12]]], ['generated mix 37', [[['F0', 0, 4, 7, 12, 48]]], [['F0', 12]]]], [['generated mix 23', [[['F0', 0, 12, 24, 12, 3], ['F1', 0, 4, 10, 12, 24]]], [['F1', 12]]], ['generated mix 17', [[['F0', 1, 12, 24, 4, 12], ['F1', 12, 12, 18, 4, 24], ['F2', 11, 12, 24, 1, 12], ['F3', 11, 10, 40, 12, 100]]], [['F0', 12], ['F2', 12], ['F1', 4]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['generated mix 33', [[['F0', 13, 12, 36, 12, 48], ['F1', 5, 4, 10, 6, 100], ['F2', 4, 4, 10, 12, 24]]], []], ['generated mix 41', [[['F0', 0, 4, 16, 1, 12], ['F1', 7, 6, 30, 1, 100], ['F2', 5, 6, 18, 12, 24]]], [['F0', 12], ['F2', 12]]], ['generated mix 49', [[['F0', 1, 12, 36, 6, 100], ['F1', 0, 12, 18, 12, 12], ['F2', 0, 10, 10, 1, 48], ['F3', 1, 6, 18, 1, 100]]], [['F1', 12], ['F2', 10], ['F0', 30], ['F3', 17]]]], [['generated mix 51', [[['F0', 4, 4, 28, 6, 12], ['F1', 1, 6, 30, 12, 0], ['F2', 9, 10, 34, 6, 3]]], [['F0', 12]]], ['generated mix 24', [[['F0', 3, 10, 10, 4, 48], ['F1', 0, 6, 9, 4, 12], ['F2', 0, 10, 13, 12, 100], ['F3', 6, 6, 6, 4, 12]]], [['F1', 8], ['F2', 12], ['F0', 4]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 43', [[['F0', 0, 6, 18, 4, 24], ['F1', 3, 4, 34, 4, 48], ['F2', 1, 4, 10, 12, 0], ['F3', 1, 4, 34, 12, 12]]], [['F0', 16], ['F3', 12], ['F1', 28]]], ['generated mix 52', [[['F0', 11, 10, 16, 6, 3], ['F1', 10, 10, 13, 4, 24], ['F2', 0, 4, 28, 1, 100], ['F3', 12, 12, 42, 4, 0]]], [['F2', 28]]], ['generated mix 60', [[['F0', 0, 10, 40, 1, 24], ['F1', 3, 6, 30, 4, 100], ['F2', 4, 4, 4, 6, 100]]], [['F0', 24], ['F1', 24]]]]]
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
reserve partial case[['A', 20]][['A', 12]]Failed
at min triggers[['A', 24]][['A', 24]]Passed
stockout small max[['B', 6]][['B', 6]]Passed
priority by ratio[['Z', 40], ['Y', 35], ['X', 35]][['Z', 40], ['Y', 35], ['X', 35]]Passed
above min idle[][]Passed
stockout no reserve[['B', 5]][]Failed
generated mix 8[['F1', 12]][['F1', 12]]Passed
generated mix 16[['F1', 3]][['F1', 3]]Passed

SHA-256 / b9efffeae6fc2ee78fafe23bedcd92d5736d46faeeeb96cf03796eb18b1fc0c6

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
N = 1
observations = []
def solve(faces):
    tasks = []
    for loc, oh, mn, mx, cp, reserve in faces:
        if oh > mn:
            continue
        avail = reserve // cp
        qty = (mx - oh) // cp * cp
        qty = min(qty, avail)
        if qty == 0 and oh == 0 and avail >= cp:
            qty = cp
        if qty == 0:
            continue
        tasks.append((Fraction(oh, mn), loc, qty))
    tasks.sort()
    return [[loc, qty] for _, loc, qty in tasks]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 8', [[['F0', 0, 12, 15, 6, 0], ['F1', 1, 10, 22, 6, 12]]], [['F1', 12]]], ['generated mix 16', [[['F0', 6, 6, 36, 1, 0], ['F1', 1, 10, 22, 1, 3], ['F2', 5, 4, 16, 6, 24], ['F3', 7, 6, 36, 6, 24]]], [['F1', 3]]]], [['generated mix 44', [[['F0', 4, 4, 4, 6, 3], ['F1', 11, 10, 10, 1, 48], ['F2', 11, 12, 24, 4, 48], ['F3', 3, 6, 9, 4, 3]]], [['F2', 12]]], ['generated mix 4', [[['F0', 1, 12, 42, 12, 24]]], [['F0', 24]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['generated mix 10', [[['F0', 0, 4, 4, 12, 12], ['F1', 5, 6, 12, 12, 24]]], [['F0', 12]]], ['generated mix 18', [[['F0', 5, 6, 9, 6, 24], ['F1', 1, 12, 15, 4, 3], ['F2', 3, 12, 15, 12, 0], ['F3', 7, 6, 30, 6, 24]]], []], ['generated mix 26', [[['F0', 7, 6, 6, 12, 48], ['F1', 0, 4, 28, 6, 12], ['F2', 0, 6, 30, 6, 0], ['F3', 1, 6, 6, 1, 3]]], [['F1', 12], ['F3', 3]]]], [['generated mix 66', [[['F0', 12, 12, 42, 1, 48], ['F1', 0, 12, 15, 6, 3], ['F2', 1, 4, 28, 12, 12]]], [['F2', 12], ['F0', 30]]], ['generated mix 10', [[['F0', 0, 4, 4, 12, 12], ['F1', 5, 6, 12, 12, 24]]], [['F0', 12]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 21', [[['F0', 0, 4, 16, 1, 24], ['F1', 11, 10, 22, 6, 12], ['F2', 0, 6, 18, 4, 24], ['F3', 3, 4, 34, 6, 48], ['F4', 12, 12, 24, 12, 100]]], [['F0', 16], ['F2', 16], ['F3', 30], ['F4', 12]]], ['generated mix 29', [[['F0', 1, 12, 36, 1, 100], ['F1', 0, 4, 16, 1, 100], ['F2', 3, 12, 18, 4, 24], ['F3', 7, 6, 6, 1, 48]]], [['F1', 16], ['F0', 35], ['F2', 12]]], ['generated mix 37', [[['F0', 0, 4, 7, 12, 48]]], [['F0', 12]]]], [['generated mix 23', [[['F0', 0, 12, 24, 12, 3], ['F1', 0, 4, 10, 12, 24]]], [['F1', 12]]], ['generated mix 17', [[['F0', 1, 12, 24, 4, 12], ['F1', 12, 12, 18, 4, 24], ['F2', 11, 12, 24, 1, 12], ['F3', 11, 10, 40, 12, 100]]], [['F0', 12], ['F2', 12], ['F1', 4]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['generated mix 33', [[['F0', 13, 12, 36, 12, 48], ['F1', 5, 4, 10, 6, 100], ['F2', 4, 4, 10, 12, 24]]], []], ['generated mix 41', [[['F0', 0, 4, 16, 1, 12], ['F1', 7, 6, 30, 1, 100], ['F2', 5, 6, 18, 12, 24]]], [['F0', 12], ['F2', 12]]], ['generated mix 49', [[['F0', 1, 12, 36, 6, 100], ['F1', 0, 12, 18, 12, 12], ['F2', 0, 10, 10, 1, 48], ['F3', 1, 6, 18, 1, 100]]], [['F1', 12], ['F2', 10], ['F0', 30], ['F3', 17]]]], [['generated mix 51', [[['F0', 4, 4, 28, 6, 12], ['F1', 1, 6, 30, 12, 0], ['F2', 9, 10, 34, 6, 3]]], [['F0', 12]]], ['generated mix 24', [[['F0', 3, 10, 10, 4, 48], ['F1', 0, 6, 9, 4, 12], ['F2', 0, 10, 13, 12, 100], ['F3', 6, 6, 6, 4, 12]]], [['F1', 8], ['F2', 12], ['F0', 4]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 43', [[['F0', 0, 6, 18, 4, 24], ['F1', 3, 4, 34, 4, 48], ['F2', 1, 4, 10, 12, 0], ['F3', 1, 4, 34, 12, 12]]], [['F0', 16], ['F3', 12], ['F1', 28]]], ['generated mix 52', [[['F0', 11, 10, 16, 6, 3], ['F1', 10, 10, 13, 4, 24], ['F2', 0, 4, 28, 1, 100], ['F3', 12, 12, 42, 4, 0]]], [['F2', 28]]], ['generated mix 60', [[['F0', 0, 10, 40, 1, 24], ['F1', 3, 6, 30, 4, 100], ['F2', 4, 4, 4, 6, 100]]], [['F0', 24], ['F1', 24]]]]]
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
reserve partial case[['A', 1]][['A', 12]]Failed
at min triggers[['A', 8]][['A', 24]]Failed
stockout small max[][['B', 6]]Failed
priority by ratio[['Z', 20], ['Y', 20], ['X', 20]][['Z', 40], ['Y', 35], ['X', 35]]Failed
above min idle[][]Passed
stockout no reserve[][]Passed
generated mix 8[['F1', 2]][['F1', 12]]Failed
generated mix 16[['F1', 3]][['F1', 3]]Passed

SHA-256 / 910d69bdd2dfac8df0f3de239a048df9c41d0de02953c04c5f15fd3ae457bd5a

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
N = 1
observations = []
def solve(faces):
    tasks = []
    for loc, oh, mn, mx, cp, reserve in faces:
        if oh > mn:
            continue
        avail = reserve // cp * cp
        qty = (mx - oh) // cp * cp
        qty = min(qty, avail)
        if qty == 0 and oh == 0 and avail >= cp:
            qty = cp
        if qty == 0:
            continue
        tasks.append((Fraction(oh, mn), loc, qty))
    tasks.sort()
    return [[loc, qty] for _, loc, qty in tasks]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 8', [[['F0', 0, 12, 15, 6, 0], ['F1', 1, 10, 22, 6, 12]]], [['F1', 12]]], ['generated mix 16', [[['F0', 6, 6, 36, 1, 0], ['F1', 1, 10, 22, 1, 3], ['F2', 5, 4, 16, 6, 24], ['F3', 7, 6, 36, 6, 24]]], [['F1', 3]]]], [['generated mix 44', [[['F0', 4, 4, 4, 6, 3], ['F1', 11, 10, 10, 1, 48], ['F2', 11, 12, 24, 4, 48], ['F3', 3, 6, 9, 4, 3]]], [['F2', 12]]], ['generated mix 4', [[['F0', 1, 12, 42, 12, 24]]], [['F0', 24]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['generated mix 10', [[['F0', 0, 4, 4, 12, 12], ['F1', 5, 6, 12, 12, 24]]], [['F0', 12]]], ['generated mix 18', [[['F0', 5, 6, 9, 6, 24], ['F1', 1, 12, 15, 4, 3], ['F2', 3, 12, 15, 12, 0], ['F3', 7, 6, 30, 6, 24]]], []], ['generated mix 26', [[['F0', 7, 6, 6, 12, 48], ['F1', 0, 4, 28, 6, 12], ['F2', 0, 6, 30, 6, 0], ['F3', 1, 6, 6, 1, 3]]], [['F1', 12], ['F3', 3]]]], [['generated mix 66', [[['F0', 12, 12, 42, 1, 48], ['F1', 0, 12, 15, 6, 3], ['F2', 1, 4, 28, 12, 12]]], [['F2', 12], ['F0', 30]]], ['generated mix 10', [[['F0', 0, 4, 4, 12, 12], ['F1', 5, 6, 12, 12, 24]]], [['F0', 12]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 21', [[['F0', 0, 4, 16, 1, 24], ['F1', 11, 10, 22, 6, 12], ['F2', 0, 6, 18, 4, 24], ['F3', 3, 4, 34, 6, 48], ['F4', 12, 12, 24, 12, 100]]], [['F0', 16], ['F2', 16], ['F3', 30], ['F4', 12]]], ['generated mix 29', [[['F0', 1, 12, 36, 1, 100], ['F1', 0, 4, 16, 1, 100], ['F2', 3, 12, 18, 4, 24], ['F3', 7, 6, 6, 1, 48]]], [['F1', 16], ['F0', 35], ['F2', 12]]], ['generated mix 37', [[['F0', 0, 4, 7, 12, 48]]], [['F0', 12]]]], [['generated mix 23', [[['F0', 0, 12, 24, 12, 3], ['F1', 0, 4, 10, 12, 24]]], [['F1', 12]]], ['generated mix 17', [[['F0', 1, 12, 24, 4, 12], ['F1', 12, 12, 18, 4, 24], ['F2', 11, 12, 24, 1, 12], ['F3', 11, 10, 40, 12, 100]]], [['F0', 12], ['F2', 12], ['F1', 4]]], ['stockout small max', [[['B', 0, 2, 5, 6, 12]]], [['B', 6]]], ['priority by ratio', [[['X', 5, 10, 40, 5, 100], ['Y', 2, 8, 40, 5, 100], ['Z', 0, 6, 40, 5, 100]]], [['Z', 40], ['Y', 35], ['X', 35]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['generated mix 33', [[['F0', 13, 12, 36, 12, 48], ['F1', 5, 4, 10, 6, 100], ['F2', 4, 4, 10, 12, 24]]], []], ['generated mix 41', [[['F0', 0, 4, 16, 1, 12], ['F1', 7, 6, 30, 1, 100], ['F2', 5, 6, 18, 12, 24]]], [['F0', 12], ['F2', 12]]], ['generated mix 49', [[['F0', 1, 12, 36, 6, 100], ['F1', 0, 12, 18, 12, 12], ['F2', 0, 10, 10, 1, 48], ['F3', 1, 6, 18, 1, 100]]], [['F1', 12], ['F2', 10], ['F0', 30], ['F3', 17]]]], [['generated mix 51', [[['F0', 4, 4, 28, 6, 12], ['F1', 1, 6, 30, 12, 0], ['F2', 9, 10, 34, 6, 3]]], [['F0', 12]]], ['generated mix 24', [[['F0', 3, 10, 10, 4, 48], ['F1', 0, 6, 9, 4, 12], ['F2', 0, 10, 13, 12, 100], ['F3', 6, 6, 6, 4, 12]]], [['F1', 8], ['F2', 12], ['F0', 4]]], ['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['stockout no reserve', [[['B', 0, 2, 20, 6, 5]]], []], ['generated mix 43', [[['F0', 0, 6, 18, 4, 24], ['F1', 3, 4, 34, 4, 48], ['F2', 1, 4, 10, 12, 0], ['F3', 1, 4, 34, 12, 12]]], [['F0', 16], ['F3', 12], ['F1', 28]]], ['generated mix 52', [[['F0', 11, 10, 16, 6, 3], ['F1', 10, 10, 13, 4, 24], ['F2', 0, 4, 28, 1, 100], ['F3', 12, 12, 42, 4, 0]]], [['F2', 28]]], ['generated mix 60', [[['F0', 0, 10, 40, 1, 24], ['F1', 3, 6, 30, 4, 100], ['F2', 4, 4, 4, 6, 100]]], [['F0', 24], ['F1', 24]]]]]
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
reserve partial case[['A', 12]][['A', 12]]Passed
at min triggers[['A', 24]][['A', 24]]Passed
stockout small max[['B', 6]][['B', 6]]Passed
priority by ratio[['Z', 40], ['Y', 35], ['X', 35]][['Z', 40], ['Y', 35], ['X', 35]]Passed
above min idle[][]Passed
stockout no reserve[][]Passed
generated mix 8[['F1', 12]][['F1', 12]]Passed
generated mix 16[['F1', 3]][['F1', 3]]Passed

SHA-256 / 01d2c341a826fcf59a0442617fc8094b43806f04aae23a23b15403cdd3bf742f

Verification & scope

Stipulated min/max policy with whole-case moves only. 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:08.756759+00:00.

Case digest / dea417fcef2c524c31a6195e0571e6e8dff73bbeebe9de1e356d79365f4cdb8b