From One Client’s Rules to Any Team: A General Scheduler

The staff scheduler I built for that Fiverr client did exactly one job. It knew about his clients, his courses, his equipment, his week. It was a good staff scheduling model for precisely one business on Earth. Every sheet name, every constraint, every assumption was his. When I put it online I knew the truth: nobody else could use it without hiring me to rebuild it. So I rebuilt it once, properly, for everyone. This is how the generalization went.

Everything is supply and demand

Strip the specifics away and staff scheduling is one thing: demand for work, covered by people who can supply it, over buckets of time. I worked in a call center ages ago, and that is still the cleanest way to picture it. Demand is “we expect 3 English calls and 1 Spanish call in every half hour from 10 to 6.” Supply is the people who can answer them, each with their own availability and limits. The schedule is whatever assignment of supply to demand costs the least while covering the most.

Once you say it that way, nothing in the model needs to know what a “course” or a “call” is. A demand is a name, a penalty for leaving it uncovered, and a grid of required units per time slot. That same structure handles nurses on a clinic floor, cashiers at a fast-food rush, or a hotel front desk. I built sample datasets for all four while testing, and the model never changed — only the numbers did.

The data model that came out of it

The workbook (or the web form — more on that below) has a handful of tables. A demand registry: name, shortage penalty, and one flag I am quite proud of called concurrent. A people table with each person’s cost per hour and their work-rule limits. A skills table saying who can serve which demand, at what rate. And one small grid per demand and per person: required units per slot, availability per slot.

The concurrent flag deserves a word. Some demands are volumes: a call takes a person, and that person cannot take two calls at once. Others are presences: “someone who speaks Spanish must be on the floor.” A bilingual agent answering an English call IS your Spanish presence — she counts toward both. Marking Spanish as concurrent captures that exactly, and the solver uses her twice without cloning her.

Two design decisions saved me from my own confusion. First, no “priorities” anywhere — early drafts had priority 1 meaning best in one table and least important in another. Now every number is a weight or a cost: higher weight = more important to cover, lower cost = scheduled first. Second, people limits live in one table and skills in another, like a proper little database. The bilingual agent is one row of limits and two rows of skills, not two half-copies of herself.

Rules that make schedules humane

A mathematically optimal schedule can be inhumane. I have seen a real schedule where someone worked six and a half hours without a break. So the generalized model has shift-shape rules as first-class parameters: at most one break per day, a hard cap on the longest stretch without one, a cap on how long the break itself can be, and a minimum block length so nobody commutes in for a 90-minute stint. The break even centers itself: the minimum block auto-scales to half of a person’s longest allowed stretch, so an 8-hour day splits 4+4 or 5+3, never 6.5+1.5. That last trick replaced a fancy penalty formulation with two lines of arithmetic, and it made the whole thing solve faster.

There is also an f you can put in an availability cell: fixed. That person works that slot, period — seniority schedules, contractual shifts, the owner’s nephew — and the optimizer plans everyone else around them. The tool checks your fixed cells against the limits before solving and tells you in plain words when they conflict: “John: fixed slots need 8h on Monday but max hours per day is 6.”

INFEASIBLE is a terrible error message

The old model treated minimum guaranteed hours as hard walls. Give the solver a week where John cannot possibly get his 20 contracted hours and it answers INFEASIBLE — which tells a scheduling manager exactly nothing. The generalized version makes minimums elastic: falling short is allowed but costs. Now the same data produces a schedule plus a red flag, “John is 4 hours below his weekly minimum,” and the manager decides what to do about it. As a bonus, this turned out to be the fix for a solver performance mystery, which got long enough to become its own post.

Seeing the schedule, touching the schedule

Results come back as an interactive grid: pick any combination of demands and people and see green where you are covered, red where you are short. Select just George and you get George’s printable week. And you can click cells to hand-tweak the answer — the person who comes in at 8:30 one day “because it was optimal” can just come in at 8 — with the exact cost of your tweak shown live, no re-solve needed. The optimal schedule is a starting point; the decision maker gets the last word.

What’s next

The generalized engine is running locally with a full web form — type your data, paste it from Excel, or import a workbook, same as the philosophy in the original three-file app. The live version at staff-scheduling.kindoflost.com still runs the one-client model while I finish kicking the tires on this one. Still parked: true 24/7 operations, where Sunday’s last hour has to connect to Monday’s first — the week needs to become a circle for that, and that is a story for another day.

Tradeline Supply
Things that I use, like, and am affiliated with:
Mint Mobile offers great cell phone service for $15 flat, get $15 off using the link. Get discounted phones with service activation and no contract.
I never spend money before I check Mr Rebates or Rakuten to get cashbacks, rebates, discounts, coupons or cheaper gift cards.

Leave a Reply