{
  "$ref": "#/definitions/Choice",
  "definitions": {
    "Choice": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "pattern": "^[a-z0-9-]+$",
          "description": "Stable slug identifier, lowercase, e.g. \"ods\", \"ano\", \"spolu\". Should remain stable across election cycles. Used as the foreign key in PollResult.choice_id, DerivedResult.choice_id, and Estimate.choice_id across all pipeline layers."
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "description": "Canonical display name in the primary language of the region. Use `names` for multilingual variants."
        },
        "short_name": {
          "type": "string",
          "minLength": 1,
          "description": "Abbreviated name for charts and tables, e.g. \"ODS\", \"SPOLU\"."
        },
        "names": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "minLength": 1
          },
          "propertyNames": {
            "pattern": "^[a-z]{2}(-[A-Z]{2})?$"
          },
          "description": "Optional multilingual name map (BCP 47 locale → string). Example: { \"cs\": \"Občanská demokratická strana\", \"en\": \"Civic Democratic Party\" }"
        },
        "region": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1
            },
            {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1
              }
            }
          ],
          "description": "Region(s) this choice is active in. ISO 3166-1 alpha-2 (country) or ISO 3166-2 (sub-national) codes."
        },
        "color": {
          "type": "string",
          "description": "Primary brand color. Canonical form: CSS hex (#rrggbb or #rrggbbaa)."
        },
        "logo_url": {
          "type": "string",
          "format": "uri",
          "description": "URL to the choice's logo (SVG or PNG preferred)."
        },
        "type": {
          "type": "string",
          "description": "Entity type. Canonical values: \"party\", \"coalition\". Other values allowed."
        },
        "members": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          },
          "description": "IDs of constituent choices (for coalitions). References other Choice.id values."
        },
        "member_shares": {
          "type": "object",
          "additionalProperties": {
            "type": "number",
            "minimum": 0
          },
          "propertyNames": {
            "minLength": 1
          },
          "description": "Fractional split weights for each member (values 0–1, sum ≈ 1). Used as the default distribution key when a poll reports only the aggregate coalition value. Example (SPOLU 2025 seats): { \"ods\": 0.67, \"top-09\": 0.19, \"kdu-csl\": 0.14 }"
        },
        "historical_results": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "election_id": {
                "type": "string",
                "minLength": 1,
                "description": "Identifier for the election, e.g. \"cz-parliament-2021\"."
              },
              "choice_id": {
                "type": "string",
                "minLength": 1,
                "description": "The choice_id as it appeared in that election. Omit when identical to the current Choice.id. Use when the party ran under a different name/coalition (e.g. storing ODS's 2021 result on the SPOLU coalition choice)."
              },
              "values": {
                "type": "object",
                "additionalProperties": {
                  "type": [
                    "string",
                    "number",
                    "null"
                  ]
                },
                "description": "Flexible numeric or string values for this election result. Recommended keys: \"percent\", \"seats\", \"rank\", \"votes\". Example: { \"percent\": 27.7, \"seats\": 71 }"
              }
            },
            "required": [
              "election_id",
              "values"
            ],
            "additionalProperties": false,
            "description": "One previous-election result stored on a Choice.\n\nLayer: reference data (embedded in Choice)\n\nUsed to track what a party, coalition, or candidate achieved in past elections, even if the choice ran under a different ID at the time."
          },
          "description": "Historical election results for this choice."
        },
        "extras": {
          "type": "object",
          "additionalProperties": {},
          "description": "Extension point for additional fields."
        }
      },
      "required": [
        "id",
        "name",
        "short_name"
      ],
      "additionalProperties": false,
      "description": "Any entity that can appear in poll results: party, coalition, or independent grouping.\n\nLayer: reference data\n\nChoice.id is the stable key used across all pipeline layers: PollResult.choice_id (source), DerivedResult.choice_id (compute), Estimate.choice_id (aggregate)."
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}