pollOnce() previously collapsed multiple bookings overlapping today for one site
down to a single candidate before computing room_state, with a weak tie-break
(prefer 'arrived' status, else whichever the API happened to return first). On a
same-day turnover — departing guest + incoming guest both returned by NewBook's
'staying' list for the same site — if neither was marked 'arrived' yet, this could
arbitrarily lock onto the incoming guest's booking (still in 'booked', prep not
started) instead of the departing guest's (which should be 'cooling_down'), even
though the departing guest was the one actually still checked into the room.
Now every candidate booking for a site is evaluated (each zone applies its own
offsets, so this only resolves once we have the zone), and the state machine picks
whichever produces the most active result: occupied > heating_up > cooling_down >
booked > vacant. Zero behaviour change for the common single-booking-per-site case.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>