Travel & Tourism// diagnostic

The draft packs an impossible day: constraining pacing without hard-coding

In short

A drafter produces impossible days because nobody supplied the constraints that would make a day impossible: component durations, transfer times for the actual vehicle, and a day budget with a latest arrival. Instructions to 'be realistic' do not survive a hard brief. A deterministic validator that rejects a day and names the assertion it broke does.

Key takeaways

  • Score a sample of drafts against a day budget first: the failures usually cluster by destination, which points at data, not the model.
  • A day budget has 6 lines, and most catalogues can supply only 2 of them without new work.
  • Deterministic assertions beat a model asked to judge feasibility, because a number either exceeds a limit or does not.
  • A retry must name the violated assertion and the day, or the model returns a differently impossible itinerary.
  • Cap retries at 2, then abstain and route the brief to a consultant with the constraint that could not be met.

The model was never given anything to violate. Ask where the 9 hours of driving came from and the answer is almost always that no transfer times were supplied at generation, the components carry no durations, and the day has no budget — so an itinerary with 6 stops is not breaking a rule, it is filling a blank. Prompt instructions about realism paper over that for easy briefs and fail on hard ones, which is exactly the wrong way round.

What routing and duration data can actually establish about feasibility — and where it stops being able to — is worked through separately in can a system tell that a day is impossible. This page assumes the answer and deals with the loop: measuring the failure, supplying the constraints, and rejecting the drafts that break them.

Score twenty drafts against a day budget before arguing about the prompt

A day budget is arithmetic, not judgement. Add up what the day actually consumes and compare it against the hours that exist. Do this over the last 20 drafts, mark each day as within or over budget, and group the overruns by destination — because that grouping decides which of 3 causes you have.

LineSourceWhat happens when it is missing
Moving time between stopsA travel-time matrix computed for the actual vehicle, or your own observed transfer timesThe single largest error. Drafts read plausibly and the coach arrives after dark
Time at each componentA duration field on the sellable componentActivity-dense days overrun even when the driving is short
Transition overhead per stopA constant you choose — parking, walking, gathering 12 people, ticket queueUnderestimates every multi-stop day by 20 to 30 minutes per stop
Meals and restFixed blocks by trip pace classLunch gets absorbed into the drive, which nobody on the trip agrees to
Check-out and check-inProperty terms, on days the trip changes hotelHotel-change days are the most commonly over-packed days in any catalogue
Day boundsEarliest start, latest arrival, driver hours where regulatedWithout a latest arrival, the arithmetic has no upper edge and never fails
The 6 lines of a day budget, and where each number comes from

Most catalogues can supply lines 4 and 6 immediately, because they are constants somebody chooses. The first 3 are the work. Skipping them and asking a model to estimate its own durations reproduces the original defect one layer down.

Three causes, told apart by how the failures cluster

  1. No travel-time data at generation. Signature: overruns correlate with distance, and the draft's own prose contains invented durations like 'about 3 hours' that match nothing in your system. This is the default state of most first builds.
  2. Components with no duration. Signature: overruns cluster on activity-heavy days rather than long-transfer days, and a query over the catalogue shows a large share of components with a null duration field. Check that share before anything else; it is usually worse than the team expects.
  3. The brief or the prompt asks for density. Signature: overruns spread evenly across destinations and move when the wording changes. 'A full itinerary', 'make the most of every day' and an eval that rewards more components all produce the same result.
  4. A fourth pattern is not a cause but a useful tell: overruns concentrated in 1 region usually mean thin data for that region rather than a general model failure, and the fix is a loading task for whoever owns that destination.

Assertions a day either passes or fails

Once the numbers exist, feasibility becomes a set of comparisons, and comparisons belong in code rather than in a second model asked for an opinion — the trade-off is set out in deterministic validation against a guardrail model. Run these after generation and before anything is rendered.

  1. Total moving time for the day is within the limit for the trip's pace class — a relaxed trip and a fast one carry different numbers, and both are configuration rather than opinion.
  2. Arrival at the final stop is no later than the day's latest arrival, computed forwards from the earliest start rather than assumed.
  3. Every consecutive pair of stops has a transfer in the matrix. A missing leg is not a short leg; it is an unknown, and unknown fails.
  4. No component is scheduled outside its operating hours, including the last-entry time, which is earlier than closing at most visited sites.
  5. Component count for the day is within the pace class limit, counted as paid or ticketed components rather than as lines of prose.
  6. Unscheduled buffer is at least the configured share of the day. A day timed to the minute is a day that fails on the first delay.

Two retries, then hand it to a consultant

