FA-77586 / Legal deadline computation / Open access
Regulatory review clock with stop-clock pauses: open ended test · case 01
A review whose last clock day coincides with an open-ended stop is reported as expired on that day.
ROOT CAUSE
The open-ended stop is treated as starting the day after its stop date.
VERIFIED REPAIR
At the open ended test decision use `d >= open_ended`, leaving the other decision sites of the model unchanged.
Unsuccessful approach: The partial repair `d >= open_ended + dt.timedelta(days=1)` shifts the stop by one day and repeats the same error.
Case contract
Stipulated: a review has days_allowed clock days, counted from the day after start. A pause [stop, resume] stops the clock on the stop day and every day before the resume day; the resume day counts. A pause with resume None is open-ended and starts on its stop day; if the clock would reach a day on or after the earliest open-ended stop before expiring, the result is None. Return the date of the last clock day.
Why this case matters
Docketing systems compute filing and response deadlines from trigger events; a wrong date can forfeit a right.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(start, days_allowed, pauses):
st = dt.date.fromisoformat(start)
paused = set()
open_ended = None
for a, b in pauses:
a = dt.date.fromisoformat(a)
if b is None:
open_ended = a if open_ended is None else min(open_ended, a)
continue
b = dt.date.fromisoformat(b)
for i in range((b - a).days):
paused.add(a + dt.timedelta(days=i))
d = st
counted = 0
while counted < days_allowed:
d += dt.timedelta(days=1)
if open_ended is not None and d > open_ended:
return None
if d in paused:
continue
counted += 1
return d.isoformat()
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: pause resume day counts', ['2024-01-01', 10, [['2024-01-04', '2024-01-08']]], '2024-01-15'),
('no pauses', ['2024-01-01', 30, []], '2024-01-31'),
('two open-ended stops', ['2024-01-01', 30, [['2024-01-20', None], ['2024-01-10', None]]], None),
('earlier open-ended listed first', ['2024-01-01', 12, [['2024-01-10', None], ['2024-01-20', None]]], None),
('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11')],
[('two open-ended stops', ['2024-01-01', 30, [['2024-01-20', None], ['2024-01-10', None]]], None),
('earlier open-ended listed first', ['2024-01-01', 12, [['2024-01-10', None], ['2024-01-20', None]]], None),
('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15')],
[('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14')],
[('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14'),
('pause then open-ended', ['2024-05-01', 20, [['2024-05-05', '2024-05-15'], ['2024-05-25', None]]], None),
('open-ended pushed by pause',
['2024-06-01', 10, [['2024-06-03', '2024-06-06'], ['2024-06-14', None]]],
None)],
[('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14'),
('pause then open-ended', ['2024-05-01', 20, [['2024-05-05', '2024-05-15'], ['2024-05-25', None]]], None),
('open-ended pushed by pause',
['2024-06-01', 10, [['2024-06-03', '2024-06-06'], ['2024-06-14', None]]],
None),
('regression: pause resume day counts', ['2024-01-01', 10, [['2024-01-04', '2024-01-08']]], '2024-01-15'),
('no pauses', ['2024-01-01', 30, []], '2024-01-31')]]
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: pause resume day counts | 2024-01-15 | 2024-01-15 | Passed |
| no pauses | 2024-01-31 | 2024-01-31 | Passed |
| two open-ended stops | None | None | Passed |
| earlier open-ended listed first | None | None | Passed |
| open-ended after expiry | 2024-01-11 | 2024-01-11 | Passed |
| open-ended on last day | 2024-01-11 | None | Failed |
| open-ended the day after | 2024-01-11 | 2024-01-11 | Passed |
SHA-256 / fced8b44fe2bb05ca9bfbfafa30088b3ab1d412f42bc7cbc492c5fd2f55bf4dc
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(start, days_allowed, pauses):
st = dt.date.fromisoformat(start)
paused = set()
open_ended = None
for a, b in pauses:
a = dt.date.fromisoformat(a)
if b is None:
open_ended = a if open_ended is None else min(open_ended, a)
continue
b = dt.date.fromisoformat(b)
for i in range((b - a).days):
paused.add(a + dt.timedelta(days=i))
d = st
counted = 0
while counted < days_allowed:
d += dt.timedelta(days=1)
if open_ended is not None and d >= open_ended + dt.timedelta(days=1):
return None
if d in paused:
continue
counted += 1
return d.isoformat()
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: pause resume day counts', ['2024-01-01', 10, [['2024-01-04', '2024-01-08']]], '2024-01-15'),
('no pauses', ['2024-01-01', 30, []], '2024-01-31'),
('two open-ended stops', ['2024-01-01', 30, [['2024-01-20', None], ['2024-01-10', None]]], None),
('earlier open-ended listed first', ['2024-01-01', 12, [['2024-01-10', None], ['2024-01-20', None]]], None),
('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11')],
[('two open-ended stops', ['2024-01-01', 30, [['2024-01-20', None], ['2024-01-10', None]]], None),
('earlier open-ended listed first', ['2024-01-01', 12, [['2024-01-10', None], ['2024-01-20', None]]], None),
('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15')],
[('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14')],
[('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14'),
('pause then open-ended', ['2024-05-01', 20, [['2024-05-05', '2024-05-15'], ['2024-05-25', None]]], None),
('open-ended pushed by pause',
['2024-06-01', 10, [['2024-06-03', '2024-06-06'], ['2024-06-14', None]]],
None)],
[('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14'),
('pause then open-ended', ['2024-05-01', 20, [['2024-05-05', '2024-05-15'], ['2024-05-25', None]]], None),
('open-ended pushed by pause',
['2024-06-01', 10, [['2024-06-03', '2024-06-06'], ['2024-06-14', None]]],
None),
('regression: pause resume day counts', ['2024-01-01', 10, [['2024-01-04', '2024-01-08']]], '2024-01-15'),
('no pauses', ['2024-01-01', 30, []], '2024-01-31')]]
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: pause resume day counts | 2024-01-15 | 2024-01-15 | Passed |
| no pauses | 2024-01-31 | 2024-01-31 | Passed |
| two open-ended stops | None | None | Passed |
| earlier open-ended listed first | None | None | Passed |
| open-ended after expiry | 2024-01-11 | 2024-01-11 | Passed |
| open-ended on last day | 2024-01-11 | None | Failed |
| open-ended the day after | 2024-01-11 | 2024-01-11 | Passed |
SHA-256 / 4d3f72f4fa5b44ef4d960ef16c5283ccc28ed80d3e8d0a494b90bb473ba9757b
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime as dt
import calendar
N = 1
observations = []
def solve(start, days_allowed, pauses):
st = dt.date.fromisoformat(start)
paused = set()
open_ended = None
for a, b in pauses:
a = dt.date.fromisoformat(a)
if b is None:
open_ended = a if open_ended is None else min(open_ended, a)
continue
b = dt.date.fromisoformat(b)
for i in range((b - a).days):
paused.add(a + dt.timedelta(days=i))
d = st
counted = 0
while counted < days_allowed:
d += dt.timedelta(days=1)
if open_ended is not None and d >= open_ended:
return None
if d in paused:
continue
counted += 1
return d.isoformat()
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: pause resume day counts', ['2024-01-01', 10, [['2024-01-04', '2024-01-08']]], '2024-01-15'),
('no pauses', ['2024-01-01', 30, []], '2024-01-31'),
('two open-ended stops', ['2024-01-01', 30, [['2024-01-20', None], ['2024-01-10', None]]], None),
('earlier open-ended listed first', ['2024-01-01', 12, [['2024-01-10', None], ['2024-01-20', None]]], None),
('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11')],
[('two open-ended stops', ['2024-01-01', 30, [['2024-01-20', None], ['2024-01-10', None]]], None),
('earlier open-ended listed first', ['2024-01-01', 12, [['2024-01-10', None], ['2024-01-20', None]]], None),
('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15')],
[('open-ended after expiry', ['2024-01-01', 10, [['2024-01-20', None]]], '2024-01-11'),
('open-ended on last day', ['2024-01-01', 10, [['2024-01-11', None]]], None),
('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14')],
[('open-ended the day after', ['2024-01-01', 10, [['2024-01-12', None]]], '2024-01-11'),
('overlapping pauses',
['2024-02-01', 15, [['2024-02-05', '2024-02-10'], ['2024-02-08', '2024-02-12']]],
'2024-02-23'),
('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14'),
('pause then open-ended', ['2024-05-01', 20, [['2024-05-05', '2024-05-15'], ['2024-05-25', None]]], None),
('open-ended pushed by pause',
['2024-06-01', 10, [['2024-06-03', '2024-06-06'], ['2024-06-14', None]]],
None)],
[('pause before start', ['2024-03-10', 5, [['2024-03-01', '2024-03-05']]], '2024-03-15'),
('weekday start', ['2024-04-02', 7, []], '2024-04-09'),
('saturday start', ['2024-04-06', 7, [['2024-04-08', '2024-04-09']]], '2024-04-14'),
('pause then open-ended', ['2024-05-01', 20, [['2024-05-05', '2024-05-15'], ['2024-05-25', None]]], None),
('open-ended pushed by pause',
['2024-06-01', 10, [['2024-06-03', '2024-06-06'], ['2024-06-14', None]]],
None),
('regression: pause resume day counts', ['2024-01-01', 10, [['2024-01-04', '2024-01-08']]], '2024-01-15'),
('no pauses', ['2024-01-01', 30, []], '2024-01-31')]]
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: pause resume day counts | 2024-01-15 | 2024-01-15 | Passed |
| no pauses | 2024-01-31 | 2024-01-31 | Passed |
| two open-ended stops | None | None | Passed |
| earlier open-ended listed first | None | None | Passed |
| open-ended after expiry | 2024-01-11 | 2024-01-11 | Passed |
| open-ended on last day | None | None | Passed |
| open-ended the day after | 2024-01-11 | 2024-01-11 | Passed |
SHA-256 / 1883e514e522c711910e6d8dd8ec4d2fea0c80f39e1b89429d7116c337ef878c
Verification & scope
Stipulated toy deadline rules evaluated offline on explicit fixtures. The contract is inspired by common court-rule structures but is not legal advice and makes no claim to reproduce any jurisdiction's rules. 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:49:27.073815+00:00.
Case digest / 87616a157d211b06a17d631d09aa48c2d16a5395f8957dafa3de8afdfea6087d