Every few weeks somebody sends me an "AI readiness score" for a website. It is always red. It never explains what the missing items would actually do for that site, and it never distinguishes between two completely different situations: You have not published an emerging protocol. You have published one, and it does not work.
The first is usually an observation. The protocol may not apply to your site, its adoption may be negligible, real agents may not touch it, and waiting may be the correct decision. The second is a genuine defect: an agent card advertising an endpoint that answers nothing, a discovery document that is not discoverable, a required field that is missing.
Collapsing those two into one number is how you manufacture urgency. A low score creates panic without explaining whether anything is at stake. A high score hides real breakage, because unrelated features compensate for broken ones. Both are dishonest, and both are commercially convenient, which is presumably why they are everywhere.
There was a second motivation, closer to home. The people who want these technologies are usually SEOs and content teams. The people who can ship them are engineers with a roadmap full of platform work. So a finding sits in a backlog for two quarters, or an agency charges a lot of money for a file that takes ten minutes to write. Telling someone what is broken is only half a product. I wanted the other half.
The core is a Lumar custom metric container (inputType: Puppeteer), organised into six categories:
| Category | Technologies | |---|---| | Discoverability | 4 | | Content | 4 | | Access | 6 | | Capabilities | 7 | | Commerce | 6 | | Trust | 3 |
Thirty technologies in total. 23 are scored. 7 are watched and deliberately not scored. That split is the product, not an implementation detail.
The rule that falls out of this is the one the whole container rests on: if a technology is not present, the collector computes nothing and emits nothing. Not Present: false. Nothing at all. There is no point validating, storing, or reporting anything about a technology a page never adopted.
That produces 309 per-URL metric fields and 185 site-wide fields, backed by 111 catalogued defects. Every defect names the clause and the revision it comes from, and whether the authority is a standard or a Lumar recommendation. We do not borrow a specification's authority for our own preferences, and the catalogue makes that distinction machine-readable rather than a matter of tone.
Page-level signals (canonical, JSON-LD, server-side rendering, Markdown twins, WebMCP) vary per URL and are read in the request handler. Site-wide signals (robots.txt, ai.txt, /.well-known/, live protocol probes) are one fact per host, so they run once per host in a postCrawl handler and emit a crawl-level item. Nine site-wide signals, one row per host per signal.
Getting this wrong is expensive. Fetch a well-known file once per URL and a 50,000-page crawl knocks on somebody's server 50,000 times for a file that has not changed.
This is where most of my early false positives came from, so it is now a hard rule.
A fetch outcome is a discriminated union: complete, truncated, absent, unreachable. Only complete carries content, so a body we stopped reading at a byte cap cannot be handed to an analyzer, because the type does not expose it.
Only an HTTP response proves absence. A 4xx or 5xx is the server saying "not here". Everything else, our own timeout, a spent budget, a reset connection, a blocked destination, is us failing to look, and must map to that signal's "unassessed" state.
Collapsing those convicts a site of our own timeout. That is the exact false positive this container exists to avoid, and the type system now refuses to let me write it.
Two registries that answer different questions src/defect-catalog/ says what can go wrong with a technology and on whose authority. One entry per emitted flag. src/tech/ says what the technology is: name, summary, adoption level, named adopters, the documents it is pinned to, the fixtures that demonstrate it.
Everything public is generated from that pair. The scanner, the documentation pages, the survey tables, and the report catalogue all come out of the same two files, so they cannot disagree with the code. When I add a defect, its documentation, its report column, and its public reference page appear because they are derived, not because I remembered to update three places.
These are emerging standards. MCP has shipped multiple revisions. Content Signals appeared and gained real adoption inside a year. Proposals turn up with a website, a GitHub repo and an enthusiastic announcement, and some of them die quietly.
