Yesterday afternoon an operator running a tour on Freebo took a live booking about two hours before the activity started. Real customer, real card charged, real reservation on the calendar. Everything worked exactly the way the system was designed to work.
My first reaction was: how is that possible, two hours out?
That reaction is the entire post.
The feature that already existed
I dropped into the code fully expecting to find a gap. A missing check somewhere in the reservation flow. A TODO about cutoff windows that had been sitting there since November.
Instead I found this, in the availability cache service:

There are two entirely separate systems for saying “don’t let a customer book this close to the start time.” A product-level booking_cutoff_number and booking_cutoff_unit (minutes / hours / days) that any operator can set on the product itself. And a set of rule-based knobs — min_notice, lead_time, cutoff_time — that ride on the availability rules engine and can encode more nuanced things like “no bookings within 12 hours” or “must book by 5pm the night before.”
The cache layer even widens the live-refresh window based on the longest cutoff you’ve configured, so the calendar can’t lie to a customer about a slot that a cutoff has already killed.
The feature was there. All of it. Multi-tiered, well-tested, in production.
The operator just hadn’t set any of it.
Defaults are the product
Every SaaS person has heard some version of “the defaults are the product.” It’s the kind of line you nod at in a Twitter thread and then, a month later, ship a settings page with everything blank.
The two-hour booking was a very expensive way for me to hear it again.
If your platform ships with “unlimited” as the default, you are shipping a product that says: whatever happens is fine with us.
— the takeaway
Nobody on the operator side is going to open a settings page called “Booking Cutoffs” on Tuesday afternoon and thoughtfully model out how much time their captains need to prep the boat, load the coolers, get to the dock. That’s not a job anyone is doing at their desk. It becomes a job the first time a booking rolls in two hours before departure and someone on the ground is scrambling.
Which is a bad time to be learning about your booking software’s defaults.
What “sensible” looks like
There is no single right cutoff. A private fishing charter with a two-person crew needs different lead time than a walk-up parasail booth on a beach. But there is a right default, which is: something above zero. Something that forces a new operator to at least look at the number and either accept it or override it.
A short list of what I think that shakes out to:
- Product default: a nonzero
booking_cutoff_numberon every new product — I’m leaning toward 2 hours as the platform default, with a nudge to raise it during onboarding for anything crew-intensive. - Onboarding step: a required “how much notice do your captains need?” step during product setup. Not a settings tab you can skip — a step that stops setup until you answer.
- Booking widget copy: “Book at least N hours ahead” rendered from that same value, so the customer isn’t the first person surprised.
- Ops alert: any confirmed booking that lands inside a smaller window (say, 4 hours) fires an out-of-band notification to the operator, not just the standard confirmation. If it slips through, someone knows.
None of that is a new feature. All of it is the same fields, wired to different defaults and a different onboarding path. Which is the point — the feature was already the feature. What was missing was the product decision about what should happen when nobody makes a decision.
What I actually shipped
Before writing this post I made two small changes.
First, the new-product form now seeds booking_cutoff_number = 2 and booking_cutoff_unit = 'hours' when the operator creates a product without touching the field. Existing products aren’t retroactively changed — that would be quietly rewriting operator config, which is the wrong kind of “helpful.”
Second, a new alert channel: any reservation confirmed inside a 4-hour window fires a distinct “SHORT NOTICE” push to the operator, on top of the normal confirmation. That way, even for operators who have consciously chosen a tight cutoff, someone on the ground finds out fast enough to actually do something about it.
Both are boring one-liner changes. But this is what most of the work on a payments-and-scheduling SaaS looks like in year two — not new features, just closing the distance between what the system allows and what a reasonable operator would actually want.
The thing I keep re-learning
The interesting bugs in a mature product are almost never bugs in the code. They’re bugs in the defaults.
Somebody typed 0 into a database column three years ago and it’s been the answer ever since. Somebody made a settings page and forgot to think about the operator who ignores it. Somebody added a feature and never asked “what happens if this is off?”
I keep waiting for the day when I stop finding these. So far, every honest look at the product turns up two more.
The two-hour booking wasn’t a system failure. It was the system faithfully executing a decision that nobody had ever actually made.
Those are the ones worth writing down.