FAILURE MAP
← Case archive

FA-94166 / Shift rostering labor rules / Open access

Reversed punch pair produces negative paid minutes · case 01

A mis-keyed out punch earlier than the in punch deducts time from the week.

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

ROOT CAUSE

Paid minutes are not clamped at zero.

VERIFIED REPAIR

Clamp paid minutes at zero.

Unsuccessful approach: Taking the absolute value pays time for a reversed pair.

Case contract

Scheduled [start, end] and raw punches in minutes. A punch in at most 7 minutes before the scheduled start is treated as the start; a punch out at most 7 minutes after the scheduled end is treated as the end. Then each time is rounded to the quarter hour: remainder 0-7 down, 8-14 up. Return [in, out, max(out - in, 0)].

Why this case matters

Punch rounding and grace periods must be neutral; asymmetric boundaries systematically underpay.

1 / The failure

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

N = 1
observations = []
def solve(sched, punch_in, punch_out):
    start, end = sched
    def q(t):
        r = t % 15
        return t - r if r <= 7 else t + 15 - r
    i = start if 0 < start - punch_in <= 7 else punch_in
    o = end if 0 < punch_out - end <= 7 else punch_out
    i, o = q(i), q(o)
    return [i, o, o - i]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative duration clamp 1', [[487, 967], 495, 474], [495, 480, 0]),
  ('regression variant: negative duration clamp 2', [[420, 660], 413, 391], [420, 390, 0]),
  ('partial repair guard 3', [[540, 780], 533, 508], [540, 510, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[420, 900], 415, 396], [420, 390, 0]),
  ('normal control 7', [[600, 840], 609, 847], [615, 840, 225]),
  ('normal control 8', [[600, 840], 593, 565], [600, 570, 0])],
 [('regression: negative duration clamp 1', [[480, 720], 483, 454], [480, 450, 0]),
  ('regression variant: negative duration clamp 2', [[420, 930], 427, 400], [420, 405, 0]),
  ('partial repair guard 3', [[600, 1080], 595, 577], [600, 570, 0]),
  ('boundary control 4', [[480, 960], 473, 967], [480, 960, 480]),
  ('boundary control 5', [[480, 960], 500, 490], [495, 495, 0]),
  ('normal control 6', [[540, 1050], 532, 527], [525, 525, 0]),
  ('normal control 7', [[420, 660], 429, 659], [435, 660, 225]),
  ('normal control 8', [[420, 930], 427, 929], [420, 930, 510])],
 [('regression: negative duration clamp 1', [[487, 727], 479, 464], [480, 465, 0]),
  ('regression variant: negative duration clamp 2', [[487, 967], 482, 464], [480, 465, 0]),
  ('partial repair guard 3', [[540, 1020], 539, 514], [540, 510, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[480, 990], 487, 991], [480, 990, 510]),
  ('normal control 7', [[540, 1050], 535, 1051], [540, 1050, 510]),
  ('normal control 8', [[600, 840], 603, 852], [600, 855, 255])],
 [('regression: negative duration clamp 1', [[420, 900], 423, 402], [420, 405, 0]),
  ('regression variant: negative duration clamp 2', [[540, 1020], 554, 524], [555, 525, 0]),
  ('partial repair guard 3', [[480, 990], 480, 462], [480, 465, 0]),
  ('boundary control 4', [[480, 960], 473, 967], [480, 960, 480]),
  ('boundary control 5', [[480, 960], 500, 490], [495, 495, 0]),
  ('normal control 6', [[600, 840], 603, 849], [600, 855, 255]),
  ('normal control 7', [[487, 967], 482, 461], [480, 465, 0]),
  ('normal control 8', [[540, 1020], 548, 1025], [555, 1020, 465])],
 [('regression: negative duration clamp 1', [[480, 960], 479, 450], [480, 450, 0]),
  ('regression variant: negative duration clamp 2', [[480, 720], 483, 454], [480, 450, 0]),
  ('partial repair guard 3', [[600, 1110], 607, 577], [600, 570, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[420, 660], 413, 391], [420, 390, 0]),
  ('normal control 7', [[540, 1020], 532, 1019], [525, 1020, 495]),
  ('normal control 8', [[480, 990], 460, 438], [465, 435, 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 fixtureActualExpectedOutcome
regression: negative duration clamp 1[495, 480, -15][495, 480, 0]Failed
regression variant: negative duration clamp 2[420, 390, -30][420, 390, 0]Failed
partial repair guard 3[540, 510, -30][540, 510, 0]Failed
boundary control 4[495, 945, 450][495, 945, 450]Passed
boundary control 5[480, 960, 480][480, 960, 480]Passed
normal control 6[420, 390, -30][420, 390, 0]Failed
normal control 7[615, 840, 225][615, 840, 225]Passed
normal control 8[600, 570, -30][600, 570, 0]Failed

SHA-256 / ef2a0defd33a7f821b5c82982297c66ccee86749ff2fe2b3b38f8fd9a39732db

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(sched, punch_in, punch_out):
    start, end = sched
    def q(t):
        r = t % 15
        return t - r if r <= 7 else t + 15 - r
    i = start if 0 < start - punch_in <= 7 else punch_in
    o = end if 0 < punch_out - end <= 7 else punch_out
    i, o = q(i), q(o)
    return [i, o, abs(o - i)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative duration clamp 1', [[487, 967], 495, 474], [495, 480, 0]),
  ('regression variant: negative duration clamp 2', [[420, 660], 413, 391], [420, 390, 0]),
  ('partial repair guard 3', [[540, 780], 533, 508], [540, 510, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[420, 900], 415, 396], [420, 390, 0]),
  ('normal control 7', [[600, 840], 609, 847], [615, 840, 225]),
  ('normal control 8', [[600, 840], 593, 565], [600, 570, 0])],
 [('regression: negative duration clamp 1', [[480, 720], 483, 454], [480, 450, 0]),
  ('regression variant: negative duration clamp 2', [[420, 930], 427, 400], [420, 405, 0]),
  ('partial repair guard 3', [[600, 1080], 595, 577], [600, 570, 0]),
  ('boundary control 4', [[480, 960], 473, 967], [480, 960, 480]),
  ('boundary control 5', [[480, 960], 500, 490], [495, 495, 0]),
  ('normal control 6', [[540, 1050], 532, 527], [525, 525, 0]),
  ('normal control 7', [[420, 660], 429, 659], [435, 660, 225]),
  ('normal control 8', [[420, 930], 427, 929], [420, 930, 510])],
 [('regression: negative duration clamp 1', [[487, 727], 479, 464], [480, 465, 0]),
  ('regression variant: negative duration clamp 2', [[487, 967], 482, 464], [480, 465, 0]),
  ('partial repair guard 3', [[540, 1020], 539, 514], [540, 510, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[480, 990], 487, 991], [480, 990, 510]),
  ('normal control 7', [[540, 1050], 535, 1051], [540, 1050, 510]),
  ('normal control 8', [[600, 840], 603, 852], [600, 855, 255])],
 [('regression: negative duration clamp 1', [[420, 900], 423, 402], [420, 405, 0]),
  ('regression variant: negative duration clamp 2', [[540, 1020], 554, 524], [555, 525, 0]),
  ('partial repair guard 3', [[480, 990], 480, 462], [480, 465, 0]),
  ('boundary control 4', [[480, 960], 473, 967], [480, 960, 480]),
  ('boundary control 5', [[480, 960], 500, 490], [495, 495, 0]),
  ('normal control 6', [[600, 840], 603, 849], [600, 855, 255]),
  ('normal control 7', [[487, 967], 482, 461], [480, 465, 0]),
  ('normal control 8', [[540, 1020], 548, 1025], [555, 1020, 465])],
 [('regression: negative duration clamp 1', [[480, 960], 479, 450], [480, 450, 0]),
  ('regression variant: negative duration clamp 2', [[480, 720], 483, 454], [480, 450, 0]),
  ('partial repair guard 3', [[600, 1110], 607, 577], [600, 570, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[420, 660], 413, 391], [420, 390, 0]),
  ('normal control 7', [[540, 1020], 532, 1019], [525, 1020, 495]),
  ('normal control 8', [[480, 990], 460, 438], [465, 435, 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 fixtureActualExpectedOutcome
regression: negative duration clamp 1[495, 480, 15][495, 480, 0]Failed
regression variant: negative duration clamp 2[420, 390, 30][420, 390, 0]Failed
partial repair guard 3[540, 510, 30][540, 510, 0]Failed
boundary control 4[495, 945, 450][495, 945, 450]Passed
boundary control 5[480, 960, 480][480, 960, 480]Passed
normal control 6[420, 390, 30][420, 390, 0]Failed
normal control 7[615, 840, 225][615, 840, 225]Passed
normal control 8[600, 570, 30][600, 570, 0]Failed

SHA-256 / 13a5b9f66e53cf73e4862e323aa215f12388628d6ca7ea34d69716710cd82806

3 / The verified repair

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

N = 1
observations = []
def solve(sched, punch_in, punch_out):
    start, end = sched
    def q(t):
        r = t % 15
        return t - r if r <= 7 else t + 15 - r
    i = start if 0 < start - punch_in <= 7 else punch_in
    o = end if 0 < punch_out - end <= 7 else punch_out
    i, o = q(i), q(o)
    return [i, o, max(o - i, 0)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative duration clamp 1', [[487, 967], 495, 474], [495, 480, 0]),
  ('regression variant: negative duration clamp 2', [[420, 660], 413, 391], [420, 390, 0]),
  ('partial repair guard 3', [[540, 780], 533, 508], [540, 510, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[420, 900], 415, 396], [420, 390, 0]),
  ('normal control 7', [[600, 840], 609, 847], [615, 840, 225]),
  ('normal control 8', [[600, 840], 593, 565], [600, 570, 0])],
 [('regression: negative duration clamp 1', [[480, 720], 483, 454], [480, 450, 0]),
  ('regression variant: negative duration clamp 2', [[420, 930], 427, 400], [420, 405, 0]),
  ('partial repair guard 3', [[600, 1080], 595, 577], [600, 570, 0]),
  ('boundary control 4', [[480, 960], 473, 967], [480, 960, 480]),
  ('boundary control 5', [[480, 960], 500, 490], [495, 495, 0]),
  ('normal control 6', [[540, 1050], 532, 527], [525, 525, 0]),
  ('normal control 7', [[420, 660], 429, 659], [435, 660, 225]),
  ('normal control 8', [[420, 930], 427, 929], [420, 930, 510])],
 [('regression: negative duration clamp 1', [[487, 727], 479, 464], [480, 465, 0]),
  ('regression variant: negative duration clamp 2', [[487, 967], 482, 464], [480, 465, 0]),
  ('partial repair guard 3', [[540, 1020], 539, 514], [540, 510, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[480, 990], 487, 991], [480, 990, 510]),
  ('normal control 7', [[540, 1050], 535, 1051], [540, 1050, 510]),
  ('normal control 8', [[600, 840], 603, 852], [600, 855, 255])],
 [('regression: negative duration clamp 1', [[420, 900], 423, 402], [420, 405, 0]),
  ('regression variant: negative duration clamp 2', [[540, 1020], 554, 524], [555, 525, 0]),
  ('partial repair guard 3', [[480, 990], 480, 462], [480, 465, 0]),
  ('boundary control 4', [[480, 960], 473, 967], [480, 960, 480]),
  ('boundary control 5', [[480, 960], 500, 490], [495, 495, 0]),
  ('normal control 6', [[600, 840], 603, 849], [600, 855, 255]),
  ('normal control 7', [[487, 967], 482, 461], [480, 465, 0]),
  ('normal control 8', [[540, 1020], 548, 1025], [555, 1020, 465])],
 [('regression: negative duration clamp 1', [[480, 960], 479, 450], [480, 450, 0]),
  ('regression variant: negative duration clamp 2', [[480, 720], 483, 454], [480, 450, 0]),
  ('partial repair guard 3', [[600, 1110], 607, 577], [600, 570, 0]),
  ('boundary control 4', [[480, 960], 488, 952], [495, 945, 450]),
  ('boundary control 5', [[480, 960], 487, 953], [480, 960, 480]),
  ('normal control 6', [[420, 660], 413, 391], [420, 390, 0]),
  ('normal control 7', [[540, 1020], 532, 1019], [525, 1020, 495]),
  ('normal control 8', [[480, 990], 460, 438], [465, 435, 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 fixtureActualExpectedOutcome
regression: negative duration clamp 1[495, 480, 0][495, 480, 0]Passed
regression variant: negative duration clamp 2[420, 390, 0][420, 390, 0]Passed
partial repair guard 3[540, 510, 0][540, 510, 0]Passed
boundary control 4[495, 945, 450][495, 945, 450]Passed
boundary control 5[480, 960, 480][480, 960, 480]Passed
normal control 6[420, 390, 0][420, 390, 0]Passed
normal control 7[615, 840, 225][615, 840, 225]Passed
normal control 8[600, 570, 0][600, 570, 0]Passed

SHA-256 / dc81baaabcefce9789aeba264e757618e03ff252607905e7ad4ddc3b1118f377

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

Case digest / 32066c1dbbf2c1cef9bdfb8ed71c47f1860c2e019fc940174e3725e9b7887b64