Ship scheduled agents on time: timezone contract and next-run tests
A scheduled agent is only as safe as its timezone contract and next-run tests before production.

A scheduled agent can look correct in the UI and still fire at the wrong hour. Codex Desktop's automation scheduling displayed a recurring weekly rule in local wall-clock terms, but its next-run math treated BYHOUR as UTC. A Codex Desktop weekly automation displayed as Fridays at 16:00 computed a next execution of 18:00 Europe/Paris on 2026-06-05. Adding DTSTART;TZID=Europe/Paris to the reported Codex Desktop RRULE did not change the computed next execution.
The timezone contract keeps the hour honest
The contract has four parts: declare the intended zone, store and compute in UTC, display local time for humans, and assert the next run after migration, DST, and vendor config changes. It separates the human label from the engine calculation.
Declare the intended zone in the schedule definition. The field names the zone the operator used when setting the task. Use a named zone identifier, not a fixed offset. A named zone carries the daylight-saving rule. A fixed offset does not. The engine should not reinterpret a local hour after the task is saved.
Store and compute in UTC. Every internal timestamp, interval, and next-run calculation uses the same canonical zone. Keep the stored value and the displayed value separate.
Display local time for humans. The operator sees the intended local hour while the engine keeps the canonical value. The display is for humans, not the engine.
Name the schedule owner in the release notes. The owner reviews the next-run assertion before the first production run and can answer why the next run moved.
That contract prevents the common split: the UI says one hour, the engine computes another. The split is the bug. It appears only after the first missed window. The operator sees the mismatch before the agent runs.
Next-run tests catch silent drift
Run the scheduler against a fixed clock. Assert the next execution before deploy. The test prints the next run in UTC and the intended local time, then fails if they disagree. The assertion is the release gate.
Log the computed next run at deploy time. The release log shows the next execution before the first run and gives a baseline for the next review.
Assert the next run after a migration. The before-and-after comparison fails if the next execution moves without a change request. Assert the next run after a daylight-saving change. The test covers the transition and the following week.
Alert when the next run moves without a change request. The notification names the old next run, the new next run, and the owner.
A next-run assertion compares the displayed schedule, the stored value, and the computed execution. If the vendor UI and the engine disagree, block the release. Treat any vendor display as a claim, not a guarantee. Verify the computed next run before you ship.
Vendor config changes break schedules too
Check vendor scheduler behavior before release. The checklist covers the UI, the stored schedule, the computed next run, and the agent runtime config.
OpenClaw, an agent runtime, has its own failure modes. A UTC-hosted OpenClaw deployment with activeHours set using Eastern time can have its heartbeat window shifted by 4-5 hours. The activeHours setting is in the wrong zone for the host.
OpenClaw switches to explicit-agent mode when any agent in agents.list[] has a heartbeat block, so agents relying on agents.defaults.heartbeat do not run heartbeats. The mode change is easy to miss. Check the mode before you blame the model.
OpenClaw v2026.3.11 had a stale timestamp bug caused by a guard in appendCronStyleCurrentTimeLine that blocked timestamp refreshing after a 'Current time:' line already existed. A version bump can change what the agent sees. Test the clock line, not just the cron entry.
Review version notes for scheduler changes. The checklist names the version, the config, and the next-run assertion. Rerun the next-run test after every migration, daylight-saving change, and vendor config change. Keep the assertion in the build pipeline so the schedule cannot move without review.