{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://hub.schema/v1/intake",
  "$comment": "Published id hub.intake.v1. Fact keys must be namespaced (prefix.). Domain-specific admission stays in admit_seed.",
  "title": "Hub intake envelope v1",
  "type": "object",
  "additionalProperties": true,
  "required": ["port", "records", "changes"],
  "properties": {
    "schema": {
      "const": "hub.intake.v1"
    },
    "port": {
      "type": "string",
      "enum": ["official_collector", "contribution", "partner_transfer"]
    },
    "records": {
      "type": "array",
      "items": { "$ref": "#/$defs/record" }
    },
    "changes": {
      "type": "array",
      "items": { "$ref": "#/$defs/change" }
    }
  },
  "$defs": {
    "record": {
      "type": "object",
      "additionalProperties": true,
      "required": ["domain", "record_id", "title", "changed_at", "change_type"],
      "properties": {
        "domain": { "type": "string", "minLength": 1 },
        "record_id": { "type": "string", "minLength": 1 },
        "title": { "type": "string" },
        "region": { "type": "string" },
        "status": { "type": "string" },
        "deadline": { "type": ["string", "null"] },
        "source_url": { "type": "string" },
        "changed_at": { "type": "string", "minLength": 1 },
        "change_type": { "$ref": "#/$defs/change_type" },
        "facts": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": true,
            "required": ["key"],
            "properties": {
              "key": {
                "type": "string",
                "minLength": 3,
                "pattern": "^[^.]+\\..+$",
                "$comment": "Mirrors check_record: facts use a domain. namespace form. Exact domain match is admit_seed."
              },
              "value": { "type": "string" },
              "excerpt_id": { "type": ["string", "null"] }
            }
          }
        },
        "excerpts": {
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": true,
            "required": ["id"],
            "properties": {
              "id": { "type": "string", "minLength": 1 },
              "section": { "type": "string" },
              "text": { "type": "string" },
              "locator": { "type": "string" }
            }
          }
        },
        "unknowns": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 3,
            "pattern": "^[^.]+\\..+$",
            "$comment": "Unknown fact keys share the same namespace form as facts.key."
          }
        },
        "capabilities": {
          "type": "array",
          "items": { "type": "string" }
        }
      }
    },
    "change": {
      "type": "object",
      "additionalProperties": true,
      "required": ["domain", "record_id", "change_type", "changed_at"],
      "properties": {
        "domain": { "type": "string", "minLength": 1 },
        "record_id": { "type": "string", "minLength": 1 },
        "change_type": { "$ref": "#/$defs/change_type" },
        "changed_at": { "type": "string", "minLength": 1 }
      }
    },
    "change_type": {
      "$comment": "Mirrors check_change_type: common kinds or a namespaced domain.kind. Exact domain match is admit_seed.",
      "oneOf": [
        { "enum": ["created", "corrected", "deadline"] },
        {
          "type": "string",
          "minLength": 3,
          "pattern": "^[^.]+\\..+$"
        }
      ]
    }
  }
}
