{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/smartcut-dev/json-schema/smartcut-dev-result-response-schema.json",
  "title": "ResultResponse",
  "description": "Complete result.\n\n**Coordinates.** Every position (`parts[].x/y`, `cuts[].x1…y2`, `offcuts[].x/y`) is measured on its stock sheet from the origin corner, with the sheet's long side (`l`) along x and its short side (`w`) along y. y = 0 is the origin edge and **y increases upward**, so \"top\" means high y. On a vertical panel saw the origin edge is the bottom rail the sheet stands on; with `guillotineOptions.verticalPanelSaw` the narrow strips are placed at the top of the sheet (high y) and the waste at the bottom, and the cut `order` works from the top down.\n\n**Stacks.** Sheets that share a cutting pattern may be cut together as a stack (`saw.options.stackingMode`). A stack is listed ONCE in `stock`, with `stack` = its number of sheets; `stacks` lists every stack with each sheet's position (1 = top) and its number across the job, and each part cut from a stack carries `stacked: { sheet, of, stack }`. For a label, print \"sheet `stacked.sheet` of `stacked.of`, stack `stacked.stack`\". What the control cuts together WITHIN a sheet (strips cut in one pass) is per sheet in `metadata.productionTime.sheets[].stacking`, for saws with a cutting-time model.",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/_original/smartcut-dev-openapi-openapi.json#/components/schemas/ResultResponse",
  "type": "object",
  "properties": {
    "jobId": {
      "type": "number"
    },
    "calcTime": {
      "type": "number",
      "description": "Calculation time in milliseconds"
    },
    "saw": {
      "$ref": "#/$defs/Saw",
      "description": "Saw configuration used. On a mixed (multi-saw) job this is the job's DEFAULT saw — attribute each stock via its `sawId` and the `saws` echo."
    },
    "saws": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/IdentifiedSaw"
      },
      "description": "The identified saws a mixed job ran with (the request's `saw` array plus any hoisted inline material saws). Present ONLY on mixed jobs."
    },
    "materials": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Material"
      },
      "description": "The materials a mixed job was partitioned by. Present ONLY on mixed jobs."
    },
    "stock": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ResultStock"
      },
      "description": "Stock with layouts"
    },
    "parts": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ResultPart"
      },
      "description": "Parts with placement"
    },
    "stacks": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ResultStack"
      },
      "description": "What the saw cuts together: one entry per used `stock` entry, in `stock` order, with its depth and every sheet's position in the stack and number in the job. The depths sum to the number of sheets used. Present ONLY when at least one stack holds two or more sheets."
    },
    "stripRepeats": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ResultStripRepeat"
      },
      "description": "Identical strips across the job's sheets and within one, for an operator who stacks strips by hand (e.g. on a vertical panel saw). Each group names its member strips by `stock[].id` and strip number; each part of a member strip carries `stripGroup`. Present ONLY when at least one strip repeats."
    },
    "cuts": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Cut"
      },
      "description": "Cut instructions"
    },
    "offcuts": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Offcut"
      },
      "description": "Every remaining offcut piece. Filter on `retained` for the pieces the saw would take back as stock."
    },
    "unusableParts": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/UnusablePart"
      },
      "description": "Parts rejected BEFORE optimisation because no available stock can ever hold them (larger than every stock size, or no stock with a matching material/thickness). This is NOT the full list of parts left out of the layout — it is the \"can never fit\" subset. For a completeness check (\"did every part place?\") use metadata.unplacedParts, or compare the count of placed parts to the count requested. unusableParts also appears within metadata.unplacedParts."
    },
    "metadata": {
      "$ref": "#/$defs/Metadata",
      "description": "Complete analysis (all internal fields)"
    }
  },
  "required": [
    "jobId",
    "stock",
    "parts",
    "metadata"
  ],
  "$defs": {
    "Cut": {
      "type": "object",
      "description": "Cut instruction with coordinates",
      "properties": {
        "x1": {
          "type": "number",
          "description": "Start X coordinate of the cut"
        },
        "x2": {
          "type": "number",
          "description": "End X coordinate of the cut"
        },
        "y1": {
          "type": "number",
          "description": "Start Y coordinate of the cut"
        },
        "y2": {
          "type": "number",
          "description": "End Y coordinate of the cut"
        },
        "dimension": {
          "type": "string",
          "enum": [
            "l",
            "w"
          ],
          "description": "Cut dimension (l=horizontal, w=vertical)"
        },
        "position": {
          "type": "string",
          "enum": [
            "top",
            "bottom",
            "left",
            "right",
            "merged"
          ],
          "description": "Cut position relative to segment"
        },
        "isTrim": {
          "type": "boolean",
          "description": "Whether this is a trim cut"
        },
        "order": {
          "type": [
            "number",
            "null"
          ],
          "description": "Position of this cut in its board's cutting sequence. Numbering restarts on every board: to cut a board, take the cuts whose `stock.id` is that board and run them in ascending `order`. Stock trim cuts carry negative values and come first. With `guillotineOptions.verticalPanelSaw` the sequence works from the top of the board down."
        },
        "phase": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "description": "The saw turn this cut is made on, read from the cut's geometry: 0 = the board's first cutting direction (the opening rips), 1 = after the material is turned once, and so on. A head cut counts like any other cut: the section it opens is turned before it is ripped, so that section's first cuts are one turn later. The quantity `guillotineOptions.maxPhase` caps; `stock[].analysis.maxPhase` is the deepest on each board. Null on cuts that carry no turn (efficiency, nesting and roll layouts)."
        },
        "stock": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "ID of the stock this cut belongs to"
            }
          }
        }
      }
    },
    "Extras": {
      "type": "object",
      "description": "Extras container (V3 format)",
      "properties": {
        "banding": {
          "type": "object",
          "properties": {
            "sides": {
              "$ref": "#/$defs/SideValues"
            }
          },
          "description": "Edge banding"
        },
        "finish": {
          "type": "object",
          "properties": {
            "faces": {
              "type": "object",
              "properties": {
                "a": {
                  "type": "string",
                  "description": "Front face"
                },
                "b": {
                  "type": "string",
                  "description": "Back face"
                }
              }
            },
            "sides": {
              "$ref": "#/$defs/SideValues"
            }
          },
          "description": "Surface finish"
        },
        "planing": {
          "type": "object",
          "properties": {
            "sides": {
              "$ref": "#/$defs/SideValues"
            },
            "faces": {
              "type": "object",
              "properties": {
                "a": {
                  "type": "boolean"
                },
                "b": {
                  "type": "boolean"
                }
              }
            }
          },
          "description": "Planing operations"
        },
        "imageUpload": {
          "type": "object",
          "description": "Image upload data"
        }
      }
    },
    "IdentifiedSaw": {
      "description": "A saw with an id — the array form of `saw` and the `ResultResponse.saws` echo. Materials reference it via `sawId`.",
      "allOf": [
        {
          "$ref": "#/$defs/Saw"
        },
        {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "minLength": 1,
              "description": "Identifier materials reference via `sawId`. The FIRST element of the `saw` array is the job's default saw."
            }
          },
          "required": [
            "id"
          ]
        }
      ]
    },
    "Issue": {
      "type": "object",
      "description": "Validation issue for a part",
      "properties": {
        "message": {
          "type": "string",
          "description": "Human-readable error message"
        },
        "type": {
          "type": "string",
          "enum": [
            "error",
            "warning"
          ],
          "description": "Issue severity"
        },
        "category": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "saw",
              "stock",
              "part",
              "group",
              "machining",
              "extras"
            ]
          },
          "description": "Issue category"
        },
        "field": {
          "type": "array",
          "items": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": "Path to the field with the issue"
        }
      }
    },
    "Machining": {
      "type": [
        "object",
        "null"
      ],
      "description": "Machining operations on a part — the same shape in the request and the result.",
      "properties": {
        "holes": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "description": "X position of the hole centre, from the left edge"
              },
              "y": {
                "type": "number",
                "description": "Y position of the hole centre, from the bottom edge"
              },
              "diameter": {
                "type": "number",
                "description": "Hole diameter"
              },
              "depth": {
                "type": "number",
                "description": "Hole depth. Absent for a through hole"
              },
              "face": {
                "type": "number",
                "enum": [
                  0,
                  1
                ],
                "description": "Face index (0=front, 1=back)"
              },
              "type": {
                "type": "string",
                "enum": [
                  "regular",
                  "hinge",
                  "shelf"
                ],
                "description": "Hole type"
              },
              "edge": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "l1",
                  "l2",
                  "w1",
                  "w2"
                ],
                "description": "Edge the hole is bored into. null for a face hole"
              }
            },
            "required": [
              "x",
              "y",
              "diameter"
            ]
          },
          "description": "Drilled holes"
        },
        "hingeHoles": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "position": {
                "type": "number",
                "description": "Position along the side"
              },
              "side": {
                "type": "string",
                "enum": [
                  "l1",
                  "l2",
                  "w1",
                  "w2"
                ],
                "description": "Side the hinge is placed on"
              },
              "face": {
                "type": "number",
                "enum": [
                  0,
                  1
                ],
                "description": "Face index (0=front, 1=back)"
              },
              "numHoles": {
                "type": "number",
                "description": "Number of holes in the hinge"
              },
              "diameter": {
                "type": "number",
                "description": "Hole diameter"
              },
              "depth": {
                "type": "number",
                "description": "Hole depth"
              },
              "hingeLength": {
                "type": "number",
                "description": "Length of the hinge"
              },
              "distanceFromEdge": {
                "type": "number",
                "description": "Distance from the edge to the hole centre"
              },
              "outerSpacing": {
                "type": "number",
                "description": "Spacing from the hinge ends to the outer holes"
              }
            },
            "required": [
              "position",
              "side"
            ]
          },
          "description": "Hinge hole sets"
        },
        "corners": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "index": {
                "type": "integer",
                "enum": [
                  0,
                  1,
                  2,
                  3
                ],
                "description": "Corner (0=bottom-left, 1=bottom-right, 2=top-right, 3=top-left)"
              },
              "type": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "radius",
                  "bevel"
                ],
                "description": "Corner modification"
              },
              "size": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Size of the corner modification"
              }
            }
          },
          "description": "Corner modifications"
        },
        "grooves": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "direction": {
                "type": "string",
                "enum": [
                  "l",
                  "w"
                ],
                "description": "Groove direction (l=along the length, w=along the width)"
              },
              "position": {
                "type": "number",
                "description": "Distance from the near edge, perpendicular to the groove"
              },
              "start": {
                "type": "number",
                "description": "Start offset along the groove"
              },
              "length": {
                "type": "number",
                "description": "Groove length. Absent for the full side"
              },
              "width": {
                "type": "number",
                "description": "Groove width"
              },
              "depth": {
                "type": "number",
                "description": "Groove depth"
              },
              "face": {
                "type": "number",
                "enum": [
                  0,
                  1
                ],
                "description": "Face index (0=front, 1=back)"
              }
            }
          },
          "description": "Grooves"
        }
      }
    },
    "Material": {
      "type": "object",
      "description": "A material with a saw association — the unit a MIXED job is partitioned and optimised by. Associate it to a saw with `sawId` OR an inline `saw` (never both); with neither, it runs on the job's default saw.",
      "properties": {
        "id": {
          "type": "string",
          "description": "Material identifier stock/parts reference via their `materialId`. Defaults to `name`."
        },
        "name": {
          "type": "string",
          "description": "Material name. Stock/parts without a `materialId` attach by matching their `material` (and thickness, when `thicknesses` is set)."
        },
        "type": {
          "type": "string",
          "enum": [
            "sheet",
            "linear",
            "roll"
          ],
          "default": "sheet",
          "description": "Stock type of this material — must equal the associated saw's `stockType`."
        },
        "sawId": {
          "type": "string",
          "description": "Reference to an identified saw in the `saw` array. Mutually exclusive with inline `saw`."
        },
        "saw": {
          "$ref": "#/$defs/Saw",
          "description": "Inline saw for this material (hoisted to an identified saw with id = material id). Mutually exclusive with `sawId`."
        },
        "thicknesses": {
          "type": "array",
          "items": {
            "type": "number",
            "minimum": 0
          },
          "description": "Thicknesses this material is available in — used for name-based association."
        },
        "grain": {
          "type": "string",
          "enum": [
            "l",
            "w",
            ""
          ],
          "description": "Grain direction of the material."
        }
      },
      "required": [
        "name"
      ]
    },
    "Metadata": {
      "type": "object",
      "description": "Complete result metadata with all analysis fields",
      "properties": {
        "totalEfficiency": {
          "type": "number",
          "default": 0
        },
        "totalStockArea": {
          "type": "number",
          "default": 0
        },
        "totalStockUsedArea": {
          "type": "number",
          "default": 0
        },
        "totalStockUnusedArea": {
          "type": "number",
          "default": 0
        },
        "totalPartsArea": {
          "type": "number",
          "default": 0
        },
        "totalPartArea": {
          "type": "number",
          "description": "Total area of the placed parts, including every sheet of a stack. Same value as totalPartsArea"
        },
        "totalUnusedPartsArea": {
          "type": "number",
          "default": 0
        },
        "totalOffcutsArea": {
          "type": "number",
          "default": 0
        },
        "totalOffcuts": {
          "type": "number",
          "default": 0
        },
        "totalStockCost": {
          "type": "number",
          "default": 0
        },
        "stockAreaCost": {
          "type": "number",
          "default": 0
        },
        "bandingLengthByType": {
          "type": "object",
          "additionalProperties": {
            "type": "number"
          },
          "default": {},
          "description": "Banding per material type"
        },
        "totalBandingLength": {
          "type": "number",
          "default": 0
        },
        "finishAreaByType": {
          "type": "object",
          "additionalProperties": {
            "type": "number"
          },
          "default": {},
          "description": "Finish area per type"
        },
        "totalFinishArea": {
          "type": "number",
          "default": 0
        },
        "planingAreaByType": {
          "type": "object",
          "additionalProperties": {
            "type": "number"
          },
          "default": {},
          "description": "Planing area per type"
        },
        "totalPlaningArea": {
          "type": "number",
          "default": 0
        },
        "totalStockWeight": {
          "type": "number",
          "description": "Total weight of the stock used, from each stock's weight. 0 when no stock declares a weight"
        },
        "totalPartWeight": {
          "type": "number",
          "description": "Total weight of the placed parts, estimated from each stock's weight by volume. 0 when no stock declares a weight and thickness"
        },
        "totalCutLength": {
          "type": "number",
          "default": 0
        },
        "totalStackedCutLength": {
          "type": "number",
          "default": 0
        },
        "totalCuts": {
          "type": "number",
          "default": 0
        },
        "totalStackedCuts": {
          "type": "number",
          "default": 0
        },
        "maxPhase": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "description": "Deepest saw turn any board in the job needs — the max of stock[].analysis.maxPhase (root cuts at 0, +1 per direction flip; the quantity guillotineOptions.maxPhase caps). null when no board carries turn-stamped cuts"
        },
        "phaseStep": {
          "type": "object",
          "description": "Present when the optimiser tried a deeper turn cap than the job's (saw.guillotineOptions.adaptiveMaxPhase). Absent when none was tried.",
          "properties": {
            "from": {
              "type": "integer",
              "description": "The cap the job ran at (yours, or the saw profile's default)"
            },
            "to": {
              "type": "integer",
              "description": "The cap used when kept is true; otherwise the deepest cap tried"
            },
            "kept": {
              "type": "boolean",
              "description": "Whether a deeper cap's layout was returned"
            },
            "sheetsSaved": {
              "type": "number",
              "description": "Sheets the returned deeper layout saves (0 when none was kept)"
            },
            "secondsAdded": {
              "type": "number",
              "description": "Predicted cutting seconds the returned deeper layout adds (negative = saves). Absent without a cutting-time model"
            },
            "reason": {
              "type": "string",
              "description": "Why the returned cap won, or why none did: fewer-sheets, same-sheets-faster, same-sheets-better-offcut; more-sheets, more-stock-area, slower, same-time-no-better-offcut, no-time-estimate, hard-gate, no-result. New values may be added"
            },
            "tried": {
              "type": "array",
              "description": "Every deeper cap built, shallowest first",
              "items": {
                "type": "object",
                "properties": {
                  "cap": {
                    "type": "integer"
                  },
                  "sheets": {
                    "type": [
                      "number",
                      "null"
                    ],
                    "description": "Sheets that cap's layout needs (null = no layout)"
                  },
                  "seconds": {
                    "type": "number",
                    "description": "Its predicted cutting seconds; absent without a cutting-time model"
                  },
                  "kept": {
                    "type": "boolean",
                    "description": "Whether it beat the best layout so far"
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              }
            },
            "boards": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Stock ids of the boards cut deeper than `from`"
            },
            "note": {
              "type": "string",
              "description": "The trade in one line"
            }
          }
        },
        "productionTime": {
          "type": "object",
          "description": "The predicted PRODUCTION TIME of the job on the saw, in seconds, priced from the plates its control cuts for the file the saw gets. Present only for a saw with a cutting-time model (today: Mayer `.may`, the PC7000 control); absent otherwise.",
          "properties": {
            "model": {
              "type": "string",
              "description": "The machine time model it was priced with"
            },
            "total": {
              "type": "number",
              "description": "Seconds for the whole job: every board's stack cut once, operator feed included"
            },
            "machine": {
              "type": "number",
              "description": "The machine's share of total"
            },
            "operator": {
              "type": "number",
              "description": "The operator's share of total (bringing each sheet and strip to the saw)"
            },
            "sheets": {
              "type": "array",
              "description": "Per board (per pattern)",
              "items": {
                "type": "object",
                "properties": {
                  "stockId": {
                    "type": "string",
                    "description": "The board — `stock[].id`"
                  },
                  "seconds": {
                    "type": "number",
                    "description": "One pass of the board's stack"
                  },
                  "stackDepth": {
                    "type": "integer",
                    "description": "Sheets cut together as one stack"
                  },
                  "stripStacks": {
                    "type": "integer",
                    "description": "Strips (or columns of a strip) the control cuts together with an identical one — a pass cutting k counts k − 1"
                  },
                  "plates": {
                    "type": "integer",
                    "description": "Plates the control cuts: the sheet, then each strip or column brought back to the saw"
                  },
                  "stacking": {
                    "type": "object",
                    "description": "What the saw cuts together on this board. Absent where it could not be traced.",
                    "properties": {
                      "sheetStack": {
                        "type": "object",
                        "properties": {
                          "depth": {
                            "type": "integer",
                            "description": "Sheets cut together (1 = cut alone)"
                          },
                          "secondsSaved": {
                            "type": "number",
                            "description": "Seconds the stack saves against cutting its sheets one at a time"
                          }
                        }
                      },
                      "strips": {
                        "type": "array",
                        "description": "The board's strips in written order, each as the band it is ripped as (board frame, like `parts`)",
                        "items": {
                          "type": "object",
                          "properties": {
                            "autoId": {
                              "type": "string",
                              "description": "The strip's key"
                            },
                            "x": {
                              "type": "number"
                            },
                            "y": {
                              "type": "number"
                            },
                            "l": {
                              "type": "number"
                            },
                            "w": {
                              "type": "number"
                            }
                          }
                        }
                      },
                      "passes": {
                        "type": "array",
                        "description": "Every saw pass after the sheet, in cutting order — each strip or column brought back to the saw",
                        "items": {
                          "type": "object",
                          "properties": {
                            "level": {
                              "type": "integer",
                              "description": "1 = a strip; 2 = a column of a strip"
                            },
                            "strips": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "Per unit cut in the pass, the key of its strip"
                            },
                            "rects": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "x": {
                                    "type": "number"
                                  },
                                  "y": {
                                    "type": "number"
                                  },
                                  "l": {
                                    "type": "number"
                                  },
                                  "w": {
                                    "type": "number"
                                  }
                                }
                              },
                              "description": "Per unit cut in the pass, its rectangle"
                            }
                          }
                        }
                      },
                      "stripStacks": {
                        "type": "array",
                        "description": "The passes that cut several identical strips (or columns) together",
                        "items": {
                          "type": "object",
                          "properties": {
                            "pass": {
                              "type": "integer",
                              "description": "Index into passes"
                            },
                            "strips": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "The keys of the strips cut together"
                            },
                            "depth": {
                              "type": "integer",
                              "description": "How many are cut together"
                            },
                            "secondsSaved": {
                              "type": "number",
                              "description": "Seconds saved against cutting them one at a time"
                            }
                          }
                        }
                      },
                      "sawPasses": {
                        "type": "object",
                        "properties": {
                          "before": {
                            "type": "integer",
                            "description": "Saw passes after the sheet if every strip and column were cut alone"
                          },
                          "after": {
                            "type": "integer",
                            "description": "Saw passes after the sheet as the control cuts it"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "totalBladeArea": {
          "type": "number",
          "default": 0
        },
        "totalTrimArea": {
          "type": "number",
          "default": 0
        },
        "hasMachining": {
          "type": "boolean",
          "default": false
        },
        "numHoles": {
          "type": "number",
          "default": 0
        },
        "numCorners": {
          "type": "number",
          "default": 0
        },
        "totalPartsProduced": {
          "type": "number"
        },
        "totalUsedStock": {
          "type": "number"
        },
        "totalRollLength": {
          "type": "number"
        },
        "materialSummary": {
          "type": "object",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "used": {
                  "type": "number"
                },
                "stacks": {
                  "type": "number"
                },
                "bandingLengthByType": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "description": "Nested summary by material → thickness"
        },
        "usedStockTally": {
          "type": "object",
          "additionalProperties": {
            "type": "number"
          }
        },
        "addedPartTally": {
          "type": "object",
          "additionalProperties": {
            "type": "number"
          }
        },
        "unplacedParts": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/UnplacedPart"
          },
          "description": "Every part NOT placed in the returned layout — the authoritative completeness list. Includes BOTH parts attempted but not fitted (e.g. stock ran out with auto-add off) AND the up-front-rejected top-level unusableParts. An empty array means every requested part was placed. Use this (or compare placed vs. requested counts) to decide success — not the top-level unusableParts, which is only the \"can never fit\" subset. Quantities are collapsed per part with a count."
        },
        "warnings": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Human-readable warnings about this result, for example a sheet that cannot be fully cut on the selected saw. Empty on a sound job."
        }
      }
    },
    "Offcut": {
      "type": "object",
      "description": "Remaining offcut piece from optimization",
      "properties": {
        "id": {
          "type": "string",
          "description": "Stable identifier, unique within the job. A retained offcut is numbered `9001`, `9002`, … in board order then position; this is the number a Mayer `.may` export prints on the matching `Rest` record (its MA010 row and MA319/MA419), so a result offcut and a file Rest match by id. Any other (waste) offcut is `W1`, `W2`, …."
        },
        "l": {
          "type": "number",
          "description": "Length dimension"
        },
        "w": {
          "type": "number",
          "description": "Width dimension"
        },
        "t": {
          "type": "number",
          "description": "Thickness"
        },
        "x": {
          "type": "number",
          "description": "X coordinate position on stock"
        },
        "y": {
          "type": "number",
          "description": "Y coordinate position on stock"
        },
        "q": {
          "type": "number",
          "description": "Quantity"
        },
        "material": {
          "type": "string",
          "description": "Material name (inherited from parent stock)"
        },
        "grain": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "l",
            "w",
            ""
          ],
          "description": "Grain direction (inherited from parent stock)"
        },
        "retained": {
          "type": "boolean",
          "default": true,
          "description": "Whether the target saw would take this piece back as stock. `false` means it is below the saw's declared minimum reusable offcut, so it cannot be racked: treat it as waste. It is still listed because it is real empty space on the board. Always `true` for a saw that declares no minimum."
        },
        "stock": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "ID of the stock this offcut came from"
            }
          }
        }
      }
    },
    "ResultPart": {
      "type": "object",
      "description": "Result part with coordinates",
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier for referencing items",
          "default": ""
        },
        "name": {
          "type": "string",
          "description": "User input name",
          "default": ""
        },
        "l": {
          "type": "number",
          "description": "Dimension in the stock length direction"
        },
        "w": {
          "type": "number",
          "description": "Dimension in the stock width direction"
        },
        "t": {
          "description": "Thickness (z-axis dimension)"
        },
        "material": {
          "description": "Material name"
        },
        "q": {
          "type": "number",
          "description": "Quantity"
        },
        "trim": {
          "$ref": "#/$defs/Trim"
        },
        "notes": {
          "type": "string",
          "description": "Part notes"
        },
        "code": {
          "type": "string",
          "description": "Internal product or material code"
        },
        "customData": {
          "type": "object",
          "additionalProperties": true,
          "description": "Custom user-defined data"
        },
        "extras": {
          "$ref": "#/$defs/Extras"
        },
        "machining": {
          "$ref": "#/$defs/Machining"
        },
        "x": {
          "type": [
            "number",
            "null"
          ],
          "description": "X coordinate position",
          "default": null
        },
        "y": {
          "type": [
            "number",
            "null"
          ],
          "description": "Y coordinate position",
          "default": null
        },
        "rot": {
          "type": "integer",
          "enum": [
            0,
            1
          ],
          "description": "Rotation of the placed part: 0 = as entered, 1 = rotated 90°. (Matches the wire format — the engine emits 0/1, not true/false.)"
        },
        "added": {
          "type": "boolean",
          "description": "Whether this part was auto-added during optimization"
        },
        "stock": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "ID of the stock this part is placed on. For a part cut on a stack, the id of the stack's top sheet — the entry listed in `stock`."
            },
            "code": {
              "type": "string",
              "description": "Product/material code of the stock (if set)"
            }
          }
        },
        "stacked": {
          "type": "object",
          "description": "Present only when the part is cut on a stack of sheets. Which sheet of the stack it was cut from; `stock.id` names the stack.",
          "properties": {
            "sheet": {
              "type": "integer",
              "minimum": 1,
              "description": "Sheet the part was cut from — 1 is the top sheet of the stack"
            },
            "of": {
              "type": "integer",
              "minimum": 1,
              "description": "Number of sheets in the stack"
            },
            "stack": {
              "type": "integer",
              "minimum": 1,
              "description": "The stack's number — its `stacks[].stack`"
            }
          },
          "required": [
            "sheet",
            "of"
          ]
        },
        "stripGroup": {
          "type": "integer",
          "minimum": 1,
          "description": "Present only when the strip this part is cut from repeats: its `stripRepeats[].group`."
        }
      }
    },
    "ResultStack": {
      "type": "object",
      "description": "One stack: a cutting pattern (one `stock` entry) cut through `depth` sheets at once. A single sheet is a stack of depth 1.",
      "properties": {
        "stack": {
          "type": "integer",
          "minimum": 1,
          "description": "Stack number, 1…n in `stock` order"
        },
        "stockId": {
          "type": "string",
          "description": "The `stock[].id` of the pattern this stack is cut to"
        },
        "depth": {
          "type": "integer",
          "minimum": 1,
          "description": "Sheets in the stack, cut together"
        },
        "sheets": {
          "type": "array",
          "description": "Every sheet of the stack, top first",
          "items": {
            "type": "object",
            "properties": {
              "sheet": {
                "type": "integer",
                "minimum": 1,
                "description": "Position in the stack: 1 is the top sheet"
              },
              "number": {
                "type": "integer",
                "minimum": 1,
                "description": "The sheet's number across the whole job, 1…n"
              }
            },
            "required": [
              "sheet",
              "number"
            ]
          }
        }
      },
      "required": [
        "stack",
        "stockId",
        "depth",
        "sheets"
      ]
    },
    "ResultStock": {
      "type": "object",
      "description": "Result stock",
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier for containers (required for Stock and Segment)",
          "default": ""
        },
        "name": {
          "type": "string",
          "description": "User input name",
          "default": ""
        },
        "l": {
          "type": "number",
          "description": "Dimension in the stock length direction"
        },
        "w": {
          "type": "number",
          "description": "Dimension in the stock width direction"
        },
        "t": {
          "description": "Thickness (z-axis dimension)"
        },
        "material": {
          "description": "Material name"
        },
        "grain": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "l",
            "w",
            ""
          ],
          "description": "Grain direction"
        },
        "trim": {
          "$ref": "#/$defs/Trim"
        },
        "cost": {
          "type": "number",
          "description": "Cost per unit"
        },
        "notes": {
          "type": "string",
          "description": "Stock notes"
        },
        "code": {
          "type": "string",
          "description": "Internal product or material code"
        },
        "customData": {
          "type": "object",
          "additionalProperties": true,
          "description": "Custom user-defined data"
        },
        "type": {
          "type": "string",
          "enum": [
            "sheet",
            "linear",
            "roll"
          ],
          "description": "Stock type"
        },
        "used": {
          "type": "boolean",
          "description": "Whether this stock was used in the optimization"
        },
        "analysis": {
          "$ref": "#/$defs/StockAnalysis",
          "description": "Detailed analysis metrics for this stock item. null when the stock carries no analysis (an unused stock item)."
        },
        "stack": {
          "type": "number",
          "description": "Stack depth: the number of sheets cut to this pattern together (1 = not stacked). Sheets 2…n are not listed separately — see the response `stacks`."
        },
        "sawId": {
          "type": "string",
          "description": "Id of the saw this stock was optimised on. Present ONLY on mixed jobs — see the response `saws` echo."
        },
        "materialId": {
          "type": "string",
          "description": "Id of the material this stock belongs to. Present ONLY on mixed jobs — see the response `materials` echo."
        }
      }
    },
    "ResultStripRepeat": {
      "type": "object",
      "description": "One group of identical strips (RM-311). A strip is the band between two of a sheet's opening rips (`cuts[]` with `phase` 0). Two strips are identical when they have the same width and, position by position along the strip, the same part (or a part declared identical to it) at the same place with the same size, every dimension within half the saw's `bladeWidth`. Members may be on different sheets or on the same sheet.\n\n**Stacked sheets.** A strip on a stack of n sheets is already cut n high: it is ONE member with `sheets: n`, and `sheets` on the group counts the physical strips. A group needs two or more member strips, so a lone strip on a stack is not listed. Sheets whose opening cuts run both ways (a head cut) are not analysed.",
      "properties": {
        "group": {
          "type": "integer",
          "minimum": 1,
          "description": "Group number, 1…n in the order the first strip of each group is cut; the `stripGroup` its parts carry"
        },
        "width": {
          "type": "number",
          "description": "The strip's width: the extent of its parts across the opening rips"
        },
        "length": {
          "type": "number",
          "description": "The extent of the strip's parts along the rips"
        },
        "strips": {
          "type": "integer",
          "minimum": 2,
          "description": "Member strips in the layout (each listed in `members`)"
        },
        "sheets": {
          "type": "integer",
          "minimum": 2,
          "description": "Physical strips cut: the members' `sheets` summed (a strip on a stack of n sheets is n strips)"
        },
        "members": {
          "type": "array",
          "description": "Every strip of the group, in stock order then strip number",
          "items": {
            "type": "object",
            "properties": {
              "stockId": {
                "type": "string",
                "description": "The `stock[].id` of the sheet (or stack) the strip is on"
              },
              "stack": {
                "type": "integer",
                "minimum": 1,
                "description": "The `stacks[].stack` number, when the response lists stacks"
              },
              "strip": {
                "type": "integer",
                "minimum": 1,
                "description": "The strip's number on its sheet in cutting order, 1…n: strips are numbered in the order the rip that frees each one is cut (the cuts' `order`), counting strips that hold parts. With `guillotineOptions.verticalPanelSaw` (cut from the top down) strip 1 is the top strip"
              },
              "at": {
                "type": "number",
                "description": "The strip's offset from the origin edge across the rips (y = 0 for rips along x, x = 0 for rips along y)"
              },
              "sheets": {
                "type": "integer",
                "minimum": 1,
                "description": "Sheets this strip is cut through: its stack depth (1 = a single sheet)"
              }
            },
            "required": [
              "stockId",
              "strip",
              "at",
              "sheets"
            ]
          }
        }
      },
      "required": [
        "group",
        "width",
        "length",
        "strips",
        "sheets",
        "members"
      ]
    },
    "Saw": {
      "type": "object",
      "description": "Saw configuration. Settings that do not apply to each other are RESOLVED rather than rejected — the saw-rules registry clamps, defaults or zeroes them and the response `warnings` name the rule that fired. Browse every rule, and try your own saw against them, at https://smartcut.dev/api-docs/saw-settings",
      "properties": {
        "vendor": {
          "type": "string",
          "description": "Saw vendor (e.g. Biesse, Mayer, SCM). Part of the identity pair (`vendor` + `model`) used to look up this saw's profile, which supplies its algorithm constraints and preferences. Optional — without an identity (or a `sawProfileId`) no profile is applied."
        },
        "model": {
          "type": "string",
          "description": "Saw model name (e.g. PC7000, OptiPlanner, Pratika). Paired with `vendor` to resolve the saw profile — `GET /v3/saws` lists the recognised pairs."
        },
        "softwareVersion": {
          "type": "string",
          "description": "Saw control software version (e.g. \"CADmatic 5\") — selects the CADmatic output dialect where recognised (5 → CAD5/PTNR, 3|4 → CAD4/PTN3), otherwise provenance only."
        },
        "cutType": {
          "type": "string",
          "enum": [
            "efficiency",
            "guillotine",
            "beam",
            "nesting"
          ],
          "description": "Type of cutting algorithm. `guillotine` and `beam` produce edge-to-edge saw cuts; `efficiency` packs without the guillotine constraint; `nesting` is IRREGULAR nesting for CNC routers and similar — give each part an `outline` (and optional `holes`) and it is packed as its true shape rather than its bounding rectangle."
        },
        "cutPreference": {
          "type": "string",
          "enum": [
            "l",
            "w",
            "flex"
          ],
          "description": "Preferred cutting direction. Only applicable when cutType is 'guillotine' or 'beam'. Set to 'flex' to try both 'l' and 'w' on a per-sheet basis and keep the better orientation per sheet — charged at 2× the standard credit rate."
        },
        "bladeWidth": {
          "type": "number",
          "minimum": 0,
          "description": "Width of the saw blade"
        },
        "stockType": {
          "type": "string",
          "enum": [
            "sheet",
            "linear",
            "roll"
          ],
          "description": "Type of stock material"
        },
        "minOffcut": {
          "type": [
            "object",
            "null"
          ],
          "description": "Per-job override of this saw's minimum reusable offcut size, in the same units as every other dimension you send. A saw profile (`sawProfileId`) may already declare its own floor — sending this REPLACES it entirely for the job; the profile's value is only a default. Every leftover still ships in `offcuts`; a floor only decides each one's `retained` flag (whether this saw's operator would re-rack it), never geometry or board count. Compared orientation-free: `{ l: 150, w: 100 }` reads \"no side under 100, longer side at least 150\" — 160×95 and 95×160 give the same verdict. `area` is an independent third check. Absent → the resolved saw profile's own floor, or none.",
          "properties": {
            "l": {
              "type": "number",
              "minimum": 0,
              "description": "Minimum long side of a reusable offcut"
            },
            "w": {
              "type": "number",
              "minimum": 0,
              "description": "Minimum short side of a reusable offcut"
            },
            "area": {
              "type": "number",
              "minimum": 0,
              "description": "Minimum area of a reusable offcut, independent of side length"
            }
          }
        },
        "guillotineOptions": {
          "type": "object",
          "description": "Guillotine-specific options. Only applicable when cutType is 'guillotine' or 'beam'",
          "properties": {
            "strategy": {
              "type": "string",
              "enum": [
                "efficiency",
                "time"
              ],
              "default": "efficiency",
              "description": "Cutting strategy"
            },
            "maxPhase": {
              "type": "number",
              "minimum": 0,
              "maximum": 10,
              "default": 0,
              "description": "Maximum cutting phase — the number of turns a board may take: 0 = unlimited, 1 = two-stage cutting (rips, one turn, crosscuts — every strip takes only parts whose cross dimension matches the strip), 2 = three-stage, … Enforced exactly as sent for every cut type, except where a saw profile (sawProfileId) states the saw's own limit: then 0 takes the profile's default, and on a saw whose control counts its own turns a higher value is lowered to the saw's ceiling. Mayer (mayer-may, PC7000 control): default 3, maximum 4 — 4 is opt-in, because the PC7000 has no automatic turn table and each extra turn is one more piece the operator turns and feeds by hand; it saves stock on some jobs (7 of 713 in our Mayer test set, one sheet each). A Max `model` runs only when the resulting cap is 0 (the Mayer and Biesse profiles default to 3, so 0 there still means 3) — any cap runs the Fast model; on a beam saw it also needs a recognised saw profile."
            },
            "adaptiveMaxPhase": {
              "type": "boolean",
              "description": "Let the optimiser raise maxPhase one turn at a time, up to the saw control's own turn ceiling (Mayer PC7000: 4), when a deeper cap gives FEWER sheets, or the SAME sheets in less predicted cutting time (equal time: the larger offcut wins). It never returns more sheets than the maxPhase you set, and on a saw with no cutting-time model it raises the cap only to save a sheet. Applies only to a saw profile whose control counts its own turns and has a ceiling deeper than the job's cap (today: mayer-may); elsewhere it does nothing. The caps tried, and which one was used and why, are reported in metadata.phaseStep. Omit it to use your account default (off)."
            },
            "timeObjective": {
              "type": "boolean",
              "description": "Plan for less cutting time as well as material. The job is also planned material-first, and the faster plan is used only when it needs no more sheets and, at equal sheets, is predicted to cut faster. This roughly doubles the compute for the job, and compute is billed. Applies only to a saw profile with a cutting-time model (today: mayer-may); elsewhere it does nothing. The outcome is reported in optimisation.productionTime.guard. Omit it to use your account default (off)."
            },
            "duplicateStrips": {
              "type": "boolean",
              "description": "Convenience option: where the job holds another full copy of a strip's parts, place the identical strip next to it on the same sheet, so a saw that stacks identical strips (for example a Mayer PC7000 control) can cut the two together. It groups identical strips for stacking and may use more material than the default plan. Applies to guillotine and beam saws. Omit it to use your account default (off)."
            },
            "headCuts": {
              "type": "boolean",
              "default": false,
              "description": "Enable head cuts"
            },
            "limitStripDimensions": {
              "type": "boolean",
              "default": false,
              "description": "Prefer narrower strips, derived from the job's own parts (mean part depth, floored at a fifth of the board). Carries no dimension of its own — use maxStripWidth to state an operator limit. With both set the TIGHTER of the two wins: on a job of small parts the derived cap is usually well below any operator limit, and maxStripWidth then has no effect at all. To make your own number the cap, send it with this flag off."
            },
            "verticalPanelSaw": {
              "type": "boolean",
              "default": false,
              "description": "Arrange the layout for a vertical panel saw: narrowest strips at the top, residual waste at the bottom, cut from the top down. Works on any saw; no profile required."
            },
            "maxStripWidth": {
              "type": [
                "number",
                "null"
              ],
              "minimum": 0,
              "default": null,
              "description": "Widest assembled strip an operator can safely handle, in the same units as every other dimension you send. The optimiser steers away from strips wider than this — it opens strips on parts within the limit wherever it can. Set this alone (limitStripDimensions off) and your number IS the cap. With limitStripDimensions also on, the tighter of the two wins — the parts-derived cap is often tighter, and then this value has no effect. It is a STRONG PREFERENCE, not a guarantee — a part whose own smaller side exceeds the limit cannot be made to fit one, and layouts are never left unplaced to satisfy it. Hard rejection of an over-wide strip requires a saw profile (sawProfileId), whose oracle reports strip-width-exceeded. Null = no limit."
            }
          }
        },
        "efficiencyOptions": {
          "type": "object",
          "description": "Efficiency-specific options. Only applicable when cutType is 'efficiency'",
          "properties": {
            "primaryCompression": {
              "type": "string",
              "enum": [
                "l",
                "w"
              ],
              "default": "w",
              "description": "Primary compression direction (l=length/horizontal, w=width/vertical)"
            }
          }
        },
        "stackHeight": {
          "type": "number",
          "default": 100,
          "description": "The saw's maximum cutting height, in the same units as every other dimension you send. Sets how many sheets one pattern may be cut through at once: `⌊stackHeight ÷ sheet thickness⌋`. Applies to any saw, not only beam saws. Only read when `options.stackingMode` is not `none`."
        },
        "options": {
          "type": "object",
          "description": "General optimisation options: which stock is chosen, whether sheets with the same pattern are cut as a stack, and spacing between parts.",
          "properties": {
            "stockSelection": {
              "type": "string",
              "enum": [
                "efficiency",
                "smallest"
              ],
              "default": "efficiency",
              "description": "How the optimiser chooses between the stock sizes you send.\n\n- `efficiency`: pick the stock that gives the best material utilisation.\n- `smallest`: use the smallest stock (by area) that the parts fit on first."
            },
            "offcutPriority": {
              "type": "number",
              "minimum": 0,
              "maximum": 1,
              "default": 0.5,
              "description": "Offcut priority — how stock rows marked `offcut: true` are used against full sheets. 0 = never use offcut stock (offcut rows are left out of the job), 0.5 = offcuts compete with full sheets on score (default), 1 = always use offcuts first (an offcut is taken whenever anything fits it). Between 0.5 and 1 an offcut is taken when its fill is at least (1 − k) of the best full sheet's fill, k = (p − 0.5) × 2; values between 0 and 0.5 currently behave as 0.5. Has no effect unless some stock rows are marked `offcut: true`, and is ignored for a material whose stock rows are ALL offcuts (there is no full sheet to choose instead)."
            },
            "stackingMode": {
              "type": "string",
              "enum": [
                "dimensions",
                "identical",
                "none"
              ],
              "default": "dimensions",
              "description": "Whether sheets that share a cutting pattern are cut together as a **stack**: several sheets laid on top of each other and cut once. In the result, a stack is one `stock` entry whose `stack` is the number of sheets, and each part cut from it carries `stacked: { sheet, of }`.\n\n- `identical`: stack only when every position holds the same part (same size and material) on every sheet.\n- `dimensions`: stack when every position holds a part of the same size. The parts may be different parts, so each sheet of the stack can yield different parts.\n- `none`: never stack. Every sheet is cut individually.\n\nStack depth is capped at `⌊saw.stackHeight ÷ thickness⌋`, and at `options.maxStackSheets` when set. Thickness is the stock's `t`, or else the thickest part on the sheet. When neither is known, the height does not limit the stack. Stacking is also off when `guillotineOptions.strategy` is `time`.\n\n**Grain across a stack.** Every sheet of a stack is cut to one pattern, so each position has one place and one orientation on every sheet. A part fills a position on another sheet only if it may take that orientation: a part locked to the grain (`orientationLock`) joins a stack only where the pattern's orientation keeps its grain on that stock, so grain is never broken to make a stack. Under `identical` the part on every sheet must also carry the same `orientationLock`.\n\nThe result lists every stack in `stacks`: its depth, and each sheet with its number in the job."
            },
            "maxStackSheets": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 1,
              "description": "The most sheets one stack may hold, whatever their thickness. Applied on top of the height cap `⌊stackHeight ÷ thickness⌋` — the smaller of the two wins. Absent or null = no count limit (the height cap alone)."
            },
            "minSpacing": {
              "type": "number",
              "minimum": 0,
              "default": 0,
              "description": "Minimum gap between parts (not between a part and the stock edge), in the same units as every other dimension you send. The blade width is the floor: the gap used is the larger of `bladeWidth` and this value, not their sum. Only applies when `cutType` is `efficiency`. Other cut types space parts by the blade width, so the value is set to 0 and a warning is returned."
            },
            "minSpacingDimension": {
              "type": "object",
              "description": "A different minimum spacing for small parts. Parts whose length or width is at or below `dimension` use this `minSpacing` instead of the general one, still floored at the blade width. Only applies when `cutType` is `efficiency`.",
              "properties": {
                "dimension": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Parts with length or width equal to or smaller than this value will use the spacing below"
                },
                "minSpacing": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Minimum spacing for parts meeting the dimension threshold"
                }
              }
            }
          }
        }
      },
      "required": [
        "bladeWidth",
        "stockType"
      ]
    },
    "SideValues": {
      "type": "object",
      "description": "Side values",
      "properties": {
        "l1": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string"
            }
          ],
          "description": "Long side 1"
        },
        "l2": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string"
            }
          ],
          "description": "Long side 2"
        },
        "w1": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string"
            }
          ],
          "description": "Short side 1"
        },
        "w2": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string"
            }
          ],
          "description": "Short side 2"
        }
      }
    },
    "StockAnalysis": {
      "type": "object",
      "description": "Analysis metrics for stock item",
      "properties": {
        "partArea": {
          "type": "number",
          "description": "Total area of parts on this stock"
        },
        "areaEfficiency": {
          "type": "number",
          "description": "Percentage efficiency of this stock"
        },
        "finishArea": {
          "type": "number",
          "description": "Total finish area for parts on this stock"
        },
        "totalParts": {
          "type": "integer",
          "description": "Number of parts on this stock"
        },
        "numberOfCuts": {
          "type": "integer",
          "description": "Total number of cuts on this stock"
        },
        "stackedNumberOfCuts": {
          "type": "integer",
          "description": "Total cuts assuming stacked stock are cut once"
        },
        "cutLength": {
          "type": "number",
          "description": "Total length of cuts on this stock"
        },
        "stackedCutLength": {
          "type": "number",
          "description": "Total cut length assuming stacked stock are cut once"
        },
        "bandingLength": {
          "type": "number",
          "description": "Total banding length for parts on this stock"
        },
        "rollLength": {
          "type": "number",
          "description": "Roll length used (for roll stock)"
        },
        "maxPhase": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "description": "Deepest saw turn any cut on this board needs (root cuts at 0, +1 per direction flip) — the quantity guillotineOptions.maxPhase caps. null when the board carries no turn-stamped cuts"
        }
      }
    },
    "Trim": {
      "type": "object",
      "description": "Trim allowances",
      "properties": {
        "l1": {
          "type": "number",
          "minimum": 0,
          "default": 0,
          "description": "Long side 1 trim value"
        },
        "l2": {
          "type": "number",
          "minimum": 0,
          "default": 0,
          "description": "Long side 2 trim value"
        },
        "w1": {
          "type": "number",
          "minimum": 0,
          "default": 0,
          "description": "Short side 1 trim value"
        },
        "w2": {
          "type": "number",
          "minimum": 0,
          "default": 0,
          "description": "Short side 2 trim value"
        }
      }
    },
    "UnplacedPart": {
      "type": "object",
      "description": "A requested part that did not appear in the returned layout, with its quantity. Covers both capacity misses (would fit, but no stock was left) and structurally unusable parts (also listed in the top-level unusableParts).",
      "properties": {
        "id": {
          "type": "string",
          "description": "Part id"
        },
        "name": {
          "type": "string",
          "description": "Part name"
        },
        "count": {
          "type": "number",
          "description": "How many of this part were left unplaced"
        },
        "l": {
          "type": "number",
          "description": "Dimension in the stock length direction"
        },
        "w": {
          "type": "number",
          "description": "Dimension in the stock width direction"
        },
        "t": {
          "description": "Thickness (z-axis dimension)"
        },
        "material": {
          "description": "Material name"
        }
      }
    },
    "UnusablePart": {
      "type": "object",
      "description": "A part that cannot be placed on ANY available stock (too large for every stock size, or no stock with a matching material/thickness) — rejected up front before optimisation. Excludes placement fields; includes the validation issues explaining the rejection. Distinct from a part that was attempted but did not fit — see metadata.unplacedParts.",
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier for referencing items",
          "default": ""
        },
        "name": {
          "type": "string",
          "description": "User input name",
          "default": ""
        },
        "l": {
          "type": "number",
          "description": "Dimension in the stock length direction"
        },
        "w": {
          "type": "number",
          "description": "Dimension in the stock width direction"
        },
        "t": {
          "description": "Thickness (z-axis dimension)"
        },
        "material": {
          "description": "Material name"
        },
        "trim": {
          "$ref": "#/$defs/Trim"
        },
        "notes": {
          "type": "string",
          "description": "Part notes"
        },
        "code": {
          "type": "string",
          "description": "Internal product or material code"
        },
        "customData": {
          "type": "object",
          "additionalProperties": true,
          "description": "Custom user-defined data"
        },
        "extras": {
          "$ref": "#/$defs/Extras"
        },
        "machining": {
          "$ref": "#/$defs/Machining"
        },
        "issues": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Issue"
          },
          "description": "Validation issues explaining why the part could not be placed"
        }
      }
    }
  }
}