FAILURE MAP
← Case archive

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

Replenishment: face sitting at min not triggered · case 01

A pick face whose on-hand equals its minimum is not replenished and stocks out during the next wave.

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

ROOT CAUSE

The trigger skips faces at exactly the minimum, treating min as an exclusive reorder point.

VERIFIED REPAIR

Trigger replenishment whenever on-hand is at or below the minimum.

Unsuccessful approach: Shifting the threshold by one unit triggers faces sitting one unit above min.

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 // 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 = [[['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['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]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['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]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['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 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 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]]], ['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 9', [[['F0', 6, 6, 9, 1, 100], ['F1', 1, 12, 18, 6, 0]]], [['F0', 3]]], ['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]]], ['generated mix 27', [[['F0', 1, 12, 24, 6, 24]]], [['F0', 18]]]], [['generated mix 63', [[['F0', 10, 10, 40, 4, 24], ['F1', 1, 12, 12, 12, 12], ['F2', 0, 10, 10, 4, 24], ['F3', 0, 12, 12, 4, 12]]], [['F2', 8], ['F3', 12], ['F0', 24]]], ['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]]], ['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 20', [[['F0', 0, 12, 36, 4, 48]]], [['F0', 36]]], ['generated mix 28', [[['F0', 3, 6, 36, 6, 48], ['F1', 1, 12, 42, 12, 3]]], [['F0', 30]]], ['generated mix 36', [[['F0', 0, 6, 6, 4, 3], ['F1', 5, 6, 12, 12, 48]]], []]], [['generated mix 7', [[['F0', 0, 12, 12, 12, 100], ['F1', 0, 10, 16, 4, 48], ['F2', 4, 4, 10, 6, 100], ['F3', 1, 4, 7, 1, 100]]], [['F0', 12], ['F1', 16], ['F3', 6], ['F2', 6]]], ['generated mix 67', [[['F0', 11, 10, 10, 4, 48], ['F1', 1, 12, 12, 1, 100], ['F2', 0, 12, 36, 6, 3], ['F3', 1, 4, 10, 1, 3]]], [['F1', 11], ['F3', 3]]], ['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 32', [[['F0', 5, 4, 34, 4, 0], ['F1', 9, 10, 40, 12, 24], ['F2', 6, 6, 9, 12, 24], ['F3', 3, 6, 9, 6, 0]]], [['F1', 24]]], ['generated mix 40', [[['F0', 7, 6, 18, 6, 48], ['F1', 13, 12, 24, 1, 0], ['F2', 7, 6, 12, 12, 24]]], []], ['generated mix 48', [[['F0', 0, 12, 12, 6, 0], ['F1', 0, 10, 22, 1, 24], ['F2', 0, 12, 15, 1, 12]]], [['F1', 22], ['F2', 12]]]], [['generated mix 50', [[['F0', 11, 12, 36, 1, 12], ['F1', 0, 10, 22, 6, 12], ['F2', 4, 4, 28, 4, 48], ['F3', 1, 4, 7, 12, 0]]], [['F1', 12], ['F0', 12], ['F2', 24]]], ['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]]], ['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
at min triggers[][['A', 24]]Failed
generated mix 16[['F1', 3]][['F1', 3]]Passed
above min idle[][]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
reserve partial case[['A', 12]][['A', 12]]Passed
stockout no reserve[][]Passed
generated mix 8[['F1', 12]][['F1', 12]]Passed

