{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openagriculturetechnology.com/standard/oat-recipe-0.1.schema.json",
  "title": "oat-recipe — Open Agriculture Technology Open Grow Recipe (v0.1)",
  "description": "An open, CC-BY, self-describing interchange format for a grow recipe: a crop, its stages over a cycle, and a four-band setpoint per parameter per step. This schema validates the Open Agriculture Technology engine's portable export document (oat_recipe_export 1.x); the same primitive also serializes to a human SOP and to the edge control contract (oat_control_contract). Forward-compatible: consumers MUST ignore unknown fields and accept unknown parameter slugs.",
  "type": "object",
  "required": ["oat_recipe_export", "bundle", "stages", "charts"],
  "properties": {
    "oat_recipe_export": {
      "type": "string",
      "pattern": "^1\\.[0-9]+$",
      "description": "Serialization version of this document (the engine's export format). Additive minor bumps; consumers ignore unknown fields."
    },
    "$schema": {
      "type": "string",
      "description": "Optional self-pointer to this JSON Schema."
    },
    "exported_at": {
      "type": "string",
      "description": "ISO-8601 timestamp the document was produced."
    },
    "bundle": {
      "type": "object",
      "description": "Recipe identity. A bundle is one assembled master recipe for a crop.",
      "required": ["slug", "name"],
      "properties": {
        "slug": { "type": "string", "description": "Stable machine id for this recipe." },
        "name": { "type": ["string", "null"], "description": "Display name." },
        "cultivar": { "type": ["string", "null"], "description": "Crop / cultivar." },
        "target_use": { "type": ["string", "null"], "description": "Intended use / outcome." },
        "license": { "type": ["string", "null"], "description": "Reuse licence. Reference recipes are CC-BY-4.0." },
        "weeks": { "type": "integer", "minimum": 0, "description": "Cycle length in time steps (see time model)." },
        "forked_from": { "type": ["string", "null"], "description": "Parent bundle id, when this recipe is a fork." }
      },
      "additionalProperties": true
    },
    "stages": {
      "type": "array",
      "description": "The cycle timeline. Each stage spans an inclusive run of 0-based steps; SOP-as-data events mark the transitions.",
      "items": {
        "type": "object",
        "required": ["label", "start", "end"],
        "properties": {
          "label": { "type": "string", "description": "Stage name, e.g. Vegetative, Flower." },
          "start": { "type": "integer", "minimum": 0, "description": "First step index (0-based)." },
          "end": { "type": "integer", "minimum": 0, "description": "Last step index (inclusive)." },
          "params": {
            "type": ["object", "array", "null"],
            "description": "Stage event parameters (trigger detail, duration, training method, …)."
          }
        },
        "additionalProperties": true
      }
    },
    "designs": {
      "type": ["object", "array"],
      "description": "Right-to-repair: the means behind the targets, keyed engine → stage ('all' for whole-cycle). Free-form per engine (a light fixture plan, a feed plan). Optional; an empty designs set serializes as []."
    },
    "charts": {
      "type": "object",
      "description": "The recipe body: engine (which bundle chart stores the cell) → parameter slug → 0-based step index → four-band setpoint.",
      "propertyNames": { "$ref": "#/$defs/engine" },
      "additionalProperties": {
        "type": "object",
        "description": "parameter slug → step index → band. Slugs SHOULD come from the parameter dictionary ($defs/parameter_dictionary) but custom slugs are permitted.",
        "additionalProperties": {
          "type": "object",
          "description": "0-based step index → band.",
          "patternProperties": { "^[0-9]+$": { "$ref": "#/$defs/band" } },
          "additionalProperties": false
        }
      }
    }
  },
  "additionalProperties": true,
  "$defs": {
    "engine": {
      "description": "The bundle chart a parameter cell is stored in. (A parameter's home domain may be plant_body or location; in the recipe body it is placed in one of these five charts.)",
      "enum": ["chemistry", "environment", "light", "substrate", "cycle"]
    },
    "band": {
      "type": "object",
      "description": "The universal four-band setpoint. A human reads it as aim / OK range / act-if; a controller reads it as setpoint + warn deadband + alarm trip. Any field may be null — one-sided thresholds (e.g. a leaf-wetness ceiling) are valid.",
      "properties": {
        "target": { "type": ["number", "null"], "description": "Aim / setpoint." },
        "lower_alert": { "type": ["number", "null"], "description": "Critical low — alarm trip." },
        "lower_warning": { "type": ["number", "null"], "description": "Low — advisory deadband edge." },
        "upper_warning": { "type": ["number", "null"], "description": "High — advisory deadband edge." },
        "upper_alert": { "type": ["number", "null"], "description": "Critical high — alarm trip." },
        "unit": { "type": ["string", "null"], "description": "Canonical unit for this cell." }
      },
      "additionalProperties": true
    },
    "parameter_dictionary": {
      "description": "Informative controlled vocabulary of recipe parameters, by engine. NOT enforced (forward-compat: accept unknown/custom slugs). v0.1 adds the specialist parameters: far_red_fraction, cwsi, leaf_wetness_hours, soil_water_tension, pore_water_ec, substrate_oxygen.",
      "type": "object",
      "properties": {
        "light": {
          "const": ["dli_canopy", "photoperiod_hours", "far_red_fraction", "red_far_red_ratio"],
          "description": "Light quantity (DLI, photoperiod) and quality (far-red fraction, red:far-red ratio)."
        },
        "environment": {
          "const": ["air_temperature_day", "air_temperature_night", "relative_humidity", "vpd_air", "co2_air", "air_circulation", "cwsi", "leaf_wetness_hours"],
          "description": "Aerial climate, plus plant-response signals: cwsi (crop water stress index, derived) and leaf_wetness_hours (a max-hours ceiling)."
        },
        "chemistry": {
          "const": ["element_n_total", "element_p", "element_k", "element_ca", "element_mg", "element_s"],
          "description": "Feed strength by element."
        },
        "substrate": {
          "const": ["root_zone_temp", "dissolved_oxygen_root", "substrate_moisture", "soil_water_tension", "pore_water_ec", "substrate_oxygen"],
          "description": "Root-zone conditions: temperature, dissolved O2 (in water), moisture, soil-water tension, pore-water EC, and substrate O2 (in the pore air)."
        }
      }
    }
  }
}
