Scheduled changes
What it does
Pushes the apply step on a change request to a near-future time. The change still goes through the standard draft → dry-run gate, but instead of applying immediately on approval, Policytab holds it until the scheduled window.
The schedule itself is a scheduled_for timestamp on the change_request row. The Edge Function changes-scheduled-apply runs every five minutes and applies every eligible dry_run_complete row whose scheduled_for <= now(). Immediate previews expire after 30 minutes; once a change is explicitly scheduled, its preview may be used for up to 7 days from dry_run_at. Longer horizons require a fresh preview closer to the maintenance window.
When to use it
- Planned maintenance windows. Customer wants the change to land later, but no more than seven days after the preview was computed.
- Coordinated cutovers. Several tenants need the same change at the same wall-clock instant.
- Coordinated final clicks. Run the preview immediately before a change window, then schedule the actual write for the first cron tick in that window.
For an immediate change, skip the schedule and use Apply now.
Step-by-step
- Tenant detail → Changes → Propose change, same as the immediate flow.
- Build the payload and click Run preview. Review the warnings and obtain second-admin approval if required.
- Tick Schedule for later. A datetime picker appears, defaulting to roughly "now + 15 minutes" in your local zone.
- Pick the apply time. The picker shows your local time; the value stored on the row is UTC. The selected time must be within seven days of the current dry-run.
- Click Schedule. The row enters
dry_run_completewithscheduled_forpopulated. The dashboard's Scheduled changes card shows it counting down. - The cron runs at
*/5 * * * *. At the first tick afterscheduled_for, the Edge Function rechecks approval, live-state divergence, break-glass/blast-radius safety, and preview age. It then claims the row asapplying, links a complete pre-snapshot, performs the Graph write, captures and verifies the post-snapshot, and writesappliedon a proven success. An unverifiable or ambiguous outcome is held for reconciliation instead of being blindly retried.
Cancelling a scheduled change
Before the scheduled apply starts:
- Open the change.
- Click Cancel schedule. The change returns to its unscheduled state, and the audit log records who cancelled it. If the preview is now more than 30 minutes old, run it again before using Apply now.
After the background scheduler has started applying, you cannot cancel. Use Rollback on the applied change instead, exactly as you would for any other applied change.
Combining with the approval workflow
If require_approval is on (see Approval workflow), the order is:
- The requester runs the preview and submits it for approval.
- A different admin reviews and approves it.
- Admin schedules within the remaining 7-day scheduled preview window.
- Policytab applies it in the scheduled window.
The schedule controls appear only after approval. If the preview expires while approval is pending, re-run it and obtain fresh approval before scheduling.
Troubleshooting
- "Schedule" button missing. The preview is blocked or still waiting for approval. Resolve the warning or obtain the required approval before scheduling.
- The page says scheduled apply is not configured. Return at or after the selected time and use Apply now, or contact your Policytab operator to enable the background scheduler.
- The selected time is rejected as past. Confirm the device clock and time zone, then choose a new future time.
- My scheduled change never applied. Check three things in order:
- Is the row still in
dry_run_complete? (awaiting_approvalparks waiting for approval;cancelledmeans someone cancelled.) - Is the scheduled dry-run still valid? Scheduling beyond seven days from
dry_run_atis rejected; if it expired, re-run dry-run and schedule again. - Is the cron job actually scheduled?
select * from cron.job where jobname like '%scheduled%'in the SQL editor. Operators enable it via the Vault-backed cron migrations.
- Is the row still in
- Apply is held after the cron picks it up. A stale/diverged preview or failed safety recheck moves the row to a blocked state. A definitive pre-write or Graph rejection lands in
failed. A lost/ambiguous write response stays review-blocked until live state is reconciled; never re-run it as a fresh create merely because the response was lost. - DST handling.
scheduled_foristimestamptz. The UI converts to/from your browser zone, so a "9 PM Friday" pick is stable across DST shifts at the storage layer.
Operator note
The cron job is registered by the Vault-backed cron migrations. Operators must set edge_functions_base_url and edge_functions_service_key in Vault for the kick function to call the Edge Function.