| 01 One origin, one entity | The canonical origin as a single environment variable, everything else derived from it, and a site-wide Organization plus WebSite graph with stable ids emitted as the first structured-data block on every page. | Entity consistency is how a machine decides two pages belong to the same organisation. Stable ids let every other node reference that entity instead of redescribing it — and one origin constant means a domain cutover can't leave the site quietly asserting two competing identities. | Shipped + verified |
| 02 Per-page metadata, everywhere | One shared builder returning the full metadata shape — canonical, robots, OpenGraph, Twitter — wired into all seven detail types rather than the one somebody got right first. | Canonical and noindex are how you stop an assistant learning the wrong URL for a fact. Half-wired, they silently do nothing, and the CMS fields behind them look functional while consuming editorial trust. | Shipped + verified |
| 03 A typed node per content type | One structured-data generator per document type, each emitting a single script with a graph rather than several competing ones. The itinerary pages — the crown jewel — had none at all before this. | A site-wide blob tells a consumer that a page exists. A typed node tells it what the page is and which fields hold the answer. That's the difference between 'a page about X' and an entity with extractable properties. | Shipped + verified |
| 04 Index pages as lists | CollectionPage plus ItemList on every index, capped to the top entries with the true count declared and an explicit ordering. | Without it an index is unstructured cards. With it, an assistant answering "which X does this company recommend" can reproduce a ranked list and attribute it. Ambiguous ordering makes a reproduced list wrong in a way nobody catches. | Shipped + verified |
| 05 Sitemap and a named crawler policy | A CMS-generated sitemap with per-entry last-modified dates, and a robots file naming sixteen AI crawlers explicitly alongside the wildcard. | Sitemaps are how crawlers find pages without waiting to follow links, and the last-modified dates feed the freshness signal assistants weight. The named allowlist is a statement of intent to operators who increasingly read silence as ambiguous. | Shipped + verified |
| 06 llms.txt | A plain-text root file, around 12KB, describing what the site is, where every machine-readable endpoint lives, and one summary block per significant page — capped so it stays ingestible in a single fetch. | Fetched directly by several assistants when they meet a domain. It's the one artefact that says what a site is FOR before a model starts inferring it from page titles. | Shipped + verified |
| 07 Endpoints that publish judgement | Three JSON endpoints under a versioned envelope with a generated timestamp, permissive CORS and a long shared cache — carrying the parts a competitor can't regenerate: a four-level supplier trust tier with strengths and weaknesses, and per-stop transfer-risk disclosure on itineraries. | A model can already assemble a list. It cannot synthesise dated, opinionated judgement from ten other sources. CORS matters more than it looks — without it, browser-based LLM tooling and MCP servers simply cannot read these at all. | Shipped + verified |
| 08 Freshness as a field | Per-answer last-updated dates mapped onto the structured data, and dated claims that render an "awaiting refresh" badge once they pass ninety days. | Recency is one of the few properties a retrieval layer can check cheaply, and an undated claim is hard to cite safely. Surfacing staleness in the UI is what makes the refresh actually happen. | Shipped + verified |
| 09 Rich-result surfaces on guides | FAQ and step-guide emitters, with the step emitter gated on a minimum heading count in code because the format is rejected below three. | Both are rich-result eligible and both are what an assistant reaches for on a direct question. The gate exists so the threshold is enforced by the build rather than by somebody remembering it. | Live, never fired |
| 10 Launch hooks and crawler verification | Search-console verification, sitemap submission, an IndexNow ping on publish, a structured-data validator in CI, and log analysis confirming AI crawlers actually fetch the endpoints. | The half that tells you whether the other nine worked. IndexNow pushes new URLs to Bing, Yandex and Perplexity in minutes rather than waiting to be crawled — and the log check is the only thing that can prove a crawler ever arrived. | Specified, not built |