Parking apps for employees: a fairness ledger to the rescue
I've been building an employee parking app — the kind where a company has one underground lot, more badge holders than spaces, and someone in facilities who is tired of being the referee. The booking part was the easy weekend: lots, slots, reservations, a calendar. The part worth writing about is the question the CRUD politely avoids: when there aren't enough slots, who gets one?
No code in this post. Just the idea I ended up committed to, because I think it generalises well beyond parking: desks, GPU hours, on-call weekends off — any scarce thing a team shares.
First-come-first-served allocates alarm clocks
Almost every parking system starts as first-come-first-served, because FCFS doesn't feel like a policy at all. Everyone gets the same starting line each morning; the system just processes clicks in order. What could be fairer?
Except FCFS rewards exactly one skill — clicking fastest at seven — and it has a deeper flaw that takes a month to see: it's memoryless. Every morning it forgets who won yesterday. The race is fair; the season isn't.

Nobody can point at the day the system was unfair, because there isn't one. The unfairness lives entirely in the accumulation, and FCFS has no organ that can even see accumulation.
Give the system memory
The fix I landed on is old accounting technology: a ledger. Every time you get a slot, a line is written: grant, +1.0. Every time you release a slot you'd reserved — the day before, in time for someone else to use it — another line: release credit, −0.5. Your balance is the sum of your lines over the last 30 days.

That balance is the missing memory. It's not a score to maximise — it's closer to a tab. The lower your balance, the stronger your claim next time slots are contested.
Stop racing, start requesting
Memory only matters if something reads it, so contested days stop being a race and become a draw. During the day, anyone can request tomorrow — requests are wishes, not bookings, and the order you ask in doesn't matter. At a published cutoff (18:00 in my build), one allocation pass ranks every requester by balance, lowest first, ties going to whoever asked earlier. Winners get real reservations; everyone else is waitlisted. And each award immediately writes its +1.0 back into the ledger.

That last property is worth underlining. Under FCFS, the allocation decision is smeared across a thousand anxious clicks. Under a draw, it happens once, at a time everyone knows, by a rule everyone can read. You can disagree with a rule like that, but you can't be ambushed by it.
Winning today costs you tomorrow
The elegant part — the reason I like this design more the longer I sit with it — is that the loop is self-correcting. Every win raises your balance, which lowers your priority for the next contested day. Every loss leaves your balance flat, so you rise until you win.

Nobody has to manage the rotation — no spreadsheet, no facilities referee, no "it's B-team's week". The ledger is the rotation. Dave's two-slots-a-month problem dissolves without anyone having noticed it, decided to fix it, or negotiated who owes whom.
The scarcest thing is the freed slot
Here's the operational secret of every corporate lot: it runs full on paper and half-empty in reality. The binding constraint isn't the concrete — it's reserved-but-unused slots. Which is why the release credit isn't a gimmick; it's the mechanism that makes the whole system liquid. Freeing your slot the day before earns you −0.5, so good behaviour compounds into easier future draws. And the freed slot doesn't sit idle: the best-ranked waitlisted colleague is promoted automatically. No dispatcher, no email thread, no "is anyone using A-04 today?" in the team channel.
A ledger, not a counter
You could squint and say this is just a counter per person. The reason I want the full ledger — dated, line-item, append-only — is everything a single number can't hold. Entries can be weighted: a Friday slot isn't a Monday slot. They can decay: wins from six weeks ago stop counting against you. They can be recorded without counting: accessibility and carpool grants belong in the history, but a works council may decide they shouldn't cost anyone priority. All of that is policy, and policy changes — the ledger absorbs the changes; a counter would have to be reinvented for each one.
And the killer feature isn't algorithmic at all. In Luxembourg, where I'm building this, every company above fifteen employees has a délégation du personnel — an employee delegation — and a parking policy is exactly the kind of thing that lands on its table. HR doesn't need a clever allocator. HR needs to defend the outcome to the person who lost. An append-only ledger means "why not me?" is answered with lines, not with a shrug: here are your grants, here is your balance, here is who ranked above you and why. A counter produces a score. A ledger produces reasons.
Fairness is memory plus transparency
That's the whole idea, and I think it's the honest definition. A system is fair when it remembers what it already gave you, and when it can show its reasoning to the people it disappoints. Everything else in my build — the nightly draw, the release credits, the waitlist promotion — is plumbing around those two properties.
Where it goes next: no-show penalties (a reserved slot that stays empty should cost more than a released one), decay curves, and maybe a weighted lottery instead of a strict sort, so low-balance folks are likely rather than guaranteed to win — strict determinism has its own failure mode once people learn to game the calendar. But those are tunings. The load-bearing decisions are the ledger and the published rule, and I'd reuse both for any scarce resource a team shares.