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).
Who can do what
Section titled “Who can do what”| Operations | Admin | |
|---|---|---|
| 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
Section titled “The policies”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.
Rollout modes (Admin)
Section titled “Rollout modes (Admin)”Each policy has a mode per surface:
| Surface | Where |
|---|---|
| server | The save itself, on the server |
| web | The booking form, checked in the browser |
| board | The dispatch board |
| widget | The public quote/booking widget |
| driver | The driver app — it can only add warnings; it never refuses a stop |
| Mode | Effect |
|---|---|
| off | Not checked. Default for every surface. |
| shadow | Checked and recorded, refuses nothing. |
| enforce | Refuses, 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.
Read what is in force
Section titled “Read what is in force”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.
Change a rule
Section titled “Change a rule”- New draft from published — copies the live version into the Draft editor. (Or Import JSON to load a file as the draft.)
- Edit the JSON and click Save draft. Lint lists anything wrong with the document.
- 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.
- Discard draft throws the draft away.
Publish (Admin)
Section titled “Publish (Admin)”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, rollback and diff
Section titled “Versions, rollback and diff”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.
Disagreements
Section titled “Disagreements”While a surface is in shadow, every case where the policy and the old checks disagree is recorded. Disagreements by kind summarises them:
| Kind | Means |
|---|---|
legacy_only | Old checks refused, the policy did not — the policy misses this |
policy_only | The policy would refuse, old checks do not — the policy adds this |
severity_mismatch | Both refused, at different severities |
client_server_mismatch | Browser and server judged the same save differently |
unevaluable | A 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.
Reading the log before you enforce
Section titled “Reading the log before you enforce”legacy_onlyrows 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_onlyrows are the point. They are what the policy adds. Check the Example for a few to confirm they are bookings you really want refused.unevaluablerows mean a rule needs data the booking did not carry. If that rule is anerroror 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.
What operators see elsewhere
Section titled “What operators see elsewhere”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
policyexception is raised for dispatch.
In off or shadow, none of these appear.