How customer ETAs get sent
The route saves the business miles; the ETAs save the customer a wasted afternoon by the door. This post is about the outbound side: how the planner sends each customer a sensible arrival window, the one place a model is allowed near the system, and how a driver tapping ‘done’ on one stop quietly slides everyone else’s ETA earlier or later so the windows stay true as the day runs.
Key takeaways
- Each customer gets one arrival window for their stop — “due between 10:30 and 11:30” — not a raw clock time.
- The window is computed from the route and the average stop time; a model only turns the numbers into a friendly sentence.
- Driver check-offs flow back through EventBridge, and the remaining ETAs are recomputed from where the van actually is.
- ETAs go out by SES email for free, or SMS through SNS where the per-message carrier fee is worth it.
- It only ever sends a window. It can’t reschedule or cancel; a slipping round triggers an update, not a decision.
A window, not a time
The route already knows, near enough, when the van reaches each stop: walk the order forward from the depot start time, add the travel time from the matrix and the average minutes spent at every earlier stop, and you have a planned arrival for stop n. The planner never tells a customer that exact minute, though, because no round survives contact with traffic and a single missing parking space. It tells them a window — the planned arrival, widened by a sensible buffer on each side — so “arrives 10:52” becomes “due between 10:30 and 11:30.” A window the van comfortably hits beats a precise time it misses by four minutes; the buffer is the difference between a customer who trusts the messages and one who stops reading them.
The numbers — the window, the stop position, the customer’s name and address — are all computed by the same plain code that built the route. The only thing left is to say it like a person. That’s the one job handed to a model.
The one place a model runs
For each customer, a single Bedrock Claude Haiku 4.5 call is given the already-computed facts — business name, customer name, the window, and whether this is the first notice or an update — and asked to write one short, friendly message in the business’s voice. It is told, firmly, to use only those facts: invent no times, promise no specifics beyond the window, add no apology the business didn’t ask for. The model never sees the route, never computes a time, and never decides who gets a message; it dresses numbers it was handed. If you’d rather not run a model at all, the same facts drop straight into a fixed template — “Hi {name}, your delivery from {business} is due between {from} and {to} today” — and the system works identically, a little less warmly. The model is a convenience on the wording, never a dependency on the logic.
drp-eta computes a window per stop and Bedrock writes the sentence; SES or SNS sends it. When the driver checks a stop off, the event flows through EventBridge and the remaining windows are recomputed from where the van actually is.Keeping the window honest
A window sent at 6am and never touched again is a lie by lunchtime. The planner keeps it honest with the check-offs from Part 4. Every time the driver marks a stop done, that tap becomes an EventBridge event — stop, van, the actual time it was completed — and the ETA function picks it up. It now knows two things the morning plan only guessed: which stops are genuinely finished, and what time it really is. So it re-walks the remaining stops from the van’s current position and the current clock, producing fresh windows for everyone still waiting.
Most of the time the change is small and no message goes out — a window that moves four minutes isn’t worth a buzz in someone’s pocket. But when the round has slipped enough that a later customer’s window has genuinely moved — the van is half an hour down after a bad stretch — that customer gets one updated message: “running a little behind; your delivery is now due between 14:15 and 15:15.” The threshold for sending an update is a setting, so a business can choose how chatty it wants to be. The customer who took the morning off to wait in finds out at 1pm that it’ll be after lunch — from a text, not from staring out of the window.
Email is cheap; SMS when it counts
Two channels carry the messages. SES email is effectively free and fine for the many customers who’ll be near a phone anyway. SMS through SNS lands more reliably and gets read faster, which matters for a tight window or a customer who has to physically be there to receive — but each text carries a per-message carrier fee that sits outside the AWS bill (Part 6 is careful about this). So the channel is a per-customer choice driven by the settings doc and the data on the stop: a flagged “text me” preference, or a stop with a narrow window, gets an SMS; the rest get email. Either way it’s one message per customer per change, never a stream.
And the boundary is firm: the ETA side only ever tells. It can’t move an appointment, can’t cancel a stop, can’t promise a redelivery. If a customer replies “I won’t be in,” that’s a human’s job to handle — the reply lands with whoever runs the round, with the stop and the round attached. A slipping route makes the planner send a new window; it never makes the planner make a decision.
Why this shape
- Send a window, not a minute. A buffered window the van hits keeps customers trusting the messages.
- The model only writes. Bedrock turns computed numbers into a sentence; swap in a template and lose nothing structural.
- Check-offs keep it true. Each “done” event recomputes the remaining windows from where the van really is.
- Quiet unless it matters. A window moves silently until it crosses a threshold; then one update goes out, never a stream.
- Tell, never decide. The ETA side can’t reschedule or cancel; anything that needs a choice goes to a person.