{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://siteline.to/schemas/scan-result.schema.json",
  "title": "Siteline Scan Result",
  "description": "The structured result of a Siteline agent-readiness scan. Covers Signal, Navigate, Absorb, and Perform pillars.",
  "type": "object",
  "required": ["ok", "normalizedURL", "domain", "scannedAt", "grade", "score", "label"],
  "properties": {
    "ok": { "type": "boolean", "const": true },
    "normalizedURL": { "type": "string", "format": "uri" },
    "domain": { "type": "string" },
    "scannedAt": { "type": "string", "format": "date-time" },
    "resultId": { "type": "string", "description": "Identifier issued only after durable storage confirms the save. New scans use domain-slug-v2-identity-hash-YYYYMMDD; the hash includes the full normalized request URL and site-type hint. Existing legacy IDs remain readable." },
    "persistence": {"type": "object", "description": "Report storage outcome. An unsaved scan has no resultId or shareable report; retry to save it.", "required": ["stored"], "properties": {"stored": {"type": "boolean"}, "reason": {"type": "string", "enum": ["unavailable", "timeout", "failed", "invalid_scope"]}, "detail": {"type": "string"}}},
    "grade": { "type": "string", "enum": ["A", "B", "C", "D", "F"] },
    "score": { "type": "integer", "minimum": 0, "maximum": 100 },
    "label": {
      "type": "string",
      "enum": ["Agent-Usable", "Nearly Agent-Ready", "Mostly Usable", "Needs Clearer Paths", "Needs More Agentic Resources", "Needs Agentic Foundations", "Hard for Agents", "Agent-Blocked or Unusable"]
    },
    "likelyFailureMode": { "type": "string" },
    "pillars": {
      "type": "object",
      "description": "Per-pillar scores (0-100).",
      "properties": {
        "access": { "type": "integer", "minimum": 0, "maximum": 100 },
        "navigability": { "type": "integer", "minimum": 0, "maximum": 100 },
        "readability": { "type": "integer", "minimum": 0, "maximum": 100 },
        "actionHandoff": { "type": "integer", "minimum": 0, "maximum": 100 }
      }
    },
    "provenance": {
      "type": "object",
      "properties": {
        "rubricVersion": { "type": "string" },
        "scannerVersion": { "type": "string" },
        "scanDurationMs": { "type": "integer" },
        "pagesFetched": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "url": { "type": ["string", "null"] },
              "statusCode": { "type": ["integer", "null"] },
              "role": { "type": "string", "enum": ["primary", "robots", "llms-txt", "agents-json", "mcp-json", "security-txt", "openapi", "llms-full-txt", "api-manifest", "changelog", "feed", "sitemap", "route", "https-probe"] },
              "bodyTruncated": { "type": "boolean", "description": "True when the fetched response body exceeded Siteline's internal byte cap before parsing." }
            }
          }
        },
        "checksRun": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "pillar": { "type": "string" },
              "check": { "type": "string" },
              "status": { "type": "string", "enum": ["pass", "warn", "fail", "blocked", "not_applicable"] }
            }
          }
        },
        "agentUAsTested": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "userAgent": { "type": "string" },
              "statusCode": { "type": "integer" },
              "blocked": { "type": "boolean" }
            }
          }
        }
      }
    },
    "page": {
      "type": "object",
      "properties": {
        "statusCode": { "type": "integer" },
        "timedOut": { "type": "boolean" },
        "botBlocked": { "type": "boolean" },
        "blockType": { "type": ["string", "null"] },
        "bodyTruncated": { "type": "boolean" }
      }
    },
    "robots": {
      "type": "object",
      "properties": {
        "url": { "type": ["string", "null"] },
        "statusCode": { "type": ["integer", "null"] },
        "ok": { "type": "boolean" },
        "bodyTruncated": { "type": "boolean" }
      }
    },
    "informationalResources": {
      "type": "object",
      "properties": {
        "llmsTxt": {
          "type": ["object", "null"],
          "properties": {
            "url": { "type": "string" },
            "statusCode": { "type": "integer" },
            "ok": { "type": "boolean" },
            "bodyTruncated": { "type": "boolean" }
          }
        },
        "agentsJson": {
          "type": ["object", "null"],
          "properties": {
            "url": { "type": "string" },
            "statusCode": { "type": "integer" },
            "ok": { "type": "boolean" },
            "bodyTruncated": { "type": "boolean" }
          }
        }
      }
    },
    "summary": {
      "type": "object",
      "properties": {
        "headline": { "type": "string" },
        "detail": { "type": "string" }
      }
    },
    "findings": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "status": { "type": "string", "enum": ["pass", "warn", "fail", "blocked", "not_applicable"] },
          "reason": { "type": "string" },
          "explanationCode": { "type": "string", "enum": ["control_labels_missing", "cta_text_unclear", "handoff_unverified"], "description": "Optional explanation for a non-passing form/CTA finding. Distinguishes labeling, action-text and unverified-handoff guidance without changing the check status or score. Older results may omit this field." },
          "title": { "type": "string" },
          "impact": { "type": "string" },
          "remediation": { "type": ["string", "null"] },
          "group": { "type": "string", "enum": ["blockers", "coreIssues", "opportunities"] },
          "summary": { "type": "string" },
          "confidence": { "type": "string", "enum": ["high", "medium", "low"] },
          "evidence": {
            "description": "Raw evidence for reproducibility. Server reachability findings use an object; CTA ambiguity findings may use an array of matched labels, hrefs, selectors, and rule ids.",
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "url": { "type": ["string", "null"] },
                  "statusCode": { "type": "integer" },
                  "blockType": { "type": ["string", "null"] },
                  "serverHeader": { "type": ["string", "null"] },
                  "bodyExcerpt": { "type": ["string", "null"] }
                }
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": { "type": "string" },
                    "element": { "type": "string" },
                    "text": { "type": "string" },
                    "href": { "type": ["string", "null"] },
                    "selector": { "type": "string" },
                    "rule": { "type": "string" }
                  }
                }
              }
            ]
          }
        }
      }
    },
    "informational": {
      "type": "object",
      "description": "Informational signals that are useful for reporting but do not necessarily affect scoring.",
      "properties": {
        "semanticResources": {
          "type": "object",
          "description": "Detection-only static semantic resources. These do not affect score, Layer 2 purposes, findings, or remediation tier.",
          "properties": {
            "assistantGuide": { "type": "object" },
            "ontologyJson": { "type": "object" },
            "relationshipsYaml": { "type": "object" },
            "htmlLinks": { "type": "object" }
          }
        }
      },
      "additionalProperties": true
    },
    "findingGroups": {
      "type": "object",
      "properties": {
        "blockers": { "type": "array" },
        "coreIssues": { "type": "array" },
        "opportunities": { "type": "array" }
      }
    },
    "agenticEnablement": {
      "type": "object",
      "description": "Layer 2 assessment: qualitative evaluation of machine-readable resources the site provides for AI agents. The level caps the maximum achievable grade.",
      "properties": {
        "level": {
          "type": "integer",
          "minimum": 0,
          "maximum": 4,
          "description": "Agentic enablement level. 0=no resources (cap D), 1=minimal (cap D), 2=moderate (cap C), 3=strong (cap B), 4=comprehensive (no cap, can reach A)."
        },
        "totalQuality": {
          "type": "integer",
          "minimum": 0,
          "description": "Sum of quality scores across all assessed purposes. Each purpose scores 0 (absent), 1 (present but weak), or 2 (well-implemented)."
        },
        "maxQuality": {
          "type": "integer",
          "description": "Maximum possible quality score (number of purposes times 2)."
        },
        "purposes": {
          "type": "object",
          "description": "Per-purpose quality scores. Where multiple resources serve the same purpose, the best score counts.",
          "additionalProperties": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2
          }
        },
        "details": {
          "type": "object",
          "description": "Per-resource quality scores (individual resource breakdown).",
          "additionalProperties": {
            "type": "integer",
            "minimum": 0,
            "maximum": 2
          }
        }
      }
    },
    "remediationTier": {
      "type": "object",
      "description": "Suggested remediation approach based on the primary failure mode.",
      "properties": {
        "category": {
          "type": "string",
          "enum": ["self-fix", "workshop", "audit", "none"]
        },
        "reason": { "type": "string" },
        "selfFixable": {
          "type": "array",
          "items": { "type": "string" }
        },
        "requiresIntervention": {
          "type": "array",
          "items": { "type": "string" }
        },
        "suggestedNext": { "type": ["string", "null"] }
      }
    },
    "external": {
      "type": "object",
      "description": "Attributed third-party baseline panels. Informational only: never feeds score, grade, or level. Absent when panels are disabled or the scan failed.",
      "properties": {
        "cloudflare": {
          "type": "object",
          "description": "Cloudflare Agent Readiness baseline (isitagentready.com), attributed and versioned. available:false means their scanner could not be reached; that never fails a Siteline scan.",
          "required": ["available", "informational", "attribution"],
          "properties": {
            "available": { "type": "boolean" },
            "informational": { "type": "boolean", "const": true },
            "attribution": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "url": { "type": "string", "format": "uri" }
              }
            },
            "adapterVersion": { "type": "string" },
            "fetchedAt": { "type": "string", "format": "date-time" },
            "level": { "type": ["integer", "null"], "minimum": 0, "maximum": 5 },
            "maxLevel": { "type": ["integer", "null"] },
            "levelLabel": { "type": ["string", "null"] },
            "categories": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" },
                  "passing": { "type": "integer" },
                  "total": { "type": "integer" },
                  "checks": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "status": { "type": "string", "enum": ["pass", "fail"] },
                        "note": { "type": "string" }
                      }
                    }
                  }
                }
              }
            },
            "raw": { "type": "string" },
            "note": { "type": "string" }
          }
        }
      }
    },
    "standards": {
      "type": "object",
      "description": "PAICE standards conformance panel (Graceful Boundaries, GuideCheck, future standards). Informational only: never feeds score, grade, or level.",
      "properties": {
        "version": { "type": "string" },
        "informational": { "type": "boolean", "const": true },
        "note": { "type": "string" },
        "entries": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["id", "name", "informational", "detected", "statement"],
            "properties": {
              "id": { "type": "string" },
              "name": { "type": "string" },
              "specURL": { "type": "string", "format": "uri" },
              "informational": { "type": "boolean", "const": true },
              "detected": { "type": "boolean" },
              "statement": { "type": "string" },
              "passiveLevelEvidence": { "type": ["integer", "null"] },
              "conformant": { "type": "boolean" },
              "source": { "type": "string" },
              "discoveryPath": { "type": ["string", "null"] },
              "evidence": { "type": "array", "items": { "type": "string" } },
              "findings": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "detail": { "type": "string" }
                  }
                }
              },
              "note": { "type": "string" }
            }
          }
        }
      }
    },
    "requestId": { "type": "string" },
    "_cacheStatus": { "type": "string", "enum": ["HIT", "KV_HIT", "MISS"] },
    "_rescanBlocked": { "type": "boolean" }
  }
}
