The gates: what this site refuses to ship
Updated 2026-09-04
Before any change to this site is committed, the build runs 110 automated refusals over the rendered output. Each one names a specific way a page can be wrong — a link to nothing, a title that will be truncated, a dataset whose CSV disagrees with its JSON, a link to the company that funds this site with no disclosure beside it. A failed gate is not a warning: the suite exits non-zero and the site does not deploy until the underlying problem is fixed. Weakening a gate to make a change pass is not allowed, which is the only reason a list like this is worth publishing.
The gates are one half of how this site is checked. The other half — primary sources, adversarial review, and what happens when we cannot verify something — is in methodology. When something gets through anyway, it goes in corrections, alongside the errors these gates caught before publish.
Content integrity (10)
| Code | What the build refuses to ship |
|---|---|
DUP-FAQ | The same question answered in the FAQ data of two pages, where the two entries would compete in one rich result. |
MATRIX-INCOMPLETE | The HealthKit-to-Health-Connect type table with any row missing its Apple or its Android identifier. |
APIS-COUNT | An API directory with a different number of product pages than there are products in the cost model. |
APIS-MISSING | A build in which a product named by the cost model has no directory page. |
APIS-NO-COVERAGE | A directory page that lists no pages covering its product, which is a thin page pretending to be an entity. |
TOOLS | A build where an interactive tool page has dropped out, which nothing else would notice because the tools have no data file behind them. |
GATE-UNDESCRIBED | A gate that exists in the build but is described nowhere on this page, which would make the published list an understatement. |
GATE-STALE | A row on this page describing a gate the build no longer runs. |
GATE-PAGE-MISSING | A build where this page did not render its table of gates at all. |
GATE-PAGE-ROWS | A rendered gates table holding a different number of rows than there are described gates. |
Links and anchors (11)
| Code | What the build refuses to ship |
|---|---|
PHANTOM-LINK | A page carrying an internal link to a URL that no built page answers. |
LINK-TO-404 | A site that links to a route which builds a file but renders notFound() to the reader. |
ORPHAN | A published page that no other page on the site links to. |
QUESTIONS-HUBS | A build where a cluster stops generating its /questions index and a whole topic disappears from the list. |
QUESTIONS-DEAD-ANCHOR | A question-index deep link whose FAQ anchor no longer exists on the page it points into. |
FACTS-NO-ANSWERS | A build with no answers.json to resolve published fact citations against. |
FACTS-ANSWERS-INVALID | An answers.json that does not parse when the citation anchors are checked. |
FACTS-MISSING | An answers.json with no facts section, so the citable fragment URLs are not published at all. |
FACTS-NO-FRAGMENT | A published fact whose id has no fragment, leaving nothing precise for a machine reader to cite. |
FACTS-NO-PAGE | A published fact pointing at a page that is not in the build output. |
FACTS-DEAD-ANCHOR | A published fact whose fragment does not resolve on the page it points into, which would break every citation already made to it. |
Metadata (6)
| Code | What the build refuses to ship |
|---|---|
TITLE-* | A page whose rendered title tag is longer than 60 characters and would be truncated in results. |
DESC-* | A page whose meta description is longer than 155 characters. |
NO-CANONICAL | A page with no rel=canonical link telling crawlers which URL is the real one. |
NO-OG-IMAGE | A page with no og:image, which would share as a blank card everywhere it is linked. |
DUP-TITLE | Two pages shipping the identical title tag, so neither can be told apart in a result list. |
DUP-DESC | Two pages shipping the identical meta description. |
Structured data / GEO (17)
| Code | What the build refuses to ship |
|---|---|
BAD-JSON-LD | A page carrying a JSON-LD block that does not parse as JSON. |
MULTI-BREADCRUMB | A page emitting more than one BreadcrumbList, which makes its breadcrumb trail ambiguous. |
APIS-NO-ENTITY | A directory page with no SoftwareApplication node identifying the product it describes. |
GEO-NO-ROBOTS | A build with no robots.txt in its output. |
GEO-ROBOTS | A robots.txt that does not explicitly allow each named AI crawler. |
GEO-ROBOTS-SURFACE | A robots.txt that does not point crawlers at llms.txt, answers.json and the changes feed. |
GEO-NO-ANSWERS | A build with no answers.json in its output. |
GEO-ANSWERS-INVALID | An answers.json that does not parse as JSON. |
GEO-ANSWERS-COUNT | An answers.json holding a different number of records than there are cluster spokes. |
GEO-ANSWERS-FIELDS | An answers.json record missing its question, answer, URL, markdown mirror or last-reviewed date. |
GEO-NO-MD-ALT | A hub or spoke with no rel=alternate link advertising its markdown mirror. |
GEO-NO-DESCRIBEDBY | A hub or spoke with no rel=describedby link to its structured description. |
GEO-NO-COLLECTIONPAGE | A cluster hub with no CollectionPage or ItemList describing what it collects. |
GEO-NO-FAQPAGE | A spoke page with no FAQPage data, unless it is a post that explicitly opted out. |
GEO-NO-SPEAKABLE | A spoke page that names no speakable section for voice and assistant surfaces. |
GEO-NO-TECHARTICLE | A spoke page with no TechArticle node identifying it as documentation. |
GEO-NO-FAQ-ANCHOR | A page publishing FAQ data whose answers carry no per-answer anchor, so an assistant cannot deep link the one it quoted. |
Feeds and mirrors (30)
| Code | What the build refuses to ship |
|---|---|
GEO-NO-MD-MIRRORS | A build with no /md markdown mirrors at all, leaving machine readers nothing clean to fetch. |
GEO-MIRROR-COUNT | A build where the number of markdown spoke mirrors does not match the number of spoke pages. |
GEO-HUB-MIRRORS | A build missing a markdown index for a cluster, or the site index mirror. |
GEO-MD-FRONTMATTER | A markdown mirror that does not open with the YAML front matter a parser reads instead of prose. |
GEO-MD-CANONICAL | A markdown mirror whose front matter does not name the canonical URL of the page it mirrors. |
GEO-MD-REWRITE | A cluster missing from the rewrite list, which would make its conventional /cluster/slug.md addresses 404. |
GEO-NO-LLMS | A build with no llms.txt in its output. |
GEO-LLMS-MISSING | A spoke page that llms.txt does not list, so a model reading the index never learns it exists. |
GEO-LLMS-SURFACE | An llms.txt that fails to advertise the answers, changes and full-text surfaces. |
GEO-NO-CHANGES-FEED | A build with no changes.xml in its output. |
GEO-CHANGES-FEED-EMPTY | A changes feed that contains no items. |
ICS-MISSING | A build with no changes calendar in its output. |
ICS-EMPTY | A changes calendar containing no events. |
ICS-PARITY | A changes calendar holding a different number of events than the changes feed holds items. |
ICS-UNTERMINATED | A calendar file with no END:VCALENDAR, which a strict client will reject outright. |
ICS-FOLD | A calendar file with lines over the 75-octet limit the format allows. |
ICS-LINE-ENDINGS | A calendar file that is not CRLF-terminated as the format requires. |
FEED-COUNT | A build with a different number of per-cluster RSS feeds than there are populated clusters. |
FEED-EMPTY | A cluster feed that contains no items. |
FEED-NO-SELF | A cluster feed with no self link, so readers cannot tell where it lives. |
FEED-UNESCAPED-AMP | A feed containing a raw ampersand outside CDATA, which breaks strict readers. |
FEED-NO-JSON | A build with no feed.json in its output. |
FEED-JSON-VERSION | A feed.json that declares no JSON Feed version, so conforming clients will not read it. |
FEED-JSON-ITEMS | A feed.json with no items array. |
FEED-JSON-INVALID | A feed.json that does not parse. |
NO-OPENSEARCH | A build with no OpenSearch descriptor in its output. |
OPENSEARCH-TARGET | An OpenSearch descriptor that does not point at the site's own results page. |
NO-MANIFEST | A build with no web app manifest in its output. |
MANIFEST-FIELDS | A web app manifest missing its name, start URL or icons. |
MANIFEST-INVALID | A web app manifest that does not parse as JSON. |
Datasets and artifacts (12)
| Code | What the build refuses to ship |
|---|---|
DATASET-UNGATED | A dataset published under /datasets that no check in the QA suite covers. |
DATASET-MISSING | A build where a dataset the site advertises has no JSON or no CSV file on disk. |
DATASET-EMPTY | A dataset file whose items array is empty, which a generator can produce silently. |
DATASET-NO-LICENCE | A dataset published without the licence field that tells a reuser what they may do with it. |
DATASET-CSV-ROWS | A dataset whose CSV export carries a different number of rows than its JSON. |
DATASET-INVALID | A dataset JSON file that does not parse. |
KIT-MISSING | A build where a file in the downloadable decision kit is absent. |
KIT-EMPTY | A kit file that exists but is zero bytes. |
KIT-UNGATED | A file published under /kit that no check in the QA suite covers. |
DATASET-NO-MANIFEST | Datasets published without the manifest that records their hashes and row counts. |
DATASET-UNMANIFESTED | A dataset the manifest does not cover, so its changes never show up in the published diff. |
DATASET-MANIFEST-STALE | A manifest whose recorded byte sizes disagree with the dataset files actually on disk. |
Disclosure (3)
| Code | What the build refuses to ship |
|---|---|
KINESTEX-NOTE | A build where the disclosed first-party link renders on a different number of pages than the map declares. |
KINESTEX-UNDISCLOSED | A page linking to the site's funder without the funding disclosure beside it. |
FIRSTPARTY | A page whose prose features the site's funder three or more times with no funding disclosure anywhere on it. |
Blog (14)
| Code | What the build refuses to ship |
|---|---|
POST-FRONTMATTER | A post file with no YAML front matter. |
POST-NO-TITLE | A post whose front matter declares no title. |
POST-TITLE-* | A post title over 45 characters, which overflows the tab once the site suffix is appended. |
POST-NO-DESC | A post whose front matter declares no description. |
POST-DESC-* | A post description longer than 155 characters. |
POST-NO-DATE | A post with no publication date in its front matter. |
POST-NO-UPDATED | A post with no last-updated stamp in its front matter. |
POST-NOT-BUILT | A live post that silently stopped building and would be invisible rather than broken. |
POST-FAQ-RENDER | A build where the number of posts rendering their FAQ block does not match the number that declare FAQs. |
POST-PLACE-PARSE | A build in which the blog placement map cannot be read out of the component source, so neither half of the placement check can run. |
POST-PLACE-SLUG | A placement pointing at a post slug that is not a live post. |
POST-PLACE-PATH | A placement that would surface a post on a page which does not exist. |
POST-LINKS | A build where the blog link block renders on a different set of pages than the placement map declares. |
POST-EXEMPT-CREEP | More than two posts opting out of the FAQ requirement, which would turn an announcement exemption into the default. |
Derived blocks (7)
| Code | What the build refuses to ship |
|---|---|
REFERENCE-CALLOUT | A build where the reference callout renders on a different number of guides than the map declares, which is how a renamed slug drops it. |
APP-STACK | A build where the derived type-and-API stack block is missing from any /build guide that should carry it. |
HK-GROUP-COVERAGE | A set of HealthKit group pages that does not carry every identifier in the dataset exactly once. |
HK-GROUP-PARTIAL | A build where only some of the HealthKit group pages were generated. |
METRIC-FACTS | A /data guide that quietly lost its derived HealthKit facts block because the join behind it stopped matching. |
ARCH-DIAGRAM | An /architecture page publishing without its hand-drawn mechanism figure. |
ARCH-DIAGRAM-LEAK | The architecture diagram marker appearing on any page outside the /architecture cluster. |
What the gates cannot do
Every check above tests form, not truth. A rate limit copied wrong from a vendor page, a benchmark recalled from memory, a deprecation date off by a quarter — each of those is a well-formed sentence on a well-formed page, and it would pass all 110 of these gates without a murmur. Nothing automated catches a claim that is simply false. That is what the verification rules in methodology are for: primary sources fetched at write time, unverifiable claims marked rather than filled in, and dated review stamps you can hold us to. The gates make the mechanical failures impossible. They do not make us right.