Server-side ISO timestamp captured immediately before the DB
lookup that produced schedule. Same semantic as
ScheduleTransitionPayload.at.
Campaign (or team-campaign) id the schedule belongs to. Client
stores flat under schedules[campaignID].
Full ordered schedule for the campaign at server-time at.
Empty array = campaign has no schedule.
Wire payload for a full schedule push, keyed by campaign.
Pushed from the UDP schedule emitter on:
campaign_schedule_entriesmutation (sync-schedule-lambda, admin edit, upstream Tiltify change)scheduleTransitionnudge — carries the full array so consumers don't need to refetch to reconcile past + future blocks)scheduleis the complete ordered list of ScheduleTransitionBlock rows for the campaign at server-timeat. Consumers replace theirschedules[campaignID]slot wholesale on every push — same convention as UpdateLeaderboardMessage and UpdateLeaderboardExclusionsMessage. An empty array means "campaign has no schedule" (never seen one, or the last block was deleted).Older clients that don't recognize
"updateSchedule"silently drop the message (default: break;inprocessMessage) — safe to roll out ahead of the UDP-side emitter.