{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "methodology",
  "type": "object",
  "required": ["published_at", "stats", "stages", "basket", "freshness",
               "inventory", "validation", "variants", "limitations"],
  "additionalProperties": false,
  "properties": {
    "published_at": {"type": "string"},
    "methodology_version": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
    "changelog": {"type": "array", "items": {"type": "object",
      "required": ["date", "area", "change"], "additionalProperties": false,
      "properties": {"date": {"type": "string"}, "area": {"type": "string"},
                     "change": {"type": "string"}}}},
    "stats": {
      "type": "object",
      "required": ["series_count", "obs_count", "source_count", "tracker_corr",
                   "live_coverage_pct", "engine_version", "rebase"],
      "additionalProperties": false,
      "properties": {
        "series_count": {"type": "integer", "minimum": 1},
        "obs_count": {"type": "integer", "minimum": 1},
        "source_count": {"type": "integer", "minimum": 1},
        "tracker_corr": {"type": ["number", "null"], "minimum": -1, "maximum": 1},
        "live_coverage_pct": {"type": "number", "minimum": 0, "maximum": 100},
        "engine_version": {"type": "string"},
        "rebase": {"type": "string"}
      }
    },
    "stages": {
      "type": "array", "minItems": 5, "maxItems": 5,
      "items": {
        "type": "object",
        "required": ["n", "name", "description", "formula"],
        "additionalProperties": false,
        "properties": {
          "n": {"type": "integer"},
          "name": {"type": "string"},
          "description": {"type": "string"},
          "formula": {"type": ["string", "null"]}
        }
      }
    },
    "basket": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["code", "label", "weight", "mode", "live_sources",
                     "live_active", "official_series", "yoy_pct"],
        "additionalProperties": false,
        "properties": {
          "code": {"type": "string"},
          "label": {"type": "string"},
          "weight": {"type": "number", "exclusiveMinimum": 0, "maximum": 1},
          "mode": {"enum": ["live", "bls_cf"]},
          "live_sources": {"type": "array", "items": {"type": "string"}},
          "live_active": {"type": "array", "items": {"type": "string"}},
          "official_series": {"type": "string"},
          "yoy_pct": {"type": ["number", "null"]}
        }
      }
    },
    "freshness": {
      "type": "object",
      "required": ["fresh_count", "total"],
      "additionalProperties": false,
      "properties": {
        "fresh_count": {"type": "integer", "minimum": 0},
        "total": {"type": "integer", "minimum": 1},
        "expected_absent": {"type": "integer", "minimum": 0}
      }
    },
    "inventory": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["code", "name", "source", "route", "cadence",
                     "latest_obs", "fresh"],
        "additionalProperties": false,
        "properties": {
          "code": {"type": "string"},
          "name": {"type": "string"},
          "source": {"type": "string"},
          "route": {"type": "string"},
          "cadence": {"type": "string"},
          "latest_obs": {"type": ["string", "null"]},
          "fresh": {"type": "boolean"},
          "absence": {"type": ["string", "null"],
                      "enum": ["suppressed", "intermittent", "discontinued", null]}
        }
      }
    },
    "validation": {
      "type": "object",
      "required": ["gauge", "tracker", "bls_reconstruction"],
      "additionalProperties": false,
      "properties": {
        "gauge": {"$ref": "#/$defs/stats"},
        "col": {"$ref": "#/$defs/stats"},
        "tracker": {"$ref": "#/$defs/stats"},
        "supercore": {"$ref": "#/$defs/stats"},
        "pce": {"$ref": "#/$defs/stats"},
        "bls_reconstruction": {
          "type": "object",
          "required": ["weighted_bls_yoy_pct", "official_yoy_pct"],
          "additionalProperties": false,
          "properties": {
            "weighted_bls_yoy_pct": {"type": "number"},
            "official_yoy_pct": {"type": "number"}
          }
        }
      }
    },
    "variants": {
      "type": "object",
      "required": ["gauge", "col", "tracker", "supercore", "pce"],
      "additionalProperties": false,
      "properties": {
        "gauge": {"type": "string"},
        "col": {"type": "string"},
        "tracker": {"type": "string"},
        "supercore": {"type": "string"},
        "pce": {"type": "string"}
      }
    },
    "limitations": {"type": "array", "minItems": 1, "items": {"type": "string"}}
  },
  "$defs": {
    "stats": {
      "type": "object",
      "required": ["corr", "mean_abs_gap_pp", "window"],
      "additionalProperties": false,
      "properties": {
        "corr": {"type": ["number", "null"], "minimum": -1, "maximum": 1},
        "mean_abs_gap_pp": {"type": ["number", "null"]},
        "window": {"type": "string"},
        "lead_lag": {"oneOf": [
          {"type": "null"},
          {"type": "object",
           "required": ["best_shift_months", "corr"],
           "additionalProperties": false,
           "properties": {
             "best_shift_months": {"type": "integer", "minimum": 0, "maximum": 6},
             "corr": {"type": "number", "minimum": -1, "maximum": 1}}}]}
      }
    }
  }
}
