Check criteria reference - scanner v1.24.0

Versioned HonestClaw scanner check criteria. Source of truth is the Acc-generated check-reference markdown for this scanner version.

Markdown source

Criteria

# Check criteria reference — scanner v1.24.0

- scanner_version: 1.24.0
- Provenance: regenerated and diff-verified against the code in this commit by the contract test; see this file's git history.

Generated by `scripts/generate-check-reference.ts` from the check registry (`src/scanner/checks`). Do not edit by hand; regenerate after any rungs change. Graded structure (declared rungs, weights, categories, totals) is immutable per scanner version and requires a SCANNER_VERSION bump (A1 invariant); criteria sentences may be completed or corrected in place at the same version (delete the file and regenerate), because the CI drift test guarantees the committed document matches the code either way.

## State points

A check contributes `STATE_POINTS[state] / 100 × maxPoints` (`src/scanner/types.ts`):

| State | Points (of 100) |
|---|---|
| unknown | 0 |
| not_detected | 0 |
| detected | 10 |
| parseable | 35 |
| useful | 70 |
| high_confidence | 100 |

## Global negative-rung semantics (applies to every check)

A check's positive rungs (`detected` and above) are earned by its own grading
code, summarized per check below. When no clean positive signal is found, the
shared classifier (`src/scanner/classify-state.ts`) resolves the state from
the most informative HTTP outcome across the paths the check probed:

| Winning outcome | Resolved state |
|---|---|
| 2xx without the check's signal | `not_detected` |
| 401 / 403 (gated) | `detected` for existence-kind checks (the gate proves something is there); `unknown` for content-kind checks (the content cannot be assessed) |
| 404 / 410 | `not_detected` |
| 429 / 5xx / other reached status | `unknown` |
| status 0 (timeout / network / SSRF) | `unknown` |
| nothing probed / reachable | `unknown` |

**Honest-exhaustion rule**: a `not_detected` conclusion requires complete
evidence. When the scan's fetch/render budget latched before the check
resolved, a would-be `not_detected` resolves `unknown` instead (out of the
score denominator, lowers confidence). Positive evidence always stands.

**Orchestration overlays** (`src/scanner/scoring.ts`) can additionally force
two states onto ANY check after it returns, beyond its declared rungs:

- `not_detected` — a robots.txt `'*'`-baseline block on a surface the check
  needed forces a conclusive `not_detected` (`stampRobots`); a compliant
  generic agent is locked out, so the surface is a real gap.
- `unknown` — the runtime-budget truncation demotion, the no-work-item
  fallback, and the fail-open error catch all resolve `unknown`.

These two states form the globally assignable envelope
(`GLOBALLY_ASSIGNABLE_STATES` in `classify-state.ts`).

## Checks by dimension

"Reachable states" are the check's declared `rungs` keys — every state its own grading code can resolve to (the global envelope above can additionally force `not_detected`/`unknown`). "Cap" is the highest declared state; "effective max" is `maxPoints × STATE_POINTS[cap] / 100`, the most the check can actually contribute.

### discoverability

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| api-existence | 5 | yes | unknown, not_detected, detected, parseable | parseable | 1.75 | Checks whether the domain exposes an API endpoint. |
| api-versioning | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether the API uses versioned endpoints. |
| api-catalog | 3 | yes | unknown, not_detected, detected | detected | 0.3 | Checks whether the domain publishes an RFC 9727 API Catalog at /.well-known/api-catalog. |
| robots-txt | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the site publishes a valid robots.txt that declares a sitemap. |
| sitemap-xml | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the site publishes a valid, machine-readable XML sitemap. |
| canonical-domain | 2 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Checks whether the site resolves to one canonical origin (root/www convergence, canonical tag). |
| subdomain-sweep | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether agent-relevant surfaces live at conventional subdomains (api.*, docs.*). |

Dimension totals (scored checks): maxPoints 24, effective max 18.05.

Rung criteria:

- **api-existence**
  - `unknown`: The locations where an API would show itself could not be read during the scan (no response or only temporary errors), so API presence could not be judged.
  - `not_detected`: The conventional API paths and spec locations checked returned only regular web pages, missing-page responses, or errors, with no sign of an API.
  - `detected`: Something API-shaped is present: an API path returned an authentication challenge or a non-HTML response, or a spec-like document exists that does not declare both servers and paths.
  - `parseable`: A published spec declares its servers and paths, or a conventional API path serves structured JSON rather than a web page.
- **api-versioning**
  - `unknown`: The spec, API responses, and documentation pages where version information would appear could not be read during the scan, so versioning could not be judged.
  - `not_detected`: No version information was found in the API spec, in response headers, in URL paths, or on the documentation pages checked.
  - `detected`: A version appears only in an API URL path (such as /v1), or versioning is mentioned, but not on a dedicated documentation page whose title or heading names the topic.
  - `parseable`: The API declares its version in its spec (info.version) or returns it in a version header, or a dedicated versioning page exists that does not yet describe the versioning scheme.
  - `useful`: A documentation page dedicated to versioning describes how the API is versioned.
  - `high_confidence`: The versioning documentation also describes what happens to old versions (deprecation, sunset, or retirement).
