{
  "title": "Carpet cleaning estimate calculator form specification",
  "version": "1.0",
  "currency_representation": "Three-letter label only; no conversion",
  "fields": [
    {
      "name": "area_unit",
      "type": "enum",
      "allowed": [
        "ft2",
        "m2"
      ],
      "required": true,
      "purpose": "Applies consistently to all room areas and rates."
    },
    {
      "name": "rooms",
      "type": "array<object>",
      "required": true,
      "minimum_items": 1,
      "fields": [
        {
          "name": "room_id",
          "type": "stable string",
          "required": true
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        },
        {
          "name": "area",
          "type": "finite number",
          "required": true,
          "exclusive_minimum": 0
        },
        {
          "name": "rate_per_area_unit",
          "type": "finite number",
          "required": true,
          "minimum": 0
        }
      ]
    },
    {
      "name": "addons",
      "type": "array<object>",
      "required": false,
      "fields": [
        {
          "name": "addon_id",
          "type": "stable string",
          "required": true
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        },
        {
          "name": "fixed_amount",
          "type": "finite number",
          "required": true,
          "minimum": 0
        }
      ]
    },
    {
      "name": "minimum_charge",
      "type": "finite number",
      "required": true,
      "minimum": 0
    },
    {
      "name": "currency",
      "type": "string",
      "required": true,
      "pattern": "^[A-Z]{3}$"
    },
    {
      "name": "exports",
      "type": "array<enum>",
      "allowed": [
        "itemized CSV",
        "quote PDF"
      ],
      "required": true
    }
  ],
  "formula": {
    "room_subtotal": "sum(room.area × room.rate_per_area_unit)",
    "subtotal": "room_subtotal + sum(addon.fixed_amount)",
    "minimum_adjustment": "max(0, minimum_charge − subtotal)",
    "total": "subtotal + minimum_adjustment"
  },
  "validation": [
    "Require at least one positive finite room area.",
    "Reject blank, nonfinite, or negative rate, add-on, or minimum values.",
    "Do not add region, industry, tax, or default price assumptions.",
    "Exports must match displayed inputs and totals."
  ]
}
