Move refreshMaintenanceCache() to after sites are loaded into
liveState. Previously it ran before the site loading loop, so on
the first iteration liveState was empty and the cache resolved
to nothing. This caused groups to briefly show DOWN on startup
for children that were in maintenance, until the next poll cycle
repopulated the cache.
checkGroup() now detects status transitions and persists them as
state change records, same as individual monitors. Groups also
get StatusChangedAt updates and log entries for down/recovery
events. This enables history and SLA views for group monitors.