Model 8 · Spec

Rota Optimiser Rules

A single-page reference of every rule the optimiser follows. Read top to bottom. If something doesn't match how you actually run the rota, flag it before signing. Once signed, this is the locked spec.

Version: 1.0 — awaiting signature
Last updated: 20 April 2026
Engine: Google OR-Tools CP-SAT
What we agreed
A single-page specification of every rule the optimiser follows, written in plain English and signed off by Liam before go-live. After sign-off, the spec is locked and any change goes through a versioned update.
How we've delivered it
All hard and soft rules grouped by priority tier, with a sign-off box at the bottom. Known open items (chain V2, Pareto sweep, traveller tags, Jersey) are listed explicitly so Liam signs off on the current rules with visibility of what's iterative.
Overview Priorities Hard Rules Twin Events Roadtrips Dealer Tiers Soft Preferences Data Defaults Open Questions Sign-off
What it does

The Short Version

Each week there are roughly 60 events, around 40 active dealers, and millions of possible ways to staff them. The optimiser solves the whole week as one problem. It respects every hard rule in this document, tries to satisfy every soft preference, and picks the assignment that minimises total fleet travel.

The engine is Google's OR-Tools CP-SAT constraint solver. Each week solves in under a second. The output is a complete dealer assignment for every event, ready to paste into the rota sheet.

What follows is the complete specification. Hard rules the optimiser will never break. Soft preferences it tries to satisfy in priority order. Data defaults it reads from your spreadsheet. Special rules for specific dealers.

What it cares about

Goals in Priority Order

When rules conflict, higher-priority goals win. Items 1-3 are non-negotiable. Items 4-6 flex when they have to.

  1. Fill every seat. An unfilled seat is treated as catastrophic. The optimiser will accept long drives or tight schedules before it leaves a seat empty.
  2. Use every dealer near their target. Dealers shouldn't be benched. The optimiser spreads work so every active dealer hits roughly their weekly quota.
  3. Avoid roadtrips. The ideal is zero roadtrips. Long trips are only assigned when no closer dealer has capacity. Each roadtrip carries a heavy penalty in the objective.
  4. Minimise total fleet travel. Once the first three are satisfied, the next goal is the lowest total drive time across the team.
  5. Bundle nearby events on consecutive days. A dealer who worked Yorkshire on Monday is preferred for another Yorkshire event on Tuesday over a Suffolk event.
  6. Spread the burden fairly. Tiebreaker only. The optimiser tries not to dump all the heavy travel on one dealer.
Cannot be broken

Hard Rules

Absolute constraints. The optimiser will never violate these, even if it means a seat stays unfilled.

H1

Every event gets at least 2 dealers

Standard events staff 2. Twin events and 3-dealer events staff 3 (see rule T1). The solver cannot assign fewer than 2.

H2

One event per dealer per day

A dealer works a maximum of one event per day. Twin events are the exception: if a dealer does both halves of a twin pair, that counts as one event for daily-limit purposes (see T1).

H3

Weekly cap from yearly quota

Each dealer's yearly quota divided by 47 working weeks gives their weekly target. Their hard weekly ceiling is target + 1. Twin pairs count as one event (0.75 weight) against this cap.

Examples:

  • Adam Chapman (174/year) — target 3.7/week, hard cap 5
  • Charlotte Cropper (130/year) — target 2.8/week, hard cap 4
  • Andrew Wood (24/year) — target 0.5/week, hard cap 2

To raise a dealer's cap, raise their yearly quota. 47 = 52 minus 2 shutdown weeks minus 3 typical holiday weeks.

H4

Holiday blackouts

A dealer on holiday cannot be assigned to an event on that date. Holidays come from the Holidays tab in the sheet and from the dedicated Holiday Days sheet in the enriched file. Both sources are merged.

H5

Recurring weekday blocks from dealer comments

Phrases like "does not work Tuesdays" in a dealer's comment field create hard weekday blocks. The solver parses the comment and refuses to schedule that dealer on the named day.

H6

Only active dealers

A dealer needs a yearly quota greater than zero (either Jan-Apr or May-onwards) to be eligible for any assignment. Inactive dealers are excluded from the candidate pool.