- **api-catalog**
  - `unknown`: The /.well-known/api-catalog path could not be read during the scan (no response, a temporary error, or an access restriction), so the catalog could not be checked.
  - `not_detected`: No API catalog was found at /.well-known/api-catalog or at a location announced in a Link header.
  - `detected`: The site serves an API catalog as JSON at /.well-known/api-catalog (RFC 9727) or at a location announced in a Link header.
- **robots-txt**
  - `unknown`: The /robots.txt file could not be read during the scan (no response, a temporary error, or an access restriction), so its presence could not be judged.
  - `not_detected`: Requesting /robots.txt returned no robots file (a missing-page response, an error, or an HTML page in its place).
  - `detected`: A non-HTML file is served at /robots.txt, but it contains no recognized robots directives.
  - `parseable`: The site serves a robots.txt that parses as a valid robots file (at least one User-agent group), but it does not declare a sitemap.
  - `useful`: The robots.txt declares at least one Sitemap URL.
  - `high_confidence`: A Sitemap URL declared in robots.txt also loads and parses as valid sitemap XML.
- **sitemap-xml**
  - `unknown`: The standard sitemap locations could not be read during the scan (no response, a temporary error, or an access restriction), so no conclusion was recorded.
  - `not_detected`: No valid XML sitemap was found at the standard locations or at any address declared in robots.txt.
  - `detected`: A sitemap location returned XML, but it does not parse as a valid urlset or sitemap index with page locations.
  - `parseable`: The site serves a valid XML sitemap, though its entries carry no last-modified dates or list only the homepage.
  - `useful`: The sitemap lists pages beyond the homepage and includes last-modified dates for them.
  - `high_confidence`: The dated sitemap also lists documentation, pricing, API, or developer pages among its URLs.
- **canonical-domain**
  - `unknown`: The root address could not be reached during the scan, so the site's canonical host could not be observed.
  - `not_detected`: Neither the root address nor the www address resolved to a usable homepage (both returned missing-page or error responses).
  - `detected`: The root address responds, but the root and www addresses do not settle on a single host (or the www side could not be assessed).
  - `parseable`: The root and www addresses resolve to the same single host.
  - `useful`: The root and www addresses resolve to the same host, and the homepage includes a canonical link tag.
  - `high_confidence`: The canonical link tag on the homepage names the same host that the root and www addresses resolve to.
- **subdomain-sweep**
  - `unknown`: The conventional subdomains could not be probed conclusively during the scan (lookups failed or only temporary errors came back), so their presence could not be judged.
  - `not_detected`: None of the conventional subdomains checked (api.*, docs.*, developer.*, dev.*) is live.
  - `detected`: At least one conventional subdomain (api.* or a docs-family host) is live, or one answered with an access challenge.
  - `parseable`: A live conventional subdomain serves the kind of content its name indicates (an api host serving non-HTML data, or a docs host serving pages).
  - `useful`: Both an api-family subdomain and a docs-family subdomain are live.
  - `high_confidence`: Both an api-family and a docs-family subdomain are live, and each serves the kind of content its name indicates.

### content_accessibility

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| llms-txt | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether the domain publishes an llms.txt file for LLM consumption. |
| llms-full-txt | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the domain publishes an llms-full.txt file with comprehensive inline LLM-readable content. |
| markdown-twin | 3 | yes | unknown, not_detected, detected, parseable | parseable | 1.05 | Checks whether a markdown twin (.md) is published alongside docs HTML pages (V1 detection only). |
| ai-txt | 2 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Checks whether the domain publishes an ai.txt file declaring AI crawler policy. |
| raw-content-extractability | 8 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 8 | Checks whether meaningful content is extractable from raw HTML without JavaScript (not behind a JS shell, with usable main content). |
| freshness-signals | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the site publishes freshness signals (Last-Modified, ETag, sitemap lastmod) for content. |
| crawl-cost-estimate | 2 | no (informational) | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Estimates crawl cost legibility from sitemap URL count and robots.txt Crawl-delay directives (informational — discoverability checks own sitemap/Crawl-delay scoring). |

Dimension totals (scored checks): maxPoints 24, effective max 22.05.

Rung criteria:

- **llms-txt**
  - `unknown`: The llms.txt locations could not be read during the scan (no response, a temporary error, or an access restriction), so the file's presence could not be judged.
  - `not_detected`: No llms.txt file was found at /llms.txt or /.well-known/llms.txt (an HTML page served at those paths does not count).
  - `detected`: A non-HTML file is served at an llms.txt path, but it lacks the H1 title line that begins a structured llms.txt.
  - `parseable`: The llms.txt begins with a valid title line but lists few or no links organized under section headings.
  - `useful`: The llms.txt lists at least three links under one or more section headings (a fuller index published on a non-primary subdomain also lands here).
  - `high_confidence`: An llms.txt on the main domain lists ten or more links organized across two or more section headings.
