{
  "url": "https://orvanipeptides.com",
  "finalUrl": "https://orvanipeptides.com/us",
  "scannedAt": "2026-11-11T23:08:09.623Z",
  "engine": "ARI-100",
  "score": 85,
  "core": 82,
  "bonus": 3,
  "bonusSignals": [
    "agent-skills",
    "md-negotiation",
    "llms-full"
  ],
  "grade": "B",
  "gradeLabel": "Agent-aware",
  "level": 4,
  "accessScore": 100,
  "accessCoverage": {
    "tested": 21,
    "of": 21
  },
  "a11yScore": 90,
  "a11yReport": {
    "score": 90,
    "checks": {
      "img-alt": {
        "result": "pass",
        "note": "0/16 missing alt"
      },
      "form-label": {
        "result": "fail",
        "note": "4 unlabelled"
      },
      "control-name": {
        "result": "pass",
        "note": "see structure check"
      },
      "media-dims": {
        "result": "pass",
        "note": "0 without dimensions"
      },
      "aria-refs": {
        "result": "pass",
        "note": ""
      },
      "iframe-title": {
        "result": "not_applicable",
        "note": "0 iframes"
      },
      "heading-levels": {
        "result": "pass",
        "note": "0 skipped"
      },
      "tabindex": {
        "result": "pass",
        "note": ""
      },
      "zoom": {
        "result": "pass",
        "note": ""
      },
      "doc-title": {
        "result": "pass",
        "note": ""
      },
      "label-in-name": {
        "result": "pass",
        "note": ""
      },
      "skip-link": {
        "result": "pass",
        "note": ""
      },
      "lang-valid": {
        "result": "pass",
        "note": ""
      },
      "aria-hidden-focus": {
        "result": "pass",
        "note": ""
      },
      "nested-interactive": {
        "result": "pass",
        "note": ""
      },
      "empty-heading": {
        "result": "pass",
        "note": ""
      },
      "meta-refresh": {
        "result": "pass",
        "note": ""
      },
      "autocomplete": {
        "result": "pass",
        "note": ""
      },
      "table-headers": {
        "result": "not_applicable",
        "note": ""
      },
      "svg-title": {
        "result": "fail",
        "note": ""
      },
      "captions": {
        "result": "not_applicable",
        "note": ""
      },
      "list-structure": {
        "result": "pass",
        "note": ""
      },
      "aria-valid": {
        "result": "pass",
        "note": "0 invalid roles"
      }
    },
    "applicable": 20,
    "total": 23
  },
  "domains": [
    {
      "id": "access",
      "name": "Reachability & Access",
      "weight": 20,
      "blurb": "A crawler that is turned away at the edge reads nothing you wrote.",
      "score": 95.6,
      "checks": 15,
      "passed": 13,
      "applicable": 15,
      "total": 15
    },
    {
      "id": "render",
      "name": "Render & Delivery",
      "weight": 10,
      "blurb": "Text that only exists after JavaScript runs does not exist for most agents.",
      "score": 86.7,
      "checks": 11,
      "passed": 8,
      "applicable": 11,
      "total": 11
    },
    {
      "id": "structure",
      "name": "Structure & Semantics",
      "weight": 12,
      "blurb": "Headings, titles and landmarks are the outline an agent extracts passages from.",
      "score": 100,
      "checks": 13,
      "passed": 13,
      "applicable": 13,
      "total": 14
    },
    {
      "id": "data",
      "name": "Structured Data",
      "weight": 12,
      "blurb": "Facts declared in JSON-LD do not have to be inferred from prose.",
      "score": 85.7,
      "checks": 11,
      "passed": 8,
      "applicable": 11,
      "total": 12
    },
    {
      "id": "discovery",
      "name": "Discovery Files",
      "weight": 14,
      "blurb": "The files an agent reads before it reads a page.",
      "score": 91.9,
      "checks": 18,
      "passed": 15,
      "applicable": 18,
      "total": 18
    },
    {
      "id": "interfaces",
      "name": "Agent Interfaces",
      "weight": 14,
      "blurb": "What an agent can call once it decides to act.",
      "score": 54.3,
      "checks": 27,
      "passed": 10,
      "applicable": 27,
      "total": 27
    },
    {
      "id": "commerce",
      "name": "Operability & Commerce",
      "weight": 10,
      "blurb": "Real controls, real prices, real checkout — for agents that buy.",
      "score": 38.9,
      "checks": 12,
      "passed": 3,
      "applicable": 12,
      "total": 13
    },
    {
      "id": "trust",
      "name": "Trust & Authority",
      "weight": 8,
      "blurb": "Who said it, when, and can the claim be checked.",
      "score": 88.9,
      "checks": 10,
      "passed": 8,
      "applicable": 10,
      "total": 10
    }
  ],
  "checks": [
    {
      "id": "robots-valid",
      "domain": "access",
      "weight": 3,
      "tier": "essential",
      "title": "robots.txt is reachable and valid",
      "how": "GET /robots.txt returns 200, text/plain, and at least one User-agent group with parseable rules.",
      "fix": "Fix robots.txt at {{origin}}/robots.txt: it must return HTTP 200 with Content-Type text/plain, contain at least one \"User-agent: *\" group, and contain no HTML. Current evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "robots.txt HTTP 200, 2 groups",
      "points": 1
    },
    {
      "id": "ai-search-bots",
      "domain": "access",
      "weight": 5,
      "tier": "essential",
      "title": "AI search crawlers are allowed",
      "how": "Live request as OAI-SearchBot, Claude-SearchBot and PerplexityBot all return 200 (not 403/challenge/empty).",
      "fix": "Unblock the AI search crawlers on {{origin}}. In robots.txt add a group with User-agent lines for OAI-SearchBot, Claude-SearchBot, PerplexityBot and \"Allow: /\", then confirm the CDN/WAF does not challenge them. Current evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "11/11 verifiable AI search crawlers allowed",
      "points": 1
    },
    {
      "id": "ai-user-agents",
      "domain": "access",
      "weight": 4,
      "tier": "essential",
      "title": "Live AI agents can fetch a page a person asked about",
      "how": "Live request as ChatGPT-User, Claude-User and Perplexity-User return 200.",
      "fix": "Allow user-initiated AI agents on {{origin}}: add ChatGPT-User, Claude-User and Perplexity-User to the allowed robots group and remove any firewall rule keyed on those user agents. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "8/8 verifiable live AI agents allowed",
      "points": 1
    },
    {
      "id": "search-engines",
      "domain": "access",
      "weight": 5,
      "tier": "essential",
      "title": "Classic search engines are allowed",
      "how": "Live request as Googlebot and Bingbot return 200.",
      "fix": "Allow Googlebot and Bingbot for {{origin}} in robots.txt and at the edge — AI answer surfaces are fed by these indexes. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "allowed: Googlebot, bingbot",
      "points": 1
    },
    {
      "id": "no-edge-block",
      "domain": "access",
      "weight": 5,
      "tier": "essential",
      "title": "The edge does not challenge AI crawlers",
      "how": "A request carrying an AI user agent gets a 200 with comparable body size to a browser request; no \"cf-mitigated\", JS challenge or 403.",
      "fix": "Stop the CDN/WAF on {{origin}} from challenging AI crawlers: add an allow rule for the AI user agents ahead of managed bot protection, and make sure the challenge response is not being served instead of HTML. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "no AI crawler was challenged",
      "points": 1
    },
    {
      "id": "no-blanket-disallow",
      "domain": "access",
      "weight": 3,
      "tier": "essential",
      "title": "No blanket Disallow: / applies to everyone",
      "how": "The wildcard group does not disallow the whole site, or a wildcard-by-path rule does not shadow the AI groups.",
      "fix": "Remove \"User-agent: * / Disallow: /\" from robots.txt on {{origin}}, or scope it to private paths only (/cart, /checkout, /account, /admin). Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "wildcard group does not disallow the site",
      "points": 1
    },
    {
      "id": "bot-policy-deliberate",
      "domain": "access",
      "weight": 2,
      "tier": "recommended",
      "title": "AI bot policy is named, not inherited",
      "how": "robots.txt names at least 6 known AI crawlers in explicit groups.",
      "fix": "Name the AI crawlers explicitly in robots.txt for {{origin}} instead of relying on a wildcard, so each one has a deliberate policy. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "16 named user-agent groups",
      "points": 1
    },
    {
      "id": "training-policy",
      "domain": "access",
      "weight": 1,
      "tier": "recommended",
      "title": "Training policy is explicit",
      "how": "A stated allow/block for training-only crawlers (CCBot, Google-Extended, Bytespider) or a Content-Signal line.",
      "fix": "State a training policy on {{origin}}: either name CCBot / Google-Extended / Bytespider explicitly in robots.txt, or add a Content-Signal line (search=yes, ai-input=yes, ai-train=no). Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "Content-Signal: search=yes, ai-input=yes, ai-train=yes",
      "points": 1
    },
    {
      "id": "no-captcha",
      "domain": "access",
      "weight": 3,
      "tier": "essential",
      "title": "No CAPTCHA on primary pages",
      "how": "Homepage and sampled inner pages contain no visible CAPTCHA widget or captcha JS gate on first paint.",
      "fix": "Remove the visible CAPTCHA from {{url}}; agents stop at them. Keep challenges on login/contact forms only. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "no CAPTCHA on first paint",
      "points": 1
    },
    {
      "id": "no-gate",
      "domain": "access",
      "weight": 3,
      "tier": "essential",
      "title": "No age/consent/geo wall in front of content",
      "how": "Server HTML contains the real page content, not an interstitial; no IP-based redirect to another locale on first hit.",
      "fix": "Serve real content from {{url}} in the server HTML and overlay any age/consent gate client-side; serve a default region at / instead of a geo redirect. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "content is not behind an interstitial",
      "points": 1
    },
    {
      "id": "indexable",
      "domain": "access",
      "weight": 5,
      "tier": "essential",
      "title": "Page is indexable",
      "how": "No noindex in meta robots or X-Robots-Tag, no nofollow on the canonical.",
      "fix": "Remove noindex from {{url}}: drop it from the meta robots tag and the X-Robots-Tag header. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "indexable",
      "points": 1
    },
    {
      "id": "snippets-allowed",
      "domain": "access",
      "weight": 2,
      "tier": "essential",
      "title": "Snippets and large image previews are allowed",
      "how": "meta robots or X-Robots-Tag permits snippets (max-snippet >= 0) and max-image-preview:large.",
      "fix": "On {{origin}} set \"max-snippet:-1, max-image-preview:large\" in the meta robots tag or X-Robots-Tag so assistants can quote the page. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "snippet directives incomplete",
      "points": 0.5
    },
    {
      "id": "robots-coherent",
      "domain": "access",
      "weight": 2,
      "tier": "recommended",
      "title": "robots.txt does not disallow what the site advertises",
      "how": "No sitemap URL, discovery file, or manifest the site publishes is disallowed for the crawler that needs it.",
      "fix": "On {{origin}} make robots.txt consistent with the files you publish: allow /llms.txt, /sitemap.xml and every /.well-known/ endpoint you advertise. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "declared resources are crawlable",
      "points": 1
    },
    {
      "id": "crawl-budget",
      "domain": "access",
      "weight": 1,
      "tier": "recommended",
      "title": "Infrastructure paths are excluded from crawl budget",
      "how": "/api/, /cdn-cgi/ and parameter permutations are disallowed; content and static assets are allowed.",
      "fix": "On {{origin}} exclude infrastructure from crawl budget: Disallow /api/ and /cdn-cgi/, then re-Allow /static/ and your badge/sitemap paths. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "infrastructure paths excluded",
      "points": 1
    },
    {
      "id": "ssr-home",
      "domain": "render",
      "weight": 5,
      "tier": "essential",
      "title": "Homepage content is in the raw HTML",
      "how": "At least 500 characters of meaningful text and at least one H1 appear in the response body with scripts stripped.",
      "fix": "Server-render the homepage of {{origin}}: ship at least 500 characters of real text and an H1 in the initial HTML response rather than after hydration (SSR/SSG, or prerender). Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "1481 chars of text, 1 H1 in raw HTML",
      "points": 1
    },
    {
      "id": "ssr-inner",
      "domain": "render",
      "weight": 4,
      "tier": "essential",
      "title": "Inner pages carry text without JavaScript",
      "how": "Sampled inner pages each return 400+ characters of text with scripts stripped.",
      "fix": "Server-render the inner pages of {{origin}} ({{evidence}}): move the primary copy into the HTML response for each template, not only the homepage.",
      "result": "pass",
      "evidence": "2/2 sampled inner pages carry 400+ chars without JS",
      "points": 1
    },
    {
      "id": "status-200",
      "domain": "render",
      "weight": 4,
      "tier": "essential",
      "title": "Canonical URL answers 200 within one hop",
      "how": "The scanned URL returns 200 after at most one redirect.",
      "fix": "Collapse redirects on {{url}}: aim for 0-1 hops to the final 200 URL and link the final URL directly. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "HTTP 200, 1 redirect(s)",
      "points": 1
    },
    {
      "id": "real-404",
      "domain": "render",
      "weight": 3,
      "tier": "essential",
      "title": "Unknown URLs return a real 404",
      "how": "A made-up path returns 404 (not 200, not a soft 404 page).",
      "fix": "Return a real 404 status for unknown paths on {{origin}} instead of a 200 soft-404 page, and include links to real pages in the body. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "unknown path returned 404",
      "points": 1
    },
    {
      "id": "content-type",
      "domain": "render",
      "weight": 2,
      "tier": "essential",
      "title": "Correct Content-Type and charset",
      "how": "text/html; charset=utf-8 on HTML, text/plain for llms.txt and robots.txt.",
      "fix": "Set correct Content-Type headers on {{origin}}: text/html; charset=utf-8 for pages, text/plain; charset=utf-8 for robots.txt, llms.txt and markdown mirrors. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "content-type text/html; charset=utf-8",
      "points": 1
    },
    {
      "id": "ttfb",
      "domain": "render",
      "weight": 3,
      "tier": "recommended",
      "title": "Response is fast enough for an agent timeout",
      "how": "Time to first byte under 800 ms and full body under 3 s from a cold request.",
      "fix": "Speed up the server response for {{url}}: TTFB should land under 800 ms. Cache the HTML at the edge, and remove synchronous calls from the render path. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "1358 ms to first byte",
      "points": 0.5
    },
    {
      "id": "page-weight",
      "domain": "render",
      "weight": 2,
      "tier": "recommended",
      "title": "Page weight is reasonable",
      "how": "HTML document under 1 MB and no unbounded inline payloads.",
      "fix": "Reduce the HTML payload of {{url}} to under 1 MB: move large inline JSON/state blobs and base64 images out of the document. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "78 KB of HTML",
      "points": 1
    },
    {
      "id": "compression",
      "domain": "render",
      "weight": 1,
      "tier": "recommended",
      "title": "Text responses are compressed",
      "how": "br or gzip accepted and returned for HTML/JSON.",
      "fix": "Enable Brotli/gzip compression for HTML and JSON on {{origin}}. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "no compression header relayed",
      "points": 0.5
    },
    {
      "id": "text-ratio",
      "domain": "render",
      "weight": 2,
      "tier": "recommended",
      "title": "Text-to-markup ratio is workable",
      "how": "Visible text / HTML bytes above 5% after stripping scripts, styles, nav and footer.",
      "fix": "Raise the text-to-markup ratio on {{url}} to at least 5%: trim wrapper divs and inline styles, and put the copy in plain elements. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "text/markup 1.9%",
      "points": 0
    },
    {
      "id": "no-js-only",
      "domain": "render",
      "weight": 3,
      "tier": "essential",
      "title": "Primary content does not depend on client rendering",
      "how": "The page text is identical with JavaScript disabled at the HTML level (no empty root node).",
      "fix": "Remove the JavaScript dependency for primary content on {{origin}}: the raw response must not be an empty mount node. Render on the server and hydrate. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "document has content before scripts run",
      "points": 1
    },
    {
      "id": "streaming-stable",
      "domain": "render",
      "weight": 1,
      "tier": "recommended",
      "title": "Document is parseable without executing scripts",
      "how": "No document.write after load, no content injected above the fold on a timer.",
      "fix": "On {{origin}} stop injecting above-the-fold content after load (no document.write, no delayed hero render), so a non-executing parser sees the final DOM. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "no blocking document.write",
      "points": 1
    },
    {
      "id": "title",
      "domain": "structure",
      "weight": 3,
      "tier": "essential",
      "title": "Title is unique and the right length",
      "how": "A <title> of 15-65 characters that names the page, not just the brand.",
      "fix": "Rewrite the <title> of {{url}} to 15-65 characters that names the specific page, brand last. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "title 55 chars: \"Orvani Peptides · Research peptides, made in Texas, USA\"",
      "points": 1
    },
    {
      "id": "meta-description",
      "domain": "structure",
      "weight": 3,
      "tier": "essential",
      "title": "Meta description is present and useful",
      "how": "Meta description 50-170 characters, unique per page.",
      "fix": "Write a 50-170 character meta description for {{url}} that states what the page answers. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "149 chars",
      "points": 1
    },
    {
      "id": "one-h1",
      "domain": "structure",
      "weight": 3,
      "tier": "essential",
      "title": "Exactly one H1 states the page subject",
      "how": "One H1 in the document, not empty, distinct from the title tag.",
      "fix": "Ensure exactly one non-empty H1 on {{url}} that states the page subject; demote extra H1s to H2. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "1 H1: \"Orvani Peptides\"",
      "points": 1
    },
    {
      "id": "heading-order",
      "domain": "structure",
      "weight": 2,
      "tier": "recommended",
      "title": "Headings are sequential and descriptive",
      "how": "No skipped levels; H2s describe the section, not \"Section 1\".",
      "fix": "Fix the heading outline on {{url}}: no skipped levels (H2 to H4), and make each H2 describe its section. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "0 skipped level(s), 2 H2(s)",
      "points": 1
    },
    {
      "id": "canonical",
      "domain": "structure",
      "weight": 3,
      "tier": "essential",
      "title": "Canonical points at itself",
      "how": "A rel=canonical link to the URL being served (or the deliberate canonical target).",
      "fix": "Add a self-referencing rel=canonical to {{url}} that matches the URL actually served (https, final host, no tracking params). Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "canonical https://orvanipeptides.com/us",
      "points": 1
    },
    {
      "id": "lang",
      "domain": "structure",
      "weight": 2,
      "tier": "essential",
      "title": "Language is declared and well-formed",
      "how": "html lang is a valid BCP-47 tag (e.g. en, en-US).",
      "fix": "Set a valid BCP-47 lang attribute on <html> for {{origin}} (for example lang=\"en-US\"). Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "lang=\"en\"",
      "points": 1
    },
    {
      "id": "og-tags",
      "domain": "structure",
      "weight": 2,
      "tier": "recommended",
      "title": "Open Graph title, description and image",
      "how": "og:title, og:description and og:image (1200x630) present.",
      "fix": "Add Open Graph tags to {{url}}: og:title, og:description, og:image (1200x630 absolute URL), og:url, og:type. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "og:title yes, og:description yes, og:image yes",
      "points": 1
    },
    {
      "id": "twitter-card",
      "domain": "structure",
      "weight": 1,
      "tier": "recommended",
      "title": "Card metadata for chat previews",
      "how": "twitter:card plus title/description/image.",
      "fix": "Add twitter:card, twitter:title, twitter:description and twitter:image to {{url}}. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "twitter:card present",
      "points": 1
    },
    {
      "id": "viewport",
      "domain": "structure",
      "weight": 1,
      "tier": "optional",
      "title": "Viewport is set and pinch-zoom is not disabled",
      "how": "A viewport meta without user-scalable=no or maximum-scale=1.",
      "fix": "Set <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> on {{origin}} and remove user-scalable=no / maximum-scale=1. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "viewport \"width=device-width, initial-scale=1, viewport-fit=cover\"",
      "points": 1
    },
    {
      "id": "landmarks",
      "domain": "structure",
      "weight": 2,
      "tier": "recommended",
      "title": "Content is separated by landmarks",
      "how": "main or article element, plus nav/header/footer.",
      "fix": "Wrap the primary copy of {{url}} in <main> or <article> and keep nav/header/footer outside it, so a parser can isolate the content. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "main/article landmark present",
      "points": 1
    },
    {
      "id": "a11y-names",
      "domain": "structure",
      "weight": 3,
      "tier": "essential",
      "title": "Controls expose accessible names",
      "how": "Every button, link and input has text, aria-label or an associated label.",
      "fix": "Give every interactive control on {{url}} an accessible name: visible text, aria-label, or a <label for>. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "0 control(s) without an accessible name",
      "points": 1
    },
    {
      "id": "link-text",
      "domain": "structure",
      "weight": 1,
      "tier": "recommended",
      "title": "Link text describes the destination",
      "how": "No \"click here\" / \"read more\" as the only link text on sampled pages.",
      "fix": "Replace generic link text on {{url}} (\"click here\", \"read more\") with the destination name. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "0 generic link label(s)",
      "points": 1
    },
    {
      "id": "href-lang",
      "domain": "structure",
      "weight": 1,
      "tier": "optional",
      "title": "Alternate language versions are declared",
      "how": "hreflang plus x-default when more than one locale is served.",
      "fix": "Declare hreflang alternates plus x-default on {{origin}} for each locale you serve. Evidence: {{evidence}}.",
      "result": "not_applicable",
      "evidence": "single locale site",
      "points": null
    },
    {
      "id": "img-alt",
      "domain": "structure",
      "weight": 2,
      "tier": "recommended",
      "title": "Images carry text alternatives",
      "how": "All content images have alt, decorative images have alt=\"\".",
      "fix": "Add alt text to content images on {{url}} and alt=\"\" to decorative ones. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "0/16 images without alt",
      "points": 1
    },
    {
      "id": "jsonld",
      "domain": "data",
      "weight": 4,
      "tier": "essential",
      "title": "JSON-LD structured data is present",
      "how": "At least one application/ld+json block with a parseable @context.",
      "fix": "Add a JSON-LD block to {{url}} with @context https://schema.org and a @type that matches the page. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "1/1 JSON-LD block(s) parse; types: Organization, PostalAddress, ContactPoint, WebSite, SearchAction, ItemPage",
      "points": 1
    },
    {
      "id": "jsonld-type",
      "domain": "data",
      "weight": 3,
      "tier": "recommended",
      "title": "Declared type matches the page",
      "how": "WebPage/Organization for a homepage; Article, Product, Service, FAQPage, HowTo as appropriate.",
      "fix": "Declare the correct schema type on {{url}} ({{evidence}}) — Product for a product page, Article for editorial, Service for a service, FAQPage when the page answers questions.",
      "result": "pass",
      "evidence": "declared: Organization, PostalAddress, ContactPoint, WebSite, SearchAction, ItemPage",
      "points": 1
    },
    {
      "id": "org-entity",
      "domain": "data",
      "weight": 3,
      "tier": "recommended",
      "title": "Publisher entity is declared and linked",
      "how": "Organization or Person node with name, url, logo, and sameAs to the profiles the brand owns.",
      "fix": "Add an Organization (or Person) JSON-LD node on {{origin}} with name, url, logo, and sameAs links to the profiles the brand actually owns. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "entity with sameAs",
      "points": 1
    },
    {
      "id": "dates",
      "domain": "data",
      "weight": 2,
      "tier": "recommended",
      "title": "Published and modified dates are declared",
      "how": "datePublished and dateModified in the page schema.",
      "fix": "Add datePublished and dateModified to the schema on {{url}}, kept in sync with the visible date. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "no dates in schema",
      "points": 0.5
    },
    {
      "id": "breadcrumb",
      "domain": "data",
      "weight": 1,
      "tier": "recommended",
      "title": "BreadcrumbList declares the page position",
      "how": "A BreadcrumbList with name+item for each level.",
      "fix": "Add a BreadcrumbList to {{url}} whose items match the visible breadcrumb. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "BreadcrumbList present",
      "points": 1
    },
    {
      "id": "product-facts",
      "domain": "data",
      "weight": 4,
      "tier": "recommended",
      "title": "Product facts are in machine-readable form",
      "how": "Product schema with name, image, offers.price, priceCurrency and availability.",
      "fix": "Add Product JSON-LD to {{url}} with name, image, sku, offers.price, offers.priceCurrency, offers.availability and brand. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "Product node without full offers",
      "points": 1
    },
    {
      "id": "product-variants",
      "domain": "data",
      "weight": 2,
      "tier": "recommended",
      "title": "Variants are modelled",
      "how": "hasVariant / ProductGroup entries or an ItemList of variants with size/colour identifiers.",
      "fix": "Model the variants of {{url}} in schema with hasVariant (or a ProductGroup with variesBy) including each size/colour and its own offer. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "variants not modelled",
      "points": 0
    },
    {
      "id": "offer-terms",
      "domain": "data",
      "weight": 2,
      "tier": "recommended",
      "title": "Shipping and return terms are in structured data",
      "how": "shippingDetails and hasMerchantReturnPolicy on the offer.",
      "fix": "Add shippingDetails (OfferShippingDetails) and hasMerchantReturnPolicy to the offers on {{url}}. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "shipping details present",
      "points": 1
    },
    {
      "id": "faq-howto",
      "domain": "data",
      "weight": 1,
      "tier": "optional",
      "title": "Answer-shaped extras where the page answers questions",
      "how": "FAQPage / HowTo / Question blocks when the page contains those answers.",
      "fix": "Mark the question-and-answer pairs on {{url}} as FAQPage, and any ordered steps as HowTo, matching the visible copy. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "Organization,PostalAddress,ContactPoint,WebSite,SearchAction,ItemPage,BreadcrumbList,ListItem,Product,Brand,ImageObject,Offer,OfferShippingDetails,MonetaryAmount,DefinedRegion,ShippingDeliveryTime,QuantitativeValue,MerchantReturnPolicy,FAQPage,Question,Answer",
      "points": 1
    },
    {
      "id": "jsonld-truthful",
      "domain": "data",
      "weight": 2,
      "tier": "recommended",
      "title": "Structured data matches visible content",
      "how": "No price/name mismatch between JSON-LD and the rendered HTML.",
      "fix": "Reconcile JSON-LD with the visible page on {{url}}: {{evidence}} — the declared values must equal what a human sees.",
      "result": "partial",
      "evidence": "schema 30.40 vs page 9.99",
      "points": 0.5
    },
    {
      "id": "reviews",
      "domain": "data",
      "weight": 1,
      "tier": "optional",
      "title": "Ratings or reviews are declared, if real",
      "how": "AggregateRating / Review present only where genuinely shown.",
      "fix": "If reviews are genuinely shown on {{url}}, declare AggregateRating with reviewCount and the individual Review nodes; otherwise leave them out. Evidence: {{evidence}}.",
      "result": "not_applicable",
      "evidence": "ratings",
      "points": null
    },
    {
      "id": "jsonld-valid",
      "domain": "data",
      "weight": 4,
      "tier": "essential",
      "title": "Structured data validates",
      "how": "No parse errors, no missing required properties for the declared type.",
      "fix": "Fix the JSON-LD validation errors on {{url}}: {{evidence}}. Every block must parse and carry the required properties for its type.",
      "result": "pass",
      "evidence": "1 block(s) parse cleanly",
      "points": 1
    },
    {
      "id": "sitemap",
      "domain": "discovery",
      "weight": 4,
      "tier": "essential",
      "title": "A sitemap is declared and lists live URLs",
      "how": "Sitemap referenced in robots.txt, returns XML, entries return 200.",
      "fix": "Publish a sitemap index on {{origin}}, reference it from robots.txt, and list only 200-status canonical URLs. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "declared in robots, 2 URLs in first sitemap",
      "points": 1
    },
    {
      "id": "sitemap-lastmod",
      "domain": "discovery",
      "weight": 2,
      "tier": "recommended",
      "title": "Sitemap entries carry real lastmod",
      "how": "lastmod present and not identical for every URL unless that is true.",
      "fix": "Add truthful <lastmod> values to the sitemap on {{origin}} from real content timestamps. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "no lastmod",
      "points": 0.5
    },
    {
      "id": "sitemap-segmented",
      "domain": "discovery",
      "weight": 1,
      "tier": "recommended",
      "title": "Sitemaps are split by content type",
      "how": "A sitemap index with child sitemaps for pages, products, posts.",
      "fix": "Split the sitemap on {{origin}} into an index plus child sitemaps per content type (pages, products, posts, images). Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "index of child sitemaps",
      "points": 1
    },
    {
      "id": "llms-txt",
      "domain": "discovery",
      "weight": 3,
      "tier": "essential",
      "title": "/llms.txt exists and is served as text",
      "how": "200 at /llms.txt (or /.well-known/llms.txt) with text/plain and a non-empty body.",
      "fix": "Publish /llms.txt on {{origin}} as text/plain: a single H1, a one-line blockquote summary, then H2 sections of [name](url) links to the pages that answer the most common questions. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "HTTP 200, 7590 bytes, text/plain; charset=utf-8",
      "points": 1
    },
    {
      "id": "llms-conform",
      "domain": "discovery",
      "weight": 2,
      "tier": "recommended",
      "title": "llms.txt follows the published format",
      "how": "H1 first, blockquote summary, H2 sections, links in [name](url) form, optional ## Optional section.",
      "fix": "Restructure /llms.txt on {{origin}} to the published format: H1, blockquote summary under it, H2 sections whose bullets are [name](url) with optional \": note\" suffixes, and a ## Optional section for secondary links. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "H1 true, blockquote true, 6 H2, 29 links",
      "points": 1
    },
    {
      "id": "llms-full",
      "domain": "discovery",
      "weight": 1,
      "tier": "optional",
      "title": "/llms-full.txt offers one-request ingestion",
      "how": "A single-document variant exists.",
      "fix": "Publish /llms-full.txt on {{origin}} concatenating the primary content of the site in Markdown for one-request ingestion, and link it from /llms.txt. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "llms-full.txt HTTP 200",
      "points": 1
    },
    {
      "id": "md-mirror",
      "domain": "discovery",
      "weight": 2,
      "tier": "recommended",
      "title": "A Markdown mirror of the page exists",
      "how": "/<path>.md or /<path>/index.md returns text/markdown.",
      "fix": "Publish a Markdown mirror for each page on {{origin}}: serve /<path>.md with Content-Type text/markdown and the same content as the HTML. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "https://orvanipeptides.com/us.md → HTTP 200",
      "points": 1
    },
    {
      "id": "md-negotiation",
      "domain": "discovery",
      "weight": 3,
      "tier": "recommended",
      "title": "Content negotiation returns Markdown on request",
      "how": "Accept: text/markdown yields text/markdown, with Vary: Accept.",
      "fix": "Support Accept: text/markdown on {{origin}}: return the Markdown mirror with Content-Type text/markdown and add Vary: Accept so caches stay separate. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "Accept: text/markdown → text/markdown; charset=utf-8, Vary: Accept",
      "points": 1
    },
    {
      "id": "md-alternate",
      "domain": "discovery",
      "weight": 1,
      "tier": "recommended",
      "title": "HTML advertises its Markdown twin",
      "how": "<link rel=\"alternate\" type=\"text/markdown\" href=\"...\">.",
      "fix": "Add <link rel=\"alternate\" type=\"text/markdown\" href=\"/<path>.md\"> to the head of {{url}}. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "markdown alternate link present",
      "points": 1
    },
    {
      "id": "sitemap-md",
      "domain": "discovery",
      "weight": 1,
      "tier": "recommended",
      "title": "A Markdown sitemap lists the pages in one read",
      "how": "/sitemap.md returns text/markdown listing the site's pages as [title](url).",
      "fix": "Publish /sitemap.md on {{origin}}: a Markdown list of the site's pages as [title](url), one line each, so an agent gets the whole map in one cheap request. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "sitemap.md lists 66 link(s)",
      "points": 1
    },
    {
      "id": "link-headers",
      "domain": "discovery",
      "weight": 2,
      "tier": "recommended",
      "title": "HTTP Link headers point at machine resources",
      "how": "Link: <...>; rel=\"describedby\"/\"alternate\"/\"api-catalog\" on page responses.",
      "fix": "Add Link response headers on {{origin}} pointing at its machine-readable resources: rel=\"describedby\" to /llms.txt, rel=\"api-catalog\" to /.well-known/api-catalog, rel=\"alternate\" to the Markdown mirror. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "</.well-known/api-catalog>; rel=\"api-catalog\"",
      "points": 1
    },
    {
      "id": "dns-aid",
      "domain": "discovery",
      "weight": 1,
      "tier": "bonus",
      "title": "DNS advertises agent endpoints",
      "how": "A discovery TXT/HTTPS record (e.g. _agents or _index._agents) resolves.",
      "fix": "Publish a DNS discovery record for {{origin}} (a TXT record listing the agent endpoints the site exposes) so an agent learns the surface before fetching a page. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no _agents TXT record",
      "points": 0
    },
    {
      "id": "agents-md",
      "domain": "discovery",
      "weight": 2,
      "tier": "recommended",
      "title": "A skill file tells coding agents how to work with the site",
      "how": "/AGENTS.md or /.well-known/agents.md exists.",
      "fix": "Publish /AGENTS.md on {{origin}} describing how a coding agent should build against or use the site: install, configuration, and worked examples. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "AGENTS.md HTTP 200",
      "points": 1
    },
    {
      "id": "agents-md-depth",
      "domain": "discovery",
      "weight": 1,
      "tier": "recommended",
      "title": "The skill file is substantive",
      "how": "Contains at least two of: install, configuration, usage examples.",
      "fix": "Deepen /AGENTS.md on {{origin}} to include install steps, configuration, and at least one complete usage example. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "1/3 of install, configuration, examples",
      "points": 0.5
    },
    {
      "id": "content-signal",
      "domain": "discovery",
      "weight": 2,
      "tier": "recommended",
      "title": "Content usage preferences are declared",
      "how": "A Content-Signal line stating search / ai-input / ai-train.",
      "fix": "Add a Content-Signal line to robots.txt on {{origin}}, e.g. \"Content-Signal: search=yes, ai-input=yes, ai-train=no\", so usage terms are machine-readable. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "search=yes, ai-input=yes, ai-train=yes",
      "points": 1
    },
    {
      "id": "llms-indexes-agents",
      "domain": "discovery",
      "weight": 1,
      "tier": "recommended",
      "title": "The index file advertises the agent entry points",
      "how": "llms.txt or the discovery index names the MCP/API endpoints.",
      "fix": "Add a section to /llms.txt on {{origin}} listing the machine interfaces an agent can call (API base, MCP endpoint, A2A card) with one line each. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "llms.txt names machine interfaces",
      "points": 1
    },
    {
      "id": "describedby",
      "domain": "discovery",
      "weight": 1,
      "tier": "optional",
      "title": "The page declares the index that covers it",
      "how": "rel=\"describedby\" link element or Link header to the covering llms.txt.",
      "fix": "Add a rel=\"describedby\" link to the covering /llms.txt from every page on {{origin}} so an agent can widen from one page to the index. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "rel=describedby to the index",
      "points": 1
    },
    {
      "id": "discovery-file-404",
      "domain": "discovery",
      "weight": 1,
      "tier": "optional",
      "title": "Discovery files do not 404 quietly",
      "how": "Every file the site advertises resolves; no advertised card points at a dead endpoint.",
      "fix": "Remove or publish the advertised-but-missing discovery artefacts on {{origin}}: {{evidence}}. A card for an interface that does not exist is worse than no card.",
      "result": "pass",
      "evidence": "0 advertised file(s) missing",
      "points": 1
    },
    {
      "id": "openapi",
      "domain": "interfaces",
      "weight": 4,
      "tier": "essential",
      "title": "An OpenAPI description is published",
      "how": "/openapi.json or /.well-known/openapi.json parses and declares paths.",
      "fix": "Publish /openapi.json on {{origin}} (OpenAPI 3.1) describing every public endpoint, with operation summaries and example responses. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "17 paths",
      "points": 1
    },
    {
      "id": "api-catalog",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "An API catalog linkset is published",
      "how": "/.well-known/api-catalog returns an RFC 9727 linkset.",
      "fix": "Publish /.well-known/api-catalog on {{origin}} as an RFC 9727 linkset pointing at the API, its OpenAPI description and its docs. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "RFC 9727 linkset",
      "points": 1
    },
    {
      "id": "oauth-protected-resource",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "Protected resources declare their authorization server",
      "how": "/.well-known/oauth-protected-resource (RFC 9728) resolves.",
      "fix": "Publish /.well-known/oauth-protected-resource on {{origin}} naming the resource and its authorization server, so an agent can discover how to get a token without scraping docs. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "oauth-as",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "Authorization server metadata is published",
      "how": "/.well-known/oauth-authorization-server (RFC 8414) resolves.",
      "fix": "Publish /.well-known/oauth-authorization-server on {{origin}} with issuer, authorization_endpoint, token_endpoint and grant types. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "scopes",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "Permissions are scoped",
      "how": "OAuth/OpenAPI declares named scopes or per-endpoint permissions rather than all-or-nothing.",
      "fix": "Replace all-or-nothing credentials on {{origin}} with named scopes (for example read:catalog, write:cart) declared in the OpenAPI security scheme and the authorization-server metadata. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "scopes declared",
      "points": 1
    },
    {
      "id": "auth-md",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "Agent sign-up is documented for machines",
      "how": "/auth.md or a machine-readable credential section exists.",
      "fix": "Publish /auth.md on {{origin}} telling an agent how to register, get a credential and revoke it, with the exact request/response shapes. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "auth.md HTTP 200",
      "points": 1
    },
    {
      "id": "mcp-card",
      "domain": "interfaces",
      "weight": 3,
      "tier": "essential",
      "title": "An MCP server card describes the server",
      "how": "/.well-known/mcp.json or /.well-known/mcp/server-card.json parses.",
      "fix": "Publish an MCP server card at /.well-known/mcp.json on {{origin}}: name, description, transport, endpoint, and the tool list with input schemas. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "MCP card: $schema, name, title, description, version, websiteUrl",
      "points": 1
    },
    {
      "id": "mcp-card-fields",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "The MCP card carries the fields a client needs",
      "how": "Transport, endpoint, auth requirement and at least one tool with an input schema.",
      "fix": "Complete the MCP server card on {{origin}}: transport, endpoint URL, auth requirement, and every tool with a declared input schema and description. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "3/4 required groups in the card",
      "points": 1
    },
    {
      "id": "mcp-live",
      "domain": "interfaces",
      "weight": 3,
      "tier": "essential",
      "title": "The advertised MCP endpoint answers",
      "how": "The endpoint from the card responds to an initialize/tools list request.",
      "fix": "Make the MCP endpoint advertised by {{origin}} actually answer: respond to initialize and tools/list at the URL in the card, and keep the card in sync with the deployed tool set. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "MCP endpoint answered 200",
      "points": 1
    },
    {
      "id": "a2a-card",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "An A2A agent card is published",
      "how": "/.well-known/agent-card.json parses with name, capabilities, skills.",
      "fix": "Publish a /.well-known/agent-card.json on {{origin}} describing the agent: name, description, capabilities, skills and endpoint. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "agent card present",
      "points": 1
    },
    {
      "id": "agent-skills",
      "domain": "interfaces",
      "weight": 1,
      "tier": "bonus",
      "title": "Agent skills are indexable",
      "how": "/.well-known/agent-skills/index.json lists skill documents.",
      "fix": "Publish /.well-known/agent-skills/index.json on {{origin}} listing each skill document with name, description and URL. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "skills index present",
      "points": 1
    },
    {
      "id": "webmcp",
      "domain": "interfaces",
      "weight": 1,
      "tier": "bonus",
      "title": "Site actions are exposed to in-browser agents",
      "how": "WebMCP tool registration is present in the page source.",
      "fix": "Register the site's real actions (search, filter, add to cart) as WebMCP tools on {{origin}} so a browser agent can call them without guessing at the DOM. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no WebMCP registration",
      "points": 0
    },
    {
      "id": "ard",
      "domain": "interfaces",
      "weight": 1,
      "tier": "bonus",
      "title": "One index lists every agent interface",
      "how": "An ARD / AI-catalog manifest enumerates the MCP, A2A, skills and API surfaces.",
      "fix": "Publish an ARD manifest at /.well-known/ard.json on {{origin}} listing every agentic artefact with its type and URL, and advertise it with rel=\"ard\". Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "agents-json",
      "domain": "interfaces",
      "weight": 1,
      "tier": "recommended",
      "title": "A wildcard agent manifest is published",
      "how": "/.well-known/agents.json parses and enumerates agents or actions with a URL each.",
      "fix": "Publish /.well-known/agents.json on {{origin}}: a JSON document naming each agent or action the site accepts, with the URL to call and the input it expects. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "agent-permissions",
      "domain": "interfaces",
      "weight": 1,
      "tier": "recommended",
      "title": "Per-action permissions are declared",
      "how": "/.well-known/agent-permissions.json parses and maps actions to scopes or consent rules.",
      "fix": "Publish /.well-known/agent-permissions.json on {{origin}} mapping each action an agent may take to the scope it needs and whether a human must confirm it. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "nlweb-ask",
      "domain": "interfaces",
      "weight": 1,
      "tier": "recommended",
      "title": "A natural-language query endpoint answers",
      "how": "GET /ask?query= returns a JSON answer with results, not an HTML page.",
      "fix": "Expose a natural-language query endpoint at {{origin}}/ask that accepts ?query= and returns JSON (answer plus result URLs), so an agent can ask the site directly instead of crawling it. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "/ask → HTTP 404, text/html; charset=utf-8",
      "points": 0
    },
    {
      "id": "a2ui",
      "domain": "interfaces",
      "weight": 1,
      "tier": "bonus",
      "title": "The interface is declared for agent-driven UI",
      "how": "The page or its headers declare an A2UI surface, or the app publishes an A2UI manifest.",
      "fix": "Declare an agent-driven UI surface on {{origin}}: mark the page (or publish a manifest) as A2UI so a reviewing agent knows the controls are renderable from a declared schema rather than inferred from the DOM. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no A2UI declaration",
      "points": 0
    },
    {
      "id": "pap",
      "domain": "interfaces",
      "weight": 1,
      "tier": "bonus",
      "title": "A personal-agent profile is published",
      "how": "/.well-known/personal-agent.json parses with the identity and consent rules for agents acting for a signed-in user.",
      "fix": "Publish /.well-known/personal-agent.json on {{origin}} describing how an agent acting for a signed-in person is identified and what it may do on their behalf. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "web-bot-auth",
      "domain": "access",
      "weight": 1,
      "tier": "bonus",
      "title": "The site publishes its own bot signing keys",
      "how": "/.well-known/http-message-signatures-directory returns a JWKS an agent can verify this site's outbound bot requests against.",
      "fix": "Publish a signing-key directory at {{origin}}/.well-known/http-message-signatures-directory so another site can verify requests this site's bots send. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "json-errors",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "Errors are machine-readable",
      "how": "Unknown API routes return JSON with a type/title/status, not an HTML error page.",
      "fix": "Return RFC 9457 problem-details JSON for every error on {{origin}}, including unknown routes, so an agent can recover instead of parsing an HTML error page. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "unknown API path returned text/html; charset=utf-8",
      "points": 0.5
    },
    {
      "id": "rate-limit-headers",
      "domain": "interfaces",
      "weight": 1,
      "tier": "recommended",
      "title": "Rate limits are declared in headers",
      "how": "RateLimit-* / X-RateLimit-* or Retry-After on API responses.",
      "fix": "Emit RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset (and Retry-After on 429) from the API on {{origin}}. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no rate-limit headers",
      "points": 0
    },
    {
      "id": "fc-friendly",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "The API is easy to call from a model",
      "how": "Flat parameters, enums over free text, descriptions on every field, no nested auth dance.",
      "fix": "Simplify the API surface on {{origin}} for function calling: flat named parameters, enums instead of free-text where possible, and a description on every field in the OpenAPI spec. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "0 described properties in the schema",
      "points": 0.5
    },
    {
      "id": "dev-portal",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "A developer portal is reachable from the homepage",
      "how": "A link to docs/API reference from the homepage or main nav.",
      "fix": "Link the developer docs from the homepage and main navigation of {{origin}} — one hop, not three. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no developer link",
      "points": 0
    },
    {
      "id": "public-api",
      "domain": "interfaces",
      "weight": 3,
      "tier": "recommended",
      "title": "A public API answers without a human",
      "how": "At least one documented endpoint responds to an unauthenticated request.",
      "fix": "Expose at least one unauthenticated read endpoint on {{origin}} that returns the site's core facts as JSON, and document it in the OpenAPI spec. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "GET paths declared",
      "points": 0.5
    },
    {
      "id": "agent-instruction",
      "domain": "interfaces",
      "weight": 2,
      "tier": "recommended",
      "title": "The site tells an agent when to use it",
      "how": "A when-to-use / instructions block in the manifest, llms.txt or MCP card.",
      "fix": "Add a when-to-use block to {{origin}} (in llms.txt, the MCP card or the agent manifest) stating what the agent is for, what it must not do, and one worked call. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no when-to-use block",
      "points": 0
    },
    {
      "id": "idempotency",
      "domain": "interfaces",
      "weight": 1,
      "tier": "optional",
      "title": "Writes are retry-safe",
      "how": "Idempotency-Key accepted on POST, or a documented natural key.",
      "fix": "Accept an Idempotency-Key header on mutating endpoints of {{origin}} and document it, so an agent can retry without duplicating work. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "Idempotency-Key documented",
      "points": 0
    },
    {
      "id": "agent-discovery-path",
      "domain": "interfaces",
      "weight": 1,
      "tier": "optional",
      "title": "Discovery lives at predictable paths",
      "how": "The well-known paths used are the conventional ones, not bespoke URLs.",
      "fix": "Move the machine-readable artefacts on {{origin}} to their conventional paths (/.well-known/*, /llms.txt, /sitemap.xml) and keep redirects from the old ones. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "conventional paths probed",
      "points": 1
    },
    {
      "id": "payment-negotiation",
      "domain": "interfaces",
      "weight": 1,
      "tier": "optional",
      "title": "Paid access is discoverable by an agent",
      "how": "A 402 challenge carries the payment requirements, or pricing is machine-readable.",
      "fix": "Make paid access discoverable on {{origin}}: return HTTP 402 with a machine-readable list of accepted payment options, or publish a machine-readable price list. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "x402 discovery HTTP 404",
      "points": 0
    },
    {
      "id": "ucp-profile",
      "domain": "commerce",
      "weight": 3,
      "tier": "recommended",
      "title": "A commerce profile is published",
      "how": "/.well-known/ucp returns a valid commerce protocol profile.",
      "fix": "Publish a commerce profile at /.well-known/ucp on {{origin}} declaring the merchant, the catalogue, and the endpoints an agent may call. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "HTTP 404",
      "points": 0
    },
    {
      "id": "agent-endpoint",
      "domain": "commerce",
      "weight": 3,
      "tier": "recommended",
      "title": "The advertised commerce endpoint is live",
      "how": "The endpoint in the profile responds with catalogue/cart operations.",
      "fix": "Make the commerce endpoint advertised by {{origin}} answer for real: catalogue read, cart create, cart update. Register {{evidence}}.",
      "result": "not_applicable",
      "evidence": "no endpoint advertised",
      "points": null
    },
    {
      "id": "checkout-permalink",
      "domain": "commerce",
      "weight": 2,
      "tier": "recommended",
      "title": "A cart can be handed back to a shopper",
      "how": "A cart or checkout permalink an agent can send to a human.",
      "fix": "Add a shareable cart/checkout permalink on {{origin}} that carries line items in the URL, so an agent can build a cart and hand the link to a person. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no cart permalink",
      "points": 0
    },
    {
      "id": "x402",
      "domain": "commerce",
      "weight": 1,
      "tier": "bonus",
      "title": "Machine payment is accepted",
      "how": "x402 accepts array on a 402 response, or an advertised payment resource.",
      "fix": "Accept machine payment on {{origin}}: answer with HTTP 402 and an x402 accepts array (asset, amount, network, payTo) on the paid resource. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no x402 accepts array",
      "points": 0
    },
    {
      "id": "ap2",
      "domain": "commerce",
      "weight": 1,
      "tier": "bonus",
      "title": "Delegated payment authorization is advertised",
      "how": "AP2 support declared on the agent card or commerce profile.",
      "fix": "Advertise delegated payment authorization on {{origin}} (AP2 extension on the agent card or commerce profile) with the mandate shapes you accept. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "AP2 advertised",
      "points": 0
    },
    {
      "id": "acp-profile",
      "domain": "commerce",
      "weight": 1,
      "tier": "bonus",
      "title": "A checkout protocol profile is published",
      "how": "/.well-known/acp.json or equivalent.",
      "fix": "Publish a checkout-protocol profile at /.well-known/acp.json on {{origin}} naming the checkout endpoint and supported payment methods. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "acp profile HTTP 404",
      "points": 0
    },
    {
      "id": "add-to-cart",
      "domain": "commerce",
      "weight": 3,
      "tier": "essential",
      "title": "Add-to-cart is a real labelled control",
      "how": "A <button> or <input type=submit> inside a form, with an accessible name, not a div with a click handler.",
      "fix": "Replace the add-to-cart div on {{url}} with a real <button type=\"submit\"> inside a <form>, with an accessible name that includes the product. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no add-to-cart control",
      "points": 0
    },
    {
      "id": "variant-controls",
      "domain": "commerce",
      "weight": 3,
      "tier": "essential",
      "title": "Variant pickers are real form controls",
      "how": "select/input/radiogroup elements with names and labels for each option.",
      "fix": "Convert the variant pickers on {{url}} to real form controls (select or radio inputs) with a label per option, so an agent can set a value. Evidence: {{evidence}}.",
      "result": "fail",
      "evidence": "no variant form controls",
      "points": 0
    },
    {
      "id": "site-search",
      "domain": "commerce",
      "weight": 3,
      "tier": "essential",
      "title": "Search works through a GET URL",
      "how": "A search form that produces a shareable ?q= URL returning results in HTML.",
      "fix": "Make site search on {{origin}} work over GET with a ?q= parameter that returns results in the server HTML, so an agent can construct a search URL. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "no GET search form",
      "points": 0.5
    },
    {
      "id": "pdp-facts-html",
      "domain": "commerce",
      "weight": 4,
      "tier": "essential",
      "title": "Price, stock and variants are in the HTML",
      "how": "Product name, price, currency and availability in the raw HTML of the product page.",
      "fix": "Put product name, price, currency and availability in the server HTML of {{url}} — not fetched client-side — with the variants listed. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "price in server HTML",
      "points": 1
    },
    {
      "id": "guest-checkout",
      "domain": "commerce",
      "weight": 2,
      "tier": "recommended",
      "title": "A cart can be built without an account",
      "how": "Cart add succeeds unauthenticated; checkout does not require login before payment.",
      "fix": "Allow an unauthenticated cart on {{origin}} and do not force account creation before payment; if accounts are required by policy, say so in llms.txt with the exact steps. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "no login wall before cart",
      "points": 1
    },
    {
      "id": "checkout-docs",
      "domain": "commerce",
      "weight": 2,
      "tier": "recommended",
      "title": "Checkout terms an agent needs are documented",
      "how": "Shipping, returns, tax/VAT and lead time stated in text an agent can read.",
      "fix": "Document the checkout terms an agent must know on {{origin}}: shipping cost and regions, return window, tax handling, and lead time. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "checkout terms incomplete",
      "points": 0.5
    },
    {
      "id": "policy-links",
      "domain": "commerce",
      "weight": 2,
      "tier": "recommended",
      "title": "Policy pages are linked sitewide",
      "how": "Returns, shipping, terms, privacy and contact reachable from every page.",
      "fix": "Link returns, shipping, terms, privacy and contact from the footer of every page on {{origin}}. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "4/5 policy pages linked",
      "points": 1
    },
    {
      "id": "author",
      "domain": "trust",
      "weight": 3,
      "tier": "recommended",
      "title": "A named, accountable author or publisher",
      "how": "Visible author byline or declared publisher with a real identity.",
      "fix": "Show a named author or accountable publisher on {{url}}, with a link to an about page that establishes who they are. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "author declared",
      "points": 1
    },
    {
      "id": "visible-date",
      "domain": "trust",
      "weight": 2,
      "tier": "recommended",
      "title": "A visible publish or update date",
      "how": "A human-readable date on the page matching the schema dates.",
      "fix": "Show a visible publish or last-updated date on {{url}} that matches dateModified in the schema. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "no visible date",
      "points": 0.5
    },
    {
      "id": "sources",
      "domain": "trust",
      "weight": 2,
      "tier": "recommended",
      "title": "Claims are checkable",
      "how": "Outbound links to primary sources for factual claims.",
      "fix": "Add outbound links to primary sources for the factual claims on {{url}} — the operator documentation, study or specification, not another summary. Evidence: {{evidence}}.",
      "result": "partial",
      "evidence": "1 outbound source link(s)",
      "points": 0.5
    },
    {
      "id": "about-contact",
      "domain": "trust",
      "weight": 2,
      "tier": "recommended",
      "title": "About and contact are reachable",
      "how": "An about page and a contact method one hop from the page.",
      "fix": "Publish a reachable About and Contact page on {{origin}} and link both from the footer. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "about/contact reachable",
      "points": 1
    },
    {
      "id": "org-completeness",
      "domain": "trust",
      "weight": 2,
      "tier": "recommended",
      "title": "The organization node is complete",
      "how": "legalName, address, contactPoint, logo, sameAs in the Organization schema.",
      "fix": "Complete the Organization schema on {{origin}} with legalName, address, contactPoint, logo and sameAs. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "legalName declared",
      "points": 1
    },
    {
      "id": "entity-consistency",
      "domain": "trust",
      "weight": 2,
      "tier": "recommended",
      "title": "The brand is named the same way everywhere",
      "how": "Consistent brand string across title, og:site_name, schema name, llms.txt and footer.",
      "fix": "Make the brand name identical across the title suffix, og:site_name, schema Organization.name, llms.txt heading and footer on {{origin}} — one canonical string. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "brand string \"Orvani Peptides · Research pep\"",
      "points": 1
    },
    {
      "id": "https",
      "domain": "trust",
      "weight": 2,
      "tier": "essential",
      "title": "Every page is served over HTTPS",
      "how": "HTTPS with a valid certificate; http:// redirects to https://.",
      "fix": "Serve {{origin}} only over HTTPS and 301 every http:// URL to https://. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "https origin, http:// answered 301",
      "points": 1
    },
    {
      "id": "mixed-content",
      "domain": "trust",
      "weight": 1,
      "tier": "recommended",
      "title": "No insecure subresources",
      "how": "No http:// script/img/css on an https page.",
      "fix": "Rewrite the http:// subresources on {{url}} to https:// and keep the scheme relative. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "no insecure subresources",
      "points": 1
    },
    {
      "id": "security-headers",
      "domain": "trust",
      "weight": 1,
      "tier": "optional",
      "title": "Baseline security headers are set",
      "how": "HSTS, X-Content-Type-Options: nosniff, and a Referrer-Policy.",
      "fix": "Set Strict-Transport-Security, X-Content-Type-Options: nosniff and Referrer-Policy: strict-origin-when-cross-origin on {{origin}}. Evidence: {{evidence}}.",
      "result": "pass",
      "evidence": "HSTS yes, nosniff yes",
      "points": 1
    },
    {
      "id": "no-broken-links",
      "domain": "trust",
      "weight": 1,
      "tier": "recommended",
      "title": "Sampled internal links resolve",
      "how": "No 404s among the internal links sampled from the page.",
      "fix": "Fix the broken internal links found on {{url}}: {{evidence}}.",
      "result": "pass",
      "evidence": "0 broken among 3 sampled links",
      "points": 1
    }
  ],
  "crawlers": [
    {
      "ua": "OAI-SearchBot",
      "platform": "ChatGPT search",
      "role": "search",
      "weight": 10,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1098,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "ChatGPT-User",
      "platform": "ChatGPT",
      "role": "user",
      "weight": 9,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1093,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Claude-SearchBot",
      "platform": "Claude search",
      "role": "search",
      "weight": 10,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1185,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Claude-User",
      "platform": "Claude",
      "role": "user",
      "weight": 9,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1085,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "PerplexityBot",
      "platform": "Perplexity",
      "role": "search",
      "weight": 10,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1094,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Perplexity-User",
      "platform": "Perplexity",
      "role": "user",
      "weight": 9,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1082,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Googlebot",
      "platform": "Google / AI Overviews",
      "role": "search",
      "weight": 10,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1191,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Google-Agent",
      "platform": "Google AI Mode",
      "role": "user",
      "weight": 7,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1190,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Google-GeminiNotebook",
      "platform": "Gemini",
      "role": "user",
      "weight": 5,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1090,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "bingbot",
      "platform": "Bing / Copilot",
      "role": "search",
      "weight": 8,
      "tier": 1,
      "status": 200,
      "bytes": 79544,
      "ms": 1183,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Applebot",
      "platform": "Siri / Apple Intelligence",
      "role": "search",
      "weight": 6,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1261,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "meta-webindexer",
      "platform": "Meta AI",
      "role": "search",
      "weight": 5,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1265,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "meta-externalfetcher",
      "platform": "Meta AI",
      "role": "user",
      "weight": 5,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1265,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "MistralAI-Index",
      "platform": "Mistral Le Chat",
      "role": "search",
      "weight": 4,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1267,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "MistralAI-User",
      "platform": "Mistral Le Chat",
      "role": "user",
      "weight": 4,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1268,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Amzn-SearchBot",
      "platform": "Alexa",
      "role": "search",
      "weight": 4,
      "tier": 2,
      "status": 200,
      "bytes": 79544,
      "ms": 1271,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Amzn-User",
      "platform": "Alexa",
      "role": "user",
      "weight": 3,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1355,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "DuckAssistBot",
      "platform": "DuckDuckGo AI",
      "role": "search",
      "weight": 3,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1361,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "YouBot",
      "platform": "You.com",
      "role": "search",
      "weight": 3,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1358,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "GPTBot",
      "platform": "OpenAI training",
      "role": "train",
      "weight": 0,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1364,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "ClaudeBot",
      "platform": "Anthropic training",
      "role": "train",
      "weight": 0,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1362,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Google-Extended",
      "platform": "Gemini training",
      "role": "train",
      "weight": 0,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1365,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Applebot-Extended",
      "platform": "Apple training",
      "role": "train",
      "weight": 0,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1447,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "CCBot",
      "platform": "Common Crawl",
      "role": "train",
      "weight": 0,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1456,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Bytespider",
      "platform": "ByteDance",
      "role": "train",
      "weight": 0,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1449,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "meta-externalagent",
      "platform": "Meta training",
      "role": "train",
      "weight": 0,
      "tier": 3,
      "status": 200,
      "bytes": 79544,
      "ms": 1450,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "cohere-ai",
      "platform": "Cohere training",
      "role": "train",
      "weight": 0,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1454,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "AI2Bot",
      "platform": "Allen Institute",
      "role": "train",
      "weight": 0,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1456,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Diffbot",
      "platform": "Diffbot",
      "role": "other",
      "weight": 1,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1538,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Amazonbot",
      "platform": "Amazon",
      "role": "train",
      "weight": 0,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1539,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "GoogleOther",
      "platform": "Google other",
      "role": "other",
      "weight": 1,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1542,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    },
    {
      "ua": "Google-CloudVertexBot",
      "platform": "Vertex AI",
      "role": "train",
      "weight": 0,
      "tier": 4,
      "status": 200,
      "bytes": 79544,
      "ms": 1542,
      "robotsAllowed": true,
      "rule": "allow: /",
      "blocked": false,
      "challenged": false,
      "verdict": "allowed"
    }
  ],
  "fixes": [
    {
      "id": "ucp-profile",
      "domain": "commerce",
      "title": "A commerce profile is published",
      "weight": 3,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 3,
      "prompt": "Publish a commerce profile at /.well-known/ucp on https://orvanipeptides.com declaring the merchant, the catalogue, and the endpoints an agent may call. Evidence: HTTP 404."
    },
    {
      "id": "add-to-cart",
      "domain": "commerce",
      "title": "Add-to-cart is a real labelled control",
      "weight": 3,
      "result": "fail",
      "evidence": "no add-to-cart control",
      "recoverable": 3,
      "prompt": "Replace the add-to-cart div on https://orvanipeptides.com/us with a real <button type=\"submit\"> inside a <form>, with an accessible name that includes the product. Evidence: no add-to-cart control."
    },
    {
      "id": "variant-controls",
      "domain": "commerce",
      "title": "Variant pickers are real form controls",
      "weight": 3,
      "result": "fail",
      "evidence": "no variant form controls",
      "recoverable": 3,
      "prompt": "Convert the variant pickers on https://orvanipeptides.com/us to real form controls (select or radio inputs) with a label per option, so an agent can set a value. Evidence: no variant form controls."
    },
    {
      "id": "text-ratio",
      "domain": "render",
      "title": "Text-to-markup ratio is workable",
      "weight": 2,
      "result": "fail",
      "evidence": "text/markup 1.9%",
      "recoverable": 2,
      "prompt": "Raise the text-to-markup ratio on https://orvanipeptides.com/us to at least 5%: trim wrapper divs and inline styles, and put the copy in plain elements. Evidence: text/markup 1.9%."
    },
    {
      "id": "product-variants",
      "domain": "data",
      "title": "Variants are modelled",
      "weight": 2,
      "result": "fail",
      "evidence": "variants not modelled",
      "recoverable": 2,
      "prompt": "Model the variants of https://orvanipeptides.com/us in schema with hasVariant (or a ProductGroup with variesBy) including each size/colour and its own offer. Evidence: variants not modelled."
    },
    {
      "id": "oauth-protected-resource",
      "domain": "interfaces",
      "title": "Protected resources declare their authorization server",
      "weight": 2,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 2,
      "prompt": "Publish /.well-known/oauth-protected-resource on https://orvanipeptides.com naming the resource and its authorization server, so an agent can discover how to get a token without scraping docs. Evidence: HTTP 404."
    },
    {
      "id": "oauth-as",
      "domain": "interfaces",
      "title": "Authorization server metadata is published",
      "weight": 2,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 2,
      "prompt": "Publish /.well-known/oauth-authorization-server on https://orvanipeptides.com with issuer, authorization_endpoint, token_endpoint and grant types. Evidence: HTTP 404."
    },
    {
      "id": "dev-portal",
      "domain": "interfaces",
      "title": "A developer portal is reachable from the homepage",
      "weight": 2,
      "result": "fail",
      "evidence": "no developer link",
      "recoverable": 2,
      "prompt": "Link the developer docs from the homepage and main navigation of https://orvanipeptides.com — one hop, not three. Evidence: no developer link."
    },
    {
      "id": "agent-instruction",
      "domain": "interfaces",
      "title": "The site tells an agent when to use it",
      "weight": 2,
      "result": "fail",
      "evidence": "no when-to-use block",
      "recoverable": 2,
      "prompt": "Add a when-to-use block to https://orvanipeptides.com (in llms.txt, the MCP card or the agent manifest) stating what the agent is for, what it must not do, and one worked call. Evidence: no when-to-use block."
    },
    {
      "id": "checkout-permalink",
      "domain": "commerce",
      "title": "A cart can be handed back to a shopper",
      "weight": 2,
      "result": "fail",
      "evidence": "no cart permalink",
      "recoverable": 2,
      "prompt": "Add a shareable cart/checkout permalink on https://orvanipeptides.com that carries line items in the URL, so an agent can build a cart and hand the link to a person. Evidence: no cart permalink."
    },
    {
      "id": "ttfb",
      "domain": "render",
      "title": "Response is fast enough for an agent timeout",
      "weight": 3,
      "result": "partial",
      "evidence": "1358 ms to first byte",
      "recoverable": 1.5,
      "prompt": "Speed up the server response for https://orvanipeptides.com/us: TTFB should land under 800 ms. Cache the HTML at the edge, and remove synchronous calls from the render path. Evidence: 1358 ms to first byte."
    },
    {
      "id": "public-api",
      "domain": "interfaces",
      "title": "A public API answers without a human",
      "weight": 3,
      "result": "partial",
      "evidence": "GET paths declared",
      "recoverable": 1.5,
      "prompt": "Expose at least one unauthenticated read endpoint on https://orvanipeptides.com that returns the site's core facts as JSON, and document it in the OpenAPI spec. Evidence: GET paths declared."
    },
    {
      "id": "site-search",
      "domain": "commerce",
      "title": "Search works through a GET URL",
      "weight": 3,
      "result": "partial",
      "evidence": "no GET search form",
      "recoverable": 1.5,
      "prompt": "Make site search on https://orvanipeptides.com work over GET with a ?q= parameter that returns results in the server HTML, so an agent can construct a search URL. Evidence: no GET search form."
    },
    {
      "id": "snippets-allowed",
      "domain": "access",
      "title": "Snippets and large image previews are allowed",
      "weight": 2,
      "result": "partial",
      "evidence": "snippet directives incomplete",
      "recoverable": 1,
      "prompt": "On https://orvanipeptides.com set \"max-snippet:-1, max-image-preview:large\" in the meta robots tag or X-Robots-Tag so assistants can quote the page. Evidence: snippet directives incomplete."
    },
    {
      "id": "dates",
      "domain": "data",
      "title": "Published and modified dates are declared",
      "weight": 2,
      "result": "partial",
      "evidence": "no dates in schema",
      "recoverable": 1,
      "prompt": "Add datePublished and dateModified to the schema on https://orvanipeptides.com/us, kept in sync with the visible date. Evidence: no dates in schema."
    },
    {
      "id": "jsonld-truthful",
      "domain": "data",
      "title": "Structured data matches visible content",
      "weight": 2,
      "result": "partial",
      "evidence": "schema 30.40 vs page 9.99",
      "recoverable": 1,
      "prompt": "Reconcile JSON-LD with the visible page on https://orvanipeptides.com/us: schema 30.40 vs page 9.99 — the declared values must equal what a human sees."
    },
    {
      "id": "sitemap-lastmod",
      "domain": "discovery",
      "title": "Sitemap entries carry real lastmod",
      "weight": 2,
      "result": "partial",
      "evidence": "no lastmod",
      "recoverable": 1,
      "prompt": "Add truthful <lastmod> values to the sitemap on https://orvanipeptides.com from real content timestamps. Evidence: no lastmod."
    },
    {
      "id": "dns-aid",
      "domain": "discovery",
      "title": "DNS advertises agent endpoints",
      "weight": 1,
      "result": "fail",
      "evidence": "no _agents TXT record",
      "recoverable": 1,
      "prompt": "Publish a DNS discovery record for https://orvanipeptides.com (a TXT record listing the agent endpoints the site exposes) so an agent learns the surface before fetching a page. Evidence: no _agents TXT record."
    },
    {
      "id": "webmcp",
      "domain": "interfaces",
      "title": "Site actions are exposed to in-browser agents",
      "weight": 1,
      "result": "fail",
      "evidence": "no WebMCP registration",
      "recoverable": 1,
      "prompt": "Register the site's real actions (search, filter, add to cart) as WebMCP tools on https://orvanipeptides.com so a browser agent can call them without guessing at the DOM. Evidence: no WebMCP registration."
    },
    {
      "id": "ard",
      "domain": "interfaces",
      "title": "One index lists every agent interface",
      "weight": 1,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 1,
      "prompt": "Publish an ARD manifest at /.well-known/ard.json on https://orvanipeptides.com listing every agentic artefact with its type and URL, and advertise it with rel=\"ard\". Evidence: HTTP 404."
    },
    {
      "id": "agents-json",
      "domain": "interfaces",
      "title": "A wildcard agent manifest is published",
      "weight": 1,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 1,
      "prompt": "Publish /.well-known/agents.json on https://orvanipeptides.com: a JSON document naming each agent or action the site accepts, with the URL to call and the input it expects. Evidence: HTTP 404."
    },
    {
      "id": "agent-permissions",
      "domain": "interfaces",
      "title": "Per-action permissions are declared",
      "weight": 1,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 1,
      "prompt": "Publish /.well-known/agent-permissions.json on https://orvanipeptides.com mapping each action an agent may take to the scope it needs and whether a human must confirm it. Evidence: HTTP 404."
    },
    {
      "id": "nlweb-ask",
      "domain": "interfaces",
      "title": "A natural-language query endpoint answers",
      "weight": 1,
      "result": "fail",
      "evidence": "/ask → HTTP 404, text/html; charset=utf-8",
      "recoverable": 1,
      "prompt": "Expose a natural-language query endpoint at https://orvanipeptides.com/ask that accepts ?query= and returns JSON (answer plus result URLs), so an agent can ask the site directly instead of crawling it. Evidence: /ask → HTTP 404, text/html; charset=utf-8."
    },
    {
      "id": "a2ui",
      "domain": "interfaces",
      "title": "The interface is declared for agent-driven UI",
      "weight": 1,
      "result": "fail",
      "evidence": "no A2UI declaration",
      "recoverable": 1,
      "prompt": "Declare an agent-driven UI surface on https://orvanipeptides.com: mark the page (or publish a manifest) as A2UI so a reviewing agent knows the controls are renderable from a declared schema rather than inferred from the DOM. Evidence: no A2UI declaration."
    },
    {
      "id": "pap",
      "domain": "interfaces",
      "title": "A personal-agent profile is published",
      "weight": 1,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 1,
      "prompt": "Publish /.well-known/personal-agent.json on https://orvanipeptides.com describing how an agent acting for a signed-in person is identified and what it may do on their behalf. Evidence: HTTP 404."
    },
    {
      "id": "web-bot-auth",
      "domain": "access",
      "title": "The site publishes its own bot signing keys",
      "weight": 1,
      "result": "fail",
      "evidence": "HTTP 404",
      "recoverable": 1,
      "prompt": "Publish a signing-key directory at https://orvanipeptides.com/.well-known/http-message-signatures-directory so another site can verify requests this site's bots send. Evidence: HTTP 404."
    },
    {
      "id": "json-errors",
      "domain": "interfaces",
      "title": "Errors are machine-readable",
      "weight": 2,
      "result": "partial",
      "evidence": "unknown API path returned text/html; charset=utf-8",
      "recoverable": 1,
      "prompt": "Return RFC 9457 problem-details JSON for every error on https://orvanipeptides.com, including unknown routes, so an agent can recover instead of parsing an HTML error page. Evidence: unknown API path returned text/html; charset=utf-8."
    },
    {
      "id": "rate-limit-headers",
      "domain": "interfaces",
      "title": "Rate limits are declared in headers",
      "weight": 1,
      "result": "fail",
      "evidence": "no rate-limit headers",
      "recoverable": 1,
      "prompt": "Emit RateLimit-Limit / RateLimit-Remaining / RateLimit-Reset (and Retry-After on 429) from the API on https://orvanipeptides.com. Evidence: no rate-limit headers."
    },
    {
      "id": "fc-friendly",
      "domain": "interfaces",
      "title": "The API is easy to call from a model",
      "weight": 2,
      "result": "partial",
      "evidence": "0 described properties in the schema",
      "recoverable": 1,
      "prompt": "Simplify the API surface on https://orvanipeptides.com for function calling: flat named parameters, enums instead of free-text where possible, and a description on every field in the OpenAPI spec. Evidence: 0 described properties in the schema."
    },
    {
      "id": "idempotency",
      "domain": "interfaces",
      "title": "Writes are retry-safe",
      "weight": 1,
      "result": "fail",
      "evidence": "Idempotency-Key documented",
      "recoverable": 1,
      "prompt": "Accept an Idempotency-Key header on mutating endpoints of https://orvanipeptides.com and document it, so an agent can retry without duplicating work. Evidence: Idempotency-Key documented."
    },
    {
      "id": "payment-negotiation",
      "domain": "interfaces",
      "title": "Paid access is discoverable by an agent",
      "weight": 1,
      "result": "fail",
      "evidence": "x402 discovery HTTP 404",
      "recoverable": 1,
      "prompt": "Make paid access discoverable on https://orvanipeptides.com: return HTTP 402 with a machine-readable list of accepted payment options, or publish a machine-readable price list. Evidence: x402 discovery HTTP 404."
    },
    {
      "id": "x402",
      "domain": "commerce",
      "title": "Machine payment is accepted",
      "weight": 1,
      "result": "fail",
      "evidence": "no x402 accepts array",
      "recoverable": 1,
      "prompt": "Accept machine payment on https://orvanipeptides.com: answer with HTTP 402 and an x402 accepts array (asset, amount, network, payTo) on the paid resource. Evidence: no x402 accepts array."
    },
    {
      "id": "ap2",
      "domain": "commerce",
      "title": "Delegated payment authorization is advertised",
      "weight": 1,
      "result": "fail",
      "evidence": "AP2 advertised",
      "recoverable": 1,
      "prompt": "Advertise delegated payment authorization on https://orvanipeptides.com (AP2 extension on the agent card or commerce profile) with the mandate shapes you accept. Evidence: AP2 advertised."
    },
    {
      "id": "acp-profile",
      "domain": "commerce",
      "title": "A checkout protocol profile is published",
      "weight": 1,
      "result": "fail",
      "evidence": "acp profile HTTP 404",
      "recoverable": 1,
      "prompt": "Publish a checkout-protocol profile at /.well-known/acp.json on https://orvanipeptides.com naming the checkout endpoint and supported payment methods. Evidence: acp profile HTTP 404."
    },
    {
      "id": "checkout-docs",
      "domain": "commerce",
      "title": "Checkout terms an agent needs are documented",
      "weight": 2,
      "result": "partial",
      "evidence": "checkout terms incomplete",
      "recoverable": 1,
      "prompt": "Document the checkout terms an agent must know on https://orvanipeptides.com: shipping cost and regions, return window, tax handling, and lead time. Evidence: checkout terms incomplete."
    },
    {
      "id": "visible-date",
      "domain": "trust",
      "title": "A visible publish or update date",
      "weight": 2,
      "result": "partial",
      "evidence": "no visible date",
      "recoverable": 1,
      "prompt": "Show a visible publish or last-updated date on https://orvanipeptides.com/us that matches dateModified in the schema. Evidence: no visible date."
    },
    {
      "id": "sources",
      "domain": "trust",
      "title": "Claims are checkable",
      "weight": 2,
      "result": "partial",
      "evidence": "1 outbound source link(s)",
      "recoverable": 1,
      "prompt": "Add outbound links to primary sources for the factual claims on https://orvanipeptides.com/us — the operator documentation, study or specification, not another summary. Evidence: 1 outbound source link(s)."
    },
    {
      "id": "compression",
      "domain": "render",
      "title": "Text responses are compressed",
      "weight": 1,
      "result": "partial",
      "evidence": "no compression header relayed",
      "recoverable": 0.5,
      "prompt": "Enable Brotli/gzip compression for HTML and JSON on https://orvanipeptides.com. Evidence: no compression header relayed."
    },
    {
      "id": "agents-md-depth",
      "domain": "discovery",
      "title": "The skill file is substantive",
      "weight": 1,
      "result": "partial",
      "evidence": "1/3 of install, configuration, examples",
      "recoverable": 0.5,
      "prompt": "Deepen /AGENTS.md on https://orvanipeptides.com to include install steps, configuration, and at least one complete usage example. Evidence: 1/3 of install, configuration, examples."
    }
  ],
  "counts": {
    "total": 120,
    "applicable": 117,
    "pass": 78,
    "partial": 14,
    "fail": 25,
    "notApplicable": 3,
    "inconclusive": 0
  },
  "durationMs": 7320,
  "cache": {
    "hit": true,
    "ageMs": 965172,
    "ttlMs": 21600000
  }
}
