{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/buildbatch-co-uk/json-schema/buildbatch-co-uk-plan-answer-schema.json",
  "title": "PlanAnswer",
  "x-generated": "2026-11-03",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/buildbatch-co-uk-openapi.json#/components/schemas/PlanAnswer",
  "type": "object",
  "required": [
    "api",
    "document",
    "v",
    "ok",
    "understood",
    "room",
    "lines",
    "listUrl",
    "honesty"
  ],
  "properties": {
    "api": {
      "type": "string",
      "const": "buildbatch-assistant"
    },
    "document": {
      "type": "string",
      "const": "plan"
    },
    "v": {
      "type": "integer",
      "const": 1
    },
    "ok": {
      "type": "boolean",
      "const": true
    },
    "understood": {
      "type": "object",
      "description": "What was understood: job, walls, ceiling, trim, room, openings, answers, and the lists defaulted[] (a parameter left out and the value used) and ignored[] (a parameter not read, or without effect, and why). room is {shape: \"rectangle\", lengthM, widthM, heightM}, {shape: \"drawn\", cornersM, heightM} or, for a loft, slab or patio given as an area, {shape: \"area\", areaM2, heightM}; heightM is null when no height was needed or given. With tiles or wallpaper on some walls only (walls.length), room also has wallsLengthM, the length of wall covered in place of the room's perimeter; walls.length on painted walls is listed in ignored[]."
    },
    "room": {
      "type": "object",
      "description": "description, floorAreaM2, perimeterM, ceilingAreaM2, wallAreaM2 {gross, openings, net}, doors, windows. A figure that was not measured is null, never 0: given as an area, perimeterM and the wall areas are null, because how far it is round is not known; a patio, a slab or a loft floor has no ceiling, so ceilingAreaM2 is null."
    },
    "summary": {
      "type": "object",
      "description": "counts, and toBuy[] and toCheck[] as short lines to read out."
    },
    "statuses": {
      "type": "object",
      "description": "What need, check, have and not-needed mean."
    },
    "lines": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Line"
      }
    },
    "leftovers": {
      "type": "array",
      "items": {
        "type": "object"
      }
    },
    "assumptions": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "warnings": {
      "type": "array",
      "description": "Safety and condition warnings, each with the line ids it comes from.",
      "items": {
        "type": "object"
      }
    },
    "listUrl": {
      "type": "string",
      "format": "uri",
      "description": "Show this to the person: it opens the whole list (the working, tick-off, print, save). Free, no account."
    },
    "startUrl": {
      "type": "string",
      "format": "uri",
      "description": "Opens the planner with the same figures filled in, to change them."
    },
    "shops": {
      "type": "array",
      "items": {
        "type": "object"
      }
    },
    "honesty": {
      "type": "object",
      "description": "What to pass on: the template and formula versions, whose figures these are, that nobody outside the build has reviewed it, that there is no price, what the shop links are, and to check the figures and the product's instructions."
    }
  },
  "$defs": {
    "Line": {
      "type": "object",
      "required": [
        "id",
        "label",
        "group",
        "type",
        "status",
        "why"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "Stable within the template version."
        },
        "label": {
          "type": "string"
        },
        "group": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": [
            "material",
            "preparation",
            "consumable",
            "tool",
            "ppe"
          ]
        },
        "status": {
          "type": "string",
          "enum": [
            "need",
            "check",
            "have",
            "not-needed"
          ]
        },
        "defaultStatus": {
          "type": "string"
        },
        "quantity": {
          "type": [
            "string",
            "null"
          ],
          "description": "For example \"1 × 5 L tin (5 L)\". Null when the line has no quantity: see measurement and checkFirst."
        },
        "packs": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "count": {
                "type": "number"
              },
              "label": {
                "type": "string"
              },
              "size": {
                "type": "number"
              },
              "unit": {
                "type": "string"
              }
            }
          }
        },
        "needed": {
          "type": [
            "object",
            "null"
          ]
        },
        "buying": {
          "type": [
            "object",
            "null"
          ]
        },
        "leftOver": {
          "type": [
            "object",
            "null"
          ]
        },
        "measurement": {
          "type": [
            "object",
            "null"
          ],
          "description": "A derived figure the list gives when it cannot name a purchase."
        },
        "why": {
          "type": "string"
        },
        "checkFirst": {
          "type": [
            "string",
            "null"
          ],
          "description": "What decides it, for a line marked check."
        },
        "before": {
          "type": "boolean",
          "description": "True for a line that is not a thing to buy but has to be in place before the work starts (a flat, sound wall to tile on). Say it before the list."
        },
        "question": {
          "type": [
            "object",
            "null"
          ],
          "description": "The one question the line still asks the person, with the answers it offers: { ask, answers[] }. Its answer changes the list. Null once answered, or when the line asks nothing."
        },
        "working": {
          "type": [
            "string",
            "null"
          ]
        },
        "assumptions": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "figures": {
          "type": [
            "object",
            "null"
          ],
          "description": "kind is \"generic\" (the planner's labelled example), \"user\" (sent in the call) or \"typical\" (a coverage or a pack size found from makers' own figures or products on sale; note says from what). pack is \"generic\" where the line's pack is still the labelled example though another of its figures was sent (an allowance for cuts with no pack size): note says which is which."
        },
        "warnings": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "find": {
          "type": [
            "object",
            "null"
          ],
          "description": "searchWords, kind and shops (shop id to that shop's own search address), or items[] of those for a line that names several things."
        }
      }
    }
  }
}