FA-94231 / Shift rostering labor rules / Open access
Overlapping callouts paid twice · case 01
Two overlapping callout records pay the shared minutes at full rate twice.
ROOT CAUSE
Callout minutes are summed per record instead of over their union.
VERIFIED REPAIR
Pay the union of callout minutes once.
Unsuccessful approach: Paying the span from first callout start to last end also pays the idle gaps between callouts.
Case contract
Standby window [start, end], callout intervals and hourly rate in cents; minutes from Monday 00:00. Callout minutes (union of callouts, inside or outside standby) pay full rate. Standby minutes not in a callout pay a third of rate on weekdays and half on Saturday/Sunday (days 5-6). Return total cents, computed exactly and rounded half up once.
Why this case matters
On-call allowances interact with callout pay; double payment and wrong day attribution are common.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(standby, callouts, rate):
s0, e0 = standby
busy = set()
for s, e in callouts:
busy.update(range(s, e))
units = 0
for t in range(s0, e0):
if t in busy:
continue
units += 20 if (t // 1440) % 7 < 5 else 30
units += 60 * sum(e - s for s, e in callouts)
return (units * rate + 1800) // 3600
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: overlapping callouts 1', [[0, 60], [[0, 30], [15, 45]], 1800], 1500),
('regression variant: overlapping callouts 2',
[[4200, 4800], [[4456, 4576], [4414, 4504], [4798, 4828]], 3000], 16867),
('partial repair guard 3', [[5400, 5640], [[5640, 5760], [5348, 5468]], 1999], 9906),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[1080, 1920], [[1692, 1752], [1402, 1492]], 1800], 11400),
('normal control 7', [[2520, 3960], [[3928, 4018]], 2400], 22373),
('normal control 8', [[1440, 2880], [[2512, 2542], [2250, 2310]], 1800], 16200)],
[('regression: overlapping callouts 1', [[5340, 5940], [[5348, 5378], [5293, 5353]], 1999], 9073),
('regression variant: overlapping callouts 2',
[[2760, 3600], [[2911, 2971], [3430, 3520], [2914, 3034]], 1800], 12660),
('partial repair guard 3', [[8220, 8820], [[8187, 8247], [8269, 8299]], 1800], 10845),
('boundary control 4', [[0, 60], [], 1800], 600), ('boundary control 5', [[0, 3], [], 30], 1),
('normal control 6', [[6840, 8280], [], 1999], 21989),
('normal control 7', [[5760, 6360], [[5953, 6043]], 1999], 8662),
('normal control 8', [[2520, 3360], [[3252, 3282], [3025, 3145], [3101, 3191]], 3000], 20533)],
[('regression: overlapping callouts 1', [[8640, 8880], [[8660, 8750], [8748, 8838]], 1800], 6270),
('regression variant: overlapping callouts 2',
[[3900, 4140], [[4088, 4178], [4121, 4181], [3949, 4039]], 2400], 8627),
('partial repair guard 3', [[6840, 7680], [[7144, 7264], [6829, 6919], [6824, 6854]], 1999], 16592),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[6780, 7620], [[7470, 7560], [6740, 6830], [6903, 6963]], 1999], 16936),
('normal control 7', [[5340, 6180], [[5289, 5409], [5942, 6002], [5458, 5548]], 3000], 23850),
('normal control 8', [[5640, 6240], [[5947, 6007], [5613, 5733], [5788, 5908]], 2400], 16360)],
[('regression: overlapping callouts 1', [[5760, 6000], [[5788, 5908], [5761, 5791]], 1800], 5340),
('regression variant: overlapping callouts 2',
[[2520, 3120], [[2929, 3049], [2501, 2561], [2522, 2612]], 1800], 10810),
('partial repair guard 3', [[8520, 8760], [[8600, 8630], [8558, 8588]], 3000], 7500),
('boundary control 4', [[0, 60], [], 1800], 600), ('boundary control 5', [[0, 3], [], 30], 1),
('normal control 6', [[2520, 3120], [[3112, 3232], [2573, 2663]], 2400], 15093),
('normal control 7', [[7200, 8640], [[8288, 8348], [7751, 7871]], 1999], 26987),
('normal control 8', [[2760, 3600], [[2814, 2904]], 2400], 13600)],
[('regression: overlapping callouts 1', [[8520, 8760], [[8576, 8696], [8730, 8850], [8520, 8580]], 2400],
12520),
('regression variant: overlapping callouts 2',
[[5760, 6000], [[5737, 5797], [5741, 5801], [5873, 5933]], 2400], 6813),
('partial repair guard 3', [[6780, 7620], [[7592, 7712], [6879, 6999], [7600, 7660]], 3000], 26800),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[1320, 1560], [[1512, 1602], [1410, 1470]], 1800], 5820),
('normal control 7', [[2760, 3000], [[2993, 3083]], 1800], 5030),
('normal control 8', [[8220, 9060], [], 1999], 13993)]]
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: overlapping callouts 1 | 1950 | 1500 | Failed |
| regression variant: overlapping callouts 2 | 19267 | 16867 | Failed |
| partial repair guard 3 | 9906 | 9906 | Passed |
| boundary control 4 | 3267 | 3267 | Passed |
| boundary control 5 | 900 | 900 | Passed |
| normal control 6 | 11400 | 11400 | Passed |
| normal control 7 | 22373 | 22373 | Passed |
| normal control 8 | 16200 | 16200 | Passed |
SHA-256 / 0f6ce2ca3435a01a49b6f9caffbb808c2c3b66e5f5b1551bb9322c02c514668b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(standby, callouts, rate):
s0, e0 = standby
busy = set()
for s, e in callouts:
busy.update(range(s, e))
units = 0
for t in range(s0, e0):
if t in busy:
continue
units += 20 if (t // 1440) % 7 < 5 else 30
units += 60 * (max((e for s, e in callouts), default=0) - min((s for s, e in callouts), default=0))
return (units * rate + 1800) // 3600
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: overlapping callouts 1', [[0, 60], [[0, 30], [15, 45]], 1800], 1500),
('regression variant: overlapping callouts 2',
[[4200, 4800], [[4456, 4576], [4414, 4504], [4798, 4828]], 3000], 16867),
('partial repair guard 3', [[5400, 5640], [[5640, 5760], [5348, 5468]], 1999], 9906),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[1080, 1920], [[1692, 1752], [1402, 1492]], 1800], 11400),
('normal control 7', [[2520, 3960], [[3928, 4018]], 2400], 22373),
('normal control 8', [[1440, 2880], [[2512, 2542], [2250, 2310]], 1800], 16200)],
[('regression: overlapping callouts 1', [[5340, 5940], [[5348, 5378], [5293, 5353]], 1999], 9073),
('regression variant: overlapping callouts 2',
[[2760, 3600], [[2911, 2971], [3430, 3520], [2914, 3034]], 1800], 12660),
('partial repair guard 3', [[8220, 8820], [[8187, 8247], [8269, 8299]], 1800], 10845),
('boundary control 4', [[0, 60], [], 1800], 600), ('boundary control 5', [[0, 3], [], 30], 1),
('normal control 6', [[6840, 8280], [], 1999], 21989),
('normal control 7', [[5760, 6360], [[5953, 6043]], 1999], 8662),
('normal control 8', [[2520, 3360], [[3252, 3282], [3025, 3145], [3101, 3191]], 3000], 20533)],
[('regression: overlapping callouts 1', [[8640, 8880], [[8660, 8750], [8748, 8838]], 1800], 6270),
('regression variant: overlapping callouts 2',
[[3900, 4140], [[4088, 4178], [4121, 4181], [3949, 4039]], 2400], 8627),
('partial repair guard 3', [[6840, 7680], [[7144, 7264], [6829, 6919], [6824, 6854]], 1999], 16592),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[6780, 7620], [[7470, 7560], [6740, 6830], [6903, 6963]], 1999], 16936),
('normal control 7', [[5340, 6180], [[5289, 5409], [5942, 6002], [5458, 5548]], 3000], 23850),
('normal control 8', [[5640, 6240], [[5947, 6007], [5613, 5733], [5788, 5908]], 2400], 16360)],
[('regression: overlapping callouts 1', [[5760, 6000], [[5788, 5908], [5761, 5791]], 1800], 5340),
('regression variant: overlapping callouts 2',
[[2520, 3120], [[2929, 3049], [2501, 2561], [2522, 2612]], 1800], 10810),
('partial repair guard 3', [[8520, 8760], [[8600, 8630], [8558, 8588]], 3000], 7500),
('boundary control 4', [[0, 60], [], 1800], 600), ('boundary control 5', [[0, 3], [], 30], 1),
('normal control 6', [[2520, 3120], [[3112, 3232], [2573, 2663]], 2400], 15093),
('normal control 7', [[7200, 8640], [[8288, 8348], [7751, 7871]], 1999], 26987),
('normal control 8', [[2760, 3600], [[2814, 2904]], 2400], 13600)],
[('regression: overlapping callouts 1', [[8520, 8760], [[8576, 8696], [8730, 8850], [8520, 8580]], 2400],
12520),
('regression variant: overlapping callouts 2',
[[5760, 6000], [[5737, 5797], [5741, 5801], [5873, 5933]], 2400], 6813),
('partial repair guard 3', [[6780, 7620], [[7592, 7712], [6879, 6999], [7600, 7660]], 3000], 26800),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[1320, 1560], [[1512, 1602], [1410, 1470]], 1800], 5820),
('normal control 7', [[2760, 3000], [[2993, 3083]], 1800], 5030),
('normal control 8', [[8220, 9060], [], 1999], 13993)]]
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: overlapping callouts 1 | 1500 | 1500 | Passed |
| regression variant: overlapping callouts 2 | 27967 | 16867 | Failed |
| partial repair guard 3 | 15637 | 9906 | Failed |
| boundary control 4 | 3267 | 3267 | Passed |
| boundary control 5 | 900 | 900 | Passed |
| normal control 6 | 17400 | 11400 | Failed |
| normal control 7 | 22373 | 22373 | Passed |
| normal control 8 | 22260 | 16200 | Failed |
SHA-256 / 823013e16fdc75085d54c11882744d84538c43cdb4d083e40b79346be6feaae4
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(standby, callouts, rate):
s0, e0 = standby
busy = set()
for s, e in callouts:
busy.update(range(s, e))
units = 0
for t in range(s0, e0):
if t in busy:
continue
units += 20 if (t // 1440) % 7 < 5 else 30
units += 60 * len(busy)
return (units * rate + 1800) // 3600
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: overlapping callouts 1', [[0, 60], [[0, 30], [15, 45]], 1800], 1500),
('regression variant: overlapping callouts 2',
[[4200, 4800], [[4456, 4576], [4414, 4504], [4798, 4828]], 3000], 16867),
('partial repair guard 3', [[5400, 5640], [[5640, 5760], [5348, 5468]], 1999], 9906),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[1080, 1920], [[1692, 1752], [1402, 1492]], 1800], 11400),
('normal control 7', [[2520, 3960], [[3928, 4018]], 2400], 22373),
('normal control 8', [[1440, 2880], [[2512, 2542], [2250, 2310]], 1800], 16200)],
[('regression: overlapping callouts 1', [[5340, 5940], [[5348, 5378], [5293, 5353]], 1999], 9073),
('regression variant: overlapping callouts 2',
[[2760, 3600], [[2911, 2971], [3430, 3520], [2914, 3034]], 1800], 12660),
('partial repair guard 3', [[8220, 8820], [[8187, 8247], [8269, 8299]], 1800], 10845),
('boundary control 4', [[0, 60], [], 1800], 600), ('boundary control 5', [[0, 3], [], 30], 1),
('normal control 6', [[6840, 8280], [], 1999], 21989),
('normal control 7', [[5760, 6360], [[5953, 6043]], 1999], 8662),
('normal control 8', [[2520, 3360], [[3252, 3282], [3025, 3145], [3101, 3191]], 3000], 20533)],
[('regression: overlapping callouts 1', [[8640, 8880], [[8660, 8750], [8748, 8838]], 1800], 6270),
('regression variant: overlapping callouts 2',
[[3900, 4140], [[4088, 4178], [4121, 4181], [3949, 4039]], 2400], 8627),
('partial repair guard 3', [[6840, 7680], [[7144, 7264], [6829, 6919], [6824, 6854]], 1999], 16592),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[6780, 7620], [[7470, 7560], [6740, 6830], [6903, 6963]], 1999], 16936),
('normal control 7', [[5340, 6180], [[5289, 5409], [5942, 6002], [5458, 5548]], 3000], 23850),
('normal control 8', [[5640, 6240], [[5947, 6007], [5613, 5733], [5788, 5908]], 2400], 16360)],
[('regression: overlapping callouts 1', [[5760, 6000], [[5788, 5908], [5761, 5791]], 1800], 5340),
('regression variant: overlapping callouts 2',
[[2520, 3120], [[2929, 3049], [2501, 2561], [2522, 2612]], 1800], 10810),
('partial repair guard 3', [[8520, 8760], [[8600, 8630], [8558, 8588]], 3000], 7500),
('boundary control 4', [[0, 60], [], 1800], 600), ('boundary control 5', [[0, 3], [], 30], 1),
('normal control 6', [[2520, 3120], [[3112, 3232], [2573, 2663]], 2400], 15093),
('normal control 7', [[7200, 8640], [[8288, 8348], [7751, 7871]], 1999], 26987),
('normal control 8', [[2760, 3600], [[2814, 2904]], 2400], 13600)],
[('regression: overlapping callouts 1', [[8520, 8760], [[8576, 8696], [8730, 8850], [8520, 8580]], 2400],
12520),
('regression variant: overlapping callouts 2',
[[5760, 6000], [[5737, 5797], [5741, 5801], [5873, 5933]], 2400], 6813),
('partial repair guard 3', [[6780, 7620], [[7592, 7712], [6879, 6999], [7600, 7660]], 3000], 26800),
('boundary control 4', [[7140, 7260], [[7190, 7250]], 2400], 3267),
('boundary control 5', [[7200, 7260], [], 1800], 900),
('normal control 6', [[1320, 1560], [[1512, 1602], [1410, 1470]], 1800], 5820),
('normal control 7', [[2760, 3000], [[2993, 3083]], 1800], 5030),
('normal control 8', [[8220, 9060], [], 1999], 13993)]]
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: overlapping callouts 1 | 1500 | 1500 | Passed |
| regression variant: overlapping callouts 2 | 16867 | 16867 | Passed |
| partial repair guard 3 | 9906 | 9906 | Passed |
| boundary control 4 | 3267 | 3267 | Passed |
| boundary control 5 | 900 | 900 | Passed |
| normal control 6 | 11400 | 11400 | Passed |
| normal control 7 | 22373 | 22373 | Passed |
| normal control 8 | 16200 | 16200 | Passed |
SHA-256 / c4988b55a4e1cd74d4340c121b9a0bc1b9e97c06713a9c570f8ec7196fc04b0e
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:52:02.579205+00:00.
Case digest / d267b87001276fb36f779891f5ced2e5c7a1ec6c9f12dddc4c0953e741668e02