{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://respectarium.com/spec/agent-adoption/v1/schemas/output-v1.schema.json",
  "title": "Agent-Adoption Specification V1.0 — Scanner Output",
  "description": "Canonical JSON output schema for scanners conforming to Agent-Adoption Specification V1.0. See https://respectarium.com/spec/agent-adoption/v1 for the spec text.",
  "type": "object",
  "required": [
    "spec_version",
    "profile",
    "domain",
    "scanned_at",
    "scanner",
    "score",
    "level",
    "level_name",
    "categories",
    "checks"
  ],
  "properties": {
    "spec_version": {
      "type": "string",
      "description": "The Agent-Adoption Specification version this scanner conforms to. Semver.",
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
      "examples": ["1.0.0"]
    },
    "profile": {
      "type": "string",
      "description": "The profile applied to this scan. References a profile bundled with the specification or a custom profile published by the implementation.",
      "examples": ["b2b-saas"]
    },
    "domain": {
      "type": "string",
      "description": "The brand root domain (eTLD+1) that was scanned. Lowercase, no scheme, no trailing slash.",
      "examples": ["example.com"]
    },
    "scanned_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 UTC timestamp at which the scan was performed."
    },
    "scanner": {
      "type": "object",
      "required": ["name", "version"],
      "properties": {
        "name": {
          "type": "string",
          "description": "The implementation's identifier (e.g., \"respectarium-scanner\")."
        },
        "version": {
          "type": "string",
          "description": "The implementation's version (semver or other format chosen by the implementation)."
        }
      },
      "additionalProperties": true
    },
    "score": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "description": "The aggregate agent-adoption score. Computed per the spec's score formula (§7)."
    },
    "level": {
      "type": "string",
      "enum": ["L1", "L2", "L3"],
      "description": "The assigned level (§8). v1.0 conforming scanners MUST NOT emit L4 or higher."
    },
    "level_name": {
      "type": "string",
      "enum": ["Basic Web Presence", "AI-Aware", "Agent-Optimized"],
      "description": "Human-readable level label, corresponding 1:1 to the level field."
    },
    "categories": {
      "type": "object",
      "required": ["discoverability", "accessControl", "contentReadability", "agentEndpoints"],
      "properties": {
        "discoverability": { "$ref": "#/$defs/categoryStat" },
        "accessControl": { "$ref": "#/$defs/categoryStat" },
        "contentReadability": { "$ref": "#/$defs/categoryStat" },
        "agentEndpoints": { "$ref": "#/$defs/categoryStat" }
      },
      "additionalProperties": false,
      "description": "Per-category subscores. Each category aggregates only the scored checks within it (informational checks are excluded from the per-category score)."
    },
    "checks": {
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#/$defs/checkResult" },
      "description": "Array of per-check results. Conforming v1.0 scanners SHOULD emit one entry per check defined in the spec; informational checks MAY be marked as not-supported via status=\"error\" with appropriate evidence."
    }
  },
  "additionalProperties": false,
  "$defs": {
    "categoryStat": {
      "type": "object",
      "required": ["score", "checks_passed", "checks_total"],
      "properties": {
        "score": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100,
          "description": "Per-category score in 0-100, computed using the same formula as the overall score but restricted to the scored checks within this category."
        },
        "checks_passed": {
          "type": "integer",
          "minimum": 0,
          "description": "Count of scored checks in this category that returned status=\"pass\"."
        },
        "checks_total": {
          "type": "integer",
          "minimum": 0,
          "description": "Count of scored checks in this category that were applicable (not skipped by the profile and not returned neutral or error)."
        }
      },
      "additionalProperties": false
    },
    "checkResult": {
      "type": "object",
      "required": ["id", "category", "status", "scored", "tier", "weight"],
      "properties": {
        "id": {
          "type": "string",
          "description": "The canonical check ID per the spec, in lowercase-with-hyphens.",
          "examples": ["robots-txt-exists", "markdown-negotiation"]
        },
        "category": {
          "type": "string",
          "enum": ["discoverability", "accessControl", "contentReadability", "agentEndpoints"]
        },
        "status": {
          "type": "string",
          "enum": ["pass", "fail", "neutral", "error"],
          "description": "Per-check outcome. See spec §7.4 for semantics."
        },
        "scored": {
          "type": "boolean",
          "description": "True if this check contributes to the aggregate score; false if informational. Convenience field; can be derived from tier."
        },
        "tier": {
          "type": "string",
          "enum": ["critical", "high", "medium", "low", "informational"],
          "description": "The check's tier per the spec's tier system (§6)."
        },
        "weight": {
          "type": "integer",
          "enum": [0, 2, 4, 7, 10],
          "description": "Numeric weight derived from tier. Critical=10, High=7, Medium=4, Low=2, Informational=0."
        },
        "evidence": {
          "type": "object",
          "description": "Implementation-defined evidence object describing what the scanner observed. Consumers MUST treat this field as opaque and parse defensively. The spec does not define the internal shape of this object.",
          "additionalProperties": true
        }
      },
      "additionalProperties": true
    }
  }
}