- **llms-full-txt**
  - `unknown`: The llms-full.txt locations could not be read during the scan (no response, a temporary error, or an access restriction), so the file's presence could not be judged.
  - `not_detected`: No llms-full.txt file was found at /llms-full.txt or /.well-known/llms-full.txt (an HTML page served at those paths does not count).
  - `detected`: A non-HTML file is served at an llms-full.txt path, but it lacks the H1 title line that begins a structured llms-full.txt.
  - `parseable`: The llms-full.txt begins with a valid title line, but its inline content beneath the headings runs under 5,000 characters.
  - `useful`: The llms-full.txt includes at least 5,000 characters of inline content beneath its headings.
  - `high_confidence`: The llms-full.txt includes at least 20,000 characters of inline content organized across three or more section headings.
- **markdown-twin**
  - `unknown`: The docs pages and their .md twin addresses could not be read during the scan (no response, a temporary error, or an access restriction), so twin availability could not be judged.
  - `not_detected`: No markdown (.md) version was found alongside the docs HTML pages checked (/docs and /documentation).
  - `detected`: A non-HTML file is served at a .md address next to a docs page, but its body does not read as markdown.
  - `parseable`: A markdown version of a docs page is served at its .md address alongside the HTML page.
- **ai-txt**
  - `unknown`: The ai.txt locations could not be read during the scan (no response, a temporary error, or an access restriction), so the file's presence could not be judged.
  - `not_detected`: No ai.txt file was found at /ai.txt or /.well-known/ai.txt (an HTML page served at those paths does not count).
  - `detected`: A non-HTML file is served at an ai.txt path, but it is nearly empty or contains neither policy directives nor section headings.
  - `parseable`: The ai.txt has section headings but no recognizable policy directive lines (such as Allow, Disallow, Policy, Contact, Usage, Training, or Indexing).
  - `useful`: The ai.txt declares at least one policy directive line (such as Allow, Disallow, Policy, Contact, Usage, Training, or Indexing).
  - `high_confidence`: The ai.txt declares policy directive lines and organizes them under section headings.
- **raw-content-extractability**
  - `unknown`: The probed pages could not be assessed (they did not respond, returned errors or access restrictions, or served non-HTML responses), so readability without JavaScript could not be judged.
  - `not_detected`: Every probed page is a JavaScript shell whose initial HTML carries no meaningful readable content.
  - `detected`: Only minimal readable text is present in the raw HTML of the probed pages before any JavaScript runs.
  - `parseable`: Some readable text is present in the raw HTML, but much of it is navigation and page furniture, or some probed pages are JavaScript shells.
  - `useful`: The raw HTML of a probed page carries readable text without running JavaScript (at least 1,000 visible characters, or close to half of the visible text sitting in the main content area).
  - `high_confidence`: Two or more probed pages serve readable content in their raw HTML without running JavaScript.
- **freshness-signals**
  - `unknown`: The homepage and sitemap could not be read during the scan (no response, a temporary error, or an access restriction), so freshness signals could not be observed.
  - `not_detected`: Neither the homepage headers (Last-Modified, ETag) nor the sitemap (lastmod dates) carries any freshness signal.
  - `detected`: The only freshness signal is lastmod dates in the sitemap, and none of them falls within 90 days of the scan date.
  - `parseable`: Exactly one freshness signal is present: a Last-Modified header, an ETag header, or sitemap lastmod dates updated within 90 days of the scan date.
  - `useful`: At least two of the three freshness signals are present (Last-Modified header, ETag header, sitemap lastmod dates).
  - `high_confidence`: All three freshness signals are present, and the newest sitemap lastmod date falls within 90 days of the scan date.
- **crawl-cost-estimate**
  - `unknown`: The robots.txt and sitemap could not be read during the scan (no response, a temporary error, or an access restriction), so crawl cost legibility could not be assessed.
  - `not_detected`: Neither a sitemap nor a robots.txt Crawl-delay directive was found, leaving no crawl cost information to read.
  - `detected`: The sitemap signals a large crawl (an index declaring 20 or more child sitemaps, or more than 10,000 page URLs) with no further cost guidance.
  - `parseable`: Partial crawl cost information is published: a sitemap index without page counts, a sitemap of up to 10,000 page URLs, or a Crawl-delay directive without any sitemap.
  - `useful`: The sitemap lists up to 2,000 page URLs, or a sitemap index is published together with a robots.txt Crawl-delay directive.
  - `high_confidence`: The sitemap lists 500 or fewer page URLs and robots.txt publishes a Crawl-delay directive.

### bot_access_control

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| ai-bot-rules | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether robots.txt declares access rules specifically for AI bots (a declared AI-crawler preference). |
| content-signals | 2 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Checks whether robots.txt declares Cloudflare Content Signals (search/ai-input/ai-train preferences). |
| tdmrep | 2 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Checks whether the domain declares a TDM Reservation Protocol policy at /.well-known/tdmrep.json (a declared text-and-data-mining preference). |
| rsl | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether robots.txt declares an RSL (Really Simple Licensing) License directive and, if so, how completely the linked license states its terms. |

Dimension totals (scored checks): maxPoints 12, effective max 12.

Rung criteria:

