{
  "openapi": "3.0.3",
  "info": {
    "title": "AI_IFC viewer server (Go)",
    "version": "0.2.0",
    "description": "AI_IFC 平台对外唯一入口（默认 :8090）。JSON 信封统一 `{code, message, data}`，`code=0` 成功。模型 id 格式 `^m_[0-9a-f]{16}$`；issue id 格式 `^i_[0-9a-f]{12}$`。\n\n生成方式（诚实边界：Go 用 stdlib mux，无 schema 反射）：路由清单由 `docs/scripts/gen-go-routes.mjs` 从 mux 注册自动提取，请求/响应 schema 由 `docs/scripts/go-openapi-schema.mjs` 手工维护；`gen-go-openapi.mjs` 对两者做双向覆盖漂移检测——新增路由未配 schema 或 schema 存在死路由都会令生成失败（CI 红）。\n\n鉴权：默认关闭（`apiToken`/`VIEWER_API_TOKEN` 为空）。开启后除 OPTIONS 与 `GET /v1/models/...` 只读静态文件外，全部端点需 `Authorization: Bearer <token>`（401 envelope 码 40100）。"
  },
  "servers": [
    {
      "url": "http://localhost:8090",
      "description": "Go 网关（本地默认端口）"
    }
  ],
  "tags": [
    {
      "name": "chat",
      "description": "对话式 AI 建模（demo 模块）"
    },
    {
      "name": "models",
      "description": "模型上传/列表/详情/删除/下载/重试"
    },
    {
      "name": "issues",
      "description": "设计审查 Issue 与截图"
    },
    {
      "name": "overrides",
      "description": "metadata override 属性改写 + change log"
    },
    {
      "name": "edit",
      "description": "编辑代理（只读/对比端点）"
    },
    {
      "name": "script",
      "description": "script-as-source 编辑代理（暂存/沙箱/大版本）"
    },
    {
      "name": "static",
      "description": "静态资源（直挂，不走 JSON 信封）"
    }
  ],
  "paths": {
    "/api/v1/chat/projects": {
      "post": {
        "summary": "创建项目（kind 必选）",
        "description": "创建项目。kind 必选（ifc|cad|cad->ifc，强制预选）。ifc 管线建项目即初始化骨架模型（script-as-source 骨架脚本沙箱构建出最小 IFC v1，分配 modelId）；cad/cad->ifc 保持空白，agent 会话内经 init_model 工具按需初始化 DXF。",
        "operationId": "postApiV1ChatProjects",
        "tags": [
          "chat"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body，title 可空，kind 必选",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kind"
                ],
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "默认 \"AI 项目\""
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "ifc",
                      "cad",
                      "cad->ifc"
                    ],
                    "description": "项目类型（决定 Agent 派发方向与装配）"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat/projects/{id}": {
      "delete": {
        "summary": "删除项目（级联）",
        "description": "删除项目并级联清理绑定产物：项目 + 会话（chat-sessions）+ 事件日志（chat/{agentID}.jsonl）+ 方案（plans/{projectID}）+ 项目下模型（issues/changes/overrides + store 目录）。与 DELETE /models/{id}（单模型，不级联）区分——删除项目即删全套。",
        "operationId": "deleteApiV1ChatProjectsId",
        "tags": [
          "chat"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "description": "始终为 null"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat/sessions": {
      "get": {
        "summary": "会话列表",
        "description": "列出全部 chat 会话（demo 模块，内存态 + chat-sessions.json 持久化）。",
        "operationId": "getApiV1ChatSessions",
        "tags": [
          "chat"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ChatSessionList"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "创建会话（同 modelId 幂等）",
        "description": "创建 chat 会话并绑定模型（进程内 Eino agent）。同一 modelId 永远只有一个会话——退出再打开返回同一会话。modelId 可空（会话不绑定模型）。",
        "operationId": "postApiV1ChatSessions",
        "tags": [
          "chat"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ChatSession"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSessionBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/chat/sessions/{cid}/abort": {
      "post": {
        "summary": "中止会话当前 turn",
        "description": "中止 AI 当前响应（前端 busy 时\"发送\"变\"停止\"调用此端点）。",
        "operationId": "postApiV1ChatSessionsCidAbort",
        "tags": [
          "chat"
        ],
        "parameters": [
          {
            "name": "cid",
            "in": "path",
            "required": true,
            "description": "chat 会话 id",
            "schema": {
              "type": "string",
              "pattern": "^c_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/AbortResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat/sessions/{cid}/answer": {
      "post": {
        "summary": "HITL 回答（D3b）——question.ask 后的用户回答续跑",
        "description": "body {interruptId, answer} → Agent.Resume（ResumeParams.Targets[interruptId] = AskUserInfo.UserAnswer）续跑。interruptId 来自 question.ask SSE 帧。",
        "operationId": "postApiV1ChatSessionsCidAnswer",
        "tags": [
          "chat"
        ],
        "parameters": [
          {
            "name": "cid",
            "in": "path",
            "required": true,
            "description": "chat 会话 id",
            "schema": {
              "type": "string",
              "pattern": "^c_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/AcceptedResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body，interruptId + answer",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "interruptId",
                  "answer"
                ],
                "properties": {
                  "interruptId": {
                    "type": "string",
                    "description": "question.ask 帧的 interruptId"
                  },
                  "answer": {
                    "type": "string",
                    "description": "用户回答"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat/sessions/{cid}/events": {
      "get": {
        "summary": "会话事件流（SSE）",
        "description": "Server-Sent Events：`event: <type>` + `data: <json>` 帧。事件类型含 session.creating / session.idle / message / session.error / viewer.committed / viewer.notify_failed 等。非信封响应。",
        "operationId": "getApiV1ChatSessionsCidEvents",
        "tags": [
          "chat"
        ],
        "parameters": [
          {
            "name": "cid",
            "in": "path",
            "required": true,
            "description": "chat 会话 id",
            "schema": {
              "type": "string",
              "pattern": "^c_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream 事件流",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "SSE 帧（event + data）"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat/sessions/{cid}/messages": {
      "get": {
        "summary": "会话消息历史",
        "description": "回填会话历史（重新打开会话时）。data 形状与 opencode 历史形状对齐（Eino 事件日志投影）。",
        "operationId": "getApiV1ChatSessionsCidMessages",
        "tags": [
          "chat"
        ],
        "parameters": [
          {
            "name": "cid",
            "in": "path",
            "required": true,
            "description": "chat 会话 id",
            "schema": {
              "type": "string",
              "pattern": "^c_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "description": "消息数组（opencode 兼容形状）"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "发送消息给 AI",
        "description": "把用户消息（含绑定模型时的系统上下文）异步交给进程内 Eino agent。返回 accepted=true 表示已受理，事件经 SSE 推送。",
        "operationId": "postApiV1ChatSessionsCidMessages",
        "tags": [
          "chat"
        ],
        "parameters": [
          {
            "name": "cid",
            "in": "path",
            "required": true,
            "description": "chat 会话 id",
            "schema": {
              "type": "string",
              "pattern": "^c_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/AcceptedResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body，text 必填非空",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostMessageBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/models": {
      "get": {
        "summary": "模型列表",
        "description": "列出全部模型，按 createdAt 降序（前端 2s 轮询直至所有模型脱离 converting）。",
        "operationId": "getApiV1Models",
        "tags": [
          "models"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ModelList"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "上传 IFC 模型",
        "description": "上传 IFC 文件并触发异步转换（→ converter 产出 XKT/metadata）。仅 `.ifc`，≤200MB。",
        "operationId": "postApiV1Models",
        "tags": [
          "models"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "ok（status=converting）",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Model"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误；超出大小上限",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "multipart/form-data：字段 file",
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": ".ifc 文件（≤200MB）"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}": {
      "delete": {
        "summary": "删除模型",
        "description": "删除该模型的 IFC、XKT、metadata、状态文件及 issues/changes/overrides。",
        "operationId": "deleteApiV1ModelsId",
        "tags": [
          "models"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok（data: null）",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "description": "始终为 null"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "模型详情",
        "description": "单模型详情，结构与列表项相同。",
        "operationId": "getApiV1ModelsId",
        "tags": [
          "models"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Model"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/changes": {
      "get": {
        "summary": "修改记录（change log）",
        "description": "按 createdAt 降序返回 ChangeEntry[]（无记录时为 `[]`）。",
        "operationId": "getApiV1ModelsIdChanges",
        "tags": [
          "overrides"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ChangeList"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/download": {
      "get": {
        "summary": "下载原始 IFC",
        "description": "下载原始 IFC 文件（非信封响应），带 Content-Disposition attachment。",
        "operationId": "getApiV1ModelsIdDownload",
        "tags": [
          "models"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "原始 .ifc 文件流",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/edit/diff": {
      "post": {
        "summary": "版本语义 diff（代理 edit-service）",
        "description": "代理 `POST /models/{id}/diff`：对比两个大版本快照（target 可为 \"current\" 表示 uploads 现态），返回 GlobalId 键的 added/removed/changed 属性级 diff。",
        "operationId": "postApiV1ModelsIdEditDiff",
        "tags": [
          "edit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/DiffResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "diff timed out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DiffBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/edit/history": {
      "get": {
        "summary": "编辑历史（代理 edit-service，只读）",
        "description": "代理 `GET /models/{id}/history`：持久化编辑历史（直改退役后只读保留历史数据）。",
        "operationId": "getApiV1ModelsIdEditHistory",
        "tags": [
          "edit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EditHistoryEntry"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/edit/pending": {
      "delete": {
        "summary": "丢弃 pending（代理 edit-service）",
        "description": "代理 `DELETE /models/{id}/pending`：丢弃全部 pending（卸载并从磁盘重载内存模型）。",
        "operationId": "deleteApiV1ModelsIdEditPending",
        "tags": [
          "edit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/DiscardedResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "当前 pending（代理 edit-service，只读）",
        "description": "代理 `GET /models/{id}/pending`：列出当前 pending（直改退役后仅供 script-run 回放簿记）。",
        "operationId": "getApiV1ModelsIdEditPending",
        "tags": [
          "edit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PendingEntry"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/edit/versions": {
      "get": {
        "summary": "版本快照列表（代理 edit-service）",
        "description": "代理 `GET /models/{id}/versions`：列出大版本快照（未提交前 versions=[]、current=null）。",
        "operationId": "getApiV1ModelsIdEditVersions",
        "tags": [
          "edit"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/EditVersionsResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/entities/{entityId}/properties": {
      "put": {
        "summary": "改写实体属性（metadata override）",
        "description": "属性修改走 metadata override（不改 IFC 本体）。fields 必填非空；字段名不在白名单返回 40001；空串值 = 清除该字段 override。每字段写一条 change log。返回该实体当前生效的 override 集合。",
        "operationId": "putApiV1ModelsIdEntitiesEntityIdProperties",
        "tags": [
          "overrides"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          },
          {
            "name": "entityId",
            "in": "path",
            "required": true,
            "description": "实体 id（IFC GlobalId）",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok（该实体当前生效 override）",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/OverrideFields"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PropertiesPatch"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/issues": {
      "get": {
        "summary": "Issue 列表",
        "description": "返回该模型全部 Issue，按 createdAt 降序。",
        "operationId": "getApiV1ModelsIdIssues",
        "tags": [
          "issues"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/IssueList"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "创建 Issue",
        "description": "multipart/form-data：`issue` 字段为 JSON 字符串（entityId/entityName/entityType/title/comment/author?/provenance?/camera?），title 必填；`screenshot` 可选 PNG ≤5MB。返回含生成的 id、status=open、默认 author/provenance 与 screenshot 相对路径。",
        "operationId": "postApiV1ModelsIdIssues",
        "tags": [
          "issues"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Issue"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误；超出大小上限",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "multipart/form-data：issue（JSON 字符串，必填）+ screenshot（PNG，≤5MB，可选）",
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "issue"
                ],
                "properties": {
                  "issue": {
                    "type": "string",
                    "description": "Issue JSON 字符串（见组件 IssueInput 结构）"
                  },
                  "screenshot": {
                    "type": "string",
                    "format": "binary",
                    "description": "PNG ≤5MB"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/issues/{issueId}": {
      "delete": {
        "summary": "删除 Issue",
        "description": "删除 Issue 及其截图文件。",
        "operationId": "deleteApiV1ModelsIdIssuesIssueId",
        "tags": [
          "issues"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          },
          {
            "name": "issueId",
            "in": "path",
            "required": true,
            "description": "issue id",
            "schema": {
              "type": "string",
              "pattern": "^i_[0-9a-f]{12}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok（data: null）",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "nullable": true,
                      "description": "始终为 null"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "更新 Issue",
        "description": "JSON body：title/comment/status 仅更新传入字段。",
        "operationId": "patchApiV1ModelsIdIssuesIssueId",
        "tags": [
          "issues"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          },
          {
            "name": "issueId",
            "in": "path",
            "required": true,
            "description": "issue id",
            "schema": {
              "type": "string",
              "pattern": "^i_[0-9a-f]{12}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Issue"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body（全字段可选）",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssuePatch"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/overrides": {
      "get": {
        "summary": "属性 Override 集合",
        "description": "返回全部 override：`{ [entityId]: { [field]: value } }`（无 override 时为 `{}`）。",
        "operationId": "getApiV1ModelsIdOverrides",
        "tags": [
          "overrides"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Overrides"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/retry": {
      "post": {
        "summary": "重试失败模型转换",
        "description": "仅 `failed` 模型可重试：重新入队转换并返回更新后的模型对象（status=converting）。",
        "operationId": "postApiV1ModelsIdRetry",
        "tags": [
          "models"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok（status=converting）",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Model"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script": {
      "get": {
        "summary": "当前脚本（代理 edit-service）",
        "description": "代理 `GET /models/{id}/script`：当前暂存脚本（或最后保存的大版本 base）。纯 IFC 上传的 legacy 模型无脚本 → 404。",
        "operationId": "getApiV1ModelsIdScript",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptStatus"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "暂存脚本（代理 edit-service）",
        "description": "代理 `PUT /models/{id}/script`：全量替换脚本或仅改 PARAMS 块（script/params 恰好二选一）。写入 WPS 式 10 步暂存链。",
        "operationId": "putApiV1ModelsIdScript",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptState"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StageScriptBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/diff": {
      "post": {
        "summary": "大版本脚本 diff（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/diff`：两大版本的 unified 文本 diff + PARAMS 变更 + 统计（AI 主要面向的 diff）。",
        "operationId": "postApiV1ModelsIdScriptDiff",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptDiffResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScriptDiffBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/discard": {
      "post": {
        "summary": "丢弃暂存（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/discard`：丢弃暂存编辑，回到最后保存的大版本（不产生版本）。",
        "operationId": "postApiV1ModelsIdScriptDiscard",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "modelId",
                        "discarded",
                        "script"
                      ],
                      "properties": {
                        "modelId": {
                          "type": "string"
                        },
                        "discarded": {
                          "type": "boolean"
                        },
                        "script": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/locate": {
      "get": {
        "summary": "定位 guid 脚本调用点（代理 edit-service）",
        "description": "代理 `GET /models/{id}/script/locate?guid=`：guid → designKey → 脚本调用点（行/列/片段）。miss 返回 200 {found:false}（不 5xx）。staging 与 map 分叉时降级 {found:false, stale:true}。",
        "operationId": "getApiV1ModelsIdScriptLocate",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          },
          {
            "name": "guid",
            "in": "query",
            "required": true,
            "description": "IFC GlobalId",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/LocateResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/params": {
      "get": {
        "summary": "脚本 PARAMS（代理 edit-service）",
        "description": "代理 `GET /models/{id}/script/params`：ast 提取当前脚本的 PARAMS dict（不执行）。",
        "operationId": "getApiV1ModelsIdScriptParams",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptParams"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/redo": {
      "post": {
        "summary": "重做暂存（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/redo`：前进一步暂存链（无可重做 → 409）。",
        "operationId": "postApiV1ModelsIdScriptRedo",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "modelId",
                        "script",
                        "canUndo"
                      ],
                      "properties": {
                        "modelId": {
                          "type": "string"
                        },
                        "script": {
                          "type": "string"
                        },
                        "canUndo": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/rollback": {
      "post": {
        "summary": "回滚到大版本（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/rollback`：恢复指定大版本的脚本到暂存并重新运行进 uploads。成功后排 XKT 重转。",
        "operationId": "postApiV1ModelsIdScriptRollback",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptRollbackResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RollbackBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/run": {
      "post": {
        "summary": "沙箱运行脚本（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/run`：沙箱运行当前暂存脚本并原子替换 uploads/{id}.ifc（不产生版本）。成功后排 XKT 重转（模型 status → converting）。沙箱最长 60s。",
        "operationId": "postApiV1ModelsIdScriptRun",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptRunResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/save": {
      "post": {
        "summary": "保存为大版本（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/save`：沙箱运行后快照 scripts/v{n}.py + versions/v{n}.ifc（原子、lockstep）。运行失败 → 422 且不产生版本。成功后排 XKT 重转。",
        "operationId": "postApiV1ModelsIdScriptSave",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptSaveResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body（可选）",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveBody"
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/staging/diff": {
      "get": {
        "summary": "暂存步骤小版本 diff（代理 edit-service）",
        "description": "代理 `GET /models/{id}/script/staging/diff`：暂存链步间 diff（默认最近两步）。query（from/to）原样透传。",
        "operationId": "getApiV1ModelsIdScriptStagingDiff",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "起始步骤下标（0-based，默认最新两步中的前一步）",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "结束步骤下标（默认最新一步）",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptDiffResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/script/undo": {
      "post": {
        "summary": "撤销暂存（代理 edit-service）",
        "description": "代理 `POST /models/{id}/script/undo`：回退一步暂存链（无可撤销 → 409）。",
        "operationId": "postApiV1ModelsIdScriptUndo",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "modelId",
                        "script",
                        "canRedo"
                      ],
                      "properties": {
                        "modelId": {
                          "type": "string"
                        },
                        "script": {
                          "type": "string"
                        },
                        "canRedo": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "状态冲突（无脚本可执行/无可撤销/暂存步骤不足等）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/models/{id}/scripts": {
      "get": {
        "summary": "大版本列表（代理 edit-service）",
        "description": "代理 `GET /models/{id}/scripts`：脚本大版本列表（legacy IFC-only 模型为空）。",
        "operationId": "getApiV1ModelsIdScripts",
        "tags": [
          "script"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScriptList"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{projectID}/{name}": {
      "get": {
        "summary": "读方案产物（plan.json / bim_supplement.json）",
        "description": "读项目下的方案产物当前态（plan/cad/ifc 共享项目资源）。name 白名单：plan.json / bim_supplement.json。未落盘 404。",
        "operationId": "getApiV1ProjectsProjectIDName",
        "tags": [
          "plan"
        ],
        "parameters": [
          {
            "name": "projectID",
            "in": "path",
            "required": true,
            "description": "项目 id（方案级存储键）",
            "schema": {
              "type": "string",
              "pattern": "^p_[0-9a-f]{16}$"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "产物名（plan.json|bim_supplement.json）",
            "schema": {
              "type": "string",
              "enum": [
                "plan.json",
                "bim_supplement.json"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "projectId": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "version": {
                          "type": "string",
                          "example": "v1"
                        },
                        "content": {
                          "type": "object"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "写方案产物（plan.json / bim_supplement.json，方案级版本化）",
        "description": "写项目下的方案产物并归档历史（plan_history/{name}/v{n}.json 递增）。body {content: <json 对象>}；content.project 必须 = projectID（共享 ID 对齐）。返回新版本名。",
        "operationId": "putApiV1ProjectsProjectIDName",
        "tags": [
          "plan"
        ],
        "parameters": [
          {
            "name": "projectID",
            "in": "path",
            "required": true,
            "description": "项目 id（方案级存储键）",
            "schema": {
              "type": "string",
              "pattern": "^p_[0-9a-f]{16}$"
            }
          },
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "产物名（plan.json|bim_supplement.json）",
            "schema": {
              "type": "string",
              "enum": [
                "plan.json",
                "bim_supplement.json"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "projectId": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "version": {
                          "type": "string",
                          "example": "v1"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body，content 为方案 JSON 对象",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "object",
                    "description": "方案产物（合法 JSON 对象；project 字段 = projectID）"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{projectID}/deliver": {
      "post": {
        "summary": "plan 交付（B2）——aiplan land 确定性 CLI 执行 → 落方案级目录",
        "description": "body {plan, bimSupplement} → 临时输入 → aiplan land（skill venv 可执行）→ 产出落方案级目录（PlanStore.Put 版本化）。aiplan 未配置 → 503。",
        "operationId": "postApiV1ProjectsProjectIDDeliver",
        "tags": [
          "plan"
        ],
        "parameters": [
          {
            "name": "projectID",
            "in": "path",
            "required": true,
            "description": "项目 id（方案级存储键）",
            "schema": {
              "type": "string",
              "pattern": "^p_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "projectId": {
                          "type": "string"
                        },
                        "planVersion": {
                          "type": "string"
                        },
                        "bimVersion": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "上游服务不可达或错误（edit-service / cad-edit-service）",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        },
        "requestBody": {
          "description": "JSON body，plan 与 bimSupplement 为方案 JSON 对象",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "plan": {
                    "type": "object",
                    "description": "plan.json（project 字段 = projectID）"
                  },
                  "bimSupplement": {
                    "type": "object",
                    "description": "bim_supplement.json（project 字段 = projectID）"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{projectID}/plan_history": {
      "get": {
        "summary": "列方案产物历史版本",
        "description": "列项目下某方案产物的历史版本（v{n} 升序）。query name 缺省 plan.json。",
        "operationId": "getApiV1ProjectsProjectIDPlan_history",
        "tags": [
          "plan"
        ],
        "parameters": [
          {
            "name": "projectID",
            "in": "path",
            "required": true,
            "description": "项目 id（方案级存储键）",
            "schema": {
              "type": "string",
              "pattern": "^p_[0-9a-f]{16}$"
            }
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "产物名（默认 plan.json）",
            "schema": {
              "type": "string",
              "enum": [
                "plan.json",
                "bim_supplement.json"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "projectId": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "history": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/projects/{projectID}/plan_history/{base}/{target}/diff": {
      "get": {
        "summary": "方案级 JSON diff（历史版本间 / 历史 vs current）",
        "description": "比较方案产物的两个版本（base/target 为 v{n} 或 current），返回字段级差异（add/remove/modify + 路径）。方案演化可追溯（B3）。",
        "operationId": "getApiV1ProjectsProjectIDPlan_historyBaseTargetDiff",
        "tags": [
          "plan"
        ],
        "parameters": [
          {
            "name": "projectID",
            "in": "path",
            "required": true,
            "description": "项目 id（方案级存储键）",
            "schema": {
              "type": "string",
              "pattern": "^p_[0-9a-f]{16}$"
            }
          },
          {
            "name": "base",
            "in": "path",
            "required": true,
            "description": "基准版本（v{n} 或 current）",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "target",
            "in": "path",
            "required": true,
            "description": "目标版本（v{n} 或 current）",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "产物名（默认 plan.json）",
            "schema": {
              "type": "string",
              "enum": [
                "plan.json",
                "bim_supplement.json"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "code",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "code": {
                      "type": "integer",
                      "enum": [
                        0
                      ]
                    },
                    "message": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "projectId": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "base": {
                          "type": "string"
                        },
                        "target": {
                          "type": "string"
                        },
                        "changes": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "op": {
                                "type": "string",
                                "enum": [
                                  "add",
                                  "remove",
                                  "modify"
                                ]
                              },
                              "path": {
                                "type": "string"
                              },
                              "before": {},
                              "after": {}
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "参数/校验错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "服务器内部错误",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models/{id}/issues/{file}": {
      "get": {
        "summary": "Issue 截图静态服务",
        "description": "非信封响应。`file` 必须匹配 `i_[0-9a-f]{12}\\.png`，否则 404。",
        "operationId": "getV1ModelsIdIssuesFile",
        "tags": [
          "static"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          },
          {
            "name": "file",
            "in": "path",
            "required": true,
            "description": "截图文件名",
            "schema": {
              "type": "string",
              "pattern": "^i_[0-9a-f]{12}\\.png$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PNG 图片",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models/{id}/metadata.json": {
      "get": {
        "summary": "模型元数据（xeokit 元模型）",
        "description": "非信封响应。converter 用 web-ifc 从原 IFC 提取的空间结构树 + 属性集，可直接作为 XKTLoaderPlugin.load({metaModelSrc}) 输入。",
        "operationId": "getV1ModelsIdMetadataJson",
        "tags": [
          "static"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "xeokit 元模型 JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "见 rest-api.md「metadata.json Schema」"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models/{id}/model.xkt": {
      "get": {
        "summary": "XKT 几何数据",
        "description": "非信封响应。XKT 二进制几何数据（支持 Range 请求）。",
        "operationId": "getV1ModelsIdModelXkt",
        "tags": [
          "static"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "XKT 二进制流",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/models/{id}/render.json": {
      "get": {
        "summary": "CAD 渲染数据（render payload v2）",
        "description": "非信封响应。services/cad 在 script/run、script/save 成功后原子发布的实体级渲染 JSON（schemaVersion 2，实体带 XDATA key），供前端 Canvas 2D 预览；仅 kind=dxf 模型存在。",
        "operationId": "getV1ModelsIdRenderJson",
        "tags": [
          "static"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "模型 id",
            "schema": {
              "type": "string",
              "pattern": "^m_[0-9a-f]{16}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "render payload v2 JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "见 rest-api.md「render.json Schema」"
                }
              }
            }
          },
          "404": {
            "description": "模型/Issue/会话/资源不存在",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Model": {
        "type": "object",
        "required": [
          "id",
          "name",
          "size",
          "status",
          "createdAt",
          "error"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$",
            "description": "模型 id"
          },
          "name": {
            "type": "string",
            "description": "文件名"
          },
          "size": {
            "type": "integer",
            "format": "int64",
            "description": "IFC 文件字节数"
          },
          "status": {
            "type": "string",
            "enum": [
              "converting",
              "ready",
              "failed"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO8601 UTC"
          },
          "error": {
            "type": "string",
            "description": "失败原因（ready 时为空串）"
          }
        }
      },
      "ModelList": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/Model"
        }
      },
      "Camera": {
        "type": "object",
        "required": [
          "eye",
          "look",
          "up"
        ],
        "properties": {
          "eye": {
            "type": "array",
            "minItems": 3,
            "maxItems": 3,
            "items": {
              "type": "number"
            }
          },
          "look": {
            "type": "array",
            "minItems": 3,
            "maxItems": 3,
            "items": {
              "type": "number"
            }
          },
          "up": {
            "type": "array",
            "minItems": 3,
            "maxItems": 3,
            "items": {
              "type": "number"
            }
          }
        }
      },
      "Provenance": {
        "type": "object",
        "required": [
          "source"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "UI",
              "AI",
              "USER"
            ],
            "description": "变更来源"
          },
          "origin": {
            "type": "string"
          }
        }
      },
      "Issue": {
        "type": "object",
        "required": [
          "id",
          "entityId",
          "entityName",
          "entityType",
          "title",
          "comment",
          "status",
          "author",
          "provenance",
          "camera",
          "screenshot",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^i_[0-9a-f]{12}$",
            "description": "issue id"
          },
          "entityId": {
            "type": "string"
          },
          "entityName": {
            "type": "string"
          },
          "entityType": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "comment": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "checking",
              "resolved"
            ]
          },
          "author": {
            "type": "string",
            "description": "默认 local-user"
          },
          "provenance": {
            "$ref": "#/components/schemas/Provenance"
          },
          "camera": {
            "$ref": "#/components/schemas/Camera"
          },
          "screenshot": {
            "type": "string",
            "description": "相对路径 issues/{id}.png，无截图时为空串"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "IssueList": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/Issue"
        }
      },
      "IssuePatch": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "comment": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "checking",
              "resolved"
            ]
          }
        },
        "description": "仅更新传入字段；title 清空后非空才合法"
      },
      "IssueInput": {
        "type": "object",
        "required": [
          "entityId",
          "entityName",
          "entityType",
          "title",
          "comment"
        ],
        "properties": {
          "entityId": {
            "type": "string"
          },
          "entityName": {
            "type": "string"
          },
          "entityType": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "comment": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "provenance": {
            "$ref": "#/components/schemas/Provenance"
          },
          "camera": {
            "$ref": "#/components/schemas/Camera"
          }
        }
      },
      "ChangeEntry": {
        "type": "object",
        "required": [
          "id",
          "entityId",
          "entityName",
          "field",
          "oldValue",
          "newValue",
          "author",
          "provenance",
          "operation",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^c_[0-9a-f]{12}$",
            "description": "change id"
          },
          "entityId": {
            "type": "string"
          },
          "entityName": {
            "type": "string"
          },
          "field": {
            "type": "string",
            "description": "白名单字段：Name/Description/Classification/FireRating/Comments"
          },
          "oldValue": {
            "type": "string",
            "description": "被覆盖前的值"
          },
          "newValue": {
            "type": "string",
            "description": "空字符串 = 清除该字段 override"
          },
          "author": {
            "type": "string"
          },
          "provenance": {
            "$ref": "#/components/schemas/Provenance"
          },
          "operation": {
            "type": "string",
            "enum": [
              "update"
            ]
          },
          "diff": {
            "type": "object",
            "description": "脚本 diff（optional）"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ChangeList": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/ChangeEntry"
        }
      },
      "OverrideFields": {
        "type": "object",
        "additionalProperties": {
          "type": "string"
        },
        "description": "entityId → 字段 → 值 的 override 集合"
      },
      "Overrides": {
        "type": "object",
        "additionalProperties": {
          "$ref": "#/components/schemas/OverrideFields"
        },
        "description": "全部 override：{ [entityId]: { [field]: value } }，无 override 时为 {}"
      },
      "PropertiesPatch": {
        "type": "object",
        "required": [
          "fields"
        ],
        "properties": {
          "entityName": {
            "type": "string"
          },
          "fields": {
            "type": "object",
            "minProperties": 1,
            "additionalProperties": {
              "type": "string"
            },
            "description": "字段名 ∈ {Name, Description, Classification, FireRating, Comments}；空串值 = 清除 override"
          },
          "author": {
            "type": "string",
            "description": "默认 local-user"
          },
          "provenance": {
            "$ref": "#/components/schemas/Provenance"
          }
        }
      },
      "ChatSession": {
        "type": "object",
        "required": [
          "chatSessionId",
          "opencodeSessionId",
          "modelId",
          "title",
          "createdAt"
        ],
        "properties": {
          "chatSessionId": {
            "type": "string",
            "pattern": "^c_[0-9a-f]{16}$"
          },
          "opencodeSessionId": {
            "type": "string",
            "description": "历史字段名（契约兼容保留）；Eino 接管后语义为 agent 会话 ID"
          },
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$",
            "description": "空串 = 未绑定模型"
          },
          "title": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ChatSessionList": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/ChatSession"
        }
      },
      "CreateSessionBody": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "默认 \"chat\""
          },
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$",
            "description": "绑定模型；同 modelId 幂等复用已有会话"
          }
        }
      },
      "PostMessageBody": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1
          }
        }
      },
      "ScriptStatus": {
        "type": "object",
        "required": [
          "modelId",
          "script",
          "staged",
          "canUndo",
          "canRedo",
          "maxSteps"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "script": {
            "type": "string"
          },
          "staged": {
            "type": "integer",
            "minimum": 0
          },
          "canUndo": {
            "type": "boolean"
          },
          "canRedo": {
            "type": "boolean"
          },
          "maxSteps": {
            "type": "integer"
          }
        }
      },
      "StageScriptBody": {
        "type": "object",
        "properties": {
          "script": {
            "type": "string",
            "description": "脚本全文（与 params 恰好二选一）"
          },
          "params": {
            "type": "object",
            "description": "PARAMS 块改写（与 script 恰好二选一）"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "ScriptState": {
        "type": "object",
        "required": [
          "modelId",
          "staged",
          "canUndo",
          "canRedo"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "staged": {
            "type": "integer",
            "minimum": 0
          },
          "canUndo": {
            "type": "boolean"
          },
          "canRedo": {
            "type": "boolean"
          }
        }
      },
      "ScriptParams": {
        "type": "object",
        "required": [
          "modelId",
          "params"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "params": {
            "type": "object"
          }
        }
      },
      "ScriptVersionInfo": {
        "type": "object",
        "required": [
          "version",
          "createdAt"
        ],
        "properties": {
          "version": {
            "type": "string",
            "pattern": "^v\\d+$"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "ScriptList": {
        "type": "object",
        "required": [
          "modelId",
          "scripts",
          "versions"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "scripts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScriptVersionInfo"
            }
          },
          "versions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScriptVersionInfo"
            }
          }
        }
      },
      "ScriptRunResult": {
        "type": "object",
        "required": [
          "modelId",
          "ok"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "ok": {
            "type": "boolean",
            "const": true
          },
          "semanticDiff": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SemanticDiffCounts"
              },
              {
                "type": "null"
              }
            ],
            "description": "构件级 {added, removed, changed} 计数（旧 uploads 产物 vs 本次 run）；diff 失败/首次 run 无旧产物时为 null"
          }
        }
      },
      "SemanticDiffCounts": {
        "type": "object",
        "required": [
          "added",
          "removed",
          "changed"
        ],
        "properties": {
          "added": {
            "type": "integer"
          },
          "removed": {
            "type": "integer"
          },
          "changed": {
            "type": "integer"
          }
        }
      },
      "SaveBody": {
        "type": "object",
        "properties": {
          "note": {
            "type": "string"
          }
        }
      },
      "ScriptSaveResult": {
        "type": "object",
        "required": [
          "modelId",
          "version",
          "staged",
          "alignment"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "version": {
            "type": "string",
            "pattern": "^v\\d+$"
          },
          "staged": {
            "type": "integer",
            "minimum": 0
          },
          "alignment": {
            "type": "object",
            "nullable": true,
            "properties": {
              "added": {
                "type": "integer"
              },
              "removed": {
                "type": "integer"
              },
              "changed": {
                "type": "integer"
              }
            }
          }
        }
      },
      "RollbackBody": {
        "type": "object",
        "required": [
          "version"
        ],
        "properties": {
          "version": {
            "type": "string",
            "pattern": "^v\\d+$"
          }
        }
      },
      "ScriptRollbackResult": {
        "type": "object",
        "required": [
          "modelId",
          "version",
          "script"
        ],
        "properties": {
          "modelId": {
            "type": "string",
            "pattern": "^m_[0-9a-f]{16}$"
          },
          "version": {
            "type": "string",
            "pattern": "^v\\d+$"
          },
          "script": {
            "type": "string"
          }
        }
      },
      "ScriptDiffBody": {
        "type": "object",
        "required": [
          "base",
          "target"
        ],
        "properties": {
          "base": {
            "type": "string",
            "pattern": "^v\\d+$"
          },
          "target": {
            "type": "string",
            "pattern": "^v\\d+$"
          }
        }
      },
      "ScriptDiffResult": {
        "type": "object",
        "required": [
          "base",
          "target",
          "engine"
        ],
        "properties": {
          "base": {
            "type": "string"
          },
          "target": {
            "type": "string"
          },
          "engine": {
            "type": "string",
            "const": "script"
          },
          "diff": {
            "type": "string",
            "description": "unified 文本 diff"
          },
          "params": {
            "type": "object",
            "description": "PARAMS 变更"
          },
          "stats": {
            "type": "object",
            "description": "diff 统计"
          },
          "buildingChanges": {
            "type": [
              "array",
              "null"
            ],
            "description": "building.json 交付索引字段级差异（两侧均有 sidecar 时非空；否则 null）",
            "items": {
              "type": "object",
              "properties": {
                "op": {
                  "type": "string",
                  "enum": [
                    "add",
                    "remove",
                    "modify"
                  ]
                },
                "path": {
                  "type": "string"
                },
                "before": {},
                "after": {}
              }
            }
          }
        }
      },
      "LocateResult": {
        "type": "object",
        "required": [
          "found"
        ],
        "properties": {
          "found": {
            "type": "boolean"
          },
          "designKey": {
            "type": "string"
          },
          "stale": {
            "type": "boolean",
            "description": "staging 与 map 分叉，行号不可信"
          },
          "line": {
            "type": "integer"
          },
          "col": {
            "type": "integer"
          },
          "snippet": {
            "type": "string"
          },
          "origin": {
            "type": "string"
          }
        }
      },
      "DiffBody": {
        "type": "object",
        "required": [
          "base",
          "target"
        ],
        "properties": {
          "base": {
            "type": "string",
            "pattern": "^v\\d+$"
          },
          "target": {
            "type": "string",
            "description": "版本号或 \"current\"（uploads 现态）"
          }
        }
      },
      "DiffResult": {
        "type": "object",
        "required": [
          "base",
          "target"
        ],
        "properties": {
          "base": {
            "type": "string"
          },
          "target": {
            "type": "string"
          },
          "added": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "新增 GlobalId"
          },
          "removed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "删除 GlobalId"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "guid": {
                  "type": "string"
                },
                "changes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string"
                      },
                      "old": {},
                      "new": {}
                    }
                  }
                }
              }
            }
          }
        }
      },
      "EditVersionsResult": {
        "type": "object",
        "required": [
          "versions",
          "current"
        ],
        "properties": {
          "versions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScriptVersionInfo"
            }
          },
          "current": {
            "type": "string",
            "nullable": true,
            "description": "最新版本号（无任何提交时为 null）"
          }
        }
      },
      "PendingEntry": {
        "type": "object",
        "additionalProperties": true,
        "description": "pending 项（L1 直改退役后仅供 script-run 回放簿记，形状以运行服务为准）"
      },
      "EditHistoryEntry": {
        "type": "object",
        "additionalProperties": true,
        "description": "持久化编辑历史条目（含 operation 字段；直改退役后只读保留）"
      },
      "AbortResult": {
        "type": "object",
        "required": [
          "aborted"
        ],
        "properties": {
          "aborted": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "AcceptedResult": {
        "type": "object",
        "required": [
          "accepted"
        ],
        "properties": {
          "accepted": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "DiscardedResult": {
        "type": "object",
        "required": [
          "discarded"
        ],
        "properties": {
          "discarded": {
            "type": "integer"
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "业务错误码（≠0）"
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "null"
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "可选：默认鉴权关闭；启用（VIEWER_API_TOKEN 非空）后需 Bearer 令牌。"
      }
    }
  }
}