The loop is short by design. Regenerate with the violated assertion and the offending day pinned in the instruction, keep the days that passed, and cap the attempts at 2. Beyond that the retries stop converging: a brief asking for 4 regions in 8 days is not a generation problem, and 6 more attempts will not discover a shorter road.

  • Regenerate the failing day only, holding the rest of the trip fixed, so a retry cannot quietly rewrite days a reviewer already accepted.
  • Escalate with the constraint that could not be met, not with an apology. The abstention path and what the handoff should contain is modelled in when the drafter should refuse to draft.
  • Log every violation with the brief identifier, the destination and the assertion. Over a month that log is a ranked list of missing durations and missing transfer legs — the most useful backlog this system produces.
  • Report the retry rate as an operational metric. A rate climbing after a catalogue import usually means new components landed with null durations.
  • Trace a single brief end to end when the loop misbehaves, in the manner of one brief run through a grounded drafter, rather than reasoning about the aggregate.

A model asked to be realistic will be realistic on the briefs that were easy anyway. A validator that fails a day at 9 hours 10 minutes against a 6-hour limit is realistic on the brief that pays for the trip.

Where the durations and transfer times come from

This is the part teams postpone, and the whole loop is worthless without it. Durations belong on the sellable component alongside season and region — the unit argued for in indexing your own products so a model can find them — and transfer times belong in a matrix built for the vehicle that will actually do the drive.

  • Use your own observed transfer times wherever you have them. Operations records what a transfer really took, and a coach with 20 passengers, a driver break and a comfort stop does not match a car-profile estimate.
  • Where you have no observations, take a routing estimate and apply a per-region correction factor derived from the transfers you have measured. Record which of the 2 sources produced each number.
  • Model the transfer as a component in its own right rather than a gap between components. The reasoning is in what a dispatch build taught us about transfer days, which is our own build in a neighbouring domain and says so plainly.
  • Make pace a parameter with 3 or 4 named classes, not a hard-coded number. A trekking group, a family with young children and an incentive group have different limits on the same road.
  • Keep the limits in configuration a consultant can change, with the change recorded. Pacing rules are commercial judgement, and burying them in code guarantees they go stale.

What a feasible day still gets wrong

Passing every assertion means the day is possible, which is a lower bar than good. A day can be within budget and still be 3 mediocre stops in a row, or 4 hours of driving with the interesting hour placed after everyone has stopped looking out of the window. That judgement stays with the consultant, and no amount of validation replaces it.

  • Client-specific limits are not in the catalogue. Reduced mobility, small children, a group that will not tolerate an early start — these arrive in the brief and belong in the pace class chosen for that trip.
  • Local conditions beat the matrix. Market day, a religious procession, a road being resurfaced: the ground operator knows and your matrix does not.
  • Feasible is not sellable. A validator has nothing to say about whether a day is worth paying for, which is why the review step exists.
  • The general pattern here — a mechanical check placed immediately before something irreversible — is the same one used at commitment time in putting a price recheck between basket and charge, and it is worth building both for the same reason.

None of this is large. A day budget, 6 assertions, a bounded retry and a violations log is a fortnight of work in most stacks, and it is the difference between a drafter that saves a consultant an hour and one that costs them 2 checking it. That is the shape of most MVP and product builds in this area, and the rest of the guardrail set — grounding, seasonality, provenance, review — sits in letting a model draft the trip within our wider travel and tourism work.

Frequently asked questions

Short answers to the follow-ups this page tends to raise.

Why does telling the model to keep days realistic stop working?

Because it never worked on the briefs that matter. An instruction shifts the output distribution, so it holds on ordinary requests and collapses on the constrained ones — a long distance, a short trip, a region with thin data — which are precisely the briefs where an impossible day is expensive. A limit the system can compute either holds or fails, and it fails visibly.

Should a second model check feasibility instead of a validator?

No, for anything that reduces to a number against a limit. Moving time, arrival time, component count and operating hours are comparisons, and code does them identically every run at negligible cost. Keep model judgement for the questions that are genuinely qualitative, such as whether a day is varied or well shaped, and even then treat the output as advice for a reviewer.

How many retries should a failing draft get?

Two, then escalate. Retries help when the model has an alternative available and a specific violation to work with, and stop helping when the brief itself is infeasible — 4 regions in 8 days does not become possible on the fifth attempt. Cap it, hand the brief to a consultant with the constraint that failed, and log the case so the pattern is visible.

We have no transfer-time data at all. Where do we start?

With the transfers your operations team already runs, because you have the real numbers in your own records. Extract observed durations for your busiest 50 routes, use a routing estimate with a regional correction factor for the rest, and record which source each number came from. Partial data plus a validator beats complete data that never arrives.

  • pacing
  • validation
  • itinerary drafting
  • guardrails
// shipped work

The work behind this page

Builds from our portfolio that this page draws on.

Read next

Working on something in this space?

Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.

Start the conversation