- **ai-bot-rules**
  - `unknown`: The robots.txt file could not be read during the scan (no response, a temporary error, or an access restriction), so AI bot rules could not be checked.
  - `not_detected`: Either no plain-text robots.txt is served, or the one served names no AI-specific crawler.
  - `detected`: robots.txt names at least one AI-specific crawler (such as GPTBot or ClaudeBot) but declares no rule lines for it.
  - `parseable`: robots.txt declares an explicit rule (such as Allow or Disallow) for one AI-specific crawler.
  - `useful`: robots.txt declares explicit rules for two distinct AI-specific crawlers.
  - `high_confidence`: robots.txt declares explicit rules for three or more distinct AI-specific crawlers.
- **content-signals**
  - `unknown`: The robots.txt file could not be read during the scan (no response, a temporary error, or an access restriction), so Content Signals could not be checked.
  - `not_detected`: Either no plain-text robots.txt is served, or the one served contains no Content-Signal line.
  - `detected`: robots.txt contains a Content-Signal line, but no recognized signal (search, ai-input, ai-train) carries an unambiguous yes or no value.
  - `parseable`: One recognized Content Signal (search, ai-input, or ai-train) is declared with an unambiguous yes or no value for at least one crawler.
  - `useful`: Two of the three recognized Content Signals are declared with unambiguous yes or no values.
  - `high_confidence`: All three recognized Content Signals (search, ai-input, ai-train) are declared with unambiguous yes or no values.
- **tdmrep**
  - `unknown`: The /.well-known/tdmrep.json path could not be read during the scan (no response, a temporary error, or an access restriction), so the TDM policy could not be checked.
  - `not_detected`: No JSON tdmrep file was found at /.well-known/tdmrep.json.
  - `detected`: A tdmrep.json is served, but it is not valid JSON, is not a rules structure, or declares no rule with a valid tdm-reservation value (0 or 1).
  - `parseable`: The tdmrep.json declares at least one rule with a valid tdm-reservation value, but only for specific paths, not the domain root.
  - `useful`: The tdmrep.json declares a rule with a valid tdm-reservation value covering the domain root.
  - `high_confidence`: The domain-root rule also links a tdm-policy URL (an http or https address).
- **rsl**
  - `unknown`: The robots.txt file could not be read during the scan (no response, a temporary error, or an access restriction), so no RSL License directive could be looked for.
  - `not_detected`: Either no plain-text robots.txt is served, or it contains no License directive pointing to an RSL license file.
  - `detected`: robots.txt declares an RSL License directive, but no linked file could be read as an RSL document carrying the RSL namespace and a license entry.
  - `parseable`: The linked RSL document parses with a license entry, but the license states no usage or payment terms.
  - `useful`: The linked RSL license states machine-readable terms: at least one permitted or prohibited usage, or a payment model.
  - `high_confidence`: The RSL license states an explicit AI usage term (ai-train, ai-input, ai-index, or ai-all) together with a payment model.

### protocol_and_capability_discovery

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| link-headers | 2 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Checks whether the API advertises related resources via RFC 8288 Link headers. |
| well-known-index | 2 | yes | unknown, not_detected, detected, parseable | parseable | 0.7 | Checks whether the site publishes machine-readable /.well-known/ descriptors. |
| openapi-spec | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether an OpenAPI/Swagger specification is published. |
| sdk-availability | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether official SDKs or client libraries are available. |
| mcp-descriptor | 5 | no (informational) | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether the domain publishes a machine-readable MCP server descriptor. |
| mcp-support | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether the company documents or operates an MCP server that clients can connect to. |
| mcp-server-card | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the domain publishes an MCP Server Card for pre-connection discovery. |
| a2a-agent-card | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the domain publishes an A2A Agent Card for agent-to-agent discovery. |
| webmcp | 3 | no (informational) | unknown | unknown | 0 | Checks whether the site exposes WebMCP tools via navigator.modelContext at page load. |
| graphql-surface | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the domain advertises a GraphQL transport surface (static GET only — no introspection POST). |
| dns-aid | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the domain publishes a DNS-AID agent index at _index._agents.{domain}. |
| rate-limit-docs | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether rate limiting is documented. |
| auth-discovery | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether the site publishes a standardized, machine-readable authentication-discovery surface (OAuth 2.0 AS metadata / OpenID Connect Discovery / RFC 9728 Protected Resource Metadata) an agent can use to authenticate. |

Dimension totals (scored checks): maxPoints 41, effective max 39.7.

Rung criteria:

- **link-headers**
  - `unknown`: The probed API and homepage responses could not be read during the scan (no response, a temporary error, or an access restriction), so Link headers could not be checked.
  - `not_detected`: No Link header appears on any probed response.
  - `detected`: A Link header is present on a probed response, but no entry in it parses with a rel type.
  - `parseable`: A Link header parses with at least one rel type.
  - `useful`: A Link header includes an agent-relevant rel type (api-catalog, service-desc, service-doc, or describedby) pointing at a target address.
  - `high_confidence`: The agent-relevant Link target also loads (a successful response at the linked address).
- **well-known-index**
  - `unknown`: The covered /.well-known/ paths could not be read during the scan (no response, a temporary error, or an access restriction), or a change-password response could not be compared against its control address, so no conclusion was recorded.
  - `not_detected`: Neither covered descriptor was found: no gpc.json, and no change-password response distinguishable from the site's handling of a deliberately nonexistent address.
  - `detected`: A covered /.well-known/ file is served but does not parse in its expected format (a gpc.json that is not valid JSON).
  - `parseable`: A covered descriptor is served and parses: a valid gpc.json, or a change-password address treated differently from a deliberately nonexistent control address.
