FAILURE MAP
← Case archive

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

Hazmat audit: bays compared across aisles · case 01

Products in different aisles with the same bay number are reported as too close.

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

ROOT CAUSE

The aisle equality guard is missing, so bay numbers from different aisles are compared.

VERIFIED REPAIR

Only compare placements in the same aisle.

Unsuccessful approach: Treating neighbouring aisles as the same aisle still compares bay numbers that are not adjacent.

Case contract

placements [[sku, hazard class, aisle, bay]]; rules [[class_a, class_b, min_bay_gap]] apply in either order within the same aisle. A rule class matches a hazard class equal to it or a division of it ("4" matches "4.1"). A pair violates when |bay difference| < min_gap. Different SKUs only. Return sorted unique [sku_low, sku_high] pairs.

Why this case matters

Dangerous goods storage requires separation between incompatible hazard classes.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(placements, rules):
    def matches(cls, rule):
        return cls == rule or cls.startswith(rule + '.')
    found = set()
    n = len(placements)
    for i in range(n):
        for j in range(i + 1, n):
            sa, ca, aa, ba = placements[i]
            sb, cb, ab, bb = placements[j]
            if sa == sb:
                continue
            gap = abs(ba - bb)
            for ra, rb, min_gap in rules:
                hit = (matches(ca, ra) and matches(cb, rb)) or (matches(ca, rb) and matches(cb, ra))
                if hit and gap < min_gap:
                    found.add(tuple(sorted([sa, sb])))
    return [list(p) for p in sorted(found)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 4', [[['H0', '8', 2, 3], ['H1', '8', 1, 6], ['H2', '5.1', 2, 3], ['H3', '3', 1, 3], ['H4', '4.3', 2, 4], ['H5', '4.3', 2, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 7', [[['H0', '2.1', 2, 1], ['H1', '5.2', 1, 6], ['H2', '4.1', 1, 6], ['H3', '8', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 54', [[['H0', '8', 2, 4], ['H1', '4.1', 1, 4], ['H2', '2.1', 1, 1]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 46', [[['H0', '2.1', 1, 5], ['H1', '8', 2, 4], ['H2', '9', 2, 2], ['H3', '5.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 8', [[['H0', '5.1', 1, 6], ['H1', '3', 1, 1], ['H2', '5.2', 1, 2], ['H3', '2.1', 2, 1], ['H0', '5.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]]], [['generated mix 8', [[['H0', '5.1', 1, 6], ['H1', '3', 1, 1], ['H2', '5.2', 1, 2], ['H3', '2.1', 2, 1], ['H0', '5.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 80', [[['H0', '5.1', 2, 2], ['H1', '2.1', 1, 4], ['H0', '5.1', 2, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['reverse order', [[['O', '5.1', 1, 1], ['G', '2.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['G', 'O']]], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['same class rule', [[['P', '5.2', 1, 3], ['Q', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['P', 'Q']]], ['generated mix 20', [[['H0', '8', 1, 5], ['H1', '5.2', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 28', [[['H0', '4.3', 2, 3], ['H1', '5.1', 1, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 61', [[['H0', '5.1', 2, 3], ['H1', '3', 1, 3], ['H2', '9', 2, 2], ['H3', '9', 2, 2], ['H4', '8', 1, 1], ['H5', '4.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['generated mix 31', [[['H0', '3', 1, 6], ['H1', '4.1', 2, 4], ['H2', '2.1', 2, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 39', [[['H0', '8', 1, 2], ['H1', '8', 2, 5], ['H2', '3', 1, 1], ['H3', '4.3', 2, 3], ['H0', '8', 1, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]], ['generated mix 61', [[['H0', '5.1', 2, 3], ['H1', '3', 1, 3], ['H2', '9', 2, 2], ['H3', '9', 2, 2], ['H4', '8', 1, 1], ['H5', '4.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same class rule', [[['P', '5.2', 1, 3], ['Q', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['P', 'Q']]], ['reverse order', [[['O', '5.1', 1, 1], ['G', '2.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['G', 'O']]], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['generated mix 42', [[['H0', '8', 2, 1], ['H1', '3', 2, 6], ['H2', '3', 1, 5], ['H3', '5.2', 2, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 50', [[['H0', '8', 1, 2], ['H1', '2.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]]]
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
other aisle[['F', 'O']][]Failed
generated mix 4[['H1', 'H5'], ['H2', 'H3']][]Failed
adjacent oxidizer[['F', 'O']][['F', 'O']]Passed
division match[['C', 'W']][['C', 'W']]Passed
same sku twice[][]Passed
two pairs[['A', 'Z'], ['B', 'C']][['A', 'Z'], ['B', 'C']]Passed
gap equal ok[][]Passed
generated mix 7[][]Passed

SHA-256 / 580d6183a13ba3f31930cc8aa83b3e4559173e384b6735f5297e4abce3053b30

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(placements, rules):
    def matches(cls, rule):
        return cls == rule or cls.startswith(rule + '.')
    found = set()
    n = len(placements)
    for i in range(n):
        for j in range(i + 1, n):
            sa, ca, aa, ba = placements[i]
            sb, cb, ab, bb = placements[j]
            if sa == sb or abs(aa - ab) > 1:
                continue
            gap = abs(ba - bb)
            for ra, rb, min_gap in rules:
                hit = (matches(ca, ra) and matches(cb, rb)) or (matches(ca, rb) and matches(cb, ra))
                if hit and gap < min_gap:
                    found.add(tuple(sorted([sa, sb])))
    return [list(p) for p in sorted(found)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 4', [[['H0', '8', 2, 3], ['H1', '8', 1, 6], ['H2', '5.1', 2, 3], ['H3', '3', 1, 3], ['H4', '4.3', 2, 4], ['H5', '4.3', 2, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 7', [[['H0', '2.1', 2, 1], ['H1', '5.2', 1, 6], ['H2', '4.1', 1, 6], ['H3', '8', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 54', [[['H0', '8', 2, 4], ['H1', '4.1', 1, 4], ['H2', '2.1', 1, 1]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 46', [[['H0', '2.1', 1, 5], ['H1', '8', 2, 4], ['H2', '9', 2, 2], ['H3', '5.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 8', [[['H0', '5.1', 1, 6], ['H1', '3', 1, 1], ['H2', '5.2', 1, 2], ['H3', '2.1', 2, 1], ['H0', '5.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]]], [['generated mix 8', [[['H0', '5.1', 1, 6], ['H1', '3', 1, 1], ['H2', '5.2', 1, 2], ['H3', '2.1', 2, 1], ['H0', '5.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 80', [[['H0', '5.1', 2, 2], ['H1', '2.1', 1, 4], ['H0', '5.1', 2, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['reverse order', [[['O', '5.1', 1, 1], ['G', '2.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['G', 'O']]], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['same class rule', [[['P', '5.2', 1, 3], ['Q', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['P', 'Q']]], ['generated mix 20', [[['H0', '8', 1, 5], ['H1', '5.2', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 28', [[['H0', '4.3', 2, 3], ['H1', '5.1', 1, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 61', [[['H0', '5.1', 2, 3], ['H1', '3', 1, 3], ['H2', '9', 2, 2], ['H3', '9', 2, 2], ['H4', '8', 1, 1], ['H5', '4.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['generated mix 31', [[['H0', '3', 1, 6], ['H1', '4.1', 2, 4], ['H2', '2.1', 2, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 39', [[['H0', '8', 1, 2], ['H1', '8', 2, 5], ['H2', '3', 1, 1], ['H3', '4.3', 2, 3], ['H0', '8', 1, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]], ['generated mix 61', [[['H0', '5.1', 2, 3], ['H1', '3', 1, 3], ['H2', '9', 2, 2], ['H3', '9', 2, 2], ['H4', '8', 1, 1], ['H5', '4.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same class rule', [[['P', '5.2', 1, 3], ['Q', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['P', 'Q']]], ['reverse order', [[['O', '5.1', 1, 1], ['G', '2.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['G', 'O']]], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['generated mix 42', [[['H0', '8', 2, 1], ['H1', '3', 2, 6], ['H2', '3', 1, 5], ['H3', '5.2', 2, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 50', [[['H0', '8', 1, 2], ['H1', '2.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]]]
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
other aisle[['F', 'O']][]Failed
generated mix 4[['H1', 'H5'], ['H2', 'H3']][]Failed
adjacent oxidizer[['F', 'O']][['F', 'O']]Passed
division match[['C', 'W']][['C', 'W']]Passed
same sku twice[][]Passed
two pairs[['A', 'Z'], ['B', 'C']][['A', 'Z'], ['B', 'C']]Passed
gap equal ok[][]Passed
generated mix 7[][]Passed

SHA-256 / 399264f96e62b2c1a189eaf41fe3548f4921647649360dc3844aad004850d854

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(placements, rules):
    def matches(cls, rule):
        return cls == rule or cls.startswith(rule + '.')
    found = set()
    n = len(placements)
    for i in range(n):
        for j in range(i + 1, n):
            sa, ca, aa, ba = placements[i]
            sb, cb, ab, bb = placements[j]
            if sa == sb or aa != ab:
                continue
            gap = abs(ba - bb)
            for ra, rb, min_gap in rules:
                hit = (matches(ca, ra) and matches(cb, rb)) or (matches(ca, rb) and matches(cb, ra))
                if hit and gap < min_gap:
                    found.add(tuple(sorted([sa, sb])))
    return [list(p) for p in sorted(found)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 4', [[['H0', '8', 2, 3], ['H1', '8', 1, 6], ['H2', '5.1', 2, 3], ['H3', '3', 1, 3], ['H4', '4.3', 2, 4], ['H5', '4.3', 2, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 7', [[['H0', '2.1', 2, 1], ['H1', '5.2', 1, 6], ['H2', '4.1', 1, 6], ['H3', '8', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 54', [[['H0', '8', 2, 4], ['H1', '4.1', 1, 4], ['H2', '2.1', 1, 1]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 46', [[['H0', '2.1', 1, 5], ['H1', '8', 2, 4], ['H2', '9', 2, 2], ['H3', '5.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 8', [[['H0', '5.1', 1, 6], ['H1', '3', 1, 1], ['H2', '5.2', 1, 2], ['H3', '2.1', 2, 1], ['H0', '5.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]]], [['generated mix 8', [[['H0', '5.1', 1, 6], ['H1', '3', 1, 1], ['H2', '5.2', 1, 2], ['H3', '2.1', 2, 1], ['H0', '5.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 80', [[['H0', '5.1', 2, 2], ['H1', '2.1', 1, 4], ['H0', '5.1', 2, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['reverse order', [[['O', '5.1', 1, 1], ['G', '2.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['G', 'O']]], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['same class rule', [[['P', '5.2', 1, 3], ['Q', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['P', 'Q']]], ['generated mix 20', [[['H0', '8', 1, 5], ['H1', '5.2', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 28', [[['H0', '4.3', 2, 3], ['H1', '5.1', 1, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 61', [[['H0', '5.1', 2, 3], ['H1', '3', 1, 3], ['H2', '9', 2, 2], ['H3', '9', 2, 2], ['H4', '8', 1, 1], ['H5', '4.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]], ['gap equal ok', [[['F', '3', 1, 4], ['O', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['other aisle', [[['F', '3', 1, 4], ['O', '5.1', 2, 4]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same sku twice', [[['P', '5.2', 1, 3], ['P', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['two pairs', [[['A', '3', 1, 1], ['Z', '5.1', 1, 2], ['B', '3', 1, 5], ['C', '5.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['A', 'Z'], ['B', 'C']]], ['generated mix 31', [[['H0', '3', 1, 6], ['H1', '4.1', 2, 4], ['H2', '2.1', 2, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 39', [[['H0', '8', 1, 2], ['H1', '8', 2, 5], ['H2', '3', 1, 1], ['H3', '4.3', 2, 3], ['H0', '8', 1, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]], [['generated mix 16', [[['H0', '5.2', 1, 6], ['H1', '4.1', 1, 5], ['H2', '2.1', 1, 2], ['H3', '5.1', 1, 1], ['H4', '5.1', 1, 1], ['H5', '8', 2, 5], ['H0', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['H0', 'H2'], ['H2', 'H3'], ['H2', 'H4']]], ['generated mix 61', [[['H0', '5.1', 2, 3], ['H1', '3', 1, 3], ['H2', '9', 2, 2], ['H3', '9', 2, 2], ['H4', '8', 1, 1], ['H5', '4.1', 2, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['same class rule', [[['P', '5.2', 1, 3], ['Q', '5.2', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['P', 'Q']]], ['reverse order', [[['O', '5.1', 1, 1], ['G', '2.1', 1, 3]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['G', 'O']]], ['adjacent oxidizer', [[['F', '3', 1, 4], ['O', '5.1', 1, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['F', 'O']]], ['division match', [[['W', '4.3', 2, 2], ['C', '8', 2, 2]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], [['C', 'W']]], ['generated mix 42', [[['H0', '8', 2, 1], ['H1', '3', 2, 6], ['H2', '3', 1, 5], ['H3', '5.2', 2, 5]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []], ['generated mix 50', [[['H0', '8', 1, 2], ['H1', '2.1', 1, 6]], [['3', '5.1', 2], ['4', '8', 1], ['5.2', '5.2', 1], ['2.1', '5', 3]]], []]]]
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
other aisle[][]Passed
generated mix 4[][]Passed
adjacent oxidizer[['F', 'O']][['F', 'O']]Passed
division match[['C', 'W']][['C', 'W']]Passed
same sku twice[][]Passed
two pairs[['A', 'Z'], ['B', 'C']][['A', 'Z'], ['B', 'C']]Passed
gap equal ok[][]Passed
generated mix 7[][]Passed

SHA-256 / 9942adbe4c928b805c1fe3635df882afa76a53efdd53b2dfc3706c903865ba83

Verification & scope

Stipulated bay-gap rule table; not a regulatory segregation chart. 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:09.886176+00:00.

Case digest / cafdbcd949e33fd56de896b5fc2ccd1c4d6e4e15ca4316b9623d9e7c8e746813