{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://opengdd.org/schema/core/v0.8/personalization.schema.json",
  "title": "OpenGDD v0.7 personalization file",
  "type": "object",
  "required": ["questions"],
  "additionalProperties": false,
  "properties": {
    "questions": {
      "type": "array",
      "items": { "$ref": "#/$defs/question" },
      "description": "SPEC 5. Questions are applied in list order. An empty list is legal and declares no questions."
    }
  },
  "$defs": {
    "question": {
      "type": "object",
      "required": ["id", "prompt", "type", "default"],
      "additionalProperties": false,
      "allOf": [
        {
          "if": { "properties": { "type": { "const": "choice" } }, "required": ["type"] },
          "then": {
            "required": ["options"],
            "properties": { "default": { "type": "string" } }
          },
          "else": { "not": { "required": ["options"] } }
        },
        {
          "if": { "properties": { "type": { "const": "number" } }, "required": ["type"] },
          "then": {
            "properties": {
              "default": { "type": "number" },
              "sets": { "$ref": "#/$defs/tuningKey" }
            }
          },
          "else": {
            "properties": { "default": { "type": "string" } }
          }
        }
      ],
      "properties": {
        "id": { "type": "string", "minLength": 1 },
        "prompt": { "type": "string", "minLength": 1 },
        "type": { "enum": ["choice", "text", "number"] },
        "default": {
          "type": ["string", "number"],
          "description": "Required answer used when a build supplies none. Choice defaults name an option; a number default must sit inside the target range when sets is present."
        },
        "notes": { "type": "string" },
        "options": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/option" },
          "description": "Required only for a choice question."
        },
        "sets": {
          "$ref": "#/$defs/tuningKey",
          "description": "Optional on a number question: the one ranged key that receives the answer. Without it, the answer is recorded for the builder to interpret."
        }
      }
    },
    "option": {
      "type": "object",
      "required": ["id", "label"],
      "additionalProperties": false,
      "properties": {
        "id": { "type": "string", "minLength": 1 },
        "label": { "type": "string", "minLength": 1 },
        "notes": { "type": "string" },
        "sets": {
          "type": "object",
          "minProperties": 1,
          "propertyNames": { "$ref": "#/$defs/tuningKey" },
          "additionalProperties": { "type": "number" },
          "description": "Exact package-value assignments applied when this option is selected. A sets key never names a contract value; every target must exist, carry a range, and receive a value inside it."
        }
      }
    },
    "tuningKey": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_](?:[A-Za-z0-9_-]*[A-Za-z0-9_])?(?:\\.[A-Za-z0-9_](?:[A-Za-z0-9_-]*[A-Za-z0-9_])?)+$",
      "description": "A flat dotted package number key. Contract values are Fixed and cannot be personalization targets."
    }
  }
}