SHA-256 / c740f5c733bc262bd5a51fb627d29d90c18a030535b73cbeba90ac9886968257

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 - 1 > 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 = [[['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['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]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['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]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['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 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 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]]], ['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 9', [[['F0', 6, 6, 9, 1, 100], ['F1', 1, 12, 18, 6, 0]]], [['F0', 3]]], ['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]]], ['generated mix 27', [[['F0', 1, 12, 24, 6, 24]]], [['F0', 18]]]], [['generated mix 63', [[['F0', 10, 10, 40, 4, 24], ['F1', 1, 12, 12, 12, 12], ['F2', 0, 10, 10, 4, 24], ['F3', 0, 12, 12, 4, 12]]], [['F2', 8], ['F3', 12], ['F0', 24]]], ['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]]], ['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 20', [[['F0', 0, 12, 36, 4, 48]]], [['F0', 36]]], ['generated mix 28', [[['F0', 3, 6, 36, 6, 48], ['F1', 1, 12, 42, 12, 3]]], [['F0', 30]]], ['generated mix 36', [[['F0', 0, 6, 6, 4, 3], ['F1', 5, 6, 12, 12, 48]]], []]], [['generated mix 7', [[['F0', 0, 12, 12, 12, 100], ['F1', 0, 10, 16, 4, 48], ['F2', 4, 4, 10, 6, 100], ['F3', 1, 4, 7, 1, 100]]], [['F0', 12], ['F1', 16], ['F3', 6], ['F2', 6]]], ['generated mix 67', [[['F0', 11, 10, 10, 4, 48], ['F1', 1, 12, 12, 1, 100], ['F2', 0, 12, 36, 6, 3], ['F3', 1, 4, 10, 1, 3]]], [['F1', 11], ['F3', 3]]], ['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 32', [[['F0', 5, 4, 34, 4, 0], ['F1', 9, 10, 40, 12, 24], ['F2', 6, 6, 9, 12, 24], ['F3', 3, 6, 9, 6, 0]]], [['F1', 24]]], ['generated mix 40', [[['F0', 7, 6, 18, 6, 48], ['F1', 13, 12, 24, 1, 0], ['F2', 7, 6, 12, 12, 24]]], []], ['generated mix 48', [[['F0', 0, 12, 12, 6, 0], ['F1', 0, 10, 22, 1, 24], ['F2', 0, 12, 15, 1, 12]]], [['F1', 22], ['F2', 12]]]], [['generated mix 50', [[['F0', 11, 12, 36, 1, 12], ['F1', 0, 10, 22, 6, 12], ['F2', 4, 4, 28, 4, 48], ['F3', 1, 4, 7, 12, 0]]], [['F1', 12], ['F0', 12], ['F2', 24]]], ['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]]], ['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
at min triggers[['A', 24]][['A', 24]]Passed
generated mix 16[['F1', 3], ['F3', 24], ['F2', 6]][['F1', 3]]Failed
above min idle[['A', 12]][]Failed
stockout small max[['B', 6]][['B', 6]]Passed
priority by ratio[['Z', 40], ['Y', 35], ['X', 35]][['Z', 40], ['Y', 35], ['X', 35]]Passed
reserve partial case[['A', 12]][['A', 12]]Passed
stockout no reserve[][]Passed
generated mix 8[['F1', 12]][['F1', 12]]Passed

SHA-256 / ecd8032415eb85ec3d1cc67e224296c130353072a688c72d92ead1ebed5de6af

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 = [[['at min triggers', [[['A', 10, 10, 34, 12, 100]]], [['A', 24]]], ['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]]], ['above min idle', [[['A', 11, 10, 34, 12, 100]]], []], ['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]]], ['reserve partial case', [[['A', 0, 5, 30, 12, 20]]], [['A', 12]]], ['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 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 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]]], ['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 9', [[['F0', 6, 6, 9, 1, 100], ['F1', 1, 12, 18, 6, 0]]], [['F0', 3]]], ['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]]], ['generated mix 27', [[['F0', 1, 12, 24, 6, 24]]], [['F0', 18]]]], [['generated mix 63', [[['F0', 10, 10, 40, 4, 24], ['F1', 1, 12, 12, 12, 12], ['F2', 0, 10, 10, 4, 24], ['F3', 0, 12, 12, 4, 12]]], [['F2', 8], ['F3', 12], ['F0', 24]]], ['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]]], ['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 20', [[['F0', 0, 12, 36, 4, 48]]], [['F0', 36]]], ['generated mix 28', [[['F0', 3, 6, 36, 6, 48], ['F1', 1, 12, 42, 12, 3]]], [['F0', 30]]], ['generated mix 36', [[['F0', 0, 6, 6, 4, 3], ['F1', 5, 6, 12, 12, 48]]], []]], [['generated mix 7', [[['F0', 0, 12, 12, 12, 100], ['F1', 0, 10, 16, 4, 48], ['F2', 4, 4, 10, 6, 100], ['F3', 1, 4, 7, 1, 100]]], [['F0', 12], ['F1', 16], ['F3', 6], ['F2', 6]]], ['generated mix 67', [[['F0', 11, 10, 10, 4, 48], ['F1', 1, 12, 12, 1, 100], ['F2', 0, 12, 36, 6, 3], ['F3', 1, 4, 10, 1, 3]]], [['F1', 11], ['F3', 3]]], ['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 32', [[['F0', 5, 4, 34, 4, 0], ['F1', 9, 10, 40, 12, 24], ['F2', 6, 6, 9, 12, 24], ['F3', 3, 6, 9, 6, 0]]], [['F1', 24]]], ['generated mix 40', [[['F0', 7, 6, 18, 6, 48], ['F1', 13, 12, 24, 1, 0], ['F2', 7, 6, 12, 12, 24]]], []], ['generated mix 48', [[['F0', 0, 12, 12, 6, 0], ['F1', 0, 10, 22, 1, 24], ['F2', 0, 12, 15, 1, 12]]], [['F1', 22], ['F2', 12]]]], [['generated mix 50', [[['F0', 11, 12, 36, 1, 12], ['F1', 0, 10, 22, 6, 12], ['F2', 4, 4, 28, 4, 48], ['F3', 1, 4, 7, 12, 0]]], [['F1', 12], ['F0', 12], ['F2', 24]]], ['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]]], ['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
at min triggers[['A', 24]][['A', 24]]Passed
generated mix 16[['F1', 3]][['F1', 3]]Passed
above min idle[][]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
reserve partial case[['A', 12]][['A', 12]]Passed
stockout no reserve[][]Passed
generated mix 8[['F1', 12]][['F1', 12]]Passed

SHA-256 / 533a02ec12410b4bc5eca845802705b258dd01a8356463151b516e3dfeee7995

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

Case digest / ad21c1b20cd80383551716b81dfeb7ffe7b2647261534501427ff6c354a44203