{
  "openapi": "3.1.0",
  "info": {
    "title": "RosieOS weld planner API",
    "version": "v1",
    "description": "The weld motion planner: health, progress, planning a .weldplan into verified joint trajectories, and fetching the stored dense .rdt trajectory. Generated from the docs page https://advancedmetalresearch.com/docs/apis/weld-planner-http (source: apis/weld-planner-http.md), which cites the RosieOS source files it was written from. Routes the page lists only in a table have no body schemas. 4 operations.",
    "license": {
      "name": "Apache 2.0",
      "identifier": "Apache-2.0"
    }
  },
  "externalDocs": {
    "url": "https://advancedmetalresearch.com/docs/apis/weld-planner-http"
  },
  "servers": [
    {
      "url": "http://127.0.0.1:8796",
      "description": "Default port; see the Run the weld planner guide for binding it safely."
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Health"
    },
    {
      "name": "Progress"
    },
    {
      "name": "Plan"
    },
    {
      "name": "Fetch a trajectory"
    }
  ],
  "paths": {
    "/api/motion/health": {
      "get": {
        "summary": "Reports whether the planner's Torch build can see a CUDA device.",
        "tags": [
          "Health"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cuda": {
                      "type": "boolean",
                      "description": "true if CUDA is available"
                    },
                    "device": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name of device 0, or null without CUDA"
                    }
                  },
                  "additionalProperties": true
                }
              }
            },
            "x-rosieos-documented-fields": [
              "cuda: true if CUDA is available",
              "device: The name of device 0, or null without CUDA"
            ]
          }
        },
        "externalDocs": {
          "url": "https://advancedmetalresearch.com/docs/apis/weld-planner-http#health"
        },
        "operationId": "get_api_motion_health"
      }
    },
    "/api/motion/progress": {
      "get": {
        "summary": "The stage of the plan that is running now, for a client watching a long request.",
        "tags": [
          "Progress"
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "description": "stage is null when no plan is running. While one is, it is the last stage the planner reported, for example sweep, weldseam, freespace seed, optimize or verify. There is one slot, because only one plan runs at a time.",
        "externalDocs": {
          "url": "https://advancedmetalresearch.com/docs/apis/weld-planner-http#progress"
        },
        "operationId": "get_api_motion_progress"
      }
    },
    "/api/motion/plan": {
      "post": {
        "summary": "Plans every seam and move of the posted .weldplan, verifies them, and optionally writes the dense trajectory.",
        "tags": [
          "Plan"
        ],
        "parameters": [
          {
            "name": "k_best",
            "in": "query",
            "required": false,
            "description": "Candidate paths to keep per seam from the M4 search Default: 5. Range: 1–16.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "screen_collisions",
            "in": "query",
            "required": false,
            "description": "Screen search poses against the collision model, and include collision avoidance in M5 and M6. false means unchecked, not safe. Default: true.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "samples_per_seam",
            "in": "query",
            "required": false,
            "description": "Space the M4 lattice by sample count. Null spaces it by time, from the weld's travel speed. Default: null. Range: 2–512.",
            "schema": {
              "type": [
                "integer",
                "null"
              ]
            }
          },
          {
            "name": "run_weld_trajopt",
            "in": "query",
            "required": false,
            "description": "Run M5, the continuous weld trajectories. Minutes rather than seconds. Default: false.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "run_connecting_trajopt",
            "in": "query",
            "required": false,
            "description": "Run M6, the approach, transits, retract and taught moves Default: true.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "free_space_backend",
            "in": "query",
            "required": false,
            "description": "The M6 solver. curobo uses cuRobo for comparison and is optional at runtime. legacy is deprecated and kept to reproduce old results. Any other value returns 422. Default: bspline. Range: bspline, curobo, legacy.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "verify",
            "in": "query",
            "required": false,
            "description": "Run the verifier on M5 and M6 output Default: true.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "verify_margin_mm",
            "in": "query",
            "required": false,
            "description": "The verifier's clearance margin Default: 2.0. Range: 0–50.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "order_seams",
            "in": "query",
            "required": false,
            "description": "Reorder welds to shorten the transits. Off, the program's own weld order is kept. Default: false.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "dense",
            "in": "query",
            "required": false,
            "description": "Build, check and store the .rdt. Needs run_weld_trajopt and run_connecting_trajopt. Default: false.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "program_id",
            "in": "query",
            "required": false,
            "description": "Stamped into the plan identity. A dense trajectory needs a plain identifier (letters, digits, ., _, :, -). Default: \"\". Range: up to 120 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "manifest_revision",
            "in": "query",
            "required": false,
            "description": "Stamped into the plan identity Default: 1. Range: ≥ 1.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "plan_revision",
            "in": "query",
            "required": false,
            "description": "Stamped into the plan identity Default: 1. Range: ≥ 1.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connecting_trajectories_error": {
                      "description": "Present when M6 failed. The welds may still be good."
                    },
                    "program_order": {
                      "description": "Present when the program has taught moves: the enabled nodes in order"
                    },
                    "speed_scale": {
                      "description": "Present when the program's plan speed is below 1. times_s are already stretched and knot_velocity_deg_s already scaled."
                    },
                    "dense": {
                      "description": "With dense=true: the .rdt summary, including trajectory_digest, plan_id (<program_id>:<first 12 hex of the request digest>), program_digest (sha256: plus the request digest), dt_s, total_sample_count, total_duration_s, max_abs_qd_rad_s (rad/s), robot_cell, bytes and segments[]"
                    },
                    "dense_error": {
                      "description": "With dense=true, when no .rdt was written: {reason, detail, segment_index}"
                    }
                  },
                  "additionalProperties": true
                }
              }
            },
            "x-rosieos-documented-fields": [
              "seams[].crossed: Whether the M4 search found a path across the seam. When false, frontier and frontier_causes say where and why it stopped.",
              "seams[].trajectory: The M5 curve: knots_deg, knot_velocity_deg_s and times_s form a cubic Hermite, with its verdict and tracking reports",
              "connecting_trajectories[]: The M6 moves, in execution order: kind (approach, transit or retract), from and to seam ids (null at the home end), and a node_id for moves tied to a program node",
              "connecting_trajectories_error: Present when M6 failed. The welds may still be good.",
              "program_order: Present when the program has taught moves: the enabled nodes in order",
              "speed_scale: Present when the program's plan speed is below 1. times_s are already stretched and knot_velocity_deg_s already scaled.",
              "dense: With dense=true: the .rdt summary, including trajectory_digest, plan_id (<program_id>:<first 12 hex of the request digest>), program_digest (sha256: plus the request digest), dt_s, total_sample_count, total_duration_s, max_abs_qd_rad_s (rad/s), robot_cell, bytes and segments[]",
              "dense_error: With dense=true, when no .rdt was written: {reason, detail, segment_index}"
            ]
          },
          "400": {
            "description": "Empty body",
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "x-rosieos-bodies": [
              {
                "body": "{\"error\": \"an empty body is not a .weldplan\"}",
                "when": "Empty body"
              }
            ]
          },
          "422": {
            "description": "Unknown free_space_backend; A query parameter is out of range or the wrong type; Planning failed, including a .weldplan the planner refused to open (bad zip, digest mismatch, wrong program schema) or missing cell meshes",
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "x-rosieos-bodies": [
              {
                "body": "{\"detail\": \"unknown free_space_backend …\"}",
                "when": "Unknown free_space_backend"
              },
              {
                "body": "{\"detail\": [ … ]}",
                "when": "A query parameter is out of range or the wrong type"
              },
              {
                "body": "{\"error\": \"<type>: <message>\"}",
                "when": "Planning failed, including a .weldplan the planner refused to open (bad zip, digest mismatch, wrong program schema) or missing cell meshes"
              }
            ]
          },
          "499": {
            "description": "The client disconnected",
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "x-rosieos-bodies": [
              {
                "body": "{\"error\": \"Planning cancelled\"}",
                "when": "The client disconnected"
              }
            ]
          }
        },
        "description": "The body is the raw .weldplan bytes. Options go in the query string.\n\nThe OLP server always sends run_weld_trajopt=true, run_connecting_trajopt=true, verify=true and dense=true, plus the free-space backend and the program identity.\n\n- One plan at a time. A second request waits for the first. It can still be cancelled while it waits. - One process per plan. Each admitted request runs in a fresh Python process that owns the GPU. This costs interpreter, model and CUDA start-up on every plan. - Cancellation. If the client disconnects, the server sends SIGTERM to the planning process group, then SIGKILL after 2 s, and answers 499. A cancelled plan never stores a .rdt. - Atomic publication. The .rdt is written to the store only after the planning process succeeded and the client is still connected.\n\n200 OK with the result document, schema amr-weld-planner-v1.motion-plan-result.v1. On the wire, angles are in degrees and lengths in mm; times are in s. A trimmed example:\n\nThe values above are illustrative. The fields that matter most:\n\nSee The plan result for every block, and Verdicts for what PASS, REFUSED and FAIL mean.\n\nA plan can answer 200 OK and still have no .rdt. Then dense_error says why, and the server keeps the request and result under <dense store>/refused/ (newest 5) for diagnosis. The reasons are admission's and the encoder's:\n\nsegment_index names the failing segment when there is one.",
        "externalDocs": {
          "url": "https://advancedmetalresearch.com/docs/apis/weld-planner-http#plan"
        },
        "x-rosieos-reasons": [
          {
            "code": "result_empty",
            "meaning": "dense=true without both trajectory stages, or nothing playable in the result"
          },
          {
            "code": "identity_invalid",
            "meaning": "program_id is empty or not a plain identifier"
          },
          {
            "code": "seam_not_planned",
            "meaning": "A seam was not crossed by the search"
          },
          {
            "code": "motion_not_verified",
            "meaning": "A seam or move has no PASS, a non-zero collision, penetration or limit count, an unverifiable check, or a tracking certificate out of tolerance"
          },
          {
            "code": "motion_join_failed",
            "meaning": "The connecting moves could not be planned"
          },
          {
            "code": "motion_result_invalid",
            "meaning": "The result is malformed, for example duplicate seam ids or an unknown move kind"
          },
          {
            "code": "motion_not_planned",
            "meaning": "A program node has no planned motion"
          },
          {
            "code": "qd_limit_exceeded",
            "meaning": "A sample is faster than the cell's per-axis velocity ceiling"
          },
          {
            "code": "q_step_exceeded, boundary_qd_nonzero, boundary_q_discontinuity, time_grid_invalid, sample_count_overflow",
            "meaning": "The resampled trajectory broke an .rdt format rule; see the .rdt format"
          }
        ],
        "operationId": "post_api_motion_plan"
      }
    },
    "/api/motion/dense/{trajectory_digest}": {
      "get": {
        "summary": "Returns the stored .rdt bytes for a digest.",
        "tags": [
          "Fetch a trajectory"
        ],
        "parameters": [
          {
            "name": "trajectory_digest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "description": "The response is application/octet-stream with Cache-Control: no-store. A malformed digest returns 422 (expected sha256:<64 hex>). An unknown digest returns 404.\n\nThe store only holds trajectories that passed admission. It lives in --dense-store-dir, else WELD_PLANNER_DENSE_STORE_DIR, else ~/.cache/rosieos-olp/weld-planner-dense, as sha256-<hex>.rdt. It is a cache: if a file is gone, plan again. OLP's Load fetches from this route and answers dense_blob_not_found when the planner no longer has the file. See the .rdt format for the file layout.",
        "externalDocs": {
          "url": "https://advancedmetalresearch.com/docs/apis/weld-planner-http#fetch-a-trajectory"
        },
        "operationId": "get_api_motion_dense_trajectory_digest"
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable error code"
          },
          "detail": {
            "type": "string"
          }
        },
        "additionalProperties": true
      }
    }
  }
}