- **openapi-spec**
  - `unknown`: The spec locations and API paths could not be read during the scan (no response, a temporary error, or an access restriction), so no spec search could complete.
  - `not_detected`: No OpenAPI or Swagger specification was found at the conventional locations or at addresses the site declares.
  - `detected`: A spec-like document exists, but it is too large to parse, does not parse as JSON or YAML, or lacks the required openapi/swagger version, info, or paths fields.
  - `parseable`: A valid OpenAPI or Swagger document is published, but it declares no operations or no schemas.
  - `useful`: The spec declares operations and schemas but misses at least one of: an info.version, a servers or host declaration, three or more operations, or responses defined on at least 80 percent of operations.
  - `high_confidence`: The spec declares its version, its servers or host, three or more operations, and responses on at least 80 percent of operations.
- **sdk-availability**
  - `unknown`: The SDK and getting-started pages could not be read during the scan (no response, a temporary error, or an access restriction), so SDK availability could not be judged.
  - `not_detected`: No SDK mention was found on the SDK or getting-started pages checked.
  - `detected`: An SDK is mentioned on a general page (such as getting-started) rather than a page for SDKs or client libraries, with no concrete pointer to one.
  - `parseable`: A dedicated SDK or client-libraries page exists, but it includes no concrete pointer (an install command, a package-registry link, or a GitHub repository).
  - `useful`: The pages include one concrete SDK pointer: an install command, a package-registry link, or a GitHub repository.
  - `high_confidence`: The pages include two or more concrete SDK pointers (install commands, package-registry links, or GitHub repositories).
- **mcp-descriptor**
  - `unknown`: The MCP descriptor locations (/.well-known/mcp.json and related paths) could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No MCP server description was found at the descriptor locations checked.
  - `detected`: A file is served at an MCP descriptor location, but it does not contain the fields that describe an MCP server.
  - `parseable`: An MCP server is described, but the description includes no web address where the server can be reached.
  - `useful`: The MCP description includes a web address for the server.
  - `high_confidence`: The MCP description lists two or more tools, with descriptions and input formats on at least 80 percent of them.
- **mcp-support**
  - `unknown`: The official MCP documentation and likely endpoint locations could not be checked conclusively because they were unreachable, temporarily failing, or access-restricted.
  - `not_detected`: No first-party MCP support documentation or MCP-specific endpoint response was found.
  - `detected`: MCP is mentioned by the company, but not on a dedicated first-party support page and no live protocol response was found.
  - `parseable`: A dedicated first-party MCP page exists without a concrete endpoint, or an MCP-shaped endpoint returned structured MCP-related data.
  - `useful`: First-party documentation identifies a concrete MCP endpoint, or a live endpoint returned the expected authentication or method contract.
  - `high_confidence`: First-party documentation identifies the endpoint plus capabilities and connection details, explicitly establishes a company-operated service with those details, or the endpoint returned an MCP-specific protocol or OAuth discovery response.
- **mcp-server-card**
  - `unknown`: The Server Card locations (/.well-known/mcp/server-card.json and related paths) could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No MCP Server Card was found at the locations checked.
  - `detected`: A file is served at a Server Card location, but it does not contain the fields that describe an MCP Server Card.
  - `parseable`: A Server Card is described, but it lacks a remote endpoint entry (a type and web address) or the identity fields name, description, and version.
  - `useful`: The Server Card declares its identity and at least one remote endpoint (a type and web address).
  - `high_confidence`: A remote endpoint in the Server Card also lists its supported MCP protocol versions.
- **a2a-agent-card**
  - `unknown`: The Agent Card locations (/.well-known/agent-card.json and related paths) could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No A2A Agent Card was found at the locations checked.
  - `detected`: A file is served at an Agent Card location, but it does not contain the fields that describe an A2A Agent Card.
  - `parseable`: An Agent Card is described, but it is missing required fields (name, description, version, supported interfaces, or described skills).
  - `useful`: The Agent Card declares described skills and a supported interface with a web address.
  - `high_confidence`: The Agent Card also declares its capabilities, default input and output modes, and tags on every skill.
- **webmcp**
  - `unknown`: WebMCP tools can only be observed by loading the page in a browser, which this scanner release does not yet do, so the check always records no conclusion.
- **graphql-surface**
  - `unknown`: The conventional GraphQL paths (/graphql and variants) could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: Nothing GraphQL-shaped was found at the conventional GraphQL paths.
  - `detected`: A response exists at a GraphQL path, but it carries no recognizable GraphQL markers.
  - `parseable`: A GraphQL path answers with a GraphQL-shaped body (including the 400 or 405 error JSON real endpoints return to a plain GET), or a page carries static GraphQL documentation markers.
  - `useful`: A GraphQL path serves GraphiQL, GraphQL Playground, or Apollo markers.
  - `high_confidence`: A GraphQL path serves an interactive GraphQL IDE (GraphiQL or Playground) together with Apollo or schema markers.