New rule — needs your sign-off

Twin Events

A twin event is two roadshows on the same day in nearby venues within the same county, staffed by the same team.

T1

Same team does both halves

Twin pairs are grouped by date and county. The optimiser forces the same dealers onto both halves of a twin pair. A dealer assigned to Gosforth Tuesday morning is also assigned to Seascale Tuesday afternoon.

T2

3 dealers ideal, 2 only if capacity forces it

Per your feedback: the operational need is a 3rd dealer to set up the afternoon venue while the other two finish the morning event. The solver defaults to staffing every twin with 3 dealers. It will drop to 2 only when no other dealer has capacity — the soft penalty for an unfilled 3rd seat is high enough that the solver will accept significant extra travel before it lets a twin go understaffed.

Historical context: 11 of the 15 completed twin pairs in Jan-Apr ran with 2 dealers. You've indicated those were capacity compromises. The optimiser now closes that gap wherever it can.

T3

Twin pair counts as 0.75 against weekly quota

Even though a dealer attends two venues on a twin day, it counts as less than two events for their quota. Twin = 0.75 units, standard event = 1 unit. The solver uses integer arithmetic (4×-scaled: twin = 3, standard = 4, cap × 4) for CP-SAT compatibility.

Long trips

Roadtrip Rules

Roadtrips are the expensive edge case. These rules govern when and how they're allowed.

R1

3.5 hours = roadtrip threshold

Any drive over 3h 30min from a dealer's home postcode counts as a roadtrip and burns one of their monthly roadtrip allowances. Flat threshold across all counties. The iterative roadtrip Pareto sweep (see Open Questions) will let you visualise the trade-off at different thresholds post sign-off rather than calibrating per-county.

R2

Multi-day chains count as ONE roadtrip

A 3-day chain (stepping-stone Monday + far event Tuesday + stepping-stone Wednesday) counts as one roadtrip against the dealer's monthly cap, not three. This reflects how you actually manage long trips: one trip, one exhaustion cost, not three separate penalties.

R3

Monthly roadtrip caps per dealer

Each dealer has a monthly roadtrip cap from the spreadsheet. Values of 0, 1 or 2. The cap also encodes the dealer's travel preference — no separate happy/reluctant tag is needed because the cap already expresses it.

Cap 0 — never takes long trips (reluctant / exempt)
Local only. The solver will not assign any drive over 3.5h, regardless of seat-filling pressure.
Cap 1 — one roadtrip per month (neutral)
Available for long trips when necessary, capped at one chain per month.
Cap 2 — willing travellers (happy)
Up to two roadtrip chains per month. Preferred for unavoidable long trips.
Special dealer categories

Dealer Tiers

Some dealers sit in tiers with bespoke rules. These override the general logic.

S1

Locked dealer: Gary Trainor (GC)

Gary picks his own events. His existing rota assignments are locked — the optimiser treats them as fixed and works around them. Gary is exempt from the weekly cap (H3), holiday blocks (H4), weekday blocks (H5), and roadtrip caps (R1-R3). If you've assigned Gary to an event, that assignment stands.

Why: Gary's assignments are manually approved by you. They can legitimately exceed formula-derived constraints. For example he can work 5 days in a week where the formula would cap him at 4, or take Jersey trips during a marked holiday week. Locking bypasses those false conflicts.

S2

Reserve dealers: Andrew Wood (AW), James Moulds (JM), Oliver Reay (OR)

Used only when needed. Heavy preference penalty in the objective — the solver will prefer any non-reserve dealer with capacity. They are not inactive; they just sit at the back of the queue.

S3

Substitute dealers: Edd Thomas (ET), Lee Rushworth (LR)

Moderate preference penalty. Preferred for high-volume days or when core dealers are exhausted, not for general coverage.

S4

Ella Vasey

