Skip to content

Validation policies

The booking, quote, dispatch and driver rules — drafts, simulation, publish, rollback and rollout modes.

Validation Policies holds the rules that bookings, quotes, dispatch and the driver app are checked against. They are edited here and go live without a deploy. Under Settings → Validation Policies (/operations/settings/validation-policies).

OperationsAdmin
Read what is in force, edit drafts, lint, simulate✅✅
Publish, roll back, change rollout modes—✅

The publish, rollback and rollout-mode controls are not shown to someone who cannot use them.

The Policies table lists one row per policy — booking, quote.request, dispatch.unit, dispatch.allocation, dispatch.manifest, driver.stop, driver.run — with its mode on each surface and its published and draft versions. Click a row to work on that policy; the heading Editing <policy> names the one every panel below belongs to.

Each policy has a mode per surface:

SurfaceWhere
serverThe save itself, on the server
webThe booking form, checked in the browser
boardThe dispatch board
widgetThe public quote/booking widget
driverThe driver app — it can only add warnings; it never refuses a stop
ModeEffect
offNot checked. Default for every surface.
shadowChecked and recorded, refuses nothing.
enforceRefuses, or asks for a reason. Not allowed while nothing is published.

Type a Reason (recorded), then click the mode button under the surface. A change reaches every worker in about five seconds.

⚠️ A new version that suddenly refuses more than 30% of what the old one accepted (at least 20 attempts in 10 minutes) drops back to shadow on its own.

In force shows the published version for the selected policy:

  • a line saying which surfaces are enforcing, which are only watching (shadow), or that every surface is off;
  • In plain words — a table of rules: rule, severity (error, warning, info), what it says and when it applies;
  • Raw JSON — the exact published document.

The plain-words sentence is a reading aid. The JSON is the rule.

  1. New draft from published — copies the live version into the Draft editor. (Or Import JSON to load a file as the draft.)
  2. Edit the JSON and click Save draft. Lint lists anything wrong with the document.
  3. Set Days (default 30) and click Simulate draft. The table shows, per rule, how many recent bookings would be newly failing or newly passing, with examples. Use Refresh while it runs.
  4. Discard draft throws the draft away.

Enter a Reason of at least 10 characters and click Publish. The button stays disabled, with the reason shown beneath it, until:

  • there is a draft and the linter accepts it;
  • the draft was simulated after its last edit, and the simulation finished;
  • nobody published another version since the draft (or the simulation) was made.

If the publish would refuse bookings that were accepted before, type that newly refused count in the box to confirm.

Versions lists every version with its status and source. Each has export; an archived version has roll back (Admin), which uses the Reason from the Publish box. Pick From and To and click Diff to see what changed.

While a surface is in shadow, every case where the policy and the old checks disagree is recorded. Disagreements by kind summarises them:

KindMeans
legacy_onlyOld checks refused, the policy did not — the policy misses this
policy_onlyThe policy would refuse, old checks do not — the policy adds this
severity_mismatchBoth refused, at different severities
client_server_mismatchBrowser and server judged the same save differently
unevaluableA rule read data it did not have

The Disagreements log below it filters by policy, surface, kind, rule and date — press Apply after changing a filter. A booking a policy refused was never saved, so this log is the only record of it.

A surface is ready for enforce when this log shows nothing unexplained.

  • legacy_only rows are the blockers. Each one is a booking today’s checks refuse that the policy would let through. Enforcing the policy on that surface would start accepting them.
  • policy_only rows are the point. They are what the policy adds. Check the Example for a few to confirm they are bookings you really want refused.
  • unevaluable rows mean a rule needs data the booking did not carry. If that rule is an error or is locked, the booking counts as failing it — so fix the rule (or the data) before enforcing.
  • After a publish, set Seen since to the publish date and check the Version column, so you are reading only what the new version produced.

Only when the relevant surface is in enforce:

  • Create Booking — Save Booking can be refused with the rule’s message. If the problem is a warning that may be accepted, a This booking needs a reason dialog lists each one: type why (at least 10 characters) and click Accept and save, or Go back and fix it. The reason is recorded against the booking.
  • Dispatch board — candidates a policy refuses are hidden, behind a Show N not eligible toggle; revealed ones are greyed with their reasons. Warnings show a badge and need Acknowledge and continue with a reason before assigning.
  • Quote conversion — an accepted quote is always converted. If the booking policy would not have accepted it, the job is marked Needs review — … in its status notes and an open policy exception is raised for dispatch.

In off or shadow, none of these appear.