- **dns-aid**
  - `unknown`: The DNS queries for _index._agents.<domain> failed or timed out, so the index could not be checked.
  - `not_detected`: DNS holds no record at _index._agents.<domain> (the DNS-AID index location).
  - `detected`: A DNS answer exists at the index name but carries no usable content (an empty record set, or a TXT record without agent discovery metadata).
  - `parseable`: The index publishes a parseable record: an SVCB record, or a TXT record naming agent, mcp, or a2a metadata.
  - `useful`: The index's SVCB record includes transport or capability metadata (an alpn, port, or capability document parameter).
  - `high_confidence`: The index's SVCB record publishes both a transport protocol list (alpn) and a capability document parameter (cap).
- **rate-limit-docs**
  - `unknown`: The rate-limit documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No rate limit mention was found at the documentation locations checked.
  - `detected`: Rate limiting is mentioned, but not on a dedicated documentation page whose title or heading names the topic.
  - `parseable`: A dedicated rate-limit page exists, but it does not state a concrete numeric limit together with limit-handling information.
  - `useful`: The rate-limit page states a concrete numeric limit and how limits surface (rate-limit response headers, a documented 429, Retry-After, or backoff guidance).
  - `high_confidence`: The page also documents the 429 status, the Retry-After header, and how limits differ by tier or plan.
- **auth-discovery**
  - `unknown`: The standard authentication-discovery locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No OAuth authorization-server metadata, OpenID Connect discovery document, or protected-resource metadata was found at the standard /.well-known/ locations.
  - `detected`: An authentication-discovery file is served at a standard location, but it does not parse as valid metadata.
  - `parseable`: A valid protected-resource metadata document (RFC 9728) is published, but it names no authorization servers.
  - `useful`: The site publishes a valid OAuth authorization-server or OpenID Connect discovery document, or protected-resource metadata naming its authorization servers.
  - `high_confidence`: Valid protected-resource metadata and a valid authorization-server document are both published, or the metadata is announced in a WWW-Authenticate challenge on a protected endpoint.

### authentication_and_credentials

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| auth-documentation | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether authentication documentation exists. |
| programmatic-auth-flow | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether a programmatic (non-interactive) authentication flow is documented. |
| credential-management | 4 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 4 | Checks whether credential management (rotation, revocation, scoping) is documented. |
| sandbox-environment | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether a sandbox or test environment is available. |

Dimension totals (scored checks): maxPoints 19, effective max 19.

Rung criteria:

- **auth-documentation**
  - `unknown`: The authentication documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No authentication-related terms were found at the documentation locations checked.
  - `detected`: Authentication is mentioned, but not on a dedicated documentation page whose title or heading names the topic.
  - `parseable`: A dedicated authentication page exists, but it does not document a complete method (the credential and how a request carries it).
  - `useful`: The authentication page documents at least one complete method: the credential (API key, bearer token, or OAuth) and how a request carries it.
  - `high_confidence`: The page documents two or more complete methods, or it references an OpenAPI or Swagger security scheme.
- **programmatic-auth-flow**
  - `unknown`: The authentication documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No mention of non-interactive authentication (service accounts, client credentials, API tokens, or header-based keys) was found at the documentation locations checked.
  - `detected`: Programmatic authentication is mentioned, but not on a dedicated documentation page whose title or heading names authentication.
  - `parseable`: A dedicated authentication page exists, but it documents neither a non-interactive grant with a token endpoint nor a header-based key method.
  - `useful`: The page documents a machine-usable flow: a non-interactive grant (such as client credentials) with a token endpoint, or a header-based API key or bearer token method.
  - `high_confidence`: The page also documents scopes and token expiry or refresh.
- **credential-management**
  - `unknown`: The keys and security documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No mention of credential rotation, revocation, or key management was found at the documentation locations checked.
  - `detected`: Credential management is mentioned, but not on a dedicated documentation page whose title or heading names keys, credentials, or security.
  - `parseable`: A dedicated keys or security page exists, but it does not document how to rotate or revoke credentials.
  - `useful`: The page documents rotating or revoking keys, tokens, or other credentials.
  - `high_confidence`: The page documents rotation and revocation together with credential scoping or expiry.
- **sandbox-environment**
  - `unknown`: The sandbox and testing documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No mention of a sandbox or test environment was found at the documentation locations checked.
  - `detected`: A test environment is mentioned, but not on a dedicated documentation page whose title or heading names the topic.
  - `parseable`: A dedicated sandbox or testing page exists, but it shows neither test credentials nor a test base URL.
  - `useful`: The page shows test credentials or a test base URL.
  - `high_confidence`: The page documents separate test and live credentials together with a concrete test workflow (test data or simulations).

### documentation_quality

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| api-reference-depth | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether API reference documentation has meaningful depth. |
| changelog-presence | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether a changelog or release notes page exists. |

Dimension totals (scored checks): maxPoints 10, effective max 10.

Rung criteria:

- **api-reference-depth**
  - `unknown`: The API reference locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No API reference content (parameters, examples, status codes, or similar indicators) was found at the documentation locations checked.
  - `detected`: Reference content is mentioned, but not on a dedicated reference page whose title or heading names the reference.
  - `parseable`: A dedicated API reference page exists, but it does not show parameters together with example requests or responses.
  - `useful`: The reference page documents parameters together with example requests or responses (a curl example counts).
  - `high_confidence`: The reference page documents request and response bodies, examples, authentication, pagination, and error or status codes.
- **changelog-presence**
  - `unknown`: The changelog locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No changelog or release notes terms were found at the locations checked.
  - `detected`: A changelog is mentioned, but not on a dedicated page whose title or heading names release history.
  - `parseable`: A dedicated changelog page exists, but it lacks dated or versioned entries paired with change descriptions (added, fixed, removed, and similar).
  - `useful`: The changelog lists at least one dated or versioned entry alongside change descriptions.
  - `high_confidence`: The changelog also lists three or more distinct dated or versioned entries.

### structured_data_io

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| structured-data-io | 8 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 8 | Checks whether the API publishes a typed, consistent structured-data contract (OpenAPI response schemas). |
| data-export-api | 4 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 4 | Checks whether the API supports data export or bulk retrieval. |
| machine-readable-pricing | 1 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 1 | Checks whether pricing information is available via a machine-readable endpoint (JSON API). |

Dimension totals (scored checks): maxPoints 13, effective max 13.

Rung criteria:

- **structured-data-io**
  - `unknown`: The spec locations could not be read during the scan (no response, a temporary error, or an access restriction), so the response contract could not be assessed.
  - `not_detected`: No API spec declaring response shapes was found at the locations checked.
  - `detected`: A spec-like document exists, but it is too large to parse, does not parse, or declares no response schemas.
  - `parseable`: The spec declares response schemas, but typed responses cover fewer than 60 percent of its operations.
  - `useful`: The spec declares typed response schemas on at least 60 percent of operations, but misses a pagination pattern, a structured error response, or both.
  - `high_confidence`: The spec declares typed response schemas on at least 60 percent of operations, plus a pagination pattern and an error response with a declared schema.
- **data-export-api**
  - `unknown`: The export documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No mention of bulk export or data export was found at the documentation locations checked.
  - `detected`: Data export is mentioned, but not on a dedicated documentation page whose title or heading names export.
  - `parseable`: A dedicated export page exists, but it documents neither a bulk or export endpoint nor an export format.
  - `useful`: The page documents a bulk or export endpoint, or names an export format (CSV, NDJSON, JSONL, Parquet, or similar).
  - `high_confidence`: The page documents a bulk or export endpoint, an export format, and async-job or pagination handling for large exports.
- **machine-readable-pricing**
  - `unknown`: The machine-readable pricing paths (/pricing.json and API pricing paths) could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No JSON pricing data was found at the paths checked (/pricing.json, /api/pricing, /api/plans, and variants).
  - `detected`: A JSON-like response is served at a pricing path, but it does not parse as a JSON object or array.
  - `parseable`: Valid JSON is served at a pricing path, but no entry in it carries a price field.
  - `useful`: The JSON lists at least one plan entry with a price field.
  - `high_confidence`: The JSON lists two or more plans, each with a price, a currency, and a billing interval.

### observable_state_and_reliability

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| status-and-health | 2 | yes | unknown, not_detected, detected | detected | 0.2 | Checks whether the API exposes health or status endpoints. |
| webhook-documentation | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether webhook or event notification documentation exists. |
| error-documentation | 5 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 5 | Checks whether error codes and error handling are documented. |
| retry-and-idempotency | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether retry behavior and idempotency are documented. |
| x402-or-mpp-support | 1 | no (informational) | unknown, detected, parseable, useful | useful | 0.7 | Checks whether the API advertises machine-payable access (x402 / MPP): an HTTP 402 response, a payment-required response header, or a published /.well-known/x402.json manifest. |

Dimension totals (scored checks): maxPoints 15, effective max 13.2.

Rung criteria:

- **status-and-health**
  - `unknown`: The health and status paths could not be read during the scan (no response or only temporary errors), so no conclusion was recorded.
  - `not_detected`: No health or status endpoint was found at the conventional paths (/status, /health, /healthz, and variants).
  - `detected`: A conventional health or status path answers with a non-HTML response, or answers with an access challenge.
- **webhook-documentation**
  - `unknown`: The webhook documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No mention of webhooks or event notifications was found at the documentation locations checked.
  - `detected`: Webhooks are mentioned, but not on a dedicated documentation page whose title or heading names webhooks or events.
  - `parseable`: A dedicated webhook page exists, but it does not list at least two named event types together with a payload shape.
  - `useful`: The webhook page lists two or more named event types (such as charge.refunded) together with a payload shape.
  - `high_confidence`: The page also documents signature verification and delivery retry behavior.
- **error-documentation**
  - `unknown`: The error documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No error documentation terms were found at the documentation locations checked.
  - `detected`: Error handling is mentioned, but not on a dedicated documentation page whose title or heading names errors.
  - `parseable`: A dedicated error page exists, but it neither enumerates at least two distinct error status codes nor documents an error response shape.
  - `useful`: The error page enumerates two or more distinct error status codes, or documents an error response shape (such as a code and message object).
  - `high_confidence`: The page also names a machine-readable error format (problem details) alongside retry guidance, or mentions OpenAPI or Swagger.
