FA-93921 / Shift rostering labor rules / Open access
Spread premium stacked with split premium · case 01
Long split days receive both premiums although the spread premium replaces the split premium.
ROOT CAUSE
The spread branch adds the split premium instead of replacing it.
VERIFIED REPAIR
When spread exceeds ten hours pay exactly one hour at minimum wage.
Unsuccessful approach: Doubling the spread premium for any split still stacks the two premiums.
Case contract
Worked segments [start, end] of one workday (unordered, possibly overlapping) and a minimum wage in cents. Overlapping or touching segments merge. Spread is last end minus first start. Each gap longer than 60 minutes is a split. A spread over 600 minutes earns one hour of minimum wage and replaces any split premium; otherwise each split earns min_wage // 2, for at most two splits. Return [spread, splits, premium].
Why this case matters
Spread-of-hours and split-shift premiums are frequent roster-pay rules that depend on correct interval handling.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(segments, min_wage):
seg = sorted(segments)
merged = []
for s, e in seg:
if merged and s <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], e)
else:
merged.append([s, e])
spread = merged[-1][1] - merged[0][0]
splits = sum(1 for a, b in zip(merged, merged[1:]) if b[0] - a[1] > 60)
if spread > 600:
premium = min_wage + (min_wage // 2) * min(splits, 2)
else:
premium = (min_wage // 2) * min(splits, 2)
return [spread, splits, premium]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: premium precedence 1', [[[610, 620], [1259, 1319], [900, 1200], [600, 720]], 1520],
[719, 1, 1520]),
('regression variant: premium precedence 2', [[[420, 480], [570, 870], [430, 440], [929, 1229]], 1655],
[809, 1, 1655]),
('partial repair guard 3', [[[961, 1081], [1171, 1231], [971, 981], [600, 900]], 1655], [631, 2, 1655]),
('boundary control 4', [[[420, 1020]], 1600], [600, 0, 0]),
('boundary control 5', [[[420, 480], [550, 600], [700, 760], [840, 900], [980, 1010]], 1655],
[590, 4, 1654]),
('normal control 6', [[[660, 960], [670, 680], [600, 660]], 1701], [360, 0, 0]),
('normal control 7', [[[420, 540], [430, 440]], 1600], [120, 0, 0]),
('normal control 8', [[[600, 840]], 1520], [240, 0, 0])],
[('regression: premium precedence 1',
[[[1261, 1441], [430, 440], [780, 1020], [420, 660], [1081, 1261]], 1600], [1021, 2, 1600]),
('regression variant: premium precedence 2', [[[900, 1140], [360, 420], [600, 780]], 1600], [780, 2, 1600]),
('partial repair guard 3', [[[1291, 1471], [931, 1111], [750, 870], [480, 660], [490, 500]], 1701],
[991, 3, 1701]),
('boundary control 4', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('boundary control 5', [[[480, 720], [781, 1080]], 1600], [600, 1, 800]),
('normal control 6', [[[1021, 1261], [781, 961], [480, 720]], 1600], [781, 1, 1600]),
('normal control 7', [[[600, 660]], 1520], [60, 0, 0]),
('normal control 8', [[[570, 690], [360, 480]], 1600], [330, 1, 800])],
[('regression: premium precedence 1', [[[1110, 1410], [600, 900], [990, 1050], [1471, 1771]], 1600],
[1171, 2, 1600]),
('regression variant: premium precedence 2', [[[1320, 1560], [960, 1080], [480, 720], [970, 980]], 1600],
[1080, 2, 1600]),
('partial repair guard 3', [[[570, 810], [900, 1200], [910, 920], [420, 540]], 1701], [780, 1, 1701]),
('boundary control 4', [[[600, 630], [700, 730], [800, 830], [900, 930]], 1701], [330, 3, 1700]),
('boundary control 5', [[[420, 1021]], 1600], [601, 0, 1600]),
('normal control 6', [[[820, 830], [810, 990], [600, 720]], 1520], [390, 1, 760]),
('normal control 7', [[[480, 540]], 1600], [60, 0, 0]),
('normal control 8', [[[780, 1020], [1380, 1440], [1200, 1380], [420, 720], [1210, 1220]], 1655],
[1020, 1, 1655])],
[('regression: premium precedence 1', [[[870, 1110], [1170, 1290], [480, 540], [720, 780]], 1655],
[810, 2, 1655]),
('regression variant: premium precedence 2', [[[780, 900], [990, 1290], [360, 540], [510, 810]], 1520],
[930, 1, 1520]),
('partial repair guard 3', [[[420, 600], [661, 781], [1021, 1261]], 1701], [841, 2, 1701]),
('boundary control 4', [[[420, 600], [660, 780], [840, 1020]], 1701], [600, 0, 0]),
('boundary control 5', [[[420, 450], [520, 550], [620, 650], [720, 750]], 1600], [330, 3, 1600]),
('normal control 6', [[[600, 720]], 1600], [120, 0, 0]),
('normal control 7', [[[840, 900], [570, 750], [420, 540]], 1600], [480, 1, 800]),
('normal control 8', [[[720, 900], [420, 720], [961, 1141]], 1520], [721, 1, 1520])],
[('regression: premium precedence 1',
[[[600, 780], [931, 1171], [1291, 1351], [750, 870], [610, 620]], 1655], [751, 2, 1655]),
('regression variant: premium precedence 2', [[[1080, 1140], [420, 600], [660, 960], [1140, 1320]], 1600],
[900, 1, 1600]),
('partial repair guard 3', [[[1440, 1500], [1080, 1200], [870, 1110], [480, 780]], 1655], [1020, 2, 1655]),
('boundary control 4', [[[600, 900], [610, 620], [1000, 1100]], 1655], [500, 1, 827]),
('boundary control 5', [[[480, 720], [780, 1080]], 1600], [600, 0, 0]),
('normal control 6', [[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('normal control 7', [[[420, 660], [430, 440]], 1520], [240, 0, 0]),
('normal control 8', [[[600, 900], [610, 620]], 1701], [300, 0, 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 |
|---|---|---|---|
| regression: premium precedence 1 | [719, 1, 2280] | [719, 1, 1520] | Failed |
| regression variant: premium precedence 2 | [809, 1, 2482] | [809, 1, 1655] | Failed |
| partial repair guard 3 | [631, 2, 3309] | [631, 2, 1655] | Failed |
| boundary control 4 | [600, 0, 0] | [600, 0, 0] | Passed |
| boundary control 5 | [590, 4, 1654] | [590, 4, 1654] | Passed |
| normal control 6 | [360, 0, 0] | [360, 0, 0] | Passed |
| normal control 7 | [120, 0, 0] | [120, 0, 0] | Passed |
| normal control 8 | [240, 0, 0] | [240, 0, 0] | Passed |
SHA-256 / 5b2bc15f80b6a43ba0051960795e4b1833cba359a7b86e7830f18130c4b6f9bf
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(segments, min_wage):
seg = sorted(segments)
merged = []
for s, e in seg:
if merged and s <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], e)
else:
merged.append([s, e])
spread = merged[-1][1] - merged[0][0]
splits = sum(1 for a, b in zip(merged, merged[1:]) if b[0] - a[1] > 60)
if spread > 600:
premium = min_wage * (1 + (splits > 0))
else:
premium = (min_wage // 2) * min(splits, 2)
return [spread, splits, premium]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: premium precedence 1', [[[610, 620], [1259, 1319], [900, 1200], [600, 720]], 1520],
[719, 1, 1520]),
('regression variant: premium precedence 2', [[[420, 480], [570, 870], [430, 440], [929, 1229]], 1655],
[809, 1, 1655]),
('partial repair guard 3', [[[961, 1081], [1171, 1231], [971, 981], [600, 900]], 1655], [631, 2, 1655]),
('boundary control 4', [[[420, 1020]], 1600], [600, 0, 0]),
('boundary control 5', [[[420, 480], [550, 600], [700, 760], [840, 900], [980, 1010]], 1655],
[590, 4, 1654]),
('normal control 6', [[[660, 960], [670, 680], [600, 660]], 1701], [360, 0, 0]),
('normal control 7', [[[420, 540], [430, 440]], 1600], [120, 0, 0]),
('normal control 8', [[[600, 840]], 1520], [240, 0, 0])],
[('regression: premium precedence 1',
[[[1261, 1441], [430, 440], [780, 1020], [420, 660], [1081, 1261]], 1600], [1021, 2, 1600]),
('regression variant: premium precedence 2', [[[900, 1140], [360, 420], [600, 780]], 1600], [780, 2, 1600]),
('partial repair guard 3', [[[1291, 1471], [931, 1111], [750, 870], [480, 660], [490, 500]], 1701],
[991, 3, 1701]),
('boundary control 4', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('boundary control 5', [[[480, 720], [781, 1080]], 1600], [600, 1, 800]),
('normal control 6', [[[1021, 1261], [781, 961], [480, 720]], 1600], [781, 1, 1600]),
('normal control 7', [[[600, 660]], 1520], [60, 0, 0]),
('normal control 8', [[[570, 690], [360, 480]], 1600], [330, 1, 800])],
[('regression: premium precedence 1', [[[1110, 1410], [600, 900], [990, 1050], [1471, 1771]], 1600],
[1171, 2, 1600]),
('regression variant: premium precedence 2', [[[1320, 1560], [960, 1080], [480, 720], [970, 980]], 1600],
[1080, 2, 1600]),
('partial repair guard 3', [[[570, 810], [900, 1200], [910, 920], [420, 540]], 1701], [780, 1, 1701]),
('boundary control 4', [[[600, 630], [700, 730], [800, 830], [900, 930]], 1701], [330, 3, 1700]),
('boundary control 5', [[[420, 1021]], 1600], [601, 0, 1600]),
('normal control 6', [[[820, 830], [810, 990], [600, 720]], 1520], [390, 1, 760]),
('normal control 7', [[[480, 540]], 1600], [60, 0, 0]),
('normal control 8', [[[780, 1020], [1380, 1440], [1200, 1380], [420, 720], [1210, 1220]], 1655],
[1020, 1, 1655])],
[('regression: premium precedence 1', [[[870, 1110], [1170, 1290], [480, 540], [720, 780]], 1655],
[810, 2, 1655]),
('regression variant: premium precedence 2', [[[780, 900], [990, 1290], [360, 540], [510, 810]], 1520],
[930, 1, 1520]),
('partial repair guard 3', [[[420, 600], [661, 781], [1021, 1261]], 1701], [841, 2, 1701]),
('boundary control 4', [[[420, 600], [660, 780], [840, 1020]], 1701], [600, 0, 0]),
('boundary control 5', [[[420, 450], [520, 550], [620, 650], [720, 750]], 1600], [330, 3, 1600]),
('normal control 6', [[[600, 720]], 1600], [120, 0, 0]),
('normal control 7', [[[840, 900], [570, 750], [420, 540]], 1600], [480, 1, 800]),
('normal control 8', [[[720, 900], [420, 720], [961, 1141]], 1520], [721, 1, 1520])],
[('regression: premium precedence 1',
[[[600, 780], [931, 1171], [1291, 1351], [750, 870], [610, 620]], 1655], [751, 2, 1655]),
('regression variant: premium precedence 2', [[[1080, 1140], [420, 600], [660, 960], [1140, 1320]], 1600],
[900, 1, 1600]),
('partial repair guard 3', [[[1440, 1500], [1080, 1200], [870, 1110], [480, 780]], 1655], [1020, 2, 1655]),
('boundary control 4', [[[600, 900], [610, 620], [1000, 1100]], 1655], [500, 1, 827]),
('boundary control 5', [[[480, 720], [780, 1080]], 1600], [600, 0, 0]),
('normal control 6', [[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('normal control 7', [[[420, 660], [430, 440]], 1520], [240, 0, 0]),
('normal control 8', [[[600, 900], [610, 620]], 1701], [300, 0, 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 |
|---|---|---|---|
| regression: premium precedence 1 | [719, 1, 3040] | [719, 1, 1520] | Failed |
| regression variant: premium precedence 2 | [809, 1, 3310] | [809, 1, 1655] | Failed |
| partial repair guard 3 | [631, 2, 3310] | [631, 2, 1655] | Failed |
| boundary control 4 | [600, 0, 0] | [600, 0, 0] | Passed |
| boundary control 5 | [590, 4, 1654] | [590, 4, 1654] | Passed |
| normal control 6 | [360, 0, 0] | [360, 0, 0] | Passed |
| normal control 7 | [120, 0, 0] | [120, 0, 0] | Passed |
| normal control 8 | [240, 0, 0] | [240, 0, 0] | Passed |
SHA-256 / cc82dc9e163e89a2a7ee8e6c147762991c008c3fc6e684f2f8b6401222a008e4
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(segments, min_wage):
seg = sorted(segments)
merged = []
for s, e in seg:
if merged and s <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], e)
else:
merged.append([s, e])
spread = merged[-1][1] - merged[0][0]
splits = sum(1 for a, b in zip(merged, merged[1:]) if b[0] - a[1] > 60)
if spread > 600:
premium = min_wage
else:
premium = (min_wage // 2) * min(splits, 2)
return [spread, splits, premium]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: premium precedence 1', [[[610, 620], [1259, 1319], [900, 1200], [600, 720]], 1520],
[719, 1, 1520]),
('regression variant: premium precedence 2', [[[420, 480], [570, 870], [430, 440], [929, 1229]], 1655],
[809, 1, 1655]),
('partial repair guard 3', [[[961, 1081], [1171, 1231], [971, 981], [600, 900]], 1655], [631, 2, 1655]),
('boundary control 4', [[[420, 1020]], 1600], [600, 0, 0]),
('boundary control 5', [[[420, 480], [550, 600], [700, 760], [840, 900], [980, 1010]], 1655],
[590, 4, 1654]),
('normal control 6', [[[660, 960], [670, 680], [600, 660]], 1701], [360, 0, 0]),
('normal control 7', [[[420, 540], [430, 440]], 1600], [120, 0, 0]),
('normal control 8', [[[600, 840]], 1520], [240, 0, 0])],
[('regression: premium precedence 1',
[[[1261, 1441], [430, 440], [780, 1020], [420, 660], [1081, 1261]], 1600], [1021, 2, 1600]),
('regression variant: premium precedence 2', [[[900, 1140], [360, 420], [600, 780]], 1600], [780, 2, 1600]),
('partial repair guard 3', [[[1291, 1471], [931, 1111], [750, 870], [480, 660], [490, 500]], 1701],
[991, 3, 1701]),
('boundary control 4', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('boundary control 5', [[[480, 720], [781, 1080]], 1600], [600, 1, 800]),
('normal control 6', [[[1021, 1261], [781, 961], [480, 720]], 1600], [781, 1, 1600]),
('normal control 7', [[[600, 660]], 1520], [60, 0, 0]),
('normal control 8', [[[570, 690], [360, 480]], 1600], [330, 1, 800])],
[('regression: premium precedence 1', [[[1110, 1410], [600, 900], [990, 1050], [1471, 1771]], 1600],
[1171, 2, 1600]),
('regression variant: premium precedence 2', [[[1320, 1560], [960, 1080], [480, 720], [970, 980]], 1600],
[1080, 2, 1600]),
('partial repair guard 3', [[[570, 810], [900, 1200], [910, 920], [420, 540]], 1701], [780, 1, 1701]),
('boundary control 4', [[[600, 630], [700, 730], [800, 830], [900, 930]], 1701], [330, 3, 1700]),
('boundary control 5', [[[420, 1021]], 1600], [601, 0, 1600]),
('normal control 6', [[[820, 830], [810, 990], [600, 720]], 1520], [390, 1, 760]),
('normal control 7', [[[480, 540]], 1600], [60, 0, 0]),
('normal control 8', [[[780, 1020], [1380, 1440], [1200, 1380], [420, 720], [1210, 1220]], 1655],
[1020, 1, 1655])],
[('regression: premium precedence 1', [[[870, 1110], [1170, 1290], [480, 540], [720, 780]], 1655],
[810, 2, 1655]),
('regression variant: premium precedence 2', [[[780, 900], [990, 1290], [360, 540], [510, 810]], 1520],
[930, 1, 1520]),
('partial repair guard 3', [[[420, 600], [661, 781], [1021, 1261]], 1701], [841, 2, 1701]),
('boundary control 4', [[[420, 600], [660, 780], [840, 1020]], 1701], [600, 0, 0]),
('boundary control 5', [[[420, 450], [520, 550], [620, 650], [720, 750]], 1600], [330, 3, 1600]),
('normal control 6', [[[600, 720]], 1600], [120, 0, 0]),
('normal control 7', [[[840, 900], [570, 750], [420, 540]], 1600], [480, 1, 800]),
('normal control 8', [[[720, 900], [420, 720], [961, 1141]], 1520], [721, 1, 1520])],
[('regression: premium precedence 1',
[[[600, 780], [931, 1171], [1291, 1351], [750, 870], [610, 620]], 1655], [751, 2, 1655]),
('regression variant: premium precedence 2', [[[1080, 1140], [420, 600], [660, 960], [1140, 1320]], 1600],
[900, 1, 1600]),
('partial repair guard 3', [[[1440, 1500], [1080, 1200], [870, 1110], [480, 780]], 1655], [1020, 2, 1655]),
('boundary control 4', [[[600, 900], [610, 620], [1000, 1100]], 1655], [500, 1, 827]),
('boundary control 5', [[[480, 720], [780, 1080]], 1600], [600, 0, 0]),
('normal control 6', [[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('normal control 7', [[[420, 660], [430, 440]], 1520], [240, 0, 0]),
('normal control 8', [[[600, 900], [610, 620]], 1701], [300, 0, 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 |
|---|---|---|---|
| regression: premium precedence 1 | [719, 1, 1520] | [719, 1, 1520] | Passed |
| regression variant: premium precedence 2 | [809, 1, 1655] | [809, 1, 1655] | Passed |
| partial repair guard 3 | [631, 2, 1655] | [631, 2, 1655] | Passed |
| boundary control 4 | [600, 0, 0] | [600, 0, 0] | Passed |
| boundary control 5 | [590, 4, 1654] | [590, 4, 1654] | Passed |
| normal control 6 | [360, 0, 0] | [360, 0, 0] | Passed |
| normal control 7 | [120, 0, 0] | [120, 0, 0] | Passed |
| normal control 8 | [240, 0, 0] | [240, 0, 0] | Passed |
SHA-256 / 427ad6741a259b42e1a77dc9924d9da6f0af50b9a2b3ee217697f207c450851b
Verification & scope
Stipulated toy labor rule for a bounded roster model; it is not legal advice and does not claim conformance with any jurisdiction, award, or collective agreement. 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:51:59.528184+00:00.
Case digest / dadbee397ad8ae91867789166db4bbc48f6b3f99e9d55d467b4af539909563ba