FAILURE MAP
← Case archive

FA-94436 / Exam timetabling constraints / Open access

Extra-time minutes floored before five-minute rounding · case 01

Some extended sittings end five minutes early.

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

ROOT CAUSE

Fractional extra-time minutes are truncated.

VERIFIED REPAIR

Take the ceiling of the extended duration before rounding to five minutes.

Unsuccessful approach: Rounding to nearest still drops fractions below one half.

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: extension ceiling 1', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('regression variant: extension ceiling 2', [[['T1', 800, 91], ['W0', 600, 120]], 10, 30],
   [[['W0', 735], ['T1', 905]], []]),
  ('boundary control 3', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('boundary control 4', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 5', [[['Q1', 750, 182], ['U2', 870, 72], ['P0', 600, 72]], 10, 30],
   [[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]]),
  ('normal control 6', [[['R0', 540, 100], ['S1', 720, 60]], 50, 15], [[['R0', 690], ['S1', 810]], []]),
  ('normal control 7', [[['S1', 630, 100], ['V3', 930, 88], ['V0', 540, 180], ['R2', 750, 73]], 50, 30],
   [[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]]),
  ('normal control 8', [[['P1', 740, 100], ['P2', 830, 100], ['S0', 540, 182], ['R3', 920, 182]], 50, 15],
   [[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]])],
 [('regression: extension ceiling 1', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('regression variant: extension ceiling 2',
   [[['P1', 780, 90], ['P3', 1130, 72], ['P0', 540, 91], ['U2', 930, 182]], 33, 15],
   [[['P0', 665], ['P1', 900], ['U2', 1175], ['P3', 1230]], [['U2', 'P3']]]),
  ('partial repair guard 3',
   [[['Q0', 600, 73], ['S1', 800, 182], ['U3', 1240, 44], ['S2', 1000, 72]], 10, 30],
   [[['Q0', 685], ['S1', 1005], ['S2', 1080], ['U3', 1290]], [['S1', 'S2']]]),
  ('boundary control 4', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 5', [[['P2', 720, 60], ['R0', 540, 120], ['V1', 630, 120], ['T3', 900, 60]], 25, 30],
   [[['R0', 690], ['V1', 780], ['P2', 795], ['T3', 975]], [['R0', 'V1'], ['V1', 'P2']]]),
  ('normal control 6', [[['P1', 740, 120], ['P0', 540, 44], ['W2', 940, 72]], 15, 30],
   [[['P0', 595], ['P1', 880], ['W2', 1025]], []]),
  ('normal control 7', [[['S0', 540, 73], ['Q2', 920, 60], ['U1', 740, 100]], 15, 15],
   [[['S0', 625], ['U1', 855], ['Q2', 990]], []]),
  ('normal control 8', [[['T1', 780, 60], ['P0', 600, 182], ['Q2', 1020, 91]], 50, 15],
   [[['P0', 875], ['T1', 870], ['Q2', 1160]], [['P0', 'T1']]])],
 [('regression: extension ceiling 1', [[['A', 540, 182], ['B', 800, 60]], 10, 30],
   [[['A', 745], ['B', 870]], []]),
  ('regression variant: extension ceiling 2',
   [[['V0', 540, 44], ['W1', 690, 60], ['U3', 980, 60], ['W2', 890, 100]], 15, 30],
   [[['V0', 595], ['W1', 760], ['W2', 1005], ['U3', 1050]], [['W2', 'U3']]]),
  ('partial repair guard 3', [[['P3', 1160, 44], ['U0', 600, 44], ['W2', 960, 90], ['U1', 780, 73]], 10, 30],
   [[['U0', 650], ['U1', 865], ['W2', 1060], ['P3', 1210]], []]),
  ('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
  ('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('normal control 6', [[['S1', 740, 180], ['V0', 540, 72]], 50, 30], [[['V0', 650], ['S1', 1010]], []]),
  ('normal control 7', [[['P3', 960, 73], ['U2', 810, 88], ['T0', 540, 60], ['R1', 630, 91]], 33, 15],
   [[['T0', 620], ['R1', 755], ['U2', 930], ['P3', 1060]], [['T0', 'R1']]]),
  ('normal control 8', [[['R0', 540, 73], ['T1', 630, 150], ['R2', 810, 150], ['T3', 1050, 120]], 10, 15],
   [[['R0', 625], ['T1', 795], ['R2', 975], ['T3', 1185]], [['R0', 'T1']]])],
 [('regression: extension ceiling 1', [[['A', 540, 73], ['B', 640, 60]], 10, 15],
   [[['A', 625], ['B', 710]], []]),
  ('regression variant: extension ceiling 2', [[['P1', 720, 60], ['U0', 600, 150], ['U2', 960, 72]], 33, 15],
   [[['U0', 800], ['P1', 800], ['U2', 1060]], [['U0', 'P1']]]),
  ('partial repair guard 3', [[['S1', 780, 73], ['T0', 540, 72]], 10, 30], [[['T0', 620], ['S1', 865]], []]),
  ('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('normal control 5', [[['V1', 800, 60], ['Q0', 600, 150]], 25, 15],
   [[['Q0', 790], ['V1', 875]], [['Q0', 'V1']]]),
  ('normal control 6', [[['Q1', 750, 44], ['W0', 600, 72]], 10, 30], [[['W0', 680], ['Q1', 800]], []]),
  ('normal control 7', [[['S0', 540, 100], ['Q3', 1020, 90], ['U1', 720, 91], ['U2', 840, 60]], 10, 30],
   [[['S0', 650], ['U1', 825], ['U2', 910], ['Q3', 1120]], [['U1', 'U2']]]),
  ('normal control 8', [[['U2', 840, 44], ['W3', 1080, 150], ['V1', 660, 180], ['V0', 540, 91]], 33, 30],
   [[['V0', 665], ['V1', 900], ['U2', 900], ['W3', 1280]], [['V0', 'V1'], ['V1', 'U2']]])],
 [('regression: extension ceiling 1', [[['Q0', 600, 182], ['U1', 750, 120]], 10, 15],
   [[['Q0', 805], ['U1', 885]], [['Q0', 'U1']]]),
  ('regression variant: extension ceiling 2',
   [[['R0', 540, 60], ['V1', 660, 72], ['S2', 810, 73], ['V3', 1010, 72]], 33, 30],
   [[['R0', 620], ['V1', 760], ['S2', 910], ['V3', 1110]], []]),
  ('partial repair guard 3', [[['V2', 900, 90], ['W0', 600, 91], ['P1', 780, 88], ['Q3', 1050, 91]], 10, 30],
   [[['W0', 705], ['P1', 880], ['V2', 1000], ['Q3', 1155]], [['P1', 'V2']]]),
  ('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', [[['S0', 540, 91], ['T1', 630, 60], ['U2', 780, 91]], 33, 30],
   [[['S0', 665], ['T1', 710], ['U2', 905]], [['S0', 'T1']]]),
  ('normal control 7', [[['W1', 780, 60], ['S0', 600, 72]], 15, 15], [[['S0', 685], ['W1', 850]], []]),
  ('normal control 8', [[['R2', 830, 91], ['P0', 540, 90], ['U1', 630, 73]], 10, 15],
   [[['P0', 640], ['U1', 715], ['R2', 935]], [['P0', 'U1']]])]]
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: extension ceiling 1[[['A', 635]], []][[['A', 640]], []]Failed
regression variant: extension ceiling 2[[['W0', 735], ['T1', 900]], []][[['W0', 735], ['T1', 905]], []]Failed
boundary control 3[[['A', 720], ['B', 855]], []][[['A', 720], ['B', 855]], []]Passed
boundary control 4[[['A', 620], ['B', 710]], []][[['A', 625], ['B', 710]], []]Failed
normal control 5[[['P0', 680], ['Q1', 950], ['U2', 950]], [['Q1', 'U2']]][[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]]Failed
normal control 6[[['R0', 690], ['S1', 810]], []][[['R0', 690], ['S1', 810]], []]Passed
normal control 7[[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]][[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]]Passed
normal control 8[[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]][[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]]Passed

SHA-256 / 7c5306761b2be093589c57f2a0ee38d7ca29057032f8bf70d51641a06010ec29

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 = round(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: extension ceiling 1', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('regression variant: extension ceiling 2', [[['T1', 800, 91], ['W0', 600, 120]], 10, 30],
   [[['W0', 735], ['T1', 905]], []]),
  ('boundary control 3', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('boundary control 4', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 5', [[['Q1', 750, 182], ['U2', 870, 72], ['P0', 600, 72]], 10, 30],
   [[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]]),
  ('normal control 6', [[['R0', 540, 100], ['S1', 720, 60]], 50, 15], [[['R0', 690], ['S1', 810]], []]),
  ('normal control 7', [[['S1', 630, 100], ['V3', 930, 88], ['V0', 540, 180], ['R2', 750, 73]], 50, 30],
   [[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]]),
  ('normal control 8', [[['P1', 740, 100], ['P2', 830, 100], ['S0', 540, 182], ['R3', 920, 182]], 50, 15],
   [[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]])],
 [('regression: extension ceiling 1', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('regression variant: extension ceiling 2',
   [[['P1', 780, 90], ['P3', 1130, 72], ['P0', 540, 91], ['U2', 930, 182]], 33, 15],
   [[['P0', 665], ['P1', 900], ['U2', 1175], ['P3', 1230]], [['U2', 'P3']]]),
  ('partial repair guard 3',
   [[['Q0', 600, 73], ['S1', 800, 182], ['U3', 1240, 44], ['S2', 1000, 72]], 10, 30],
   [[['Q0', 685], ['S1', 1005], ['S2', 1080], ['U3', 1290]], [['S1', 'S2']]]),
  ('boundary control 4', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 5', [[['P2', 720, 60], ['R0', 540, 120], ['V1', 630, 120], ['T3', 900, 60]], 25, 30],
   [[['R0', 690], ['V1', 780], ['P2', 795], ['T3', 975]], [['R0', 'V1'], ['V1', 'P2']]]),
  ('normal control 6', [[['P1', 740, 120], ['P0', 540, 44], ['W2', 940, 72]], 15, 30],
   [[['P0', 595], ['P1', 880], ['W2', 1025]], []]),
  ('normal control 7', [[['S0', 540, 73], ['Q2', 920, 60], ['U1', 740, 100]], 15, 15],
   [[['S0', 625], ['U1', 855], ['Q2', 990]], []]),
  ('normal control 8', [[['T1', 780, 60], ['P0', 600, 182], ['Q2', 1020, 91]], 50, 15],
   [[['P0', 875], ['T1', 870], ['Q2', 1160]], [['P0', 'T1']]])],
 [('regression: extension ceiling 1', [[['A', 540, 182], ['B', 800, 60]], 10, 30],
   [[['A', 745], ['B', 870]], []]),
  ('regression variant: extension ceiling 2',
   [[['V0', 540, 44], ['W1', 690, 60], ['U3', 980, 60], ['W2', 890, 100]], 15, 30],
   [[['V0', 595], ['W1', 760], ['W2', 1005], ['U3', 1050]], [['W2', 'U3']]]),
  ('partial repair guard 3', [[['P3', 1160, 44], ['U0', 600, 44], ['W2', 960, 90], ['U1', 780, 73]], 10, 30],
   [[['U0', 650], ['U1', 865], ['W2', 1060], ['P3', 1210]], []]),
  ('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
  ('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('normal control 6', [[['S1', 740, 180], ['V0', 540, 72]], 50, 30], [[['V0', 650], ['S1', 1010]], []]),
  ('normal control 7', [[['P3', 960, 73], ['U2', 810, 88], ['T0', 540, 60], ['R1', 630, 91]], 33, 15],
   [[['T0', 620], ['R1', 755], ['U2', 930], ['P3', 1060]], [['T0', 'R1']]]),
  ('normal control 8', [[['R0', 540, 73], ['T1', 630, 150], ['R2', 810, 150], ['T3', 1050, 120]], 10, 15],
   [[['R0', 625], ['T1', 795], ['R2', 975], ['T3', 1185]], [['R0', 'T1']]])],
 [('regression: extension ceiling 1', [[['A', 540, 73], ['B', 640, 60]], 10, 15],
   [[['A', 625], ['B', 710]], []]),
  ('regression variant: extension ceiling 2', [[['P1', 720, 60], ['U0', 600, 150], ['U2', 960, 72]], 33, 15],
   [[['U0', 800], ['P1', 800], ['U2', 1060]], [['U0', 'P1']]]),
  ('partial repair guard 3', [[['S1', 780, 73], ['T0', 540, 72]], 10, 30], [[['T0', 620], ['S1', 865]], []]),
  ('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('normal control 5', [[['V1', 800, 60], ['Q0', 600, 150]], 25, 15],
   [[['Q0', 790], ['V1', 875]], [['Q0', 'V1']]]),
  ('normal control 6', [[['Q1', 750, 44], ['W0', 600, 72]], 10, 30], [[['W0', 680], ['Q1', 800]], []]),
  ('normal control 7', [[['S0', 540, 100], ['Q3', 1020, 90], ['U1', 720, 91], ['U2', 840, 60]], 10, 30],
   [[['S0', 650], ['U1', 825], ['U2', 910], ['Q3', 1120]], [['U1', 'U2']]]),
  ('normal control 8', [[['U2', 840, 44], ['W3', 1080, 150], ['V1', 660, 180], ['V0', 540, 91]], 33, 30],
   [[['V0', 665], ['V1', 900], ['U2', 900], ['W3', 1280]], [['V0', 'V1'], ['V1', 'U2']]])],
 [('regression: extension ceiling 1', [[['Q0', 600, 182], ['U1', 750, 120]], 10, 15],
   [[['Q0', 805], ['U1', 885]], [['Q0', 'U1']]]),
  ('regression variant: extension ceiling 2',
   [[['R0', 540, 60], ['V1', 660, 72], ['S2', 810, 73], ['V3', 1010, 72]], 33, 30],
   [[['R0', 620], ['V1', 760], ['S2', 910], ['V3', 1110]], []]),
  ('partial repair guard 3', [[['V2', 900, 90], ['W0', 600, 91], ['P1', 780, 88], ['Q3', 1050, 91]], 10, 30],
   [[['W0', 705], ['P1', 880], ['V2', 1000], ['Q3', 1155]], [['P1', 'V2']]]),
  ('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', [[['S0', 540, 91], ['T1', 630, 60], ['U2', 780, 91]], 33, 30],
   [[['S0', 665], ['T1', 710], ['U2', 905]], [['S0', 'T1']]]),
  ('normal control 7', [[['W1', 780, 60], ['S0', 600, 72]], 15, 15], [[['S0', 685], ['W1', 850]], []]),
  ('normal control 8', [[['R2', 830, 91], ['P0', 540, 90], ['U1', 630, 73]], 10, 15],
   [[['P0', 640], ['U1', 715], ['R2', 935]], [['P0', 'U1']]])]]
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: extension ceiling 1[[['A', 640]], []][[['A', 640]], []]Passed
regression variant: extension ceiling 2[[['W0', 735], ['T1', 900]], []][[['W0', 735], ['T1', 905]], []]Failed
boundary control 3[[['A', 720], ['B', 855]], []][[['A', 720], ['B', 855]], []]Passed
boundary control 4[[['A', 620], ['B', 710]], []][[['A', 625], ['B', 710]], []]Failed
normal control 5[[['P0', 680], ['Q1', 950], ['U2', 950]], [['Q1', 'U2']]][[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]]Failed
normal control 6[[['R0', 690], ['S1', 810]], []][[['R0', 690], ['S1', 810]], []]Passed
normal control 7[[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]][[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]]Passed
normal control 8[[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]][[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]]Passed

SHA-256 / c471b40d4401f75fae2c40119bcbb38ad1fbb5ce72b887103f388d0124d97f12

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: extension ceiling 1', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('regression variant: extension ceiling 2', [[['T1', 800, 91], ['W0', 600, 120]], 10, 30],
   [[['W0', 735], ['T1', 905]], []]),
  ('boundary control 3', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('boundary control 4', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
  ('normal control 5', [[['Q1', 750, 182], ['U2', 870, 72], ['P0', 600, 72]], 10, 30],
   [[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]]),
  ('normal control 6', [[['R0', 540, 100], ['S1', 720, 60]], 50, 15], [[['R0', 690], ['S1', 810]], []]),
  ('normal control 7', [[['S1', 630, 100], ['V3', 930, 88], ['V0', 540, 180], ['R2', 750, 73]], 50, 30],
   [[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]]),
  ('normal control 8', [[['P1', 740, 100], ['P2', 830, 100], ['S0', 540, 182], ['R3', 920, 182]], 50, 15],
   [[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]])],
 [('regression: extension ceiling 1', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
  ('regression variant: extension ceiling 2',
   [[['P1', 780, 90], ['P3', 1130, 72], ['P0', 540, 91], ['U2', 930, 182]], 33, 15],
   [[['P0', 665], ['P1', 900], ['U2', 1175], ['P3', 1230]], [['U2', 'P3']]]),
  ('partial repair guard 3',
   [[['Q0', 600, 73], ['S1', 800, 182], ['U3', 1240, 44], ['S2', 1000, 72]], 10, 30],
   [[['Q0', 685], ['S1', 1005], ['S2', 1080], ['U3', 1290]], [['S1', 'S2']]]),
  ('boundary control 4', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
  ('normal control 5', [[['P2', 720, 60], ['R0', 540, 120], ['V1', 630, 120], ['T3', 900, 60]], 25, 30],
   [[['R0', 690], ['V1', 780], ['P2', 795], ['T3', 975]], [['R0', 'V1'], ['V1', 'P2']]]),
  ('normal control 6', [[['P1', 740, 120], ['P0', 540, 44], ['W2', 940, 72]], 15, 30],
   [[['P0', 595], ['P1', 880], ['W2', 1025]], []]),
  ('normal control 7', [[['S0', 540, 73], ['Q2', 920, 60], ['U1', 740, 100]], 15, 15],
   [[['S0', 625], ['U1', 855], ['Q2', 990]], []]),
  ('normal control 8', [[['T1', 780, 60], ['P0', 600, 182], ['Q2', 1020, 91]], 50, 15],
   [[['P0', 875], ['T1', 870], ['Q2', 1160]], [['P0', 'T1']]])],
 [('regression: extension ceiling 1', [[['A', 540, 182], ['B', 800, 60]], 10, 30],
   [[['A', 745], ['B', 870]], []]),
  ('regression variant: extension ceiling 2',
   [[['V0', 540, 44], ['W1', 690, 60], ['U3', 980, 60], ['W2', 890, 100]], 15, 30],
   [[['V0', 595], ['W1', 760], ['W2', 1005], ['U3', 1050]], [['W2', 'U3']]]),
  ('partial repair guard 3', [[['P3', 1160, 44], ['U0', 600, 44], ['W2', 960, 90], ['U1', 780, 73]], 10, 30],
   [[['U0', 650], ['U1', 865], ['W2', 1060], ['P3', 1210]], []]),
  ('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
  ('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
  ('normal control 6', [[['S1', 740, 180], ['V0', 540, 72]], 50, 30], [[['V0', 650], ['S1', 1010]], []]),
  ('normal control 7', [[['P3', 960, 73], ['U2', 810, 88], ['T0', 540, 60], ['R1', 630, 91]], 33, 15],
   [[['T0', 620], ['R1', 755], ['U2', 930], ['P3', 1060]], [['T0', 'R1']]]),
  ('normal control 8', [[['R0', 540, 73], ['T1', 630, 150], ['R2', 810, 150], ['T3', 1050, 120]], 10, 15],
   [[['R0', 625], ['T1', 795], ['R2', 975], ['T3', 1185]], [['R0', 'T1']]])],
 [('regression: extension ceiling 1', [[['A', 540, 73], ['B', 640, 60]], 10, 15],
   [[['A', 625], ['B', 710]], []]),
  ('regression variant: extension ceiling 2', [[['P1', 720, 60], ['U0', 600, 150], ['U2', 960, 72]], 33, 15],
   [[['U0', 800], ['P1', 800], ['U2', 1060]], [['U0', 'P1']]]),
  ('partial repair guard 3', [[['S1', 780, 73], ['T0', 540, 72]], 10, 30], [[['T0', 620], ['S1', 865]], []]),
  ('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
  ('normal control 5', [[['V1', 800, 60], ['Q0', 600, 150]], 25, 15],
   [[['Q0', 790], ['V1', 875]], [['Q0', 'V1']]]),
  ('normal control 6', [[['Q1', 750, 44], ['W0', 600, 72]], 10, 30], [[['W0', 680], ['Q1', 800]], []]),
  ('normal control 7', [[['S0', 540, 100], ['Q3', 1020, 90], ['U1', 720, 91], ['U2', 840, 60]], 10, 30],
   [[['S0', 650], ['U1', 825], ['U2', 910], ['Q3', 1120]], [['U1', 'U2']]]),
  ('normal control 8', [[['U2', 840, 44], ['W3', 1080, 150], ['V1', 660, 180], ['V0', 540, 91]], 33, 30],
   [[['V0', 665], ['V1', 900], ['U2', 900], ['W3', 1280]], [['V0', 'V1'], ['V1', 'U2']]])],
 [('regression: extension ceiling 1', [[['Q0', 600, 182], ['U1', 750, 120]], 10, 15],
   [[['Q0', 805], ['U1', 885]], [['Q0', 'U1']]]),
  ('regression variant: extension ceiling 2',
   [[['R0', 540, 60], ['V1', 660, 72], ['S2', 810, 73], ['V3', 1010, 72]], 33, 30],
   [[['R0', 620], ['V1', 760], ['S2', 910], ['V3', 1110]], []]),
  ('partial repair guard 3', [[['V2', 900, 90], ['W0', 600, 91], ['P1', 780, 88], ['Q3', 1050, 91]], 10, 30],
   [[['W0', 705], ['P1', 880], ['V2', 1000], ['Q3', 1155]], [['P1', 'V2']]]),
  ('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', [[['S0', 540, 91], ['T1', 630, 60], ['U2', 780, 91]], 33, 30],
   [[['S0', 665], ['T1', 710], ['U2', 905]], [['S0', 'T1']]]),
  ('normal control 7', [[['W1', 780, 60], ['S0', 600, 72]], 15, 15], [[['S0', 685], ['W1', 850]], []]),
  ('normal control 8', [[['R2', 830, 91], ['P0', 540, 90], ['U1', 630, 73]], 10, 15],
   [[['P0', 640], ['U1', 715], ['R2', 935]], [['P0', 'U1']]])]]
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: extension ceiling 1[[['A', 640]], []][[['A', 640]], []]Passed
regression variant: extension ceiling 2[[['W0', 735], ['T1', 905]], []][[['W0', 735], ['T1', 905]], []]Passed
boundary control 3[[['A', 720], ['B', 855]], []][[['A', 720], ['B', 855]], []]Passed
boundary control 4[[['A', 625], ['B', 710]], []][[['A', 625], ['B', 710]], []]Passed
normal control 5[[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]][[['P0', 680], ['Q1', 955], ['U2', 950]], [['Q1', 'U2']]]Passed
normal control 6[[['R0', 690], ['S1', 810]], []][[['R0', 690], ['S1', 810]], []]Passed
normal control 7[[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]][[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]]Passed
normal control 8[[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]][[['S0', 815], ['P1', 890], ['P2', 980], ['R3', 1195]], [['S0', 'P1'], ['P1', 'P2'], ['P2', 'R3']]]Passed

SHA-256 / 010ef9c5c768c5d67c598f75fd3ac9b05b2a339027507afae9c08d1d81faae5d

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

Case digest / 279d32742ca12ddd6905d46e270b9886d0d244c21771b1ff36d3088ebd15a3c4