- **retry-and-idempotency**
  - `unknown`: The retry and idempotency documentation locations could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No retry or idempotency terms were found at the documentation locations checked.
  - `detected`: Retries or idempotency are mentioned, but not on a dedicated documentation page whose title or heading names the topic.
  - `parseable`: A dedicated retry or idempotency page exists, but it documents neither an idempotency-key mechanism nor a concrete retry strategy.
  - `useful`: The page documents an idempotency-key mechanism or a concrete retry strategy (backoff, 429 handling, or Retry-After).
  - `high_confidence`: The page documents both an idempotency-key mechanism and a retry strategy.
- **x402-or-mpp-support**
  - `unknown`: No machine-payment signal was observed (no HTTP 402 response, no payment-required header, and no /.well-known/x402.json manifest); because payment support can be invisible to an unauthenticated probe, a miss records no conclusion rather than an absence.
  - `detected`: A payment signal was observed: an HTTP 402 response, a payment-required response header, an x402 payment envelope in a 402 body, or a /.well-known/x402.json file carrying x402 fields without further structure.
  - `parseable`: The /.well-known/x402.json manifest is structured: it declares an x402 version or lists resource entries, though none carries a price amount.
  - `useful`: The x402 manifest lists at least one resource entry carrying a concrete price amount.

### agent_safety_and_trust

| Check | Max pts | Scored | Reachable states | Cap | Effective max | Description |
|---|---|---|---|---|---|---|
| security-txt | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the site publishes a valid security.txt for vulnerability disclosure. |
| legal-pages | 2 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 2 | Checks whether terms of service, privacy, and data-use policies are discoverable. |
| org-identity | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether the site exposes org identity signals (legal name, address, support email, socials). |
| metadata-consistency | 3 | yes | unknown, not_detected, detected, parseable, useful, high_confidence | high_confidence | 3 | Checks whether homepage metadata is internally consistent (canonical, Open Graph, schema, pricing). |

Dimension totals (scored checks): maxPoints 11, effective max 11.

Rung criteria:

- **security-txt**
  - `unknown`: The security.txt locations (/.well-known/security.txt and /security.txt) could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No security.txt file was found at /.well-known/security.txt or /security.txt (an HTML page or empty file there does not count).
  - `detected`: A non-HTML file is served at a security.txt location, but it contains no recognized RFC 9116 field.
  - `parseable`: The security.txt uses RFC 9116 field names but has no Contact line.
  - `useful`: The security.txt publishes a Contact address, but either its Expires date had already passed on the date the scan ran (or is missing or duplicated), or it lacks an Encryption or Policy line.
  - `high_confidence`: The security.txt publishes a Contact address, exactly one Expires date still in the future on the date the scan ran, and an Encryption or Policy line.
- **legal-pages**
  - `unknown`: The conventional policy paths could not be read during the scan (no response, a temporary error, or an access restriction).
  - `not_detected`: No terms of service, privacy, or data-use policy page was found at the conventional paths.
  - `detected`: A policy page was found, but not both a privacy policy and terms of service.
  - `parseable`: Both a privacy policy and terms of service were found, but at least one carries under 400 characters of readable policy text.
  - `useful`: Both the privacy policy and the terms of service carry at least 400 characters of readable policy text.
  - `high_confidence`: In addition to substantive privacy and terms pages, a data-use policy of the same substance is published.
- **org-identity**
  - `unknown`: The homepage could not be read during the scan (no response, a temporary error, or an access restriction), so identity signals could not be observed.
  - `not_detected`: The homepage shows none of the four identity signals: an organization name in structured data, a postal address, a support-style email address, or a social profile link.
  - `detected`: The homepage shows one of the four identity signals.
  - `parseable`: The homepage shows two of the four identity signals.
  - `useful`: The homepage shows three of the four identity signals.
  - `high_confidence`: The homepage shows all four identity signals: an organization name in structured data, a postal address, a support-style email address, and a social profile link.
- **metadata-consistency**
  - `unknown`: The homepage could not be read during the scan — no response, a temporary error, an access restriction, or a page that exceeded the scanner response-size limit before enough of the document was read to compare metadata.
  - `not_detected`: The homepage carries no assessable metadata: no canonical link, no Open Graph url or title tag, and no structured data block.
  - `detected`: The homepage metadata raises three or more consistency warnings (host mismatches between canonical, Open Graph, and page address; an Open Graph updated time more than two years before the scan date; unparseable structured data; or a meta-tag price that contradicts the structured-data price).
  - `parseable`: The homepage metadata raises exactly two of the consistency warnings.
  - `useful`: The homepage metadata raises exactly one of the consistency warnings; or the homepage was too large to read in full and the portion read, which included a complete document head, raised none.
  - `high_confidence`: The homepage metadata is present and raises none of the consistency warnings, including no update timestamp older than two years as of the scan date.

## Grand totals (scored checks)

- maxPoints: 169
- effective max contribution: 158 — checks whose declared cap sits below `high_confidence` cannot earn their full maxPoints, so a site that maxes every check scores 93/100, not 100.