{
  "openapi": "3.1.1",
  "info": {
    "title": "Project Backup Verifier API",
    "version": "1.0.0",
    "summary": "Check a Bundlekeep backup file by file and get a restore checklist.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://bundlekeepbackupverifier.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Check a Bundlekeep backup file by file and get a restore checklist.",
        "description": "Open a Bundlekeep backup: the tool recomputes the SHA-256 checksum of every project file, lists what each file is and what it leaves out, writes a restore checklist per app and can extract one project file for download.\n\nMethodology:\n- Validates the Bundlekeep format (version 1), unique file names, JSON content and the limits of 200 files, 10 MB per file and 50 MB in total.\n- Recomputes SHA-256 for each file and compares it with the checksum recorded when the file was added: verified (identical), changed (different) or no checksum (older backups).\n- Recognises the app and format of each file and lists the same warnings as the Project File Identifier (documents or media outside the file, kept secrets, unknown format).\n- The restore checklist groups files by app with workspace links. Restoring means downloading a file and opening it in its app; nothing is written into an app.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "bundlekeep_backup_verifier",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BundlekeepBackupVerifierInput"
              },
              "examples": {
                "example1": {
                  "summary": "Verify the workshop example backup",
                  "value": {}
                },
                "example2": {
                  "summary": "Extract the circuit from a backup",
                  "value": {
                    "extract": "led-with-series-resistor.ohmforge.json"
                  }
                },
                "example3": {
                  "summary": "Spot a changed file",
                  "value": {
                    "backup": "{\"format\":\"bundlekeep\",\"version\":1,\"name\":\"Workshop backup\",\"items\":[{\"name\":\"base-cabinet-600.kerfwise.json\",\"content\":\"{\\n  \\\"format\\\": \\\"kerfwise\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\" : \\\"Base cabinet 600\\\",\\n  \\\"cabinets\\\": [\\n    {\\n      \\\"id\\\": \\\"c1\\\",\\n      \\\"name\\\": \\\"Base 600\\\",\\n      \\\"type\\\": \\\"base\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 0,\\n      \\\"rot\\\": 0,\\n      \\\"params\\\": {\\n        \\\"width\\\": 600,\\n        \\\"height\\\": 870,\\n        \\\"depth\\\": 560,\\n        \\\"doorCount\\\": 1,\\n        \\\"shelfCount\\\": 1,\\n        \\\"topType\\\": \\\"rails\\\",\\n        \\\"countertop\\\": false\\n      }\\n    }\\n  ]\\n}\",\"app\":\"kerfwise\",\"format\":\"kerfwise\",\"sha256\":\"e6f17c489b32c4e577c7c857a650bbbbbf8a1d2f1c9daaf8718ce7f6e0e3e6dc\",\"source\":\"template\"},{\"name\":\"led-with-series-resistor.ohmforge.json\",\"content\":\"{\\n  \\\"format\\\": \\\"ohmforge\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"LED with series resistor\\\",\\n  \\\"parts\\\": [\\n    {\\n      \\\"id\\\": \\\"BT1\\\",\\n      \\\"kind\\\": \\\"battery\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 0,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"voltage\\\": \\\"9\\\",\\n        \\\"rint\\\": \\\"1\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"SW1\\\",\\n      \\\"kind\\\": \\\"switch\\\",\\n      \\\"x\\\": 4,\\n      \\\"y\\\": -6,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"closed\\\": true,\\n        \\\"ron\\\": \\\"10m\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"R1\\\",\\n      \\\"kind\\\": \\\"resistor\\\",\\n      \\\"x\\\": 10,\\n      \\\"y\\\": -6,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"value\\\": \\\"390\\\",\\n        \\\"power\\\": \\\"0.25\\\",\\n        \\\"tolerance\\\": \\\"5%\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"D1\\\",\\n      \\\"kind\\\": \\\"led\\\",\\n      \\\"x\\\": 14,\\n      \\\"y\\\": -4,\\n      \\\"rot\\\": 90,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"colour\\\": \\\"red\\\",\\n        \\\"imax\\\": \\\"20m\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"GND1\\\",\\n      \\\"kind\\\": \\\"ground\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 4,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {}\\n    }\\n  ],\\n  \\\"wires\\\": [\\n    {\\n      \\\"id\\\": \\\"w1\\\",\\n      \\\"pts\\\": [\\n        [\\n          0,\\n          -2\\n        ],\\n        [\\n          0,\\n          -6\\n        ],\\n        [\\n          2,\\n          -6\\n        ]\\n      ]\\n    },\\n    {\\n      \\\"id\\\": \\\"w2\\\",\\n      \\\"pts\\\": [\\n        [\\n          6,\\n          -6\\n        ],\\n        [\\n          8,\\n          -6\\n        ]\\n      ]\\n    },\\n    {\\n      \\\"id\\\": \\\"w3\\\",\\n      \\\"pts\\\": [\\n        [\\n          12,\\n          -6\\n        ],\\n        [\\n          14,\\n          -6\\n        ]\\n      ]\\n    },\\n    {\\n      \\\"id\\\": \\\"w4\\\",\\n      \\\"pts\\\": [\\n        [\\n          14,\\n          -2\\n        ],\\n        [\\n          14,\\n          4\\n        ],\\n        [\\n          0,\\n          4\\n        ],\\n        [\\n          0,\\n          2\\n        ]\\n      ]\\n    }\\n  ],\\n  \\\"notes\\\": [\\n    {\\n      \\\"id\\\": \\\"n1\\\",\\n      \\\"x\\\": 17,\\n      \\\"y\\\": -7,\\n      \\\"text\\\": \\\"R = (9 V − 1.9 V) / 0.02 A ≈ 355 Ω → 390 Ω\\\"\\n    },\\n    {\\n      \\\"id\\\": \\\"n2\\\",\\n      \\\"x\\\": 17,\\n      \\\"y\\\": -5,\\n      \\\"text\\\": \\\"Try 47 Ω to see the LED burn out\\\"\\n    }\\n  ],\\n  \\\"sim\\\": {\\n    \\\"mode\\\": \\\"op\\\",\\n    \\\"tran\\\": {\\n      \\\"tstop\\\": \\\"10m\\\",\\n      \\\"tstep\\\": \\\"10u\\\",\\n      \\\"method\\\": \\\"trap\\\",\\n      \\\"uic\\\": false\\n    },\\n    \\\"ac\\\": {\\n      \\\"fstart\\\": \\\"10\\\",\\n      \\\"fstop\\\": \\\"1Meg\\\",\\n      \\\"ppd\\\": 20\\n    },\\n    \\\"dc\\\": {\\n      \\\"start\\\": \\\"0\\\",\\n      \\\"stop\\\": \\\"10\\\",\\n      \\\"step\\\": \\\"0.1\\\"\\n    },\\n    \\\"speed\\\": 0.001\\n  },\\n  \\\"description\\\": \\\"Sizing an LED resistor: R = (Vs − Vf) / If = (9 V − 1.9 V) / 20 mA ≈ 355 Ω → 390 Ω (E12), giving ≈ 18 mA.\\\",\\n  \\\"instruments\\\": {\\n    \\\"meter\\\": {\\n      \\\"mode\\\": \\\"A\\\",\\n      \\\"part\\\": \\\"D1\\\"\\n    }\\n  }\\n}\",\"app\":\"ohmforge\",\"format\":\"ohmforge\",\"sha256\":\"57ea75125b44a8784e6b84b321cf3ae296a7a7f7584606a4e30067278bb0a51b\",\"source\":\"template\"},{\"name\":\"3-station-line.twinworks.json\",\"content\":\"{\\n  \\\"format\\\": \\\"twinworks-project\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"3-station line\\\",\\n  \\\"active\\\": \\\"base\\\",\\n  \\\"scenarios\\\": [\\n    {\\n      \\\"id\\\": \\\"base\\\",\\n      \\\"name\\\": \\\"Baseline\\\",\\n      \\\"notes\\\": \\\"\\\",\\n      \\\"model\\\": {\\n        \\\"format\\\": \\\"twinworks-model\\\",\\n        \\\"version\\\": 1,\\n        \\\"name\\\": \\\"3-station line\\\",\\n        \\\"description\\\": \\\"A simple serial line: random arrivals, three machines with triangular cycle times and two small buffers. The classic starting point.\\\",\\n        \\\"settings\\\": {\\n          \\\"horizon\\\": 28800,\\n          \\\"warmup\\\": 1800,\\n          \\\"seed\\\": 12345,\\n          \\\"replications\\\": 5,\\n          \\\"confidence\\\": 0.95,\\n          \\\"sampleInterval\\\": null,\\n          \\\"currency\\\": \\\"EUR\\\",\\n          \\\"timeUnit\\\": \\\"s\\\",\\n          \\\"lengthUnit\\\": \\\"m\\\",\\n          \\\"gridSize\\\": 0.5\\n        },\\n        \\\"products\\\": [\\n          {\\n            \\\"id\\\": \\\"P1\\\",\\n            \\\"name\\\": \\\"Bracket\\\",\\n            \\\"color\\\": \\\"#2563eb\\\",\\n            \\\"priority\\\": 0,\\n            \\\"materialCost\\\": 4.2,\\n            \\\"price\\\": 19,\\n            \\\"routing\\\": []\\n          }\\n        ],\\n        \\\"calendars\\\": [],\\n        \\\"pools\\\": [],\\n        \\\"nodes\\\": [\\n          {\\n            \\\"id\\\": \\\"SRC1\\\",\\n            \\\"type\\\": \\\"source\\\",\\n            \\\"name\\\": \\\"Raw parts\\\",\\n            \\\"x\\\": 2,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"arrival\\\": \\\"interval\\\",\\n            \\\"interval\\\": {\\n              \\\"type\\\": \\\"exponential\\\",\\n              \\\"mean\\\": 55\\n            },\\n            \\\"firstAt\\\": 0,\\n            \\\"batchSize\\\": 1,\\n            \\\"maxArrivals\\\": null,\\n            \\\"mix\\\": [],\\n            \\\"schedule\\\": [],\\n            \\\"repeatEvery\\\": null,\\n            \\\"whenBlocked\\\": \\\"queue\\\"\\n          },\\n          {\\n            \\\"id\\\": \\\"M1\\\",\\n            \\\"type\\\": \\\"machine\\\",\\n            \\\"name\\\": \\\"Saw\\\",\\n            \\\"x\\\": 6,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"servers\\\": 1,\\n            \\\"cycle\\\": {\\n              \\\"type\\\": \\\"triangular\\\",\\n              \\\"min\\\": 35,\\n              \\\"mode\\\": 40,\\n              \\\"max\\\": 50\\n            },\\n            \\\"cycleByProduct\\\": {},\\n            \\\"setup\\\": null,\\n            \\\"idealCycleTime\\\": null,\\n            \\\"batchSize\\\": 1,\\n            \\\"scrapPct\\\": 0,\\n            \\\"failure\\\": null,\\n            \\\"maintenance\\\": null,\\n            \\\"operator\\\": null,\\n            \\\"costPerHour\\\": 38,\\n            \\\"costPerPart\\\": 0\\n          },\\n          {\\n            \\\"id\\\": \\\"B1\\\",\\n            \\\"type\\\": \\\"buffer\\\",\\n            \\\"name\\\": \\\"Buffer 1\\\",\\n            \\\"x\\\": 10,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"capacity\\\": 5,\\n            \\\"discipline\\\": \\\"fifo\\\"\\n          },\\n          {\\n            \\\"id\\\": \\\"M2\\\",\\n            \\\"type\\\": \\\"machine\\\",\\n            \\\"name\\\": \\\"Mill\\\",\\n            \\\"x\\\": 14,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"servers\\\": 1,\\n            \\\"cycle\\\": {\\n              \\\"type\\\": \\\"triangular\\\",\\n              \\\"min\\\": 40,\\n              \\\"mode\\\": 48,\\n              \\\"max\\\": 58\\n            },\\n            \\\"cycleByProduct\\\": {},\\n            \\\"setup\\\": null,\\n            \\\"idealCycleTime\\\": null,\\n            \\\"batchSize\\\": 1,\\n            \\\"scrapPct\\\": 0,\\n            \\\"failure\\\": null,\\n            \\\"maintenance\\\": null,\\n            \\\"operator\\\": null,\\n            \\\"costPerHour\\\": 65,\\n            \\\"costPerPart\\\": 0\\n          },\\n          {\\n            \\\"id\\\": \\\"B2\\\",\\n            \\\"type\\\": \\\"buffer\\\",\\n            \\\"name\\\": \\\"Buffer 2\\\",\\n            \\\"x\\\": 18,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"capacity\\\": 5,\\n            \\\"discipline\\\": \\\"fifo\\\"\\n          },\\n          {\\n            \\\"id\\\": \\\"M3\\\",\\n            \\\"type\\\": \\\"machine\\\",\\n            \\\"name\\\": \\\"Deburr\\\",\\n            \\\"x\\\": 22,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"servers\\\": 1,\\n            \\\"cycle\\\": {\\n              \\\"type\\\": \\\"triangular\\\",\\n              \\\"min\\\": 30,\\n              \\\"mode\\\": 38,\\n              \\\"max\\\": 45\\n            },\\n            \\\"cycleByProduct\\\": {},\\n            \\\"setup\\\": null,\\n            \\\"idealCycleTime\\\": null,\\n            \\\"batchSize\\\": 1,\\n            \\\"scrapPct\\\": 0,\\n            \\\"failure\\\": null,\\n            \\\"maintenance\\\": null,\\n            \\\"operator\\\": null,\\n            \\\"costPerHour\\\": 30,\\n            \\\"costPerPart\\\": 0\\n          },\\n          {\\n            \\\"id\\\": \\\"OUT1\\\",\\n            \\\"type\\\": \\\"sink\\\",\\n            \\\"name\\\": \\\"Finished goods\\\",\\n            \\\"x\\\": 26,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\"\\n          }\\n        ],\\n        \\\"links\\\": [\\n          {\\n            \\\"id\\\": \\\"L1\\\",\\n            \\\"from\\\": \\\"SRC1\\\",\\n            \\\"to\\\": \\\"M1\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L2\\\",\\n            \\\"from\\\": \\\"M1\\\",\\n            \\\"to\\\": \\\"B1\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L3\\\",\\n            \\\"from\\\": \\\"B1\\\",\\n            \\\"to\\\": \\\"M2\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L4\\\",\\n            \\\"from\\\": \\\"M2\\\",\\n            \\\"to\\\": \\\"B2\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L5\\\",\\n            \\\"from\\\": \\\"B2\\\",\\n            \\\"to\\\": \\\"M3\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L6\\\",\\n            \\\"from\\\": \\\"M3\\\",\\n            \\\"to\\\": \\\"OUT1\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          }\\n        ],\\n        \\\"cost\\\": {\\n          \\\"overheadPerHour\\\": 20,\\n          \\\"scrapDisposal\\\": 0\\n        },\\n        \\\"notes\\\": []\\n      }\\n    }\\n  ]\\n}\",\"app\":\"twinworks\",\"format\":\"twinworks-project\",\"sha256\":\"4b094bfae3303ae29c7a57e3f3c835725ce4150c8dd350d6ca62a2aa20959008\",\"source\":\"template\"},{\"name\":\"name-tag.threadsmith.json\",\"content\":\"{\\n  \\\"format\\\": \\\"threadsmith\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"Name tag\\\",\\n  \\\"hoop\\\": \\\"130x180\\\",\\n  \\\"palette\\\": [\\n    {\\n      \\\"id\\\": \\\"sapphire\\\",\\n      \\\"name\\\": \\\"Sapphire\\\",\\n      \\\"hex\\\": \\\"#0f4c81\\\"\\n    },\\n    {\\n      \\\"id\\\": \\\"coral\\\",\\n      \\\"name\\\": \\\"Coral\\\",\\n      \\\"hex\\\": \\\"#e8705a\\\"\\n    },\\n    {\\n      \\\"id\\\": \\\"ivory\\\",\\n      \\\"name\\\": \\\"Ivory\\\",\\n      \\\"hex\\\": \\\"#fffbf0\\\"\\n    }\\n  ],\\n  \\\"objects\\\": [\\n    {\\n      \\\"id\\\": \\\"frame\\\",\\n      \\\"name\\\": \\\"Frame\\\",\\n      \\\"kind\\\": \\\"rect\\\",\\n      \\\"color\\\": \\\"sapphire\\\",\\n      \\\"x\\\": -45,\\n      \\\"y\\\": -22,\\n      \\\"w\\\": 90,\\n      \\\"h\\\": 44,\\n      \\\"r\\\": 8,\\n      \\\"stitch\\\": {\\n        \\\"type\\\": \\\"satin\\\",\\n        \\\"mode\\\": \\\"border\\\",\\n        \\\"width\\\": 3,\\n        \\\"density\\\": 0.4\\n      },\\n      \\\"underlay\\\": {\\n        \\\"center\\\": true\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"hello\\\",\\n      \\\"name\\\": \\\"Hello\\\",\\n      \\\"kind\\\": \\\"text\\\",\\n      \\\"color\\\": \\\"coral\\\",\\n      \\\"text\\\": \\\"Hello, my name is\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": -7,\\n      \\\"size\\\": 6,\\n      \\\"font\\\": \\\"single\\\",\\n      \\\"align\\\": \\\"center\\\",\\n      \\\"stitch\\\": {\\n        \\\"type\\\": \\\"running\\\",\\n        \\\"length\\\": 1.8,\\n        \\\"bean\\\": true\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"name\\\",\\n      \\\"name\\\": \\\"Name\\\",\\n      \\\"kind\\\": \\\"text\\\",\\n      \\\"color\\\": \\\"sapphire\\\",\\n      \\\"text\\\": \\\"Ada\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 14,\\n      \\\"size\\\": 16,\\n      \\\"font\\\": \\\"single\\\",\\n      \\\"align\\\": \\\"center\\\",\\n      \\\"spacing\\\": 1,\\n      \\\"stitch\\\": {\\n        \\\"type\\\": \\\"satin\\\",\\n        \\\"width\\\": 2.4,\\n        \\\"density\\\": 0.36\\n      },\\n      \\\"underlay\\\": {\\n        \\\"center\\\": true\\n      }\\n    }\\n  ]\\n}\",\"app\":\"threadsmith\",\"format\":\"threadsmith\",\"sha256\":\"2c85ac2d4b00a28a099fb597b0fb21decbf41538dca1fac2e3ca3c5a6178dfee\",\"source\":\"template\"}]}"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BundlekeepBackupVerifierResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "BundlekeepBackupVerifierInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "backup": {
            "title": "Backup (JSON text)",
            "description": "Paste a .bundlekeep.json backup, or upload the file below.",
            "type": "string",
            "maxLength": 14000000,
            "default": "{\n  \"format\": \"bundlekeep\",\n  \"version\": 1,\n  \"name\": \"Workshop backup\",\n  \"items\": [\n    {\n      \"name\": \"base-cabinet-600.kerfwise.json\",\n      \"content\": \"{\\n  \\\"format\\\": \\\"kerfwise\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"Base cabinet 600\\\",\\n  \\\"cabinets\\\": [\\n    {\\n      \\\"id\\\": \\\"c1\\\",\\n      \\\"name\\\": \\\"Base 600\\\",\\n      \\\"type\\\": \\\"base\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 0,\\n      \\\"rot\\\": 0,\\n      \\\"params\\\": {\\n        \\\"width\\\": 600,\\n        \\\"height\\\": 870,\\n        \\\"depth\\\": 560,\\n        \\\"doorCount\\\": 1,\\n        \\\"shelfCount\\\": 1,\\n        \\\"topType\\\": \\\"rails\\\",\\n        \\\"countertop\\\": false\\n      }\\n    }\\n  ]\\n}\",\n      \"app\": \"kerfwise\",\n      \"format\": \"kerfwise\",\n      \"sha256\": \"e6f17c489b32c4e577c7c857a650bbbbbf8a1d2f1c9daaf8718ce7f6e0e3e6dc\",\n      \"source\": \"template\"\n    },\n    {\n      \"name\": \"led-with-series-resistor.ohmforge.json\",\n      \"content\": \"{\\n  \\\"format\\\": \\\"ohmforge\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"LED with series resistor\\\",\\n  \\\"parts\\\": [\\n    {\\n      \\\"id\\\": \\\"BT1\\\",\\n      \\\"kind\\\": \\\"battery\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 0,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"voltage\\\": \\\"9\\\",\\n        \\\"rint\\\": \\\"1\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"SW1\\\",\\n      \\\"kind\\\": \\\"switch\\\",\\n      \\\"x\\\": 4,\\n      \\\"y\\\": -6,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"closed\\\": true,\\n        \\\"ron\\\": \\\"10m\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"R1\\\",\\n      \\\"kind\\\": \\\"resistor\\\",\\n      \\\"x\\\": 10,\\n      \\\"y\\\": -6,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"value\\\": \\\"390\\\",\\n        \\\"power\\\": \\\"0.25\\\",\\n        \\\"tolerance\\\": \\\"5%\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"D1\\\",\\n      \\\"kind\\\": \\\"led\\\",\\n      \\\"x\\\": 14,\\n      \\\"y\\\": -4,\\n      \\\"rot\\\": 90,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {\\n        \\\"colour\\\": \\\"red\\\",\\n        \\\"imax\\\": \\\"20m\\\"\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"GND1\\\",\\n      \\\"kind\\\": \\\"ground\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 4,\\n      \\\"rot\\\": 0,\\n      \\\"flip\\\": false,\\n      \\\"props\\\": {}\\n    }\\n  ],\\n  \\\"wires\\\": [\\n    {\\n      \\\"id\\\": \\\"w1\\\",\\n      \\\"pts\\\": [\\n        [\\n          0,\\n          -2\\n        ],\\n        [\\n          0,\\n          -6\\n        ],\\n        [\\n          2,\\n          -6\\n        ]\\n      ]\\n    },\\n    {\\n      \\\"id\\\": \\\"w2\\\",\\n      \\\"pts\\\": [\\n        [\\n          6,\\n          -6\\n        ],\\n        [\\n          8,\\n          -6\\n        ]\\n      ]\\n    },\\n    {\\n      \\\"id\\\": \\\"w3\\\",\\n      \\\"pts\\\": [\\n        [\\n          12,\\n          -6\\n        ],\\n        [\\n          14,\\n          -6\\n        ]\\n      ]\\n    },\\n    {\\n      \\\"id\\\": \\\"w4\\\",\\n      \\\"pts\\\": [\\n        [\\n          14,\\n          -2\\n        ],\\n        [\\n          14,\\n          4\\n        ],\\n        [\\n          0,\\n          4\\n        ],\\n        [\\n          0,\\n          2\\n        ]\\n      ]\\n    }\\n  ],\\n  \\\"notes\\\": [\\n    {\\n      \\\"id\\\": \\\"n1\\\",\\n      \\\"x\\\": 17,\\n      \\\"y\\\": -7,\\n      \\\"text\\\": \\\"R = (9 V − 1.9 V) / 0.02 A ≈ 355 Ω → 390 Ω\\\"\\n    },\\n    {\\n      \\\"id\\\": \\\"n2\\\",\\n      \\\"x\\\": 17,\\n      \\\"y\\\": -5,\\n      \\\"text\\\": \\\"Try 47 Ω to see the LED burn out\\\"\\n    }\\n  ],\\n  \\\"sim\\\": {\\n    \\\"mode\\\": \\\"op\\\",\\n    \\\"tran\\\": {\\n      \\\"tstop\\\": \\\"10m\\\",\\n      \\\"tstep\\\": \\\"10u\\\",\\n      \\\"method\\\": \\\"trap\\\",\\n      \\\"uic\\\": false\\n    },\\n    \\\"ac\\\": {\\n      \\\"fstart\\\": \\\"10\\\",\\n      \\\"fstop\\\": \\\"1Meg\\\",\\n      \\\"ppd\\\": 20\\n    },\\n    \\\"dc\\\": {\\n      \\\"start\\\": \\\"0\\\",\\n      \\\"stop\\\": \\\"10\\\",\\n      \\\"step\\\": \\\"0.1\\\"\\n    },\\n    \\\"speed\\\": 0.001\\n  },\\n  \\\"description\\\": \\\"Sizing an LED resistor: R = (Vs − Vf) / If = (9 V − 1.9 V) / 20 mA ≈ 355 Ω → 390 Ω (E12), giving ≈ 18 mA.\\\",\\n  \\\"instruments\\\": {\\n    \\\"meter\\\": {\\n      \\\"mode\\\": \\\"A\\\",\\n      \\\"part\\\": \\\"D1\\\"\\n    }\\n  }\\n}\",\n      \"app\": \"ohmforge\",\n      \"format\": \"ohmforge\",\n      \"sha256\": \"57ea75125b44a8784e6b84b321cf3ae296a7a7f7584606a4e30067278bb0a51b\",\n      \"source\": \"template\"\n    },\n    {\n      \"name\": \"3-station-line.twinworks.json\",\n      \"content\": \"{\\n  \\\"format\\\": \\\"twinworks-project\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"3-station line\\\",\\n  \\\"active\\\": \\\"base\\\",\\n  \\\"scenarios\\\": [\\n    {\\n      \\\"id\\\": \\\"base\\\",\\n      \\\"name\\\": \\\"Baseline\\\",\\n      \\\"notes\\\": \\\"\\\",\\n      \\\"model\\\": {\\n        \\\"format\\\": \\\"twinworks-model\\\",\\n        \\\"version\\\": 1,\\n        \\\"name\\\": \\\"3-station line\\\",\\n        \\\"description\\\": \\\"A simple serial line: random arrivals, three machines with triangular cycle times and two small buffers. The classic starting point.\\\",\\n        \\\"settings\\\": {\\n          \\\"horizon\\\": 28800,\\n          \\\"warmup\\\": 1800,\\n          \\\"seed\\\": 12345,\\n          \\\"replications\\\": 5,\\n          \\\"confidence\\\": 0.95,\\n          \\\"sampleInterval\\\": null,\\n          \\\"currency\\\": \\\"EUR\\\",\\n          \\\"timeUnit\\\": \\\"s\\\",\\n          \\\"lengthUnit\\\": \\\"m\\\",\\n          \\\"gridSize\\\": 0.5\\n        },\\n        \\\"products\\\": [\\n          {\\n            \\\"id\\\": \\\"P1\\\",\\n            \\\"name\\\": \\\"Bracket\\\",\\n            \\\"color\\\": \\\"#2563eb\\\",\\n            \\\"priority\\\": 0,\\n            \\\"materialCost\\\": 4.2,\\n            \\\"price\\\": 19,\\n            \\\"routing\\\": []\\n          }\\n        ],\\n        \\\"calendars\\\": [],\\n        \\\"pools\\\": [],\\n        \\\"nodes\\\": [\\n          {\\n            \\\"id\\\": \\\"SRC1\\\",\\n            \\\"type\\\": \\\"source\\\",\\n            \\\"name\\\": \\\"Raw parts\\\",\\n            \\\"x\\\": 2,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"arrival\\\": \\\"interval\\\",\\n            \\\"interval\\\": {\\n              \\\"type\\\": \\\"exponential\\\",\\n              \\\"mean\\\": 55\\n            },\\n            \\\"firstAt\\\": 0,\\n            \\\"batchSize\\\": 1,\\n            \\\"maxArrivals\\\": null,\\n            \\\"mix\\\": [],\\n            \\\"schedule\\\": [],\\n            \\\"repeatEvery\\\": null,\\n            \\\"whenBlocked\\\": \\\"queue\\\"\\n          },\\n          {\\n            \\\"id\\\": \\\"M1\\\",\\n            \\\"type\\\": \\\"machine\\\",\\n            \\\"name\\\": \\\"Saw\\\",\\n            \\\"x\\\": 6,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"servers\\\": 1,\\n            \\\"cycle\\\": {\\n              \\\"type\\\": \\\"triangular\\\",\\n              \\\"min\\\": 35,\\n              \\\"mode\\\": 40,\\n              \\\"max\\\": 50\\n            },\\n            \\\"cycleByProduct\\\": {},\\n            \\\"setup\\\": null,\\n            \\\"idealCycleTime\\\": null,\\n            \\\"batchSize\\\": 1,\\n            \\\"scrapPct\\\": 0,\\n            \\\"failure\\\": null,\\n            \\\"maintenance\\\": null,\\n            \\\"operator\\\": null,\\n            \\\"costPerHour\\\": 38,\\n            \\\"costPerPart\\\": 0\\n          },\\n          {\\n            \\\"id\\\": \\\"B1\\\",\\n            \\\"type\\\": \\\"buffer\\\",\\n            \\\"name\\\": \\\"Buffer 1\\\",\\n            \\\"x\\\": 10,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"capacity\\\": 5,\\n            \\\"discipline\\\": \\\"fifo\\\"\\n          },\\n          {\\n            \\\"id\\\": \\\"M2\\\",\\n            \\\"type\\\": \\\"machine\\\",\\n            \\\"name\\\": \\\"Mill\\\",\\n            \\\"x\\\": 14,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"servers\\\": 1,\\n            \\\"cycle\\\": {\\n              \\\"type\\\": \\\"triangular\\\",\\n              \\\"min\\\": 40,\\n              \\\"mode\\\": 48,\\n              \\\"max\\\": 58\\n            },\\n            \\\"cycleByProduct\\\": {},\\n            \\\"setup\\\": null,\\n            \\\"idealCycleTime\\\": null,\\n            \\\"batchSize\\\": 1,\\n            \\\"scrapPct\\\": 0,\\n            \\\"failure\\\": null,\\n            \\\"maintenance\\\": null,\\n            \\\"operator\\\": null,\\n            \\\"costPerHour\\\": 65,\\n            \\\"costPerPart\\\": 0\\n          },\\n          {\\n            \\\"id\\\": \\\"B2\\\",\\n            \\\"type\\\": \\\"buffer\\\",\\n            \\\"name\\\": \\\"Buffer 2\\\",\\n            \\\"x\\\": 18,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"capacity\\\": 5,\\n            \\\"discipline\\\": \\\"fifo\\\"\\n          },\\n          {\\n            \\\"id\\\": \\\"M3\\\",\\n            \\\"type\\\": \\\"machine\\\",\\n            \\\"name\\\": \\\"Deburr\\\",\\n            \\\"x\\\": 22,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\",\\n            \\\"servers\\\": 1,\\n            \\\"cycle\\\": {\\n              \\\"type\\\": \\\"triangular\\\",\\n              \\\"min\\\": 30,\\n              \\\"mode\\\": 38,\\n              \\\"max\\\": 45\\n            },\\n            \\\"cycleByProduct\\\": {},\\n            \\\"setup\\\": null,\\n            \\\"idealCycleTime\\\": null,\\n            \\\"batchSize\\\": 1,\\n            \\\"scrapPct\\\": 0,\\n            \\\"failure\\\": null,\\n            \\\"maintenance\\\": null,\\n            \\\"operator\\\": null,\\n            \\\"costPerHour\\\": 30,\\n            \\\"costPerPart\\\": 0\\n          },\\n          {\\n            \\\"id\\\": \\\"OUT1\\\",\\n            \\\"type\\\": \\\"sink\\\",\\n            \\\"name\\\": \\\"Finished goods\\\",\\n            \\\"x\\\": 26,\\n            \\\"y\\\": 6,\\n            \\\"rotation\\\": 0,\\n            \\\"calendar\\\": null,\\n            \\\"routing\\\": \\\"first\\\",\\n            \\\"note\\\": \\\"\\\"\\n          }\\n        ],\\n        \\\"links\\\": [\\n          {\\n            \\\"id\\\": \\\"L1\\\",\\n            \\\"from\\\": \\\"SRC1\\\",\\n            \\\"to\\\": \\\"M1\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L2\\\",\\n            \\\"from\\\": \\\"M1\\\",\\n            \\\"to\\\": \\\"B1\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L3\\\",\\n            \\\"from\\\": \\\"B1\\\",\\n            \\\"to\\\": \\\"M2\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L4\\\",\\n            \\\"from\\\": \\\"M2\\\",\\n            \\\"to\\\": \\\"B2\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L5\\\",\\n            \\\"from\\\": \\\"B2\\\",\\n            \\\"to\\\": \\\"M3\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          },\\n          {\\n            \\\"id\\\": \\\"L6\\\",\\n            \\\"from\\\": \\\"M3\\\",\\n            \\\"to\\\": \\\"OUT1\\\",\\n            \\\"weight\\\": 1,\\n            \\\"products\\\": [],\\n            \\\"kind\\\": \\\"normal\\\",\\n            \\\"qty\\\": 1\\n          }\\n        ],\\n        \\\"cost\\\": {\\n          \\\"overheadPerHour\\\": 20,\\n          \\\"scrapDisposal\\\": 0\\n        },\\n        \\\"notes\\\": []\\n      }\\n    }\\n  ]\\n}\",\n      \"app\": \"twinworks\",\n      \"format\": \"twinworks-project\",\n      \"sha256\": \"4b094bfae3303ae29c7a57e3f3c835725ce4150c8dd350d6ca62a2aa20959008\",\n      \"source\": \"template\"\n    },\n    {\n      \"name\": \"name-tag.threadsmith.json\",\n      \"content\": \"{\\n  \\\"format\\\": \\\"threadsmith\\\",\\n  \\\"version\\\": 1,\\n  \\\"name\\\": \\\"Name tag\\\",\\n  \\\"hoop\\\": \\\"130x180\\\",\\n  \\\"palette\\\": [\\n    {\\n      \\\"id\\\": \\\"sapphire\\\",\\n      \\\"name\\\": \\\"Sapphire\\\",\\n      \\\"hex\\\": \\\"#0f4c81\\\"\\n    },\\n    {\\n      \\\"id\\\": \\\"coral\\\",\\n      \\\"name\\\": \\\"Coral\\\",\\n      \\\"hex\\\": \\\"#e8705a\\\"\\n    },\\n    {\\n      \\\"id\\\": \\\"ivory\\\",\\n      \\\"name\\\": \\\"Ivory\\\",\\n      \\\"hex\\\": \\\"#fffbf0\\\"\\n    }\\n  ],\\n  \\\"objects\\\": [\\n    {\\n      \\\"id\\\": \\\"frame\\\",\\n      \\\"name\\\": \\\"Frame\\\",\\n      \\\"kind\\\": \\\"rect\\\",\\n      \\\"color\\\": \\\"sapphire\\\",\\n      \\\"x\\\": -45,\\n      \\\"y\\\": -22,\\n      \\\"w\\\": 90,\\n      \\\"h\\\": 44,\\n      \\\"r\\\": 8,\\n      \\\"stitch\\\": {\\n        \\\"type\\\": \\\"satin\\\",\\n        \\\"mode\\\": \\\"border\\\",\\n        \\\"width\\\": 3,\\n        \\\"density\\\": 0.4\\n      },\\n      \\\"underlay\\\": {\\n        \\\"center\\\": true\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"hello\\\",\\n      \\\"name\\\": \\\"Hello\\\",\\n      \\\"kind\\\": \\\"text\\\",\\n      \\\"color\\\": \\\"coral\\\",\\n      \\\"text\\\": \\\"Hello, my name is\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": -7,\\n      \\\"size\\\": 6,\\n      \\\"font\\\": \\\"single\\\",\\n      \\\"align\\\": \\\"center\\\",\\n      \\\"stitch\\\": {\\n        \\\"type\\\": \\\"running\\\",\\n        \\\"length\\\": 1.8,\\n        \\\"bean\\\": true\\n      }\\n    },\\n    {\\n      \\\"id\\\": \\\"name\\\",\\n      \\\"name\\\": \\\"Name\\\",\\n      \\\"kind\\\": \\\"text\\\",\\n      \\\"color\\\": \\\"sapphire\\\",\\n      \\\"text\\\": \\\"Ada\\\",\\n      \\\"x\\\": 0,\\n      \\\"y\\\": 14,\\n      \\\"size\\\": 16,\\n      \\\"font\\\": \\\"single\\\",\\n      \\\"align\\\": \\\"center\\\",\\n      \\\"spacing\\\": 1,\\n      \\\"stitch\\\": {\\n        \\\"type\\\": \\\"satin\\\",\\n        \\\"width\\\": 2.4,\\n        \\\"density\\\": 0.36\\n      },\\n      \\\"underlay\\\": {\\n        \\\"center\\\": true\\n      }\\n    }\\n  ]\\n}\",\n      \"app\": \"threadsmith\",\n      \"format\": \"threadsmith\",\n      \"sha256\": \"2c85ac2d4b00a28a099fb597b0fb21decbf41538dca1fac2e3ca3c5a6178dfee\",\n      \"source\": \"template\"\n    }\n  ]\n}"
          },
          "backupFile": {
            "title": "Backup file (optional)",
            "description": "Used instead of the pasted text when given. Upload as {filename, contentType?, contentBase64}. Max 53711 KiB. Accepts .json,application/json.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          },
          "extract": {
            "title": "File to extract (optional)",
            "description": "Exact file name from the backup; the tool returns that project file for download.",
            "type": "string",
            "maxLength": 160,
            "default": ""
          }
        },
        "required": []
      },
      "BundlekeepBackupVerifierResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "name",
              "summary",
              "inventory",
              "checklist",
              "extracted"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "summary": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "files",
                  "bytes",
                  "apps",
                  "unknown",
                  "embeddedDataUrls",
                  "verified",
                  "changed",
                  "unchecked",
                  "warnings"
                ],
                "properties": {
                  "files": {
                    "type": "integer"
                  },
                  "bytes": {
                    "type": "integer"
                  },
                  "apps": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "integer"
                    }
                  },
                  "unknown": {
                    "type": "integer"
                  },
                  "embeddedDataUrls": {
                    "type": "integer"
                  },
                  "verified": {
                    "type": "integer"
                  },
                  "changed": {
                    "type": "integer"
                  },
                  "unchecked": {
                    "type": "integer"
                  },
                  "warnings": {
                    "type": "integer"
                  }
                }
              },
              "inventory": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "app",
                    "format",
                    "projectName",
                    "bytes",
                    "embeddedDataUrls",
                    "sha256",
                    "check",
                    "warnings"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "app": {
                      "type": "string"
                    },
                    "format": {
                      "type": "string"
                    },
                    "projectName": {
                      "type": "string"
                    },
                    "bytes": {
                      "type": "integer"
                    },
                    "embeddedDataUrls": {
                      "type": "integer"
                    },
                    "sha256": {
                      "type": "string"
                    },
                    "check": {
                      "enum": [
                        "verified",
                        "changed",
                        "unchecked"
                      ]
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "checklist": {
                "type": "string"
              },
              "extracted": {
                "anyOf": [
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "artifactId",
                      "filename",
                      "mime",
                      "bytes",
                      "sha256",
                      "path"
                    ],
                    "properties": {
                      "artifactId": {
                        "type": "string"
                      },
                      "filename": {
                        "type": "string"
                      },
                      "mime": {
                        "type": "string"
                      },
                      "bytes": {
                        "type": "integer"
                      },
                      "sha256": {
                        "type": "string"
                      },
                      "path": {
                        "type": "string",
                        "description": "Download path on the same site (valid for about 2 hours)."
                      }
                    }
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}