{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://psigen.github.io/sous/schema/v0/kitchen.schema.json",
  "title": "Sous Kitchen Profile",
  "description": "What a specific kitchen HAS: equipment instances, their current state, and pantry inventory. A recipe names capability classes; this document binds them to instances. It is also the planner's initial state, which is what makes the recipe/procedure separation operational -- a pantry holding pre-diced onion satisfies a 'diced onion' requirement directly, while one holding whole onion forces a cut operation into the plan.",
  "type": "object",
  "properties": {
    "$schema": {
      "type": "string",
      "format": "uri",
      "description": "Points at this schema so editors offer completion and inline validation. This is how Sous documents become IDE-authorable."
    },
    "sous_version": {
      "type": "string",
      "const": "0.1.0"
    },
    "id": {
      "type": "string",
      "minLength": 1
    },
    "label": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "equipment": {
      "type": "array",
      "description": "Physical instances. Each declares the capability classes it provides; a single Dutch oven provides vessel, heat_source and heated_vessel at once.",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "common/identifier.schema.json#/$defs/LocalId"
          },
          "label": {
            "type": "string"
          },
          "provides": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "common/identifier.schema.json#/$defs/EquipmentClassRef"
            },
            "description": "Capability classes this instance satisfies, including inherited ones."
          },
          "attributes": {
            "type": "object",
            "description": "Concrete values for the class attributes: capacity, surface_area, dimensions, max_temperature, lidded, thermal_mass.",
            "additionalProperties": true
          },
          "count": {
            "type": "integer",
            "minimum": 1,
            "default": 1,
            "description": "How many identical instances exist. Contention on a single oven is a real scheduling constraint."
          },
          "state": {
            "$ref": "common/state.schema.json#/$defs/EquipmentState",
            "description": "Current state. Defaults to clean, ambient, off, empty."
          },
          "device": {
            "type": "object",
            "description": "Optional binding to a controllable appliance, for kitchens that can actually command setpoints.",
            "properties": {
              "protocol": {
                "type": "string",
                "enum": [
                  "matter",
                  "home_connect",
                  "mqtt",
                  "http",
                  "manual"
                ]
              },
              "identifier": {
                "type": "string"
              },
              "programs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Device program ids, e.g. Cooking.Oven.Program.HeatingMode.HotAir."
              }
            },
            "additionalProperties": true
          }
        },
        "required": [
          "id",
          "provides"
        ],
        "additionalProperties": false
      }
    },
    "pantry": {
      "type": "array",
      "description": "Available materials AND THEIR STATE. State is the whole point: 'onion, diced, 500 g' and 'onion, whole, 3 each' satisfy different recipe requirements and produce different plans.",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "common/identifier.schema.json#/$defs/LocalId"
          },
          "substance": {
            "$ref": "common/identifier.schema.json#/$defs/SubstanceRef"
          },
          "state": {
            "$ref": "common/state.schema.json#/$defs/MaterialState"
          },
          "quantity": {
            "$ref": "common/quantity.schema.json#/$defs/Quantity"
          },
          "unlimited": {
            "type": "boolean",
            "default": false,
            "description": "For staples such as water, salt and oil, where modelling a finite amount adds nothing."
          },
          "expires": {
            "type": "string",
            "format": "date"
          }
        },
        "required": [
          "substance"
        ],
        "additionalProperties": false
      }
    },
    "heat_level_map": {
      "type": "object",
      "description": "Overrides the default qualitative-to-setpoint mapping in vocab/operations.json. Induction, gas and electric differ enough that a shared default is only a starting point.",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "value": {
            "type": "number"
          },
          "unit": {
            "type": "string",
            "enum": [
              "Cel",
              "[degF]"
            ]
          }
        },
        "required": [
          "value",
          "unit"
        ],
        "additionalProperties": false
      }
    },
    "observables": {
      "type": "array",
      "description": "Which observables this kitchen can actually measure. A recipe whose termination conditions need an observable the kitchen lacks cannot reach the planner-ready profile here, even if the recipe itself is fully conformant.",
      "items": {
        "type": "string"
      }
    },
    "operators": {
      "type": "object",
      "description": "Human or robotic agents. A plan with three concurrent active tasks needs three agents, or it is not a plan.",
      "properties": {
        "count": {
          "type": "integer",
          "minimum": 0,
          "default": 1
        },
        "kind": {
          "type": "string",
          "enum": [
            "human",
            "robot",
            "mixed"
          ],
          "default": "human"
        },
        "skill": {
          "type": "string",
          "enum": [
            "novice",
            "competent",
            "professional"
          ],
          "default": "competent"
        }
      },
      "additionalProperties": false
    },
    "constraints": {
      "type": "object",
      "properties": {
        "max_concurrent_active_tasks": {
          "type": "integer",
          "minimum": 1
        },
        "forbidden_operations": {
          "type": "array",
          "items": {
            "$ref": "common/identifier.schema.json#/$defs/OperationRef"
          },
          "description": "Operations this kitchen will not perform, e.g. deep_fry in a domestic setting without extraction."
        },
        "allergen_exclusions": {
          "type": "array",
          "items": {
            "$ref": "recipe.schema.json#/$defs/Allergen"
          },
          "description": "Allergens that must not enter this kitchen at all. Stronger than a per-recipe claim."
        }
      },
      "additionalProperties": false
    }
  },
  "required": [
    "sous_version",
    "id",
    "equipment"
  ],
  "additionalProperties": false
}
