# 实用新型结构线稿（成文前必做）

**公共合同先读**：`prompts/shared/image_gen.md`（线稿只有两条路；CAD 不得当线稿、不得入文）  
**本文件合同**：`references/schemas/structure_lineart_brief.schema.yaml`  
**前置**：已有或本轮将写出的 `structure_schema.yaml` + `figure_plan.yaml`（见 `fill_structure_schema.md`）  
**与外观分流**：外观用 `design_lineart_assist.md`；禁止混用。

## 开关

- **默认开启**。不问用户。仅当用户**已经明确说不要线稿**，或 `PATENT_SKILL_SKIP_LINEART=1`，才整段跳过。  
- **禁止**把 CAD / STEP 投影、实拍当成线稿入文。CAD 只当普通材料打分，分数够才可能作图生图参考。

## 步骤

### 0. 规划途经

```bash
python ${CLAUDE_SKILL_DIR}/tools/shared/image_gen.py --case-dir "outputs/{案件标识}"
```

| mode | 做什么 |
|------|--------|
| `existing_lineart` | 材料已有合格 `kind: lineart`：入文这些 path；仍须按 `parts` overlay 件号（若原图无号） |
| `img2img` | 有合格参考图（含高分 CAD/实拍）→ 写 brief → 门禁 → 图生图轮廓；失败则先描述再文生图 |
| `txt2img` | 无过线参考图 → 写 brief（`source_paths` 可空）→ 按 StructureSchema 文生图 |

### 1. 读 YAML，联读多视 + 统一件号

1. **`Read`** `structure_schema.yaml`（或 json）与 `figure_plan.yaml`。  
2. 按 `figure_plan.relates_to` 联读总装/局部；**跨图同一 `parts.id`**。  
3. **`Write`** `structure_lineart_brief.yaml`：  
   - `enabled: true`  
   - `structure_summary` / `parts_legend` 对齐 StructureSchema（`id`+`name` 不得改号）  
   - `callout_mode` 默认 **`overlay`**  
   - 有参考图则填存在的 `source_paths`；无参考图可空。`visible_part_ids` 为本视可见件  
   - `gen_prompt`：黑白结构线稿、不发明未见结构；默认不要让模型自由编造序号（留给 overlay）  
   - `uncertain` 中的件不得列入本视必标序号

### 2. 门禁

```bash
python ${CLAUDE_SKILL_DIR}/tools/shared/structure_lineart_gate.py \
  --case-dir "outputs/{案件标识}" --prepare-jobs
```

缺少 Structure / `visible_part_ids` 不在 `parts` → 拒绝。  
成功则写出 `lineart_assist/structure_lineart_jobs.json`。

### 3. 出图（轮廓 → 锚点 → 叠标 → 语义自查）

对每一 job：

1. **轮廓层**（`mode` 不是 `existing_lineart` 时）：按 `image_gen.md` 图生图或「先描述再文生图」或文生图，写入 `output_path`。  
2. **锚点定位**（`callout_mode: overlay`）：大模型读取已经生成的**无号轮廓图**，逐个定位 job `callouts` 对应部件；把归一化 `anchor`、附近留白区 `label`、`confidence` 持久化到案件目录 `structure_callout_anchors.yaml`。合同见 `references/schemas/structure_callout_anchors.schema.yaml`。锚点须落在对应部件轮廓上或紧邻轮廓，序号应围绕结构就近分散，禁止全部排到画布边缘。
3. **精确叠标**：运行：

```bash
python ${CLAUDE_SKILL_DIR}/tools/shared/structure_callout_overlay.py \
  --case-dir "outputs/{案件标识}" \
  --anchors "outputs/{案件标识}/structure_callout_anchors.yaml"
```

Python 只校验件号合法、坐标 0..1、置信度与 label 间距；**不判断标没标对部件**。结果写入 `output_svg_path`。需要 PNG 时再用 `svg_screenshot.py --svg … --png …`。

4. **叠标后语义自查（必做，最多 2 轮校正）**：Python 通过 ≠ 图面对。须 **`Read` 叠标后的 PNG/SVG**（不要只看无号轮廓），对照本视 `visible_part_ids` + `structure_schema.parts` 的 **id+名称**：

   | 查什么 | 不合格则 |
   |--------|----------|
   | 每个必标件号是否都在图上 | 补锚点后重叠标 |
   | 引出线末端是否落在**该名称对应的构造**上（不是邻件） | 改 `anchor`/`label`，禁止改件号 |
   | 相邻易混件是否对调（腔体↔腔内件、轴↔转子、接头↔法兰、剖切符号↔零件） | 按名称把锚点挪到正确轮廓 |
   | 图上有号但 `visible_part_ids` 没有的 | 删该 callout，禁止自创件号 |
   | 序号全贴画布边缘、引出线全竖直/全水平 | 把 label 就近散开，改 `route` |

   校正只改 `structure_callout_anchors.yaml` 再跑 `structure_callout_overlay.py`（及必要时 `svg_screenshot.py`）。**禁止**为纠件号而二次文生图/图生图改轮廓。两轮后仍对不上的件写入 `uncertain` 或从本视 `visible_part_ids` 拿掉，不得硬标。

5. **`in_prompt` 降级**：仅当无法叠图时，把可见件号列表写入提示；生成后对照 `parts_legend`，错号则重做或改 overlay。
6. **`contour_only`**：只出无号轮廓；正文用部件表说明。

### 4. 回写 figure_plan

**生成（或合格已有）线稿默认入文**。CAD / 实拍条 `use_in_disclosure: false`。

```yaml
- fig: 1
  role: assembly
  path: lineart_assist/….png   # 优先带 callouts 的路径
  covers: ["1", "2", "总装"]
  kind: lineart
  relevance: 80
  quality: 80
  score: 80
  use_in_disclosure: true
  reason: 大模型生成的结构线稿（件号对齐 StructureSchema）
  relates_to: []
```

有总装+局部对时，补写 `relates_to: detail_of`。CAD 条不得改成入文。

### 5. 成文纪律

- 正文「如图 N」只引用合格线稿。  
- **禁止**把 CAD 投影写成线稿或入文。  
- **禁止**写成「已按国知局规范绘制的正式附图」。  
- 第三章部件表件号须与图上序号、`structure_schema.parts` 一致。

## 自检（内部）

- [ ] 已跑 `image_gen.py`；CAD 未当合格线稿、未入文  
- [ ] `parts_legend` / 图上件号与 StructureSchema 一致；跨图未改号  
- [ ] `structure_callout_anchors.yaml` 已落盘；已 Read 叠标后的图；件号与部件名称一一对应（非仅坐标合法）；label 就近分散，引出方向不单一；校正只改 YAML 重叠标
- [ ] `uncertain` 件未画死序号  
- [ ] 优先 overlay；未自创件号  
- [ ] 未误用 `design_lineart_*`  
