{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://api.alphahubs.uk/static/downloads/friends-data-dictionary-v2.schema.json",
  "title": "Friends Data API dictionary v2",
  "description": "Schema for the full, indexed and namespace-sharded Friends Data API dictionaries.",
  "oneOf": [
    {
      "$ref": "#/$defs/fullDictionary"
    },
    {
      "$ref": "#/$defs/dictionaryIndex"
    },
    {
      "$ref": "#/$defs/namespaceShard"
    }
  ],
  "$defs": {
    "namespace": {
      "type": "object",
      "required": [
        "name",
        "description",
        "datasetCount",
        "fieldCount"
      ],
      "properties": {
        "name": {
          "$ref": "#/$defs/pathPart"
        },
        "description": {
          "type": "string",
          "minLength": 1
        },
        "datasetCount": {
          "type": "integer",
          "minimum": 1
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        }
      },
      "additionalProperties": false
    },
    "dataset": {
      "type": "object",
      "required": [
        "object",
        "asset",
        "namespace",
        "name",
        "coverageTags",
        "description",
        "titleCn",
        "summaryCn",
        "useCasesCn",
        "grainCn",
        "timeSemanticsCn",
        "cadenceCn",
        "keyFields",
        "joins",
        "queryGuidanceCn",
        "caveatsCn",
        "relation",
        "objectKind",
        "rowMagnitude",
        "grain",
        "cadence",
        "timeColumn",
        "defaultOrder",
        "filters",
        "maxLimit",
        "maxWindowDays",
        "supportsCursor",
        "readMode",
        "contractVersion",
        "uniqueKey",
        "provenanceColumns",
        "fieldCount",
        "fields",
        "pit"
      ],
      "properties": {
        "object": {
          "const": "dataset_schema"
        },
        "asset": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_.-]+$"
        },
        "namespace": {
          "$ref": "#/$defs/pathPart"
        },
        "name": {
          "$ref": "#/$defs/pathPart"
        },
        "coverageTags": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$"
          }
        },
        "description": {
          "type": "string",
          "minLength": 1
        },
        "titleCn": {
          "type": "string",
          "minLength": 2
        },
        "summaryCn": {
          "type": "string",
          "minLength": 12
        },
        "useCasesCn": {
          "type": "array",
          "minItems": 2,
          "items": {
            "type": "string",
            "minLength": 2
          }
        },
        "grainCn": {
          "type": "string",
          "minLength": 8
        },
        "timeSemanticsCn": {
          "type": "string",
          "minLength": 8
        },
        "cadenceCn": {
          "type": "string",
          "minLength": 8
        },
        "keyFields": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/keyField"
          }
        },
        "joins": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/join"
          }
        },
        "queryGuidanceCn": {
          "type": "string",
          "minLength": 8
        },
        "caveatsCn": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string",
            "minLength": 4
          }
        },
        "relation": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_]+\\.[A-Za-z0-9_.-]+$"
        },
        "objectKind": {
          "enum": [
            "table",
            "view"
          ]
        },
        "rowMagnitude": {
          "type": "string"
        },
        "grain": {
          "type": "string",
          "minLength": 1
        },
        "cadence": {
          "type": "string",
          "minLength": 1
        },
        "timeColumn": {
          "type": [
            "string",
            "null"
          ]
        },
        "defaultOrder": {
          "$ref": "#/$defs/stringList"
        },
        "filters": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/filter"
          }
        },
        "maxLimit": {
          "type": "integer",
          "minimum": 1
        },
        "maxWindowDays": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "supportsCursor": {
          "type": "boolean"
        },
        "readMode": {
          "type": "string",
          "minLength": 1
        },
        "contractVersion": {
          "type": [
            "string",
            "null"
          ]
        },
        "uniqueKey": {
          "$ref": "#/$defs/stringList"
        },
        "provenanceColumns": {
          "$ref": "#/$defs/stringList"
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "fields": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/field"
          }
        },
        "pit": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/pit"
            }
          ]
        },
        "supportedMarkets": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Markets this dataset actually produced rows for in the observed window. Empty means none were observed, which is not the same as unsupported."
        },
        "coverage": {
          "type": "object",
          "description": "Recent observed coverage. `measured=false` means the dataset was never probed, and its empty results carry no support claim either way.",
          "required": [
            "measured",
            "windowDays",
            "windowStart"
          ],
          "properties": {
            "measured": {
              "type": "boolean"
            },
            "windowDays": {
              "type": "integer",
              "minimum": 1
            },
            "windowStart": {
              "type": "string"
            },
            "observedMarkets": {
              "type": "object"
            },
            "latestBusinessDate": {
              "type": [
                "string",
                "null"
              ]
            },
            "note": {
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        "identifier": {
          "type": "object",
          "description": "How a security is spelled for THIS dataset. The same instrument is `1208.HK` for EODHD news and `01208.HK` for CCASS/HSGT.",
          "required": [
            "namespace",
            "formatByMarket"
          ],
          "properties": {
            "namespace": {
              "type": "string"
            },
            "formatByMarket": {
              "type": "object"
            },
            "storesZeroPaddedHkCode": {
              "type": "boolean"
            },
            "stableJoinKey": {
              "type": "string"
            },
            "resolverPath": {
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        "sparseSemantics": {
          "type": [
            "string",
            "null"
          ],
          "description": "Present when absence is a fact about a ranking rather than a missing row, e.g. a Top-10 Stock Connect constituent list."
        },
        "emptyResultCodes": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Typed meanings an empty result may carry for this dataset."
        },
        "publication": {
          "type": "object",
          "required": [
            "published"
          ],
          "properties": {
            "published": {
              "type": "boolean"
            },
            "reason": {
              "type": [
                "string",
                "null"
              ]
            },
            "projectionReviewed": {
              "type": "boolean"
            }
          },
          "additionalProperties": false
        },
        "returnedFieldCount": {
          "type": "integer",
          "minimum": 0,
          "description": "Fields the API actually returns, which may be fewer than fieldCount."
        },
        "costGuard": {
          "type": "object",
          "required": [
            "tier",
            "requirement"
          ],
          "properties": {
            "tier": {
              "type": "string"
            },
            "identityFilters": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "maxWindowDays": {
              "type": "integer",
              "minimum": 1
            },
            "requirement": {
              "type": "string"
            },
            "enforcedBeforeSql": {
              "type": "boolean"
            }
          },
          "additionalProperties": false
        },
        "sourceEntitlement": {
          "type": "object",
          "required": [
            "mode",
            "decision"
          ],
          "properties": {
            "mode": {
              "type": "string"
            },
            "decision": {
              "type": "string"
            },
            "deniedSources": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "reasons": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "additionalProperties": false
        },
        "coverageDisclosure": {
          "type": "object",
          "description": "Present only on datasets that hold a measured fraction of the instrument universe. Stated up front so a caller knows the coverage before querying, rather than inferring absence from an empty page.",
          "required": [
            "coveredInstruments",
            "universeInstruments",
            "measuredOn"
          ],
          "properties": {
            "coveredInstruments": {
              "type": "integer",
              "minimum": 0
            },
            "universeInstruments": {
              "type": "integer",
              "minimum": 1
            },
            "measuredOn": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "note": {
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        "derivation": {
          "description": "Present only on an entry derived from the captured entry of its pre-rename asset id (MIG0914 rename mode); a real schema capture replaces it.",
          "type": "object",
          "required": [
            "derivedFrom",
            "basis",
            "renameMap",
            "generatedAt"
          ],
          "properties": {
            "derivedFrom": {
              "type": "string",
              "pattern": "^[a-z][a-z0-9_]*\\.[a-z0-9][a-z0-9_]*$"
            },
            "basis": {
              "type": "string",
              "minLength": 1
            },
            "renameMap": {
              "type": "string",
              "minLength": 1
            },
            "generatedAt": {
              "type": "string",
              "format": "date-time"
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "field": {
      "type": "object",
      "required": [
        "position",
        "name",
        "displayName",
        "clickhouseType",
        "jsonType",
        "nullable",
        "description",
        "descriptionSource",
        "roles",
        "filterNames"
      ],
      "properties": {
        "position": {
          "type": "integer",
          "minimum": 1
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "displayName": {
          "type": "string",
          "minLength": 1
        },
        "clickhouseType": {
          "type": "string",
          "minLength": 1
        },
        "jsonType": {
          "enum": [
            "array",
            "boolean",
            "integer",
            "number",
            "object",
            "string"
          ]
        },
        "jsonFormat": {
          "enum": [
            "date",
            "date-time"
          ]
        },
        "nullable": {
          "type": "boolean"
        },
        "description": {
          "type": "string",
          "minLength": 1
        },
        "descriptionSource": {
          "enum": [
            "warehouse_comment",
            "standard_glossary",
            "name_derived"
          ]
        },
        "roles": {
          "type": "array",
          "uniqueItems": true,
          "items": {
            "enum": [
              "time",
              "filter",
              "required_filter",
              "default_order",
              "warehouse_primary_key",
              "contract_unique_key",
              "provenance"
            ]
          }
        },
        "filterNames": {
          "$ref": "#/$defs/stringList"
        },
        "unit": {
          "type": "string",
          "minLength": 1
        },
        "returned": {
          "type": "boolean",
          "description": "Whether the API returns this field in the reviewed projection."
        },
        "withheldReason": {
          "type": "string",
          "description": "Why a field is documented but not returned."
        }
      },
      "additionalProperties": false
    },
    "keyField": {
      "type": "object",
      "required": [
        "name",
        "meaningCn"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "meaningCn": {
          "type": "string",
          "minLength": 4
        }
      },
      "additionalProperties": false
    },
    "join": {
      "type": "object",
      "required": [
        "dataset",
        "on",
        "guidanceCn"
      ],
      "properties": {
        "dataset": {
          "type": "string"
        },
        "on": {
          "type": "string"
        },
        "guidanceCn": {
          "type": "string",
          "minLength": 4
        }
      },
      "additionalProperties": false
    },
    "filter": {
      "type": "object",
      "required": [
        "name",
        "column",
        "required",
        "multipleValues",
        "jsonType",
        "example"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
        "column": {
          "type": "string",
          "minLength": 1
        },
        "required": {
          "type": "boolean"
        },
        "multipleValues": {
          "type": "boolean"
        },
        "jsonType": {
          "enum": [
            "boolean",
            "integer",
            "number",
            "string"
          ]
        },
        "example": {
          "type": [
            "boolean",
            "integer",
            "number",
            "string"
          ]
        },
        "exampleSource": {
          "type": "string",
          "description": "Provenance of the example: a verified production value, the observed coverage, or the identifier format. Never a borrowed placeholder."
        },
        "allowedValues": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "pit": {
      "type": "object",
      "required": [
        "supported",
        "asOfRequired",
        "timeColumn",
        "keyColumns",
        "maxLimit",
        "maxWindowDays"
      ],
      "properties": {
        "supported": {
          "const": true
        },
        "asOfRequired": {
          "const": true
        },
        "timeColumn": {
          "type": "string",
          "minLength": 1
        },
        "keyColumns": {
          "$ref": "#/$defs/nonEmptyStringList"
        },
        "maxLimit": {
          "type": "integer",
          "minimum": 1
        },
        "maxWindowDays": {
          "type": "integer",
          "minimum": 1
        }
      },
      "additionalProperties": false
    },
    "pathPart": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$"
    },
    "stringList": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 1
      }
    },
    "nonEmptyStringList": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 1
      }
    },
    "datasetSummary": {
      "type": "object",
      "required": [
        "object",
        "asset",
        "namespace",
        "name",
        "titleCn",
        "summaryCn",
        "coverageTags",
        "fieldCount",
        "timeColumn",
        "filters",
        "maxLimit",
        "maxWindowDays",
        "supportsCursor",
        "pitSupported",
        "detailUrl",
        "shardUrl"
      ],
      "properties": {
        "object": {
          "const": "dataset_summary"
        },
        "asset": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*\\.[a-z0-9][a-z0-9_]*$"
        },
        "namespace": {
          "$ref": "#/$defs/pathPart"
        },
        "name": {
          "$ref": "#/$defs/pathPart"
        },
        "titleCn": {
          "type": "string",
          "minLength": 1
        },
        "summaryCn": {
          "type": "string",
          "minLength": 1
        },
        "coverageTags": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_]*$"
          }
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "timeColumn": {
          "type": [
            "string",
            "null"
          ]
        },
        "filters": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/filter"
          }
        },
        "maxLimit": {
          "type": "integer",
          "minimum": 1
        },
        "maxWindowDays": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "supportsCursor": {
          "type": "boolean"
        },
        "pitSupported": {
          "type": "boolean"
        },
        "detailUrl": {
          "type": "string",
          "format": "uri"
        },
        "shardUrl": {
          "type": "string",
          "format": "uri"
        }
      },
      "additionalProperties": false
    },
    "shardReference": {
      "type": "object",
      "required": [
        "namespace",
        "datasetCount",
        "fieldCount",
        "url"
      ],
      "properties": {
        "namespace": {
          "$ref": "#/$defs/pathPart"
        },
        "datasetCount": {
          "type": "integer",
          "minimum": 1
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "url": {
          "type": "string",
          "format": "uri"
        }
      },
      "additionalProperties": false
    },
    "dictionaryIndex": {
      "type": "object",
      "required": [
        "$schema",
        "object",
        "version",
        "guidanceVersion",
        "apiVersion",
        "baseUrl",
        "generatedAt",
        "schemaObservedAt",
        "source",
        "namespaceCount",
        "datasetCount",
        "fieldCount",
        "uniqueFieldCount",
        "pitDatasetCount",
        "cursorDatasetCount",
        "namespaces",
        "fullDownload",
        "shards",
        "datasets"
      ],
      "properties": {
        "version": {
          "type": "string"
        },
        "guidanceVersion": {
          "type": "integer",
          "minimum": 1
        },
        "apiVersion": {
          "const": "v1"
        },
        "baseUrl": {
          "type": "string",
          "format": "uri"
        },
        "generatedAt": {
          "type": "string",
          "format": "date-time"
        },
        "schemaObservedAt": {
          "type": "string",
          "format": "date-time"
        },
        "source": {
          "type": "string"
        },
        "namespaceCount": {
          "type": "integer",
          "minimum": 1
        },
        "datasetCount": {
          "type": "integer",
          "minimum": 1
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "uniqueFieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "pitDatasetCount": {
          "type": "integer",
          "minimum": 0
        },
        "cursorDatasetCount": {
          "type": "integer",
          "minimum": 0
        },
        "$schema": {
          "type": "string",
          "format": "uri"
        },
        "object": {
          "const": "friends_data_dictionary_index"
        },
        "namespaces": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/namespace"
          }
        },
        "fullDownload": {
          "type": "string",
          "format": "uri"
        },
        "shards": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/shardReference"
          }
        },
        "datasets": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/datasetSummary"
          }
        }
      },
      "additionalProperties": false
    },
    "namespaceShard": {
      "type": "object",
      "required": [
        "$schema",
        "version",
        "guidanceVersion",
        "apiVersion",
        "baseUrl",
        "generatedAt",
        "schemaObservedAt",
        "source",
        "datasetCount",
        "fieldCount",
        "object",
        "namespace",
        "description",
        "datasets"
      ],
      "properties": {
        "$schema": {
          "type": "string",
          "format": "uri"
        },
        "version": {
          "type": "string"
        },
        "guidanceVersion": {
          "type": "integer",
          "minimum": 1
        },
        "apiVersion": {
          "const": "v1"
        },
        "baseUrl": {
          "type": "string",
          "format": "uri"
        },
        "generatedAt": {
          "type": "string",
          "format": "date-time"
        },
        "schemaObservedAt": {
          "type": "string",
          "format": "date-time"
        },
        "source": {
          "type": "string"
        },
        "datasetCount": {
          "type": "integer",
          "minimum": 1
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "object": {
          "const": "friends_data_dictionary_namespace"
        },
        "namespace": {
          "$ref": "#/$defs/pathPart"
        },
        "description": {
          "type": "string",
          "minLength": 1
        },
        "datasets": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/dataset"
          }
        }
      },
      "additionalProperties": false
    },
    "fullDictionary": {
      "type": "object",
      "required": [
        "$schema",
        "object",
        "version",
        "guidanceVersion",
        "apiVersion",
        "baseUrl",
        "generatedAt",
        "schemaObservedAt",
        "source",
        "namespaceCount",
        "datasetCount",
        "fieldCount",
        "uniqueFieldCount",
        "pitDatasetCount",
        "cursorDatasetCount",
        "namespaces",
        "datasets"
      ],
      "properties": {
        "$schema": {
          "type": "string",
          "format": "uri"
        },
        "object": {
          "const": "friends_data_dictionary"
        },
        "version": {
          "type": "string"
        },
        "guidanceVersion": {
          "type": "integer",
          "minimum": 1
        },
        "apiVersion": {
          "const": "v1"
        },
        "baseUrl": {
          "type": "string",
          "format": "uri"
        },
        "generatedAt": {
          "type": "string",
          "format": "date-time"
        },
        "schemaObservedAt": {
          "type": "string",
          "format": "date-time"
        },
        "source": {
          "type": "string"
        },
        "namespaceCount": {
          "type": "integer",
          "minimum": 1
        },
        "datasetCount": {
          "type": "integer",
          "minimum": 1
        },
        "fieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "uniqueFieldCount": {
          "type": "integer",
          "minimum": 1
        },
        "pitDatasetCount": {
          "type": "integer",
          "minimum": 0
        },
        "cursorDatasetCount": {
          "type": "integer",
          "minimum": 0
        },
        "namespaces": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/namespace"
          }
        },
        "datasets": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/dataset"
          }
        },
        "contractMetadataVersion": {
          "type": "string",
          "description": "Version of the derived contract block (coverage, identifier, publication, cost guard, source entitlement) attached to every dataset."
        }
      },
      "additionalProperties": false
    }
  }
}
