FAILURE MAP
← Case archive

FA-94446 / Exam timetabling constraints / Open access

Exact rest gap flagged as a conflict · case 01

Sittings separated by exactly the required rest are reported as conflicts.

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

ROOT CAUSE

The conflict test is inclusive.

VERIFIED REPAIR

Conflict only when the next start is before the extended end plus rest.

Unsuccessful approach: Dropping the rest term only catches overlaps.

Case contract

A student's exams [id, start, duration] and an extra-time percentage. Extended duration = ceil(duration * (100 + pct) / 100), then rounded up to a multiple of 5 minutes. In start order (ties by id) a pair conflicts if the next start is earlier than the previous extended end plus the rest minutes. Return [[id, extended end] in order, conflicting pairs].

Why this case matters

Access arrangements extend sittings; the timetable must still leave rest between a student's exams.

1 / The failure

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

N = 1
observations = []
def solve(exams, pct, rest):
    rows = []
    for eid, st, dur in sorted(exams, key=lambda x: (x[1], x[0])):
        ext = -(-dur * (100 + pct) // 100)
        ext = -(-ext // 5) * 5
        rows.append([eid, st, st + ext])
    conf = []
    for a, b in zip(rows, rows[1:]):
        if b[1] <= a[2] + rest:
            conf.append([a[0], b[0]])
    return [[[r[0], r[2]] for r in rows], conf]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: rest boundary 1', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('regression variant: rest boundary 2',
   [[['V0', 600, 60], ['S1', 840, 100], ['U3', 1320, 91], ['V2', 1080, 182]], 15, 30],
   [[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []]),
  ('partial repair guard 3',
   [[['W0', 540, 182], ['S2', 810, 182], ['U3', 1050, 100], ['W1', 660, 44]], 25, 15],
   [[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]]),
  ('boundary control 4', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 5', [[['S1', 800, 44], ['P0', 600, 180], ['R2', 920, 60]], 50, 30],
   [[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]]),
  ('normal control 6', [[['S2', 840, 180], ['S1', 690, 100], ['T0', 540, 120]], 25, 15],
   [[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]]),
  ('normal control 7', [[['W2', 960, 150], ['W0', 540, 150], ['R1', 780, 72]], 25, 30],
   [[['W0', 730], ['R1', 870], ['W2', 1150]], []]),
  ('normal control 8', [[['P1', 660, 120], ['U0', 540, 72]], 15, 30], [[['U0', 625], ['P1', 800]], []])],
 [('regression: rest boundary 1', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('regression variant: rest boundary 2',
   [[['W3', 1110, 73], ['R1', 840, 150], ['U0', 600, 100], ['R2', 960, 100]], 33, 15],
   [[['U0', 735], ['R1', 1040], ['R2', 1095], ['W3', 1210]], [['R1', 'R2']]]),
  ('partial repair guard 3', [[['Q1', 800, 88], ['Q0', 600, 60], ['R2', 920, 182]], 10, 30],
   [[['Q0', 670], ['Q1', 900], ['R2', 1125]], [['Q1', 'R2']]]),
  ('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 6', [[['S1', 690, 88], ['Q2', 780, 150], ['T0', 540, 44]], 33, 30],
   [[['T0', 600], ['S1', 810], ['Q2', 980]], [['S1', 'Q2']]]),
  ('normal control 7', [[['R1', 630, 90], ['S0', 540, 182]], 33, 15],
   [[['S0', 785], ['R1', 750]], [['S0', 'R1']]]),
  ('normal control 8', [[['V0', 600, 182], ['R3', 990, 90], ['S2', 900, 88], ['W1', 780, 73]], 25, 30],
   [[['V0', 830], ['W1', 875], ['S2', 1010], ['R3', 1105]], [['V0', 'W1'], ['W1', 'S2'], ['S2', 'R3']]])],
 [('regression: rest boundary 1',
   [[['S2', 900, 73], ['P1', 780, 60], ['U3', 1050, 44], ['W0', 540, 72]], 50, 30],
   [[['W0', 650], ['P1', 870], ['S2', 1010], ['U3', 1120]], []]),
  ('regression variant: rest boundary 2', [[['A', 540, 120], ['B', 720, 90]], 50, 0],
   [[['A', 720], ['B', 855]], []]),
  ('partial repair guard 3', [[['Q1', 840, 120], ['S0', 600, 182]], 25, 15],
   [[['S0', 830], ['Q1', 990]], [['S0', 'Q1']]]),
  ('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
  ('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('normal control 6', [[['P1', 720, 88], ['W2', 920, 90], ['P0', 540, 91]], 25, 15],
   [[['P0', 655], ['P1', 830], ['W2', 1035]], []]),
  ('normal control 7', [[['U2', 810, 180], ['W1', 630, 90], ['V3', 900, 180], ['S0', 540, 182]], 10, 15],
   [[['S0', 745], ['W1', 730], ['U2', 1010], ['V3', 1100]], [['S0', 'W1'], ['U2', 'V3']]]),
  ('normal control 8', [[['W0', 540, 60], ['W1', 780, 44]], 15, 15], [[['W0', 610], ['W1', 835]], []])],
 [('regression: rest boundary 1', [[['V1', 750, 150], ['W0', 600, 88]], 33, 30],
   [[['W0', 720], ['V1', 950]], []]),
  ('regression variant: rest boundary 2',
   [[['P1', 720, 73], ['R0', 600, 91], ['P2', 960, 91], ['R3', 1050, 182]], 15, 15],
   [[['R0', 705], ['P1', 805], ['P2', 1065], ['R3', 1260]], [['P2', 'R3']]]),
  ('partial repair guard 3', [[['Q2', 870, 91], ['Q0', 600, 100], ['W1', 780, 72]], 25, 30],
   [[['Q0', 725], ['W1', 870], ['Q2', 985]], [['W1', 'Q2']]]),
  ('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 6', [[['T0', 600, 88], ['W3', 1070, 44], ['Q2', 980, 150], ['U1', 780, 120]], 15, 30],
   [[['T0', 705], ['U1', 920], ['Q2', 1155], ['W3', 1125]], [['Q2', 'W3']]]),
  ('normal control 7', [[['S3', 1080, 60], ['V1', 840, 120], ['R0', 600, 44], ['U2', 960, 90]], 15, 15],
   [[['R0', 655], ['V1', 980], ['U2', 1065], ['S3', 1150]], [['V1', 'U2']]]),
  ('normal control 8', [[['V1', 630, 180], ['Q0', 540, 44]], 10, 30], [[['Q0', 590], ['V1', 830]], []])],
 [('regression: rest boundary 1',
   [[['Q2', 810, 88], ['Q1', 690, 150], ['T0', 540, 73], ['U3', 930, 88]], 15, 15],
   [[['T0', 625], ['Q1', 865], ['Q2', 915], ['U3', 1035]], [['Q1', 'Q2']]]),
  ('regression variant: rest boundary 2', [[['Q0', 540, 120], ['U1', 720, 60]], 25, 30],
   [[['Q0', 690], ['U1', 795]], []]),
  ('partial repair guard 3', [[['P2', 920, 180], ['Q0', 540, 150], ['S1', 740, 88]], 33, 30],
   [[['Q0', 740], ['S1', 860], ['P2', 1160]], [['Q0', 'S1']]]),
  ('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 6', [[['T1', 840, 72], ['V0', 600, 44]], 10, 15], [[['V0', 650], ['T1', 920]], []]),
  ('normal control 7', [[['Q1', 690, 150], ['P2', 810, 180], ['Q0', 540, 180]], 10, 15],
   [[['Q0', 740], ['Q1', 855], ['P2', 1010]], [['Q0', 'Q1'], ['Q1', 'P2']]]),
  ('normal control 8', [[['S0', 540, 120], ['U2', 920, 44], ['Q3', 1070, 90], ['W1', 740, 91]], 25, 15],
   [[['S0', 690], ['W1', 855], ['U2', 975], ['Q3', 1185]], []])]]
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: rest boundary 1[[['A', 720], ['B', 855]], [['A', 'B']]][[['A', 720], ['B', 855]], []]Failed
regression variant: rest boundary 2[[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], [['V2', 'U3']]][[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []]Failed
partial repair guard 3[[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]][[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]]Passed
boundary control 4[[['A', 625], ['B', 710]], [['A', 'B']]][[['A', 625], ['B', 710]], []]Failed
normal control 5[[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]][[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]]Passed
normal control 6[[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]][[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]]Passed
normal control 7[[['W0', 730], ['R1', 870], ['W2', 1150]], []][[['W0', 730], ['R1', 870], ['W2', 1150]], []]Passed
normal control 8[[['U0', 625], ['P1', 800]], []][[['U0', 625], ['P1', 800]], []]Passed

SHA-256 / 6f84bfe770103bc54ebf29e229e739e5379bc647fca7bc1bb27f9a959bea1804

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(exams, pct, rest):
    rows = []
    for eid, st, dur in sorted(exams, key=lambda x: (x[1], x[0])):
        ext = -(-dur * (100 + pct) // 100)
        ext = -(-ext // 5) * 5
        rows.append([eid, st, st + ext])
    conf = []
    for a, b in zip(rows, rows[1:]):
        if b[1] < a[2]:
            conf.append([a[0], b[0]])
    return [[[r[0], r[2]] for r in rows], conf]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: rest boundary 1', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('regression variant: rest boundary 2',
   [[['V0', 600, 60], ['S1', 840, 100], ['U3', 1320, 91], ['V2', 1080, 182]], 15, 30],
   [[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []]),
  ('partial repair guard 3',
   [[['W0', 540, 182], ['S2', 810, 182], ['U3', 1050, 100], ['W1', 660, 44]], 25, 15],
   [[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]]),
  ('boundary control 4', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 5', [[['S1', 800, 44], ['P0', 600, 180], ['R2', 920, 60]], 50, 30],
   [[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]]),
  ('normal control 6', [[['S2', 840, 180], ['S1', 690, 100], ['T0', 540, 120]], 25, 15],
   [[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]]),
  ('normal control 7', [[['W2', 960, 150], ['W0', 540, 150], ['R1', 780, 72]], 25, 30],
   [[['W0', 730], ['R1', 870], ['W2', 1150]], []]),
  ('normal control 8', [[['P1', 660, 120], ['U0', 540, 72]], 15, 30], [[['U0', 625], ['P1', 800]], []])],
 [('regression: rest boundary 1', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('regression variant: rest boundary 2',
   [[['W3', 1110, 73], ['R1', 840, 150], ['U0', 600, 100], ['R2', 960, 100]], 33, 15],
   [[['U0', 735], ['R1', 1040], ['R2', 1095], ['W3', 1210]], [['R1', 'R2']]]),
  ('partial repair guard 3', [[['Q1', 800, 88], ['Q0', 600, 60], ['R2', 920, 182]], 10, 30],
   [[['Q0', 670], ['Q1', 900], ['R2', 1125]], [['Q1', 'R2']]]),
  ('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 6', [[['S1', 690, 88], ['Q2', 780, 150], ['T0', 540, 44]], 33, 30],
   [[['T0', 600], ['S1', 810], ['Q2', 980]], [['S1', 'Q2']]]),
  ('normal control 7', [[['R1', 630, 90], ['S0', 540, 182]], 33, 15],
   [[['S0', 785], ['R1', 750]], [['S0', 'R1']]]),
  ('normal control 8', [[['V0', 600, 182], ['R3', 990, 90], ['S2', 900, 88], ['W1', 780, 73]], 25, 30],
   [[['V0', 830], ['W1', 875], ['S2', 1010], ['R3', 1105]], [['V0', 'W1'], ['W1', 'S2'], ['S2', 'R3']]])],
 [('regression: rest boundary 1',
   [[['S2', 900, 73], ['P1', 780, 60], ['U3', 1050, 44], ['W0', 540, 72]], 50, 30],
   [[['W0', 650], ['P1', 870], ['S2', 1010], ['U3', 1120]], []]),
  ('regression variant: rest boundary 2', [[['A', 540, 120], ['B', 720, 90]], 50, 0],
   [[['A', 720], ['B', 855]], []]),
  ('partial repair guard 3', [[['Q1', 840, 120], ['S0', 600, 182]], 25, 15],
   [[['S0', 830], ['Q1', 990]], [['S0', 'Q1']]]),
  ('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
  ('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('normal control 6', [[['P1', 720, 88], ['W2', 920, 90], ['P0', 540, 91]], 25, 15],
   [[['P0', 655], ['P1', 830], ['W2', 1035]], []]),
  ('normal control 7', [[['U2', 810, 180], ['W1', 630, 90], ['V3', 900, 180], ['S0', 540, 182]], 10, 15],
   [[['S0', 745], ['W1', 730], ['U2', 1010], ['V3', 1100]], [['S0', 'W1'], ['U2', 'V3']]]),
  ('normal control 8', [[['W0', 540, 60], ['W1', 780, 44]], 15, 15], [[['W0', 610], ['W1', 835]], []])],
 [('regression: rest boundary 1', [[['V1', 750, 150], ['W0', 600, 88]], 33, 30],
   [[['W0', 720], ['V1', 950]], []]),
  ('regression variant: rest boundary 2',
   [[['P1', 720, 73], ['R0', 600, 91], ['P2', 960, 91], ['R3', 1050, 182]], 15, 15],
   [[['R0', 705], ['P1', 805], ['P2', 1065], ['R3', 1260]], [['P2', 'R3']]]),
  ('partial repair guard 3', [[['Q2', 870, 91], ['Q0', 600, 100], ['W1', 780, 72]], 25, 30],
   [[['Q0', 725], ['W1', 870], ['Q2', 985]], [['W1', 'Q2']]]),
  ('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 6', [[['T0', 600, 88], ['W3', 1070, 44], ['Q2', 980, 150], ['U1', 780, 120]], 15, 30],
   [[['T0', 705], ['U1', 920], ['Q2', 1155], ['W3', 1125]], [['Q2', 'W3']]]),
  ('normal control 7', [[['S3', 1080, 60], ['V1', 840, 120], ['R0', 600, 44], ['U2', 960, 90]], 15, 15],
   [[['R0', 655], ['V1', 980], ['U2', 1065], ['S3', 1150]], [['V1', 'U2']]]),
  ('normal control 8', [[['V1', 630, 180], ['Q0', 540, 44]], 10, 30], [[['Q0', 590], ['V1', 830]], []])],
 [('regression: rest boundary 1',
   [[['Q2', 810, 88], ['Q1', 690, 150], ['T0', 540, 73], ['U3', 930, 88]], 15, 15],
   [[['T0', 625], ['Q1', 865], ['Q2', 915], ['U3', 1035]], [['Q1', 'Q2']]]),
  ('regression variant: rest boundary 2', [[['Q0', 540, 120], ['U1', 720, 60]], 25, 30],
   [[['Q0', 690], ['U1', 795]], []]),
  ('partial repair guard 3', [[['P2', 920, 180], ['Q0', 540, 150], ['S1', 740, 88]], 33, 30],
   [[['Q0', 740], ['S1', 860], ['P2', 1160]], [['Q0', 'S1']]]),
  ('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 6', [[['T1', 840, 72], ['V0', 600, 44]], 10, 15], [[['V0', 650], ['T1', 920]], []]),
  ('normal control 7', [[['Q1', 690, 150], ['P2', 810, 180], ['Q0', 540, 180]], 10, 15],
   [[['Q0', 740], ['Q1', 855], ['P2', 1010]], [['Q0', 'Q1'], ['Q1', 'P2']]]),
  ('normal control 8', [[['S0', 540, 120], ['U2', 920, 44], ['Q3', 1070, 90], ['W1', 740, 91]], 25, 15],
   [[['S0', 690], ['W1', 855], ['U2', 975], ['Q3', 1185]], []])]]
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: rest boundary 1[[['A', 720], ['B', 855]], []][[['A', 720], ['B', 855]], []]Passed
regression variant: rest boundary 2[[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []][[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []]Passed
partial repair guard 3[[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1']]][[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]]Failed
boundary control 4[[['A', 625], ['B', 710]], []][[['A', 625], ['B', 710]], []]Passed
normal control 5[[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]][[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]]Passed
normal control 6[[['T0', 690], ['S1', 815], ['S2', 1065]], []][[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]]Failed
normal control 7[[['W0', 730], ['R1', 870], ['W2', 1150]], []][[['W0', 730], ['R1', 870], ['W2', 1150]], []]Passed
normal control 8[[['U0', 625], ['P1', 800]], []][[['U0', 625], ['P1', 800]], []]Passed

SHA-256 / 746bf8d8ae2bc8728020df7bb61196599edffd55ebdc72e8d5aafbad4b7b728b

3 / The verified repair

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

N = 1
observations = []
def solve(exams, pct, rest):
    rows = []
    for eid, st, dur in sorted(exams, key=lambda x: (x[1], x[0])):
        ext = -(-dur * (100 + pct) // 100)
        ext = -(-ext // 5) * 5
        rows.append([eid, st, st + ext])
    conf = []
    for a, b in zip(rows, rows[1:]):
        if b[1] < a[2] + rest:
            conf.append([a[0], b[0]])
    return [[[r[0], r[2]] for r in rows], conf]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: rest boundary 1', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('regression variant: rest boundary 2',
   [[['V0', 600, 60], ['S1', 840, 100], ['U3', 1320, 91], ['V2', 1080, 182]], 15, 30],
   [[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []]),
  ('partial repair guard 3',
   [[['W0', 540, 182], ['S2', 810, 182], ['U3', 1050, 100], ['W1', 660, 44]], 25, 15],
   [[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]]),
  ('boundary control 4', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 5', [[['S1', 800, 44], ['P0', 600, 180], ['R2', 920, 60]], 50, 30],
   [[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]]),
  ('normal control 6', [[['S2', 840, 180], ['S1', 690, 100], ['T0', 540, 120]], 25, 15],
   [[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]]),
  ('normal control 7', [[['W2', 960, 150], ['W0', 540, 150], ['R1', 780, 72]], 25, 30],
   [[['W0', 730], ['R1', 870], ['W2', 1150]], []]),
  ('normal control 8', [[['P1', 660, 120], ['U0', 540, 72]], 15, 30], [[['U0', 625], ['P1', 800]], []])],
 [('regression: rest boundary 1', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('regression variant: rest boundary 2',
   [[['W3', 1110, 73], ['R1', 840, 150], ['U0', 600, 100], ['R2', 960, 100]], 33, 15],
   [[['U0', 735], ['R1', 1040], ['R2', 1095], ['W3', 1210]], [['R1', 'R2']]]),
  ('partial repair guard 3', [[['Q1', 800, 88], ['Q0', 600, 60], ['R2', 920, 182]], 10, 30],
   [[['Q0', 670], ['Q1', 900], ['R2', 1125]], [['Q1', 'R2']]]),
  ('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 6', [[['S1', 690, 88], ['Q2', 780, 150], ['T0', 540, 44]], 33, 30],
   [[['T0', 600], ['S1', 810], ['Q2', 980]], [['S1', 'Q2']]]),
  ('normal control 7', [[['R1', 630, 90], ['S0', 540, 182]], 33, 15],
   [[['S0', 785], ['R1', 750]], [['S0', 'R1']]]),
  ('normal control 8', [[['V0', 600, 182], ['R3', 990, 90], ['S2', 900, 88], ['W1', 780, 73]], 25, 30],
   [[['V0', 830], ['W1', 875], ['S2', 1010], ['R3', 1105]], [['V0', 'W1'], ['W1', 'S2'], ['S2', 'R3']]])],
 [('regression: rest boundary 1',
   [[['S2', 900, 73], ['P1', 780, 60], ['U3', 1050, 44], ['W0', 540, 72]], 50, 30],
   [[['W0', 650], ['P1', 870], ['S2', 1010], ['U3', 1120]], []]),
  ('regression variant: rest boundary 2', [[['A', 540, 120], ['B', 720, 90]], 50, 0],
   [[['A', 720], ['B', 855]], []]),
  ('partial repair guard 3', [[['Q1', 840, 120], ['S0', 600, 182]], 25, 15],
   [[['S0', 830], ['Q1', 990]], [['S0', 'Q1']]]),
  ('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
  ('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('normal control 6', [[['P1', 720, 88], ['W2', 920, 90], ['P0', 540, 91]], 25, 15],
   [[['P0', 655], ['P1', 830], ['W2', 1035]], []]),
  ('normal control 7', [[['U2', 810, 180], ['W1', 630, 90], ['V3', 900, 180], ['S0', 540, 182]], 10, 15],
   [[['S0', 745], ['W1', 730], ['U2', 1010], ['V3', 1100]], [['S0', 'W1'], ['U2', 'V3']]]),
  ('normal control 8', [[['W0', 540, 60], ['W1', 780, 44]], 15, 15], [[['W0', 610], ['W1', 835]], []])],
 [('regression: rest boundary 1', [[['V1', 750, 150], ['W0', 600, 88]], 33, 30],
   [[['W0', 720], ['V1', 950]], []]),
  ('regression variant: rest boundary 2',
   [[['P1', 720, 73], ['R0', 600, 91], ['P2', 960, 91], ['R3', 1050, 182]], 15, 15],
   [[['R0', 705], ['P1', 805], ['P2', 1065], ['R3', 1260]], [['P2', 'R3']]]),
  ('partial repair guard 3', [[['Q2', 870, 91], ['Q0', 600, 100], ['W1', 780, 72]], 25, 30],
   [[['Q0', 725], ['W1', 870], ['Q2', 985]], [['W1', 'Q2']]]),
  ('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 6', [[['T0', 600, 88], ['W3', 1070, 44], ['Q2', 980, 150], ['U1', 780, 120]], 15, 30],
   [[['T0', 705], ['U1', 920], ['Q2', 1155], ['W3', 1125]], [['Q2', 'W3']]]),
  ('normal control 7', [[['S3', 1080, 60], ['V1', 840, 120], ['R0', 600, 44], ['U2', 960, 90]], 15, 15],
   [[['R0', 655], ['V1', 980], ['U2', 1065], ['S3', 1150]], [['V1', 'U2']]]),
  ('normal control 8', [[['V1', 630, 180], ['Q0', 540, 44]], 10, 30], [[['Q0', 590], ['V1', 830]], []])],
 [('regression: rest boundary 1',
   [[['Q2', 810, 88], ['Q1', 690, 150], ['T0', 540, 73], ['U3', 930, 88]], 15, 15],
   [[['T0', 625], ['Q1', 865], ['Q2', 915], ['U3', 1035]], [['Q1', 'Q2']]]),
  ('regression variant: rest boundary 2', [[['Q0', 540, 120], ['U1', 720, 60]], 25, 30],
   [[['Q0', 690], ['U1', 795]], []]),
  ('partial repair guard 3', [[['P2', 920, 180], ['Q0', 540, 150], ['S1', 740, 88]], 33, 30],
   [[['Q0', 740], ['S1', 860], ['P2', 1160]], [['Q0', 'S1']]]),
  ('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 6', [[['T1', 840, 72], ['V0', 600, 44]], 10, 15], [[['V0', 650], ['T1', 920]], []]),
  ('normal control 7', [[['Q1', 690, 150], ['P2', 810, 180], ['Q0', 540, 180]], 10, 15],
   [[['Q0', 740], ['Q1', 855], ['P2', 1010]], [['Q0', 'Q1'], ['Q1', 'P2']]]),
  ('normal control 8', [[['S0', 540, 120], ['U2', 920, 44], ['Q3', 1070, 90], ['W1', 740, 91]], 25, 15],
   [[['S0', 690], ['W1', 855], ['U2', 975], ['Q3', 1185]], []])]]
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: rest boundary 1[[['A', 720], ['B', 855]], []][[['A', 720], ['B', 855]], []]Passed
regression variant: rest boundary 2[[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []][[['V0', 670], ['S1', 955], ['V2', 1290], ['U3', 1425]], []]Passed
partial repair guard 3[[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]][[['W0', 770], ['W1', 715], ['S2', 1040], ['U3', 1175]], [['W0', 'W1'], ['S2', 'U3']]]Passed
boundary control 4[[['A', 625], ['B', 710]], []][[['A', 625], ['B', 710]], []]Passed
normal control 5[[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]][[['P0', 870], ['S1', 870], ['R2', 1010]], [['P0', 'S1']]]Passed
normal control 6[[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]][[['T0', 690], ['S1', 815], ['S2', 1065]], [['T0', 'S1']]]Passed
normal control 7[[['W0', 730], ['R1', 870], ['W2', 1150]], []][[['W0', 730], ['R1', 870], ['W2', 1150]], []]Passed
normal control 8[[['U0', 625], ['P1', 800]], []][[['U0', 625], ['P1', 800]], []]Passed

SHA-256 / b2a9c80f580c79bb53431bcf5080458cfc50b51cd83879648ceeaaecffd21a96

Verification & scope

Stipulated toy exam-timetabling rule set for a bounded model; it does not claim conformance with any institution's regulations or a benchmark specification, and it performs no search or optimisation. 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:04.540070+00:00.

Case digest / 87555c7e9628c28ce851e5e9d3280436397a7ea88ee86b02a99be08b856fbe08