(start_hour, end_hour) tuples (end exclusive). Write coverage_gaps(shifts) returning the sorted list of uncovered hours in that window — empty means fully staffed.coverage_gaps([(9, 13), (14, 21)])
[13]
Nobody covers the 13:00 hour.
Build the set of covered hours from all shifts.
Difference against range(9, 21).