{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openyacht.org/schemas/v1/well-known.schema.json",
  "title": "OpenYacht Discovery Document",
  "description": "The document every node serves at GET /.well-known/openyacht: identity, keys, and endpoint map. The prose spec (spec/federation-protocol.md) is normative; this schema is normative for JSON shape only — on any conflict the prose wins and this schema is defective. TLS requirements, caching, and rate limits are prose rules.",
  "type": "object",
  "properties": {
    "openyacht": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+$" },
    "protocol_versions": {
      "type": "array",
      "items": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+$" },
      "minItems": 1
    },
    "node": {
      "type": "object",
      "properties": {
        "uuid": {
          "type": "string",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
          "description": "Generated at install time. Not a trust anchor — it detects that a domain now hosts a different installation."
        },
        "name": { "type": "string" },
        "software": { "type": ["string", "null"] },
        "website": {
          "anyOf": [{ "type": "string", "format": "uri" }, { "type": "null" }]
        }
      },
      "required": ["uuid", "name", "software", "website"],
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "keys": {
      "type": "array",
      "minItems": 1,
      "description": "An array so rotation can overlap; verifiers select by the request's key ID.",
      "items": {
        "type": "object",
        "properties": {
          "key_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{16}$",
            "description": "First 16 hex characters of the SHA-256 of the raw 32-byte public key."
          },
          "algorithm": { "const": "ed25519" },
          "public_key": {
            "type": "string",
            "pattern": "^[A-Za-z0-9+/]{43}=$",
            "description": "Base64 of the raw 32-byte Ed25519 public key."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
          }
        },
        "required": ["key_id", "algorithm", "public_key", "created_at"],
        "patternProperties": { "^x_": true },
        "additionalProperties": false
      }
    },
    "endpoints": {
      "type": "object",
      "description": "Map of the endpoints this node actually serves. listings, health, and capabilities are the mandatory baseline; partners and subscriptions appear when served (subscriptions is capability-gated, and a node may handle partnering out of band). Acceptance finding, 2026-08: the first live node serves only the baseline three.",
      "properties": {
        "listings": { "type": "string", "pattern": "^/" },
        "partners": { "type": "string", "pattern": "^/" },
        "subscriptions": { "type": "string", "pattern": "^/" },
        "health": { "type": "string", "pattern": "^/" },
        "capabilities": { "type": "string", "pattern": "^/" }
      },
      "required": ["listings", "health", "capabilities"],
      "patternProperties": { "^x_": true },
      "additionalProperties": false
    },
    "generated_at": {
      "type": "string",
      "format": "date-time",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
    }
  },
  "required": ["openyacht", "protocol_versions", "node", "keys", "endpoints", "generated_at"],
  "patternProperties": { "^x_": true },
  "additionalProperties": false
}
