Why this matters: the follow-up act of this round tests whether your design was structure or luck. Each variation below is a real request a scheduler team eventually hears, and each lands on a seam lesson 2 already built — the interval type, the filter pipeline, the calendar authority. Practicing the landings teaches you the meta-skill: extend by placing new behavior, not by reopening old decisions.
Multiple offices, multiple timezones
The requirement set said one building, one timezone. The moment a second office appears, the question is where timezones live — and the answer is a storage-versus-display split. Store instants, display local. Every TimeSlot already holds UTC instants; comparisons, conflict checks, and the ordered calendar never change, because "does 14:00 UTC overlap 14:30 UTC" is timezone-free arithmetic. Timezone becomes a property of the room (the building it sits in) applied at the presentation edge: a booking form in Berlin converts local input to instants on the way in, and renders instants as local time on the way out.
storage: TimeSlot(Instant, Instant) — UTC, compare freely
per room: building -> ZoneId — display metadata
edges: parse local -> instant on input
format instant -> local on output
core: UNCHANGED — overlap math never sees a timezone
The trap being probed: putting local times in the core. Then daylight-saving transitions make some local days 23 or 25 hours long, interval comparisons stop being trustworthy twice a year, and cross-office queries need conversion inside the hot path. If your overlaps line never has to know what a timezone is, you placed it correctly — that's the payoff of keeping interval math in one type.
Working hours and buffer times
Ops asks: no bookings outside 08:00–20:00, and ten minutes between meetings in the big rooms for cleanup. Both are finder and validation filters, not calendar changes. Working hours is a predicate on the candidate slot — check it in book alongside capacity, add it to suggest's filter chain. Buffer time is slightly richer: treat a room's effective occupancy as the booking's slot padded by the buffer, and ask isFree about the padded interval. The calendar still stores the real meeting times; the pad is applied by the caller that knows the room's buffer policy. The structure absorbing both without modification is the filter pipeline doing exactly what the open/closed seam promised.
Approval for large rooms
Facilities wants the 40-person auditorium to require sign-off. This is a booking-state extension: a booking gains a small lifecycle — PENDING → CONFIRMED or PENDING → REJECTED — and rooms gain a flag saying which path new bookings take. The design decision worth saying out loud: does a pending booking hold the slot? Almost always yes — otherwise two requesters race for the same slot and approval becomes a lottery. So pending bookings enter the calendar like any other (the conflict invariant doesn't care about status), and a rejection behaves exactly like a cancellation: removal. Notice what you did not touch: the interval type, the neighbor check, the finder. State machines bolt onto entities; they don't reshape structures.
Utilization analytics
"Which rooms are wasted?" is a read-side question, and the honest answer is: don't make the calendar serve it. The calendar is tuned for one query — availability — and analytics wants different shapes entirely (bookings per room per week, average fill ratio, peak hours). Keep an append-only booking log: every book and cancel appends an event, and analytics aggregates the log offline. Cheap to add, and it keeps reporting load away from the hot path. This is the same separation-of-concerns instinct as the calendar authority itself: one structure per question.
Syncing with external calendars — the direction sketch
If bookings must appear in employees' personal calendars, the clean seam is an outbound notification port: after a booking commits, publish a "booked/cancelled" event that a sync adapter translates to the external calendar's API. The hard questions live on the inbound side — what happens when someone edits or deletes the event in the external calendar — and the defensible v1 answer is: inbound edits are ignored; your system is the source of truth, and the external entry is a projection. Two-way sync means conflict resolution between systems, and that's a project, not a variation. Naming that boundary is the senior move; sketching the port is enough.
Key takeaway
Every variation lands on an existing seam: timezones split into UTC storage and per-room display so the overlap math never changes; working hours and buffers join the filter pipeline (buffers as padded intervals at the caller); approvals are a booking-state machine whose pending bookings still hold their slot; analytics reads an append-only log, never the calendar; calendar sync is an outbound port with your system as the source of truth. If a request forces you to reopen the interval type or the neighbor check, re-examine the placement before the design.