Our first law is that the model never states a fact. That is an architectural commitment, and architecture drifts. So it is also enforced at a checkpoint: every section, as it comes back from the model, is run through a set of validators written in plain code before it is persisted or shown to anybody.
There are ten. Each is a pure function of the section and the verified context it was built from, and each has one of three outcomes: fix it silently, send it back to the model once with the error attached, or degrade the section into a card that says it could not be verified.
The ten
- Entity grounding — every reference in the section must point at a place in the verified set. Unreferenced ones are dropped; if too few survive, the stage is retried with the offending ids named. It also scans the prose for capitalised venue names that are not in the set at all, which is how an invented restaurant would slip past a clean reference list.
- Budget math — the total is recomputed from the lines. Contingency is recalculated as a percentage of the subtotal. Absurd amounts are clamped and flagged. The model is never retried over arithmetic, because arithmetic is not its job.
- Best-time score — overwritten with the code formula from the climate data, so the score can never disagree with the temperature and rainfall printed next to it.
- Visa integrity — the visa section is rebuilt from the verified row verbatim and anything the model wrote for it is discarded. Then every other section is scanned for visa claims and any sentence making one is stripped.
- Phrases from seed — the local phrases come from a seeded table for the destination's language. No seed, no phrases block. A model inventing a phrase in a language you are about to speak to a stranger in is a specific kind of embarrassing.
- Cross-section dedupe — the same place appearing in dining, attractions and activities is kept once, in section order.
- Estimate labelling — every price note must carry estimate wording, or the label is appended. The flights disclaimer is forced to one canonical sentence rather than whatever phrasing came back.
- Day count — a ten-day request that came back with eight days is retried with the count stated.
Why fixing beats retrying
Only two of the ten ever go back to the model. That ratio is the point. A retry costs seconds the reader is watching tick by, and it re-rolls the dice on a section that was otherwise fine — you can lose good prose fixing a subtotal.
So anything a computer can settle, a computer settles: sums, scores, labels, duplicates, links. The model is only asked again when the section is structurally wrong in a way code cannot repair without writing content itself — a day missing from an itinerary, or a set of references so thin there is nothing left to arrange.
A validator that has never fired is either unnecessary or untested. Knowing which is worth the logging.
The checkpoint is also the dashboard
Every firing is logged. That turns the validator layer into the only honest quality metric we have: not whether plans look good, but how often the checks had to intervene, and which ones.
It is how we know where prompts are weak, which stages drift, and whether a model change made things better or quietly worse. A rise in grounding failures after a provider switch is a fact about that provider, visible the same day rather than in a support email three weeks later.
And when a section still cannot pass after its one retry, it renders as a card saying so, and the plan is marked partial. That card is not a failure of the design. It is the design doing the only thing that keeps the other nine sections worth reading.
Put it to the test
Every claim in this post is something you can check on a real plan. One sentence is enough to start one.