FAILURE MAP
← Case archive

FA-94141 / Shift rostering labor rules / Open access

Leave approved beyond the available balance · case 01

Balances go negative and no unapproved minutes are reported.

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

ROOT CAUSE

Requests are approved in full.

VERIFIED REPAIR

Approve at most the current balance.

Unsuccessful approach: Limiting by the cap still approves more than the balance.

Case contract

Per pay period [worked minutes, leave minutes requested]. Accrual is worked * rate_bp / 10000 minutes with the fractional remainder (in 1/10000 minutes) carried to later periods. After accrual the balance is capped (excess forfeited), then the request is approved up to the balance; unapproved minutes accumulate. Return [balance, forfeited, unapproved].

Why this case matters

Leave accrual ledgers attached to rosters must carry fractions and apply caps in the right order.

1 / The failure

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

N = 1
observations = []
def solve(periods, rate_bp, cap):
    bal = carry = forfeit = unappr = 0
    for worked, used in periods:
        num = worked * rate_bp + carry
        bal += num // 10000
        carry = num % 10000
        if bal > cap:
            forfeit += bal - cap
            bal = cap
        take = used
        unappr += used - take
        bal -= take
    return [bal, forfeit, unappr]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative balance 1', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('regression variant: negative balance 2',
   [[[0, 480], [2400, 900], [2280, 0], [0, 900], [2700, 0], [0, 900], [1200, 0], [0, 0]], 769, 400],
   [92, 0, 2613]),
  ('partial repair guard 3', [[[1040, 0], [2700, 2000], [0, 480]], 833, 400], [0, 0, 2169]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('normal control 6', [[[0, 480], [2280, 0], [0, 2000], [2400, 0]], 769, 1200], [184, 0, 2305]),
  ('normal control 7', [[[1956, 2000], [2400, 240], [2400, 0], [2400, 240]], 1000, 600], [240, 0, 1805]),
  ('normal control 8', [[[2700, 900], [2280, 0], [0, 0], [1674, 0]], 1207, 1200], [478, 0, 575])],
 [('regression: negative balance 1', [[[2400, 400], [0, 400]], 1207, 11200], [0, 0, 511]),
  ('regression variant: negative balance 2', [[[2280, 2000], [1070, 240], [1200, 0]], 833, 600],
   [100, 0, 1961]),
  ('partial repair guard 3', [[[2280, 240], [2280, 240]], 1000, 600], [0, 0, 24]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('normal control 5', [[[1200, 2000], [2700, 0], [2280, 240], [0, 0], [2700, 0]], 833, 600], [400, 0, 1901]),
  ('normal control 6', [[[2400, 900], [2700, 900], [1200, 900], [2280, 480]], 769, 400], [0, 0, 2521]),
  ('normal control 7', [[[0, 2000], [0, 2000], [0, 900], [2415, 0], [134, 0], [0, 0], [2400, 0]], 769, 1200],
   [380, 0, 4900]),
  ('normal control 8', [[[2700, 0], [2700, 2000]], 833, 1200], [0, 0, 1551])],
 [('regression: negative balance 1',
   [[[2406, 240], [0, 0], [2700, 2000], [129, 0], [2280, 0], [0, 480], [2700, 0], [2700, 0]], 1000, 600],
   [540, 0, 1969]),
  ('regression variant: negative balance 2', [[[1248, 0], [2280, 900], [2700, 0]], 1000, 400], [270, 0, 548]),
  ('partial repair guard 3', [[[2280, 2000], [1070, 240], [1200, 0]], 833, 600], [100, 0, 1961]),
  ('boundary control 4', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('boundary control 5', [[[2400, 400], [0, 400]], 1207, 11200], [0, 0, 511]),
  ('normal control 6', [[[2700, 900], [1720, 900], [2400, 480], [2700, 0], [1200, 900], [0, 900]], 769, 1200],
   [0, 0, 3256]),
  ('normal control 7', [[[2280, 0], [2280, 480], [2280, 2000]], 769, 600], [0, 0, 1955]),
  ('normal control 8', [[[2400, 2000], [2491, 0]], 1207, 11200], [301, 0, 1711])],
 [('regression: negative balance 1', [[[0, 2000], [0, 0], [2597, 0], [2280, 2000], [2400, 0]], 1207, 400],
   [290, 188, 3600]),
  ('regression variant: negative balance 2',
   [[[1040, 900], [2280, 240], [2400, 240], [2400, 0], [0, 900], [2280, 900], [1200, 240]], 1207, 400],
   [0, 0, 2020]),
  ('partial repair guard 3',
   [[[307, 2000], [1200, 480], [2700, 900], [2700, 2000], [1040, 240], [2400, 0], [2280, 480]], 833, 11200],
   [0, 0, 5049]),
  ('boundary control 4', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('normal control 6', [[[2700, 900], [712, 0], [1717, 0], [2280, 0]], 769, 1200], [362, 0, 693]),
  ('normal control 7', [[[0, 0], [2400, 0], [337, 900]], 1207, 400], [0, 0, 570]),
  ('normal control 8', [[[197, 900], [2700, 900]], 1207, 600], [0, 0, 1451])],
 [('regression: negative balance 1',
   [[[0, 480], [2280, 240], [344, 0], [2700, 240], [2700, 2000]], 833, 1200], [0, 0, 2292]),
  ('regression variant: negative balance 2', [[[0, 0], [0, 240]], 769, 400], [0, 0, 240]),
  ('partial repair guard 3', [[[2400, 2000], [2726, 0]], 769, 1200], [210, 0, 1816]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('normal control 6', [[[2700, 0], [1200, 0], [0, 240]], 769, 600], [59, 0, 0]),
  ('normal control 7', [[[1200, 0], [2400, 0], [0, 240], [2400, 0]], 769, 1200], [221, 0, 0]),
  ('normal control 8', [[[1200, 2000], [2700, 0], [0, 480], [2400, 480]], 1000, 11200], [0, 0, 2330])]]
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 balance 1[-100, 179, 0][0, 179, 100]Failed
regression variant: negative balance 2[-2521, 0, 0][92, 0, 2613]Failed
partial repair guard 3[-2169, 0, 0][0, 0, 2169]Failed
boundary control 4[100, 0, 0][100, 0, 0]Passed
boundary control 5[869, 0, 0][869, 0, 0]Passed
normal control 6[-2121, 0, 0][184, 0, 2305]Failed
normal control 7[-1565, 0, 0][240, 0, 1805]Failed
normal control 8[-97, 0, 0][478, 0, 575]Failed

SHA-256 / 03eb3843ccea7307f72080d0871a4c442676d0030b5c3b39134a63b7582fa7ad

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(periods, rate_bp, cap):
    bal = carry = forfeit = unappr = 0
    for worked, used in periods:
        num = worked * rate_bp + carry
        bal += num // 10000
        carry = num % 10000
        if bal > cap:
            forfeit += bal - cap
            bal = cap
        take = min(used, cap)
        unappr += used - take
        bal -= take
    return [bal, forfeit, unappr]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative balance 1', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('regression variant: negative balance 2',
   [[[0, 480], [2400, 900], [2280, 0], [0, 900], [2700, 0], [0, 900], [1200, 0], [0, 0]], 769, 400],
   [92, 0, 2613]),
  ('partial repair guard 3', [[[1040, 0], [2700, 2000], [0, 480]], 833, 400], [0, 0, 2169]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('normal control 6', [[[0, 480], [2280, 0], [0, 2000], [2400, 0]], 769, 1200], [184, 0, 2305]),
  ('normal control 7', [[[1956, 2000], [2400, 240], [2400, 0], [2400, 240]], 1000, 600], [240, 0, 1805]),
  ('normal control 8', [[[2700, 900], [2280, 0], [0, 0], [1674, 0]], 1207, 1200], [478, 0, 575])],
 [('regression: negative balance 1', [[[2400, 400], [0, 400]], 1207, 11200], [0, 0, 511]),
  ('regression variant: negative balance 2', [[[2280, 2000], [1070, 240], [1200, 0]], 833, 600],
   [100, 0, 1961]),
  ('partial repair guard 3', [[[2280, 240], [2280, 240]], 1000, 600], [0, 0, 24]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('normal control 5', [[[1200, 2000], [2700, 0], [2280, 240], [0, 0], [2700, 0]], 833, 600], [400, 0, 1901]),
  ('normal control 6', [[[2400, 900], [2700, 900], [1200, 900], [2280, 480]], 769, 400], [0, 0, 2521]),
  ('normal control 7', [[[0, 2000], [0, 2000], [0, 900], [2415, 0], [134, 0], [0, 0], [2400, 0]], 769, 1200],
   [380, 0, 4900]),
  ('normal control 8', [[[2700, 0], [2700, 2000]], 833, 1200], [0, 0, 1551])],
 [('regression: negative balance 1',
   [[[2406, 240], [0, 0], [2700, 2000], [129, 0], [2280, 0], [0, 480], [2700, 0], [2700, 0]], 1000, 600],
   [540, 0, 1969]),
  ('regression variant: negative balance 2', [[[1248, 0], [2280, 900], [2700, 0]], 1000, 400], [270, 0, 548]),
  ('partial repair guard 3', [[[2280, 2000], [1070, 240], [1200, 0]], 833, 600], [100, 0, 1961]),
  ('boundary control 4', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('boundary control 5', [[[2400, 400], [0, 400]], 1207, 11200], [0, 0, 511]),
  ('normal control 6', [[[2700, 900], [1720, 900], [2400, 480], [2700, 0], [1200, 900], [0, 900]], 769, 1200],
   [0, 0, 3256]),
  ('normal control 7', [[[2280, 0], [2280, 480], [2280, 2000]], 769, 600], [0, 0, 1955]),
  ('normal control 8', [[[2400, 2000], [2491, 0]], 1207, 11200], [301, 0, 1711])],
 [('regression: negative balance 1', [[[0, 2000], [0, 0], [2597, 0], [2280, 2000], [2400, 0]], 1207, 400],
   [290, 188, 3600]),
  ('regression variant: negative balance 2',
   [[[1040, 900], [2280, 240], [2400, 240], [2400, 0], [0, 900], [2280, 900], [1200, 240]], 1207, 400],
   [0, 0, 2020]),
  ('partial repair guard 3',
   [[[307, 2000], [1200, 480], [2700, 900], [2700, 2000], [1040, 240], [2400, 0], [2280, 480]], 833, 11200],
   [0, 0, 5049]),
  ('boundary control 4', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('normal control 6', [[[2700, 900], [712, 0], [1717, 0], [2280, 0]], 769, 1200], [362, 0, 693]),
  ('normal control 7', [[[0, 0], [2400, 0], [337, 900]], 1207, 400], [0, 0, 570]),
  ('normal control 8', [[[197, 900], [2700, 900]], 1207, 600], [0, 0, 1451])],
 [('regression: negative balance 1',
   [[[0, 480], [2280, 240], [344, 0], [2700, 240], [2700, 2000]], 833, 1200], [0, 0, 2292]),
  ('regression variant: negative balance 2', [[[0, 0], [0, 240]], 769, 400], [0, 0, 240]),
  ('partial repair guard 3', [[[2400, 2000], [2726, 0]], 769, 1200], [210, 0, 1816]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('normal control 6', [[[2700, 0], [1200, 0], [0, 240]], 769, 600], [59, 0, 0]),
  ('normal control 7', [[[1200, 0], [2400, 0], [0, 240], [2400, 0]], 769, 1200], [221, 0, 0]),
  ('normal control 8', [[[1200, 2000], [2700, 0], [0, 480], [2400, 480]], 1000, 11200], [0, 0, 2330])]]
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 balance 1[0, 179, 100][0, 179, 100]Passed
regression variant: negative balance 2[-941, 0, 1580][92, 0, 2613]Failed
partial repair guard 3[-489, 0, 1680][0, 0, 2169]Failed
boundary control 4[100, 0, 0][100, 0, 0]Passed
boundary control 5[869, 0, 0][869, 0, 0]Passed
normal control 6[-1321, 0, 800][184, 0, 2305]Failed
normal control 7[-165, 0, 1400][240, 0, 1805]Failed
normal control 8[-97, 0, 0][478, 0, 575]Failed

SHA-256 / 03ab7337062a2566c1e0d47658cb39ba3b054fe47af388f922eb3413f53ad3d6

3 / The verified repair

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

N = 1
observations = []
def solve(periods, rate_bp, cap):
    bal = carry = forfeit = unappr = 0
    for worked, used in periods:
        num = worked * rate_bp + carry
        bal += num // 10000
        carry = num % 10000
        if bal > cap:
            forfeit += bal - cap
            bal = cap
        take = min(used, bal)
        unappr += used - take
        bal -= take
    return [bal, forfeit, unappr]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: negative balance 1', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('regression variant: negative balance 2',
   [[[0, 480], [2400, 900], [2280, 0], [0, 900], [2700, 0], [0, 900], [1200, 0], [0, 0]], 769, 400],
   [92, 0, 2613]),
  ('partial repair guard 3', [[[1040, 0], [2700, 2000], [0, 480]], 833, 400], [0, 0, 2169]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('normal control 6', [[[0, 480], [2280, 0], [0, 2000], [2400, 0]], 769, 1200], [184, 0, 2305]),
  ('normal control 7', [[[1956, 2000], [2400, 240], [2400, 0], [2400, 240]], 1000, 600], [240, 0, 1805]),
  ('normal control 8', [[[2700, 900], [2280, 0], [0, 0], [1674, 0]], 1207, 1200], [478, 0, 575])],
 [('regression: negative balance 1', [[[2400, 400], [0, 400]], 1207, 11200], [0, 0, 511]),
  ('regression variant: negative balance 2', [[[2280, 2000], [1070, 240], [1200, 0]], 833, 600],
   [100, 0, 1961]),
  ('partial repair guard 3', [[[2280, 240], [2280, 240]], 1000, 600], [0, 0, 24]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('normal control 5', [[[1200, 2000], [2700, 0], [2280, 240], [0, 0], [2700, 0]], 833, 600], [400, 0, 1901]),
  ('normal control 6', [[[2400, 900], [2700, 900], [1200, 900], [2280, 480]], 769, 400], [0, 0, 2521]),
  ('normal control 7', [[[0, 2000], [0, 2000], [0, 900], [2415, 0], [134, 0], [0, 0], [2400, 0]], 769, 1200],
   [380, 0, 4900]),
  ('normal control 8', [[[2700, 0], [2700, 2000]], 833, 1200], [0, 0, 1551])],
 [('regression: negative balance 1',
   [[[2406, 240], [0, 0], [2700, 2000], [129, 0], [2280, 0], [0, 480], [2700, 0], [2700, 0]], 1000, 600],
   [540, 0, 1969]),
  ('regression variant: negative balance 2', [[[1248, 0], [2280, 900], [2700, 0]], 1000, 400], [270, 0, 548]),
  ('partial repair guard 3', [[[2280, 2000], [1070, 240], [1200, 0]], 833, 600], [100, 0, 1961]),
  ('boundary control 4', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('boundary control 5', [[[2400, 400], [0, 400]], 1207, 11200], [0, 0, 511]),
  ('normal control 6', [[[2700, 900], [1720, 900], [2400, 480], [2700, 0], [1200, 900], [0, 900]], 769, 1200],
   [0, 0, 3256]),
  ('normal control 7', [[[2280, 0], [2280, 480], [2280, 2000]], 769, 600], [0, 0, 1955]),
  ('normal control 8', [[[2400, 2000], [2491, 0]], 1207, 11200], [301, 0, 1711])],
 [('regression: negative balance 1', [[[0, 2000], [0, 0], [2597, 0], [2280, 2000], [2400, 0]], 1207, 400],
   [290, 188, 3600]),
  ('regression variant: negative balance 2',
   [[[1040, 900], [2280, 240], [2400, 240], [2400, 0], [0, 900], [2280, 900], [1200, 240]], 1207, 400],
   [0, 0, 2020]),
  ('partial repair guard 3',
   [[[307, 2000], [1200, 480], [2700, 900], [2700, 2000], [1040, 240], [2400, 0], [2280, 480]], 833, 11200],
   [0, 0, 5049]),
  ('boundary control 4', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 500]], 1207, 400], [0, 179, 100]),
  ('normal control 6', [[[2700, 900], [712, 0], [1717, 0], [2280, 0]], 769, 1200], [362, 0, 693]),
  ('normal control 7', [[[0, 0], [2400, 0], [337, 900]], 1207, 400], [0, 0, 570]),
  ('normal control 8', [[[197, 900], [2700, 900]], 1207, 600], [0, 0, 1451])],
 [('regression: negative balance 1',
   [[[0, 480], [2280, 240], [344, 0], [2700, 240], [2700, 2000]], 833, 1200], [0, 0, 2292]),
  ('regression variant: negative balance 2', [[[0, 0], [0, 240]], 769, 400], [0, 0, 240]),
  ('partial repair guard 3', [[[2400, 2000], [2726, 0]], 769, 1200], [210, 0, 1816]),
  ('boundary control 4', [[[99, 0], [99, 0], [2, 0]], 5000, 100], [100, 0, 0]),
  ('boundary control 5', [[[2400, 0], [2400, 0], [2400, 0]], 1207, 11200], [869, 0, 0]),
  ('normal control 6', [[[2700, 0], [1200, 0], [0, 240]], 769, 600], [59, 0, 0]),
  ('normal control 7', [[[1200, 0], [2400, 0], [0, 240], [2400, 0]], 769, 1200], [221, 0, 0]),
  ('normal control 8', [[[1200, 2000], [2700, 0], [0, 480], [2400, 480]], 1000, 11200], [0, 0, 2330])]]
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 balance 1[0, 179, 100][0, 179, 100]Passed
regression variant: negative balance 2[92, 0, 2613][92, 0, 2613]Passed
partial repair guard 3[0, 0, 2169][0, 0, 2169]Passed
boundary control 4[100, 0, 0][100, 0, 0]Passed
boundary control 5[869, 0, 0][869, 0, 0]Passed
normal control 6[184, 0, 2305][184, 0, 2305]Passed
normal control 7[240, 0, 1805][240, 0, 1805]Passed
normal control 8[478, 0, 575][478, 0, 575]Passed

SHA-256 / 19700bf42bda0618c71fc6de1d1deb647dc81c6c396e46473ff0bd6e2305a9fc

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

Case digest / bd86e636be67e3aba0bc53dee5dab49e0877596b1f1dd02d590d9863ec089bde