Friday assignments are soft-avoided (she can still work if it's the only option). The optimiser gets a small bonus for scheduling her at a Sheffield-area event on a Thursday (her preferred Thursday run).

Preferences, not rules

Soft Preferences

These shape the objective function. The solver trades them off against each other according to their weights (higher weight = stronger pull).

P1

Seat filling penalty (weight 10000)

Each unfilled seat adds 10000 to the cost. This is by far the heaviest penalty in the objective. It's why the solver will accept long drives to fill a seat, and why twins default to 3 dealers.

P2

Underuse penalty (weight 5000)

Each event a dealer is below their weekly target adds 5000 to the cost. This is what stops the solver from benching local dealers just because they're close to fewer events.

P3

Roadtrip start penalty (weight 1500)

Each roadtrip chain start adds 1500 to the cost, on top of the drive-time cost. Equivalent to about 25 hours of "virtual" driving. This is what makes the solver treat roadtrips as a last resort.

P4

Reserve dealer use (weight 800)

Each time a reserve dealer (AW, JM, OR) is used adds 800 to the cost. Keeps them in reserve.

P5

Substitute dealer use (weight 200)

Each time a substitute dealer (ET, LR) is used adds 200. Lower than reserves — they get called in before reserves but after core dealers.

P6

Total travel (weight 10 per minute)

The primary objective once constraints are met. Every minute of drive time across the whole fleet adds 10 to the cost.

P7

Max individual travel (weight 1 per minute)

Tiebreaker for fairness. Caps the worst-travelled dealer's total. Only kicks in when the primary total-travel objective is tied.

P8

Clustering bonus (-30 per match)

When the same dealer works the same county on consecutive days, the objective gets a 30-point bonus (reduces total cost). This pulls the solver towards consecutive-day clustering.

Inputs and assumptions

Data Defaults

What the optimiser assumes when reading your spreadsheet.

D1

Drive times — four-stage fallback

  • Stage 1: Postcode-to-postcode Haversine distance (most precise). Uses geocoded dealer and event postcodes.
  • Stage 2: Your drivetime matrix lookup for known dealer-county pairs.
  • Stage 3: County-centroid Haversine fallback when the matrix has gaps. Uses averaged built-up area centroids per county.
  • Stage 4: Unknown (only when dealer initials missing).

Current matrix gaps: Gwynedd and Merthyr Tydfil — filled by Haversine stage 3. Each run prints a summary of fallback usage.

D2

Future horizon — 6 weeks

The optimiser produces suggestions up to 6 weeks ahead. Beyond that, too many new events get added to the calendar and the rota becomes unstable. 6 weeks balances forward visibility with stability.

D3

Dealer active flag

A dealer is active if their Jan-Apr or May-onwards yearly quota is greater than zero. The May-onwards check matters for dealers who start mid-year.

D4

Twin event detection

An event is a twin if its Type field contains the word "Twin". Twin pairs are grouped by (date, county). Venues with different area names but the same county on the same date form a pair.

D5

Event sources merged and deduplicated

Events come from three sources: the main Rota tab, Liam's extra_events (Jan-Apr historical), and the May Events tab. Duplicates are removed by (date, area) comparison using case-insensitive matching ("Barrow Upon" vs "Barrow upon" are treated as the same event).

D6

Jersey trips excluded from the optimiser Decided 20 Apr

Jersey events are handled outside the optimiser. Liam selects the Jersey team manually (it's a political decision, not a travel-cost decision — ferry + accommodation changes the shape of the problem). The dealers picked for a Jersey week are then marked unavailable for normal events that same week, so the optimiser doesn't double-book them.

Known limitations

Open Questions

Items parked waiting on your input. None of these block sign-off — they're opportunities to sharpen the tool after the first review cycle.

Iterative improvements (post-sign-off)

These are known open items that we'll bolt onto the tool after the first review cycle. None of them block sign-off. Listing them here so you sign knowing what's still coming.

Lock the spec

Sign Off

Once you sign, this is the spec the optimiser runs against. Any change after sign-off goes through a versioned update. The open questions above can still be answered and bolted on, but the hard rules in this document become the contract.

If any rule in here doesn't match how you actually run the rota, flag it before signing. It's easier to fix now than unpick later.

Sign-off

I've reviewed the rules in this document. They reflect how I want the optimiser to staff the rota. Any deviations from my current practice are either bugs to fix in the data, or cases I'll confirm after running the tool against the live May rota.

Name
Role
Signature
Date