A rota can give everyone the same number of assignments and still leave a shift uncovered. The problem often starts with a reasonable shortcut: assign the next shift to the person with the lowest current workload.
Here is a small, fictional example that exposes the limitation.
| Person | Morning | Afternoon | Maximum assignments |
|---|---|---|---|
| Ada | Available | Available | 1 |
| Ben | Available | Unavailable | 1 |
Both shifts need one person. At the start, Ada and Ben have equal workloads. If a greedy tie-break assigns Ada to the morning, the afternoon is left without an eligible person: Ben is unavailable, and Ada has reached her limit.
Yet a complete schedule exists: Ben in the morning, Ada in the afternoon.
Separate constraints from preferences
Availability and maximum assignments are hard constraints. A schedule must satisfy them before its workload balance is useful.
For a slightly larger example, the checks might be:
- Every shift has its required number of people.
- Every assigned person is available for that shift.
- Nobody exceeds their own assignment limit.
- One person cannot cover two assignments in the same time group.
After those checks, compare feasible schedules using an explicit objective. One simple choice is to minimize the difference between the largest and smallest assignment counts, then use the sum of squared counts as a tie-break.
That is a definition of fairness for this model. It does not account for shift difficulty or individual preferences unless those are represented in the inputs.
A complete search you can inspect
For the two-person example, checking all combinations is small enough to write directly. This standalone JavaScript runs in Node.js and uses no packages:
const people = [
{ name: "Ada", available: ["morning", "afternoon"], max: 1 },
{ name: "Ben", available: ["morning"], max: 1 },
];
const feasible = [];
for (const morning of people) {
for (const afternoon of people) {
const assignments = [morning, afternoon];
const available = morning.available.includes("morning") &&
afternoon.available.includes("afternoon");
const withinLimits = people.every(person =>
assignments.filter(p => p === person).length <= person.max
);
if (available && withinLimits) {
feasible.push({ morning: morning.name, afternoon: afternoon.name });
}
}
}
console.log(feasible);
// [{ morning: "Ben", afternoon: "Ada" }]
This example checks availability and assignment limits. It has four combinations, so completing the search is easy. Larger instances need better ordering and pruning, and they still need an explicit stopping rule.
A search limit changes what the result means
A useful scheduling interface should distinguish these outcomes:
| Outcome | What the result establishes |
|---|---|
| Optimal | A feasible schedule meets a proven lower bound or a complete search established the best objective. |
| Feasible, search limit reached | The shown schedule satisfies the modeled constraints; a better schedule might exist. |
| Infeasible | A constraint check or a complete search established that no schedule satisfies the modeled constraints. |
| Unknown, search limit reached | The search stopped without finding a feasible schedule. This does not establish infeasibility. |
The final two states are easy to confuse in a UI. A time limit is a statement about how much searching happened, not a proof about every possible schedule.
The same distinction is useful in packing, timetabling and small resource-allocation tools.
Keep the inputs with the result
An exported schedule is easier to review when it travels with its assumptions. Keep the availability table, individual limits, time groups and solver status alongside the assignments. If an input changes, recompute the result before sharing it.
For an initial check, use a tiny example where you already know the answer. Then try an impossible case, such as two required assignments with a total capacity of one. Finally, test an invalid input and make sure an old successful result is not left looking current.
I used these checks while preparing Fair Schedule Planner, a small offline browser tool with editable availability, personal limits, shared time groups, CSV results and a workbook for recording assumptions. The supplied examples are fictional. The interface reports the search outcomes above.
If you want the ready-made interface and worksheets, the Fair Schedule Planner download is available on Payhip for $12 as a one-time purchase. A free PDF preview is available on the product page. The JavaScript example in this article is independent and free to use.
This article and the product were prepared with AI assistance. The example output was checked, and the product's documented functional checks cover availability, conflicting assignments, impossible inputs and exported result data.
Top comments (0)