FA-93896 / Shift rostering labor rules / Open access
Spread of hours computed from worked minutes instead of first-to-last span · case 01
Split days with long unpaid gaps never reach the spread premium.
ROOT CAUSE
Spread sums the worked segment lengths rather than spanning first start to last end.
VERIFIED REPAIR
Spread is the last merged end minus the first merged start.
Unsuccessful approach: Measuring from the end of the first segment drops the first segment from the span.
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 = sum(e - s for s, e in merged)
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: spread measured as worked time 1', [[[480, 720], [780, 1080]], 1600], [600, 0, 0]),
('regression variant: spread measured as worked time 2',
[[[610, 620], [1259, 1319], [900, 1200], [600, 720]], 1520], [719, 1, 1520]),
('partial repair guard 3', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('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', [[[420, 720], [840, 900], [1201, 1321], [1080, 1140]], 1520], [901, 3, 1520]),
('normal control 7', [[[570, 750], [420, 540], [580, 590]], 1701], [330, 0, 0]),
('normal control 8', [[[1081, 1261], [420, 720], [781, 901], [430, 440], [1381, 1501]], 1520],
[1081, 3, 1520])],
[('regression: spread measured as worked time 1', [[[480, 720], [781, 1080]], 1600], [600, 1, 800]),
('regression variant: spread measured as worked time 2',
[[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('partial repair guard 3', [[[1079, 1319], [1378, 1618], [720, 1020], [600, 660]], 1701], [1018, 0, 1701]),
('boundary control 4', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('normal control 5', [[[1380, 1680], [600, 840], [1090, 1100], [1080, 1140], [870, 1050]], 1655],
[1080, 1, 1655]),
('normal control 6', [[[420, 540], [510, 810], [1050, 1170]], 1655], [750, 1, 1655]),
('normal control 7', [[[910, 920], [600, 660], [1380, 1680], [900, 1200]], 1520], [1080, 2, 1520]),
('normal control 8', [[[420, 480]], 1520], [60, 0, 0])],
[('regression: spread measured as worked time 1', [[[420, 600], [660, 780], [840, 1020]], 1701],
[600, 0, 0]),
('regression variant: spread measured as worked time 2', [[[841, 1141], [1141, 1441], [600, 780]], 1600],
[841, 1, 1600]),
('partial repair guard 3', [[[600, 780]], 1520], [180, 0, 0]),
('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', [[[600, 780], [900, 1080], [1200, 1440]], 1600], [840, 2, 1600]),
('normal control 7', [[[660, 960], [370, 380], [360, 600]], 1600], [600, 0, 0]),
('normal control 8', [[[630, 750], [640, 650], [420, 540]], 1701], [330, 1, 850])],
[('regression: spread measured as worked time 1', [[[600, 900], [610, 620], [1000, 1100]], 1655],
[500, 1, 827]),
('regression variant: spread measured as worked time 2',
[[[1001, 1011], [480, 660], [630, 930], [991, 1051]], 1600], [571, 1, 800]),
('partial repair guard 3', [[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('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, 660]], 1600], [60, 0, 0]),
('normal control 7', [[[1680, 1860], [960, 1200], [1260, 1560], [600, 720]], 1600], [1260, 2, 1600]),
('normal control 8', [[[420, 720], [1019, 1139], [1139, 1319], [720, 960]], 1600], [899, 0, 1600])],
[('regression: spread measured as worked time 1', [[[900, 1000], [420, 600], [700, 800]], 1520],
[580, 2, 1520]),
('regression variant: spread measured as worked time 2', [[[900, 1140], [360, 420], [600, 780]], 1600],
[780, 2, 1600]),
('partial repair guard 3', [[[610, 620], [360, 540], [600, 900]], 1655], [540, 0, 0]),
('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', [[[480, 660]], 1600], [180, 0, 0]),
('normal control 8', [[[630, 930], [480, 540]], 1655], [450, 1, 827])]]
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: spread measured as worked time 1 | [540, 0, 0] | [600, 0, 0] | Failed |
| regression variant: spread measured as worked time 2 | [480, 1, 760] | [719, 1, 1520] | Failed |
| partial repair guard 3 | [380, 2, 1520] | [580, 2, 1520] | Failed |
| boundary control 4 | [600, 0, 0] | [600, 0, 0] | Passed |
| boundary control 5 | [260, 4, 1654] | [590, 4, 1654] | Failed |
| normal control 6 | [540, 3, 1520] | [901, 3, 1520] | Failed |
| normal control 7 | [300, 0, 0] | [330, 0, 0] | Failed |
| normal control 8 | [720, 3, 1520] | [1081, 3, 1520] | Failed |
SHA-256 / b66862ee3ef0908cea1f8f11b9ca507c45853317c10b0943316c0aea9871af3b
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][1]
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: spread measured as worked time 1', [[[480, 720], [780, 1080]], 1600], [600, 0, 0]),
('regression variant: spread measured as worked time 2',
[[[610, 620], [1259, 1319], [900, 1200], [600, 720]], 1520], [719, 1, 1520]),
('partial repair guard 3', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('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', [[[420, 720], [840, 900], [1201, 1321], [1080, 1140]], 1520], [901, 3, 1520]),
('normal control 7', [[[570, 750], [420, 540], [580, 590]], 1701], [330, 0, 0]),
('normal control 8', [[[1081, 1261], [420, 720], [781, 901], [430, 440], [1381, 1501]], 1520],
[1081, 3, 1520])],
[('regression: spread measured as worked time 1', [[[480, 720], [781, 1080]], 1600], [600, 1, 800]),
('regression variant: spread measured as worked time 2',
[[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('partial repair guard 3', [[[1079, 1319], [1378, 1618], [720, 1020], [600, 660]], 1701], [1018, 0, 1701]),
('boundary control 4', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('normal control 5', [[[1380, 1680], [600, 840], [1090, 1100], [1080, 1140], [870, 1050]], 1655],
[1080, 1, 1655]),
('normal control 6', [[[420, 540], [510, 810], [1050, 1170]], 1655], [750, 1, 1655]),
('normal control 7', [[[910, 920], [600, 660], [1380, 1680], [900, 1200]], 1520], [1080, 2, 1520]),
('normal control 8', [[[420, 480]], 1520], [60, 0, 0])],
[('regression: spread measured as worked time 1', [[[420, 600], [660, 780], [840, 1020]], 1701],
[600, 0, 0]),
('regression variant: spread measured as worked time 2', [[[841, 1141], [1141, 1441], [600, 780]], 1600],
[841, 1, 1600]),
('partial repair guard 3', [[[600, 780]], 1520], [180, 0, 0]),
('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', [[[600, 780], [900, 1080], [1200, 1440]], 1600], [840, 2, 1600]),
('normal control 7', [[[660, 960], [370, 380], [360, 600]], 1600], [600, 0, 0]),
('normal control 8', [[[630, 750], [640, 650], [420, 540]], 1701], [330, 1, 850])],
[('regression: spread measured as worked time 1', [[[600, 900], [610, 620], [1000, 1100]], 1655],
[500, 1, 827]),
('regression variant: spread measured as worked time 2',
[[[1001, 1011], [480, 660], [630, 930], [991, 1051]], 1600], [571, 1, 800]),
('partial repair guard 3', [[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('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, 660]], 1600], [60, 0, 0]),
('normal control 7', [[[1680, 1860], [960, 1200], [1260, 1560], [600, 720]], 1600], [1260, 2, 1600]),
('normal control 8', [[[420, 720], [1019, 1139], [1139, 1319], [720, 960]], 1600], [899, 0, 1600])],
[('regression: spread measured as worked time 1', [[[900, 1000], [420, 600], [700, 800]], 1520],
[580, 2, 1520]),
('regression variant: spread measured as worked time 2', [[[900, 1140], [360, 420], [600, 780]], 1600],
[780, 2, 1600]),
('partial repair guard 3', [[[610, 620], [360, 540], [600, 900]], 1655], [540, 0, 0]),
('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', [[[480, 660]], 1600], [180, 0, 0]),
('normal control 8', [[[630, 930], [480, 540]], 1655], [450, 1, 827])]]
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: spread measured as worked time 1 | [360, 0, 0] | [600, 0, 0] | Failed |
| regression variant: spread measured as worked time 2 | [599, 1, 760] | [719, 1, 1520] | Failed |
| partial repair guard 3 | [400, 2, 1520] | [580, 2, 1520] | Failed |
| boundary control 4 | [0, 0, 0] | [600, 0, 0] | Failed |
| boundary control 5 | [530, 4, 1654] | [590, 4, 1654] | Failed |
| normal control 6 | [601, 3, 1520] | [901, 3, 1520] | Failed |
| normal control 7 | [210, 0, 0] | [330, 0, 0] | Failed |
| normal control 8 | [781, 3, 1520] | [1081, 3, 1520] | Failed |
SHA-256 / 7395d6769549913b4b87a877a39914f12ded424bfe60ce9d0acfbb123e442823
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: spread measured as worked time 1', [[[480, 720], [780, 1080]], 1600], [600, 0, 0]),
('regression variant: spread measured as worked time 2',
[[[610, 620], [1259, 1319], [900, 1200], [600, 720]], 1520], [719, 1, 1520]),
('partial repair guard 3', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('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', [[[420, 720], [840, 900], [1201, 1321], [1080, 1140]], 1520], [901, 3, 1520]),
('normal control 7', [[[570, 750], [420, 540], [580, 590]], 1701], [330, 0, 0]),
('normal control 8', [[[1081, 1261], [420, 720], [781, 901], [430, 440], [1381, 1501]], 1520],
[1081, 3, 1520])],
[('regression: spread measured as worked time 1', [[[480, 720], [781, 1080]], 1600], [600, 1, 800]),
('regression variant: spread measured as worked time 2',
[[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('partial repair guard 3', [[[1079, 1319], [1378, 1618], [720, 1020], [600, 660]], 1701], [1018, 0, 1701]),
('boundary control 4', [[[900, 1000], [420, 600], [700, 800]], 1520], [580, 2, 1520]),
('normal control 5', [[[1380, 1680], [600, 840], [1090, 1100], [1080, 1140], [870, 1050]], 1655],
[1080, 1, 1655]),
('normal control 6', [[[420, 540], [510, 810], [1050, 1170]], 1655], [750, 1, 1655]),
('normal control 7', [[[910, 920], [600, 660], [1380, 1680], [900, 1200]], 1520], [1080, 2, 1520]),
('normal control 8', [[[420, 480]], 1520], [60, 0, 0])],
[('regression: spread measured as worked time 1', [[[420, 600], [660, 780], [840, 1020]], 1701],
[600, 0, 0]),
('regression variant: spread measured as worked time 2', [[[841, 1141], [1141, 1441], [600, 780]], 1600],
[841, 1, 1600]),
('partial repair guard 3', [[[600, 780]], 1520], [180, 0, 0]),
('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', [[[600, 780], [900, 1080], [1200, 1440]], 1600], [840, 2, 1600]),
('normal control 7', [[[660, 960], [370, 380], [360, 600]], 1600], [600, 0, 0]),
('normal control 8', [[[630, 750], [640, 650], [420, 540]], 1701], [330, 1, 850])],
[('regression: spread measured as worked time 1', [[[600, 900], [610, 620], [1000, 1100]], 1655],
[500, 1, 827]),
('regression variant: spread measured as worked time 2',
[[[1001, 1011], [480, 660], [630, 930], [991, 1051]], 1600], [571, 1, 800]),
('partial repair guard 3', [[[600, 840], [1501, 1561], [900, 960], [1021, 1261]], 1600], [961, 2, 1600]),
('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, 660]], 1600], [60, 0, 0]),
('normal control 7', [[[1680, 1860], [960, 1200], [1260, 1560], [600, 720]], 1600], [1260, 2, 1600]),
('normal control 8', [[[420, 720], [1019, 1139], [1139, 1319], [720, 960]], 1600], [899, 0, 1600])],
[('regression: spread measured as worked time 1', [[[900, 1000], [420, 600], [700, 800]], 1520],
[580, 2, 1520]),
('regression variant: spread measured as worked time 2', [[[900, 1140], [360, 420], [600, 780]], 1600],
[780, 2, 1600]),
('partial repair guard 3', [[[610, 620], [360, 540], [600, 900]], 1655], [540, 0, 0]),
('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', [[[480, 660]], 1600], [180, 0, 0]),
('normal control 8', [[[630, 930], [480, 540]], 1655], [450, 1, 827])]]
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: spread measured as worked time 1 | [600, 0, 0] | [600, 0, 0] | Passed |
| regression variant: spread measured as worked time 2 | [719, 1, 1520] | [719, 1, 1520] | Passed |
| partial repair guard 3 | [580, 2, 1520] | [580, 2, 1520] | Passed |
| boundary control 4 | [600, 0, 0] | [600, 0, 0] | Passed |
| boundary control 5 | [590, 4, 1654] | [590, 4, 1654] | Passed |
| normal control 6 | [901, 3, 1520] | [901, 3, 1520] | Passed |
| normal control 7 | [330, 0, 0] | [330, 0, 0] | Passed |
| normal control 8 | [1081, 3, 1520] | [1081, 3, 1520] | Passed |
SHA-256 / 11025258de4db8d57dd3343421ee62b932d9c4e4d21e24824d5be8dd50c4b774
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.388573+00:00.
Case digest / 1786c5ca00e26255abb5c62741a45d7318478bb8d86ae48e220bf346092b68c1