{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/gribstream-com/json-schema/gribstream-com-catalog-dataset-schema.json",
  "title": "CatalogDataset",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/gribstream-com-openapi.yml#/components/schemas/CatalogDataset",
  "type": "object",
  "required": [
    "code",
    "name",
    "full_name",
    "is_ensemble",
    "member_count",
    "parameter_count",
    "rolling_window"
  ],
  "properties": {
    "discovery": {
      "$ref": "#/$defs/CatalogDiscovery"
    },
    "native_grid": {
      "description": "Available on dataset details only. A small static descriptor; it contains no coordinate inventory and does not open a remote coordinate source.",
      "allOf": [
        {
          "$ref": "#/$defs/CatalogNativeGrid"
        }
      ]
    },
    "code": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "full_name": {
      "type": "string"
    },
    "display_label": {
      "type": "string",
      "description": "Human-friendly picker label that includes the short code and descriptive name."
    },
    "family": {
      "type": "string"
    },
    "family_variant": {
      "type": "string"
    },
    "provider": {
      "type": "string"
    },
    "summary": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "models_page_url": {
      "type": "string",
      "format": "uri-reference"
    },
    "api_timeseries_url": {
      "type": "string",
      "format": "uri-reference"
    },
    "api_runs_url": {
      "type": "string",
      "format": "uri-reference"
    },
    "documentation_url": {
      "type": "string",
      "format": "uri-reference"
    },
    "source_url": {
      "type": "string",
      "format": "uri"
    },
    "source_links": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Link"
      }
    },
    "spatial_resolution": {
      "$ref": "#/$defs/SpatialResolution"
    },
    "time_resolution": {
      "$ref": "#/$defs/LabeledValue"
    },
    "run_cadence": {
      "$ref": "#/$defs/LabeledValue"
    },
    "lead_time_unit": {
      "type": "string"
    },
    "min_lead_time": {
      "type": "string"
    },
    "max_lead_time": {
      "type": "string"
    },
    "is_ensemble": {
      "type": "boolean"
    },
    "member_count": {
      "type": "integer"
    },
    "members": {
      "type": "array",
      "items": {
        "type": "integer"
      }
    },
    "parameter_count": {
      "type": "integer"
    },
    "archive_start": {
      "type": "string",
      "format": "date",
      "description": "Oldest forecast run date available in this dataset for stable historical archives."
    },
    "archive_window": {
      "type": "string",
      "description": "Fixed retention label for rolling-window datasets, for example `Last 5 days`."
    },
    "mirror_retention_days": {
      "type": "integer",
      "description": "Retention period in days for datasets served from GribStream's private mirror."
    },
    "rolling_window": {
      "type": "boolean",
      "description": "True when the dataset is a moving retention window rather than a stable historical archive."
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "related_datasets": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "catalog_updated_at": {
      "type": "string",
      "format": "date-time"
    }
  },
  "additionalProperties": false,
  "$defs": {
    "CatalogDiscovery": {
      "type": "object",
      "description": "Static discovery hints, not a guarantee of indexed data or parameter-specific coverage. Projected envelopes are bounding boxes rather than coverage polygons. Native sampling and model nominal resolution are distinct.",
      "properties": {
        "grid_type": {
          "type": "string"
        },
        "nominal_resolution_km": {
          "type": "number",
          "description": "Approximate ranking hint from the catalog label, falling back to output spacing (degrees use 111.195 km per degree at the equator)."
        },
        "resolution_basis": {
          "type": "string",
          "enum": [
            "catalog_nominal",
            "output_grid_approximation"
          ]
        },
        "latitude_step_degrees": {
          "type": "number",
          "description": "Absolute native regular latitude spacing only."
        },
        "longitude_step_degrees": {
          "type": "number",
          "description": "Absolute native regular longitude spacing only; can differ from latitude spacing."
        },
        "coverage_kind": {
          "type": "string",
          "enum": [
            "grid_bounds",
            "global_domain",
            "grid_envelope",
            "unknown"
          ]
        },
        "bounds": {
          "type": "object",
          "properties": {
            "minLat": {
              "type": "number"
            },
            "maxLat": {
              "type": "number"
            },
            "minLon": {
              "type": "number"
            },
            "maxLon": {
              "type": "number"
            }
          }
        },
        "coordinates_url": {
          "type": "string",
          "format": "uri-reference",
          "description": "Authenticated, metered native coordinate inventory; requires all four geographic bounds."
        },
        "parameter": {
          "type": "object",
          "properties": {
            "code": {
              "type": "string"
            },
            "request": {
              "$ref": "#/$defs/CatalogRequestFragment"
            },
            "match": {
              "$ref": "#/$defs/CatalogSharedParameterMatch"
            }
          }
        },
        "forecast_time_utc": {
          "type": "string",
          "format": "date-time"
        },
        "reference_time_utc": {
          "type": "string",
          "format": "date-time"
        },
        "availability": {
          "type": "string"
        }
      }
    },
    "CatalogNativeGrid": {
      "type": "object",
      "required": [
        "total",
        "grid",
        "coordinates_url"
      ],
      "properties": {
        "total": {
          "type": "integer",
          "description": "Full grid size in storage positions, including positions that look past Earth on satellite rasters. This is not the number of valid geographic points or points in a bounding box."
        },
        "grid": {
          "$ref": "#/$defs/NativeGridSpecification"
        },
        "coordinates_url": {
          "type": "string",
          "format": "uri-reference",
          "description": "Metered coordinate inventory endpoint. Requires a registered bearer token and all four bounding-box fields."
        }
      },
      "additionalProperties": false
    },
    "CatalogRequestFragment": {
      "type": "object",
      "description": "Machine-readable request fragment that can be copied into forecast query payloads.\n\nThis is the primary structured representation for shared parameter presets.\n",
      "properties": {
        "variables": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/VariableSelector"
          }
        },
        "expressions": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ExpressionField"
          }
        }
      },
      "additionalProperties": false
    },
    "CatalogSharedParameterMatch": {
      "type": "object",
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "exact",
            "approximate"
          ],
          "description": "Semantic match to the shared concept, not identical values across models. A 1.5 m near-surface substitute is approximate, with no height correction."
        },
        "method": {
          "type": "string",
          "enum": [
            "direct",
            "derived"
          ]
        },
        "notes": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "ExpressionField": {
      "type": "object",
      "required": [
        "expression"
      ],
      "properties": {
        "expression": {
          "type": "string",
          "description": "Expr-language formula compiled by the server."
        },
        "alias": {
          "type": "string",
          "description": "Response key for the expression output.\n\nThe wire format allows this to be omitted, but practical clients should set it.\n"
        },
        "hidden": {
          "type": "boolean",
          "description": "When `true`, the expression result remains available to later expressions and filters,\nbut is omitted from response rows.\n"
        }
      },
      "additionalProperties": false
    },
    "LabeledValue": {
      "type": "object",
      "properties": {
        "label": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "Link": {
      "type": "object",
      "properties": {
        "label": {
          "type": "string"
        },
        "url": {
          "type": "string",
          "format": "uri"
        }
      },
      "additionalProperties": false
    },
    "NativeGridSpecification": {
      "type": "object",
      "description": "Native geometry and projection parameters. Raster dimensions and regular latitude/longitude steps apply only to the declared grid type; inapplicable scalar fields are zero (for example, dimensions on an unstructured mesh). Coordinates use double precision; AICON carries a sub-metre quantization bound.",
      "required": [
        "type",
        "nx",
        "ny",
        "firstLat",
        "firstLon",
        "latStep",
        "lonStep",
        "longitudeConvention"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "regular_latlon",
            "lambert_conformal",
            "polar_stereographic",
            "mercator",
            "lambert_azimuthal_equal_area",
            "geostationary",
            "gaussian",
            "rotated_latlon",
            "unstructured"
          ]
        },
        "nx": {
          "type": "integer"
        },
        "ny": {
          "type": "integer"
        },
        "firstLat": {
          "type": "number",
          "format": "double"
        },
        "firstLon": {
          "type": "number",
          "format": "double"
        },
        "latStep": {
          "type": "number",
          "format": "double"
        },
        "lonStep": {
          "type": "number",
          "format": "double"
        },
        "longitudeConvention": {
          "type": "string",
          "description": "Longitude wrapping used by inventory points and the source grid.",
          "enum": [
            "zero_to_360",
            "minus_180_to_180"
          ]
        },
        "projection": {
          "type": "object",
          "description": "Parameters appropriate to the declared grid type; regular grid steps are in degrees, projected raster steps are in metres or satellite scan-angle radians.",
          "additionalProperties": {
            "type": "number",
            "format": "double"
          }
        },
        "scanOrder": {
          "type": "string"
        },
        "gridId": {
          "type": "string",
          "description": "Source mesh identifier, when applicable."
        },
        "sparse": {
          "type": "boolean",
          "description": "True when some storage positions have no Earth coordinate."
        }
      }
    },
    "SpatialResolution": {
      "type": "object",
      "properties": {
        "label": {
          "type": "string"
        },
        "kind": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "VariableSelector": {
      "type": "object",
      "description": "Exact dataset selector tuple used in forecast queries.\n\nSelectors are not free-form. `name`, `level`, and optional `info` must exactly match a\nselector published for the chosen dataset, either from the dataset catalog endpoints or the\ndataset model/inventory page. Do not invent selectors from natural-language descriptions.\n",
      "required": [
        "name",
        "level"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "GRIB short name exactly as exposed by the dataset inventory or catalog. Case-sensitive. Examples include `TMP`, `UGRD`, `APCP`, `100u`, and `2t`."
        },
        "level": {
          "type": "string",
          "description": "Level text exactly as exposed by the dataset inventory or catalog variation. Must match the published selector tuple exactly."
        },
        "info": {
          "type": "string",
          "description": "Optional extra qualifier from the published selector tuple. Blank string is common. Do not invent natural-language qualifiers here."
        },
        "alias": {
          "type": "string",
          "description": "Optional response key.\n\nIf omitted, the current handlers emit the column as `NAME|LEVEL|INFO`.\n"
        },
        "hidden": {
          "type": "boolean",
          "description": "When `true`, the field is loaded and remains available to expressions and filters,\nbut is omitted from response rows. Shared-parameter derived requests use this for\nintermediate helper inputs such as wind vector components.\n"
        }
      },
      "additionalProperties": false
    }
  }
}