{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://www.snowsure.ai/.well-known/schemas/resort-conditions-v1.json",
  "title": "SnowSure Resort Conditions (v1)",
  "description": "Agent-native, typed conditions contract for a single resort. Every field carries value + provenance (source) + freshness (observedAt) + confidence, produced by the single Conditions Resolver. A null value means 'not reported' — never a stale or guessed number. status is a derived enum that never defaults to OPEN.",
  "type": "object",
  "required": [
    "schemaVersion",
    "schema",
    "meta",
    "data"
  ],
  "additionalProperties": false,
  "properties": {
    "schemaVersion": {
      "type": "string",
      "description": "SemVer of this contract. MAJOR = breaking field change, MINOR = additive, PATCH = docs.",
      "const": "1.10.0"
    },
    "schema": {
      "type": "string",
      "format": "uri",
      "description": "URL of this JSON Schema."
    },
    "meta": {
      "type": "object",
      "required": [
        "source",
        "slug",
        "generatedAt",
        "resolvedAt",
        "freshness"
      ],
      "additionalProperties": false,
      "properties": {
        "source": {
          "type": "string",
          "const": "SnowSure"
        },
        "slug": {
          "type": "string"
        },
        "generatedAt": {
          "type": "string",
          "format": "date-time",
          "description": "When this response was serialized."
        },
        "resolvedAt": {
          "type": "string",
          "format": "date-time",
          "description": "When the Resolver produced the truth; drives staleness."
        },
        "freshness": {
          "type": "object",
          "description": "Per-field staleness labels (1.1.0) for the staleness-bearing fields, derived from each field's observedAt + source against the resolver's TTLs. depthBase/depthMid/depthSummit added in 1.2.0; forecast added in 1.6.0.",
          "required": [
            "baseDepthCm",
            "depthBase",
            "depthMid",
            "depthSummit",
            "lifts",
            "runs",
            "surface",
            "forecast"
          ],
          "additionalProperties": false,
          "properties": {
            "baseDepthCm": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "depthBase": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "depthMid": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "depthSummit": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "lifts": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "runs": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "surface": {
              "$ref": "#/$defs/fieldFreshness"
            },
            "forecast": {
              "allOf": [
                {
                  "$ref": "#/$defs/fieldFreshness"
                }
              ],
              "description": "Added 1.6.0. Age of the model blend behind data.forecast. Unlike other model-sourced fields this IS age-assessed (live ≤6h, recent ≤12h, then stale): a forecast names a forward window, so an old one describes the wrong week."
            }
          }
        }
      }
    },
    "data": {
      "$ref": "#/$defs/resortConditions"
    },
    "measuredNow": {
      "description": "Live measured evidence (1.7.0): the freshest real reading per weather station near the resort, from SnowSure's observation archive — temp/wind/snow depth with station name, elevation, role, and reading age, plus the measured freezing line. Additive context beside `data`, never an input to it. null (or absent) when no station reported within its freshness window.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "object",
          "required": [
            "stations",
            "stationCount",
            "sources",
            "freezingLineM",
            "observedAt"
          ],
          "additionalProperties": false,
          "properties": {
            "stations": {
              "type": "array",
              "description": "Freshest reading per instrument, highest elevation first.",
              "items": {
                "type": "object",
                "required": [
                  "source",
                  "stationId",
                  "name",
                  "elevationM",
                  "role",
                  "tempC",
                  "windMps",
                  "snowDepthCm",
                  "observedAt",
                  "ageMinutes"
                ],
                "additionalProperties": false,
                "properties": {
                  "source": {
                    "type": "string",
                    "description": "Station network lane (e.g. snotel, imis, mistral, nws, amedas)."
                  },
                  "stationId": {
                    "type": "string"
                  },
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "elevationM": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "summit",
                      "mid",
                      "village",
                      "airport",
                      "road"
                    ],
                    "description": "Where the station sits relative to the resort's terrain."
                  },
                  "tempC": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "windMps": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "snowDepthCm": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "observedAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "ageMinutes": {
                    "type": "integer",
                    "description": "Reading age when the response was built."
                  }
                }
              }
            },
            "stationCount": {
              "type": "integer"
            },
            "sources": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "freezingLineM": {
              "type": [
                "number",
                "null"
              ],
              "description": "Elevation where the measured temperature gradient crosses 0°C, when ≥2 stations straddle zero across enough vertical."
            },
            "observedAt": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time",
              "description": "Newest observation timestamp in the set."
            }
          }
        }
      ]
    }
  },
  "$defs": {
    "fieldSource": {
      "type": "string",
      "enum": [
        "operator",
        "scraped",
        "model",
        "profile",
        "derived",
        "none"
      ],
      "description": "Provenance of the value, in trust order. operator = resort-entered via the admin/operator portal (the only source that earns the verified badge); scraped = extracted from the resort's own website/feed (added 1.3.0); model = weather model; profile = static reference; derived = computed by the resolver; none = no value."
    },
    "fieldFreshness": {
      "type": "object",
      "description": "Honest staleness label for one field (1.1.0).",
      "required": [
        "tier",
        "label",
        "ageHours"
      ],
      "additionalProperties": false,
      "properties": {
        "tier": {
          "type": "string",
          "enum": [
            "live",
            "recent",
            "stale",
            "estimated",
            "unknown"
          ],
          "description": "live = operator within the live window; recent = operator within TTL; stale = operator past TTL, or model snapshot older than 6h (1.8.0); estimated = model within 6h, profile/derived, or untimestamped operator/model; unknown = not reported."
        },
        "label": {
          "type": "string",
          "description": "Surface-ready label, e.g. 'live', 'as of 14h ago', 'stale (3d ago)', 'modelled 2h ago', 'stale (modelled 9h ago)', 'estimated', 'not reported'."
        },
        "ageHours": {
          "type": [
            "number",
            "null"
          ],
          "description": "Hours since the observation (for model fields, since the weather snapshot was captured — 1.8.0); null when there is no usable timestamp."
        }
      }
    },
    "fieldEnvelope": {
      "type": "object",
      "description": "Common provenance/freshness/confidence carried by every field.",
      "required": [
        "value",
        "source",
        "observedAt",
        "confidence"
      ],
      "properties": {
        "source": {
          "$ref": "#/$defs/fieldSource"
        },
        "observedAt": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time",
          "description": "ISO timestamp the underlying observation was made; null when unknown."
        },
        "confidence": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "0–1. Low confidence ⇒ surfaces label 'estimated/unverified' and the score down-weights it."
        }
      }
    },
    "operatingStatus": {
      "type": "string",
      "enum": [
        "OPEN",
        "CLOSED_TODAY",
        "PRE_SEASON",
        "OFF_SEASON",
        "UNKNOWN"
      ],
      "description": "Derived operating status — never defaults to OPEN. UNKNOWN is a first-class, honestly-rendered state."
    },
    "liftRunCounts": {
      "type": [
        "object",
        "null"
      ],
      "required": [
        "open",
        "total"
      ],
      "properties": {
        "open": {
          "type": [
            "integer",
            "null"
          ]
        },
        "total": {
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "description": "open and total resolve from the SAME source; open is suppressed (null) when it can't be reconciled against the profile total."
    },
    "abilityMix": {
      "type": [
        "object",
        "null"
      ],
      "required": [
        "beginner",
        "intermediate",
        "advanced",
        "expert"
      ],
      "properties": {
        "beginner": {
          "type": "number"
        },
        "intermediate": {
          "type": "number"
        },
        "advanced": {
          "type": "number"
        },
        "expert": {
          "type": "number"
        }
      },
      "description": "Terrain ability split in percent; present only when all four tiers exist and sum to ~100, else the field value is null."
    },
    "longestRun": {
      "type": [
        "object",
        "null"
      ],
      "required": [
        "name",
        "km"
      ],
      "properties": {
        "name": {
          "type": [
            "string",
            "null"
          ]
        },
        "km": {
          "type": [
            "number",
            "null"
          ]
        }
      }
    },
    "fieldStatus": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "oneOf": [
            {
              "$ref": "#/$defs/operatingStatus"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "fieldString": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "fieldNumber": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "type": [
            "number",
            "null"
          ]
        }
      }
    },
    "fieldCounts": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "$ref": "#/$defs/liftRunCounts"
        }
      }
    },
    "fieldAbility": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "$ref": "#/$defs/abilityMix"
        }
      }
    },
    "fieldLongestRun": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "$ref": "#/$defs/longestRun"
        }
      }
    },
    "snowQuality": {
      "type": [
        "object",
        "null"
      ],
      "required": [
        "densityRatio",
        "label",
        "description"
      ],
      "properties": {
        "densityRatio": {
          "type": [
            "number",
            "null"
          ],
          "description": "SWE ÷ depth (g/cm³) for the measured tier; null for the modeled tier."
        },
        "label": {
          "type": "string",
          "enum": [
            "powder",
            "packed",
            "dense",
            "icy",
            "wet",
            "spring",
            "variable"
          ]
        },
        "description": {
          "type": "string"
        },
        "refreezeRisk": {
          "type": "string",
          "enum": [
            "low",
            "moderate",
            "high"
          ],
          "description": "Likelihood the surface refreezes into a crust (modeled tier)."
        },
        "basis": {
          "type": "string",
          "enum": [
            "measured",
            "modeled"
          ],
          "description": "How the quality was determined: 'measured' (station density) or 'modeled' (current weather)."
        }
      },
      "description": "Added 1.5.0. Snow quality — measured from a station's SWE÷depth density (source 'station'), or modeled from current weather (source 'model') when no station is available."
    },
    "snowSurface": {
      "type": [
        "object",
        "null"
      ],
      "required": [
        "tempC",
        "state",
        "description"
      ],
      "properties": {
        "tempC": {
          "type": "number",
          "description": "Measured snow-surface temperature (TSS), °C."
        },
        "state": {
          "type": "string",
          "enum": [
            "melting",
            "near-freezing",
            "firm",
            "cold"
          ]
        },
        "description": {
          "type": "string"
        }
      },
      "description": "Added 1.5.0. Snow-surface state from a station's measured surface temperature (source 'station')."
    },
    "fieldSnowQuality": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "$ref": "#/$defs/snowQuality"
        }
      }
    },
    "forecastOutlook": {
      "type": "object",
      "description": "Added 1.6.0. Forward model snowfall blend — the only part of this record describing the future rather than the present. Always source 'model'. NOTE: next7dCm is the FORWARD week; the API's snowfall7dCm elsewhere is the PAST week.",
      "required": [
        "next7dCm",
        "next14dCm",
        "peak"
      ],
      "additionalProperties": false,
      "properties": {
        "next7dCm": {
          "allOf": [
            {
              "$ref": "#/$defs/fieldNumber"
            }
          ],
          "description": "Forward 7-day blended total in cm — the industry comparison window, and the field to rank on. Equals the sum of the first 7 daily rows returned by the forecast endpoint. value is null (never 0) when the blend has no data."
        },
        "next14dCm": {
          "allOf": [
            {
              "$ref": "#/$defs/fieldNumber"
            }
          ],
          "description": "Forward 14-day blended total in cm, range-guarded against the reporting models. value is null (never 0) when the blend has no data. The fortnight is SnowSure Pro: for a caller without it (anonymous, or a signed-in free reader on a resort that is not in their My Mountains) value is null with source 'none', on /api/v1/resorts/{slug}/conditions, inline on /api/v1/resorts/{slug} and in MCP get_resort alike; read next7dCm (SS-W-1462)."
        },
        "peak": {
          "oneOf": [
            {
              "type": "object",
              "required": [
                "date",
                "snowfallCm",
                "windowDays"
              ],
              "additionalProperties": false,
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "snowfallCm": {
                  "type": "number"
                },
                "windowDays": {
                  "type": "integer",
                  "const": 7,
                  "description": "Added 1.10.0 (SS-W-207). How many forward days this peak was the biggest of. Always 7 here: it is the biggest day of next7dCm's window, NOT of next14dCm's. For the biggest day of a 14-day total read forecast.peak on /api/v1/resorts/{slug}, which is computed over the fourteen daily rows that endpoint serves and carries its own windowDays."
                }
              }
            },
            {
              "type": "null"
            }
          ],
          "description": "Biggest single day inside the 7-day window, labelled with that window (windowDays). null when no snow is forecast, or when either half of the date/cm pair is missing."
        }
      }
    },
    "fieldSnowSurface": {
      "allOf": [
        {
          "$ref": "#/$defs/fieldEnvelope"
        }
      ],
      "properties": {
        "value": {
          "$ref": "#/$defs/snowSurface"
        }
      }
    },
    "depthTier": {
      "oneOf": [
        {
          "$ref": "#/$defs/fieldNumber"
        },
        {
          "type": "null"
        }
      ],
      "description": "One elevation's reconciled depth: a Field<number>, or null when the tier is genuinely unknown (NEVER interpolated)."
    },
    "depthProfile": {
      "type": "object",
      "description": "Per-elevation reconciled depth — each tier reconciled independently with its own source/observedAt/confidence (1.2.0).",
      "required": [
        "base",
        "mid",
        "summit"
      ],
      "additionalProperties": false,
      "properties": {
        "base": {
          "$ref": "#/$defs/depthTier"
        },
        "mid": {
          "$ref": "#/$defs/depthTier"
        },
        "summit": {
          "$ref": "#/$defs/depthTier"
        }
      }
    },
    "resortConditions": {
      "type": "object",
      "required": [
        "slug",
        "resolvedAt",
        "status",
        "seasonOpening",
        "seasonClosing",
        "depth",
        "displayDepthCm",
        "reportedSourceTier",
        "baseDepthCm",
        "depthVsAvgPct",
        "lifts",
        "runs",
        "surface",
        "abilityPct",
        "longestRun",
        "forecast",
        "flags"
      ],
      "additionalProperties": false,
      "properties": {
        "slug": {
          "type": "string"
        },
        "resolvedAt": {
          "type": "string",
          "format": "date-time"
        },
        "status": {
          "$ref": "#/$defs/fieldStatus"
        },
        "seasonOpening": {
          "$ref": "#/$defs/fieldString"
        },
        "seasonClosing": {
          "$ref": "#/$defs/fieldString"
        },
        "depth": {
          "$ref": "#/$defs/depthProfile"
        },
        "displayDepthCm": {
          "oneOf": [
            {
              "$ref": "#/$defs/fieldNumber"
            },
            {
              "type": "null"
            }
          ],
          "description": "Canonical headline depth. Base-preferred (base ?? mid ?? summit), except that since 1.9.0 a fresh measured tier (station/operator) leads over a model or derived base (SS-W-201). Labelled by displayDepthDetail. Null when no tier has a value."
        },
        "displayDepthDetail": {
          "description": "Added 1.9.0. Band, elevation and public source label of displayDepthCm; null when displayDepthCm is null.",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "source",
                "elevationBand",
                "elevationM",
                "sourceLabel",
                "stationName",
                "rule"
              ],
              "properties": {
                "source": {
                  "$ref": "#/$defs/fieldSource"
                },
                "elevationBand": {
                  "type": "string",
                  "enum": [
                    "base",
                    "mid",
                    "summit"
                  ]
                },
                "elevationM": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Station elevation for a station reading, else the band's resort elevation (m). Null when unknown."
                },
                "sourceLabel": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Public network or lane name: DGA, SNOTEL, Snowy Hydro, Resort Reported, Open-Meteo."
                },
                "stationName": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "rule": {
                  "type": "string",
                  "enum": [
                    "base_preferred",
                    "measured_over_model"
                  ],
                  "description": "measured_over_model when a measured tier displaced a model/derived base headline."
                }
              }
            }
          ]
        },
        "reportedSourceTier": {
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "direct_api",
                "structured_feed",
                "headless_dom",
                "vision",
                "unknown"
              ]
            },
            {
              "type": "null"
            }
          ],
          "description": "Added 1.4.0. Acquisition-quality tier of the headline depth WHEN it resolved to a scraped value: direct_api > structured_feed > headless_dom > vision. null when the headline depth is operator/model/absent. Lets consumers weight a first-party feed vs a vision read."
        },
        "baseDepthCm": {
          "$ref": "#/$defs/fieldNumber",
          "description": "Deprecated. The base-preferred headline (base ?? mid ?? summit). Equals displayDepthCm except where a measured mid/summit leads over a model base (1.9.0). Rankings use this."
        },
        "depthVsAvgPct": {
          "$ref": "#/$defs/fieldNumber",
          "description": "Headline depth as % of the historical average. Since 1.9.0 published only for a base-band headline (the stored norm's band) with no depthDisagreement; otherwise value null and depthVsAvgBasis.suppressedReason says why."
        },
        "depthVsAvgBasis": {
          "description": "Added 1.9.0. What depthVsAvgPct is computed against, or why it is null.",
          "type": "object",
          "additionalProperties": false,
          "required": [
            "averageCm",
            "averageBand",
            "readingBand",
            "readingSource",
            "suppressedReason"
          ],
          "properties": {
            "averageCm": {
              "type": [
                "number",
                "null"
              ]
            },
            "averageBand": {
              "type": "string",
              "enum": [
                "base",
                "mid",
                "summit"
              ]
            },
            "readingBand": {
              "oneOf": [
                {
                  "type": "string",
                  "enum": [
                    "base",
                    "mid",
                    "summit"
                  ]
                },
                {
                  "type": "null"
                }
              ]
            },
            "readingSource": {
              "oneOf": [
                {
                  "$ref": "#/$defs/fieldSource"
                },
                {
                  "type": "null"
                }
              ]
            },
            "suppressedReason": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "type": "string",
                  "enum": [
                    "no_depth",
                    "no_average",
                    "average_too_small",
                    "ratio_unbounded",
                    "band_mismatch",
                    "depth_disagreement"
                  ]
                }
              ]
            }
          }
        },
        "depthDisagreement": {
          "description": "Added 1.9.0. Set when a displayed model base is under 50% of a measured mid/summit, or a measured base exceeds the model summit. The measured lead is kept and depthVsAvgPct is withheld.",
          "oneOf": [
            {
              "type": "null"
            },
            {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "kind",
                "measured",
                "model",
                "ratio",
                "note"
              ],
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "model_base_below_half_measured_upper",
                    "measured_base_above_model_summit"
                  ]
                },
                "measured": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "band",
                    "cm",
                    "source"
                  ],
                  "properties": {
                    "band": {
                      "type": "string",
                      "enum": [
                        "base",
                        "mid",
                        "summit"
                      ]
                    },
                    "cm": {
                      "type": "number"
                    },
                    "source": {
                      "$ref": "#/$defs/fieldSource"
                    }
                  }
                },
                "model": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "band",
                    "cm"
                  ],
                  "properties": {
                    "band": {
                      "type": "string",
                      "enum": [
                        "base",
                        "mid",
                        "summit"
                      ]
                    },
                    "cm": {
                      "type": "number"
                    }
                  }
                },
                "ratio": {
                  "type": "number",
                  "description": "model cm / measured cm, 2 dp."
                },
                "note": {
                  "type": "string"
                }
              }
            }
          ]
        },
        "lifts": {
          "$ref": "#/$defs/fieldCounts"
        },
        "runs": {
          "$ref": "#/$defs/fieldCounts"
        },
        "surface": {
          "$ref": "#/$defs/fieldString"
        },
        "abilityPct": {
          "$ref": "#/$defs/fieldAbility"
        },
        "longestRun": {
          "$ref": "#/$defs/fieldLongestRun"
        },
        "snowQuality": {
          "oneOf": [
            {
              "$ref": "#/$defs/fieldSnowQuality"
            },
            {
              "type": "null"
            }
          ],
          "description": "Added 1.5.0. Measured snow quality (SWE÷depth density) from a station, or null when no station data."
        },
        "snowSurfaceTemp": {
          "oneOf": [
            {
              "$ref": "#/$defs/fieldSnowSurface"
            },
            {
              "type": "null"
            }
          ],
          "description": "Added 1.5.0. Snow-surface state from a station's measured surface temperature, or null."
        },
        "forecast": {
          "$ref": "#/$defs/forecastOutlook"
        },
        "flags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Machine-readable reconciliation issues, e.g. 'operator_model_divergence', 'lifts_total_mismatch'."
        }
      }
    }
  }
}
