@ -1,63 +1,63 @@
# FreeCAD Electrical Auto Routing Implementation Plan
# FreeCAD 电气自动布线实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
> ** 给智能代理执行者:** 必须使用 `superpowers:subagent-driven-development` (推荐)或 `superpowers:executing-plans` ,按任务逐项实施本计划。步骤使用复选框(`- [ ]`)语法跟踪。
**Goal:** Finish the first production-ready FreeCAD electrical auto-routing loop from QET `wires[]` tasks to saved `AutoSuggested` 3D wires with actionable diagnostics.
**目标:** 完成第一版可落地的 FreeCAD 电气自动布线闭环:从 QET `wires[]` 导线任务,到可保存的 `AutoSuggested` 3D 导线,并提供可操作诊断。
**Architecture:** Keep FreeCAD as the 3D truth source and QET as the electrical truth source. QET exports richer `wires[]` task metadata; FreeCAD consumes that task list, prepares a route-carrier graph, runs Dijkstra, stores routed wires and diagnostics in `scene.FCStd` , and never writes 3D wire geometry into the database.
**架构:** FreeCAD 作为 3D 状态真相源, QET 作为电气连接真相源。QET 导出更完整的 `wires[]` 任务元数据; FreeCAD 消费任务列表,准备布线 carrier 图,运行 Dijkstra, 随后把已布导线和诊断保存在 `scene.FCStd` 中,不把 3D 导线几何写入数据库。
**Tech Stack:** FreeCAD Python API, Qt/C++ QET export service, JSON exchange files, `unittest` , fake FreeCAD test harness, FreeCAD smoke scripts.
**技术栈:** FreeCAD Python API、Qt/C++ QET 导出服务、JSON 交换文件、`unittest`、伪 FreeCAD 测试框架、FreeCAD smoke 脚本。
---
---
## Scope Check
## 范围检查
The approved spec touches two repos, but the work is still one coherent feature because QET only supplies task metadata and FreeCAD owns all routing behavior. Treat the QET change as a small upstream contract task. Do not run QET build commands in `D:\code\zwl` ; that repo's `AGENTS.md` forbids build, cmake, make, and ninja.
已批准的规格涉及两个仓库, 但这仍是一个完整功能: QET 只提供任务元数据, FreeCAD 负责全部布线行为。把 QET 修改视为一个很小的上游数据契约任务。不要在 `D:\code\zwl` 中运行 QET 构建命令;该仓库的 `AGENTS.md` 禁止 build、cmake、make 和 ninja。
## File Structure
## 文件结构
- Modify: `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp`
- 修改: `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp`
- Responsibility: include `start_instance_id` and `end_instance_id` in exported `wires[]` entries so FreeCAD can bind local template terminals more reliably.
- 职责:在导出的 `wires[]` 条目中包含 `start_instance_id` 和 `end_instance_id` ,让 FreeCAD 更可靠地绑定本地模板端子。
- Modify: `src/Mod/FreeCADExchange/WiringImport.py`
- 修改:`src/Mod/FreeCADExchange/WiringImport.py`
- Responsibility: preserve `wire_style_id` , start/end instance IDs, and endpoint display metadata on `QETWiring_01_Tasks` .
- 职责:在 `QETWiring_01_Tasks` 上保留 `wire_style_id` 、起止 `instance_id` 和端点显示元数据。
- Modify: `src/Mod/FreeCADExchange/WiringObjects.py`
- 修改:`src/Mod/FreeCADExchange/WiringObjects.py`
- Responsibility: provide shared helpers for wire task/routed wire metadata, including route length and diagnostic payload fields.
- 职责:提供导线任务和已布导线元数据的共享辅助函数,包括路径长度和诊断 payload 字段。
- Modify: `src/Mod/FreeCADExchange/AutoRouting.py`
- 修改:`src/Mod/FreeCADExchange/AutoRouting.py`
- Responsibility: compute route length, carry `wire_style_id` , create diagnostic summaries, and enrich batch reports.
- 职责:计算路径长度、携带 `wire_style_id` 、创建诊断摘要并增强批量报告。
- Modify: `src/Mod/FreeCADExchange/AutoRoutingPanel.py`
- 修改:`src/Mod/FreeCADExchange/AutoRoutingPanel.py`
- Responsibility: show the improved batch summary without adding extra workflow steps.
- 职责:显示增强后的批量摘要,不增加额外工作流步骤。
- Modify: `tests/python/freecad_exchange_wiring_import_test.py`
- 修改: `tests/python/freecad_exchange_wiring_import_test.py`
- Responsibility: lock `wires[]` task import metadata.
- 职责:锁定 `wires[]` 任务导入元数据行为。
- Modify: `tests/python/freecad_exchange_auto_routing_test.py`
- 修改: `tests/python/freecad_exchange_auto_routing_test.py`
- Responsibility: lock auto-route metadata, diagnostic group output, and one-click reporting.
- 职责:锁定自动布线元数据、诊断分组输出和一键报告行为。
- Modify: `tests/manual/freecad_auto_routing_smoke.py`
- 修改:`tests/manual/freecad_auto_routing_smoke.py`
- Responsibility: verify the end-to-end FreeCAD document can save, reopen, and retain auto routes.
- 职责:验证端到端 FreeCAD 文档可以保存、重开并保留自动布线结果。
## Task 1: Add QET wire endpoint instance IDs to `wires[]`
## 任务 1: 给 QET `wires[]` 增加导线端点 instance ID
**Files: **
**文件: **
- Modify: `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp:412-477`
- 修改: `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp:412-477`
- Modify: `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp:928`
- 修改: `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp:928`
- [ ] **Step 1: Confirm the current export gap **
- [ ] ** 步骤 1: 确认当前导出缺口 **
Run:
运行:
```powershell
```powershell
rg -n "start_instance_id|end_instance_id|buildWireObjectsForDiagram" D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp
rg -n "start_instance_id|end_instance_id|buildWireObjectsForDiagram" D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp
```
```
Expected before this task: `buildWireObjectsForDiagram` exists, but `start_instance_id` and `end_instance_id` are not inserted into `wireObject` .
本任务开始前的预期:`buildWireObjectsForDiagram` 存在,但 `start_instance_id` 和 `end_instance_id` 尚未插入 `wireObject` 。
- [ ] **Step 2: Change the function signature **
- [ ] ** 步骤 2: 修改函数签名 **
In `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp` , change the function header from:
在 `D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp` 中,将函数头从:
```cpp
```cpp
QJsonArray buildWireObjectsForDiagram(Diagram *diagram)
QJsonArray buildWireObjectsForDiagram(Diagram *diagram)
```
```
to:
改为:
```cpp
```cpp
QJsonArray buildWireObjectsForDiagram(
QJsonArray buildWireObjectsForDiagram(
@ -65,9 +65,9 @@ QJsonArray buildWireObjectsForDiagram(
const QHash< QUuid , QString > & terminalInstanceIds)
const QHash< QUuid , QString > & terminalInstanceIds)
```
```
- [ ] **Step 3: Insert endpoint instance IDs **
- [ ] ** 步骤 3: 插入端点 instance ID **
Inside the loop that builds `wireObject` , immediately after the existing terminal UUID inserts, add:
在构建 `wireObject` 的循环中,紧跟现有端子 UUID 插入逻辑之后添加:
```cpp
```cpp
const QString startInstanceId = terminalInstanceIds.value(startTerminalUuid).trimmed();
const QString startInstanceId = terminalInstanceIds.value(startTerminalUuid).trimmed();
@ -76,7 +76,7 @@ wireObject.insert(QStringLiteral("start_instance_id"), startInstanceId);
wireObject.insert(QStringLiteral("end_instance_id"), endInstanceId);
wireObject.insert(QStringLiteral("end_instance_id"), endInstanceId);
```
```
The surrounding block should read:
周围代码块应为:
```cpp
```cpp
wireObject.insert(QStringLiteral("start_element_uuid"), uuidText(startElementUuid));
wireObject.insert(QStringLiteral("start_element_uuid"), uuidText(startElementUuid));
@ -87,33 +87,33 @@ wireObject.insert(QStringLiteral("end_terminal_uuid"), uuidText(endTerminalUuid)
wireObject.insert(QStringLiteral("end_instance_id"), endInstanceId);
wireObject.insert(QStringLiteral("end_instance_id"), endInstanceId);
```
```
- [ ] **Step 4: Pass the binding map from the exporter **
- [ ] ** 步骤 4: 从导出器传入绑定映射 **
Replace:
将:
```cpp
```cpp
wiresArray = buildWireObjectsForDiagram(diagram);
wiresArray = buildWireObjectsForDiagram(diagram);
```
```
with:
替换为:
```cpp
```cpp
wiresArray = buildWireObjectsForDiagram(diagram, terminalInstanceIds);
wiresArray = buildWireObjectsForDiagram(diagram, terminalInstanceIds);
```
```
- [ ] **Step 5: Run static verification **
- [ ] ** 步骤 5: 运行静态验证 **
Run:
运行:
```powershell
```powershell
rg -n "start_instance_id|end_instance_id|buildWireObjectsForDiagram\\(" D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp
rg -n "start_instance_id|end_instance_id|buildWireObjectsForDiagram\\(" D:\code\zwl\sources\FreeCAD\FreeCADExchangeExportService.cpp
```
```
Expected: one function definition with the new parameter, one call that passes `terminalInstanceIds` , and two JSON inserts for `start_instance_id` / `end_instance_id` .
预期:一个带新参数的函数定义,一个传入 `terminalInstanceIds` 的调用,以及两个 `start_instance_id` / `end_instance_id` JSON 插入点。
- [ ] **Step 6: Commit the QET contract change **
- [ ] ** 步骤 6: 提交 QET 契约修改 **
Run in `D:\code\zwl` :
在 `D:\code\zwl` 中运行:
```powershell
```powershell
git status --short
git status --short
@ -121,19 +121,19 @@ git add -- sources/FreeCAD/FreeCADExchangeExportService.cpp
git commit -m "feat: export freecad wire endpoint instances"
git commit -m "feat: export freecad wire endpoint instances"
```
```
Expected: the commit contains only `sources/FreeCAD/FreeCADExchangeExportService.cpp` .
预期:该提交只包含 `sources/FreeCAD/FreeCADExchangeExportService.cpp` 。
## Task 2: Preserve wire style and endpoint metadata on FreeCAD tasks
## 任务 2: 在 FreeCAD 任务上保留导线样式和端点元数据
**Files: **
**文件: **
- Modify: `src/Mod/FreeCADExchange/WiringImport.py:47-109`
- 修改:`src/Mod/FreeCADExchange/WiringImport.py:47-109`
- Modify: `src/Mod/FreeCADExchange/WiringImport.py:145-190`
- 修改:`src/Mod/FreeCADExchange/WiringImport.py:145-190`
- Modify: `src/Mod/FreeCADExchange/WiringObjects.py:181-213`
- 修改: `src/Mod/FreeCADExchange/WiringObjects.py:181-213`
- Test: `tests/python/freecad_exchange_wiring_import_test.py`
- 测试: `tests/python/freecad_exchange_wiring_import_test.py`
- [ ] **Step 1: Write the failing import test **
- [ ] ** 步骤 1: 编写失败的导入测试 **
Add this test to `tests/python/freecad_exchange_wiring_import_test.py` inside `WiringImportTest` :
把此测试添加到 `tests/python/freecad_exchange_wiring_import_test.py` 的 `WiringImportTest` 中:
```python
```python
def test_import_wire_tasks_preserves_auto_routing_metadata(self):
def test_import_wire_tasks_preserves_auto_routing_metadata(self):
@ -174,19 +174,19 @@ Add this test to `tests/python/freecad_exchange_wiring_import_test.py` inside `W
self.assertEqual("B1", task.QetEndTerminalDisplay)
self.assertEqual("B1", task.QetEndTerminalDisplay)
```
```
- [ ] **Step 2: Run the test and verify it fails **
- [ ] ** 步骤 2: 运行测试并确认失败 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_wiring_import_test.WiringImportTest.test_import_wire_tasks_preserves_auto_routing_metadata
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_wiring_import_test.WiringImportTest.test_import_wire_tasks_preserves_auto_routing_metadata
```
```
Expected: FAIL because `QetWireStyleId` is not set.
预期: FAIL, 因为尚未设置 `QetWireStyleId` 。
- [ ] **Step 3: Extend normalized wire entries **
- [ ] ** 步骤 3: 扩展规范化后的导线条目 **
In `src/Mod/FreeCADExchange/WiringImport.py` , add this helper near `_bool_value` :
在 `src/Mod/FreeCADExchange/WiringImport.py` 中,把此辅助函数添加到 `_bool_value` 附近:
```python
```python
def _int_text_value(item, field_name):
def _int_text_value(item, field_name):
@ -199,62 +199,62 @@ def _int_text_value(item, field_name):
return str(value).strip()
return str(value).strip()
```
```
Then add this field in `_normalize_wire_entry` :
然后在 `_normalize_wire_entry` 中添加此字段:
```python
```python
"wire_style_id": _int_text_value(item, "wire_style_id"),
"wire_style_id": _int_text_value(item, "wire_style_id"),
```
```
- [ ] **Step 4: Persist the style ID on tasks **
- [ ] ** 步骤 4: 在任务上持久化样式 ID **
In `_set_task_extra_properties` , add:
在 `_set_task_extra_properties` 中添加:
```python
```python
_ensure_string_property(task, "QetWireStyleId", entry["wire_style_id"])
_ensure_string_property(task, "QetWireStyleId", entry["wire_style_id"])
```
```
- [ ] **Step 5: Run the import test again **
- [ ] ** 步骤 5: 再次运行导入测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_wiring_import_test.WiringImportTest.test_import_wire_tasks_preserves_auto_routing_metadata
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_wiring_import_test.WiringImportTest.test_import_wire_tasks_preserves_auto_routing_metadata
```
```
Expected: PASS.
预期: PASS。
- [ ] **Step 6: Run the wiring import test file **
- [ ] ** 步骤 6: 运行导入测试文件 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_wiring_import_test
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_wiring_import_test
```
```
Expected: all tests in the file pass.
预期:该文件中的全部测试通过。
- [ ] **Step 7: Commit **
- [ ] ** 步骤 7: 提交 **
Run:
运行:
```powershell
```powershell
git add src/Mod/FreeCADExchange/WiringImport.py tests/python/freecad_exchange_wiring_import_test.py
git add src/Mod/FreeCADExchange/WiringImport.py tests/python/freecad_exchange_wiring_import_test.py
git commit -m "feat: preserve freecad wire task metadata"
git commit -m "feat: preserve freecad wire task metadata"
```
```
Expected: the commit contains the import code and its test.
预期:该提交包含导入代码及对应测试。
## Task 3: Store auto-route length and wire style diagnostics
## 任务 3: 保存自动布线路径长度和导线样式诊断
**Files: **
**文件: **
- Modify: `src/Mod/FreeCADExchange/AutoRouting.py:260-300`
- 修改:`src/Mod/FreeCADExchange/AutoRouting.py:260-300`
- Modify: `src/Mod/FreeCADExchange/AutoRouting.py:860-970`
- 修改:`src/Mod/FreeCADExchange/AutoRouting.py:860-970`
- Modify: `src/Mod/FreeCADExchange/AutoRouting.py:1169-1190`
- 修改: `src/Mod/FreeCADExchange/AutoRouting.py:1169-1190`
- Test: `tests/python/freecad_exchange_auto_routing_test.py`
- 测试: `tests/python/freecad_exchange_auto_routing_test.py`
- [ ] **Step 1: Write the failing routed-wire metadata test **
- [ ] ** 步骤 1: 编写失败的已布导线元数据测试 **
Add this test to `tests/python/freecad_exchange_auto_routing_test.py` inside `AutoRoutingTest` :
把此测试添加到 `tests/python/freecad_exchange_auto_routing_test.py` 的 `AutoRoutingTest` 中:
```python
```python
def test_auto_route_stores_length_and_wire_style_diagnostics(self):
def test_auto_route_stores_length_and_wire_style_diagnostics(self):
@ -289,25 +289,25 @@ Add this test to `tests/python/freecad_exchange_auto_routing_test.py` inside `Au
self.assertGreater(payload["length_mm"], 0.0)
self.assertGreater(payload["length_mm"], 0.0)
```
```
If the test file does not already import `json` , add:
如果测试文件还没有导入 `json` ,添加:
```python
```python
import json
import json
```
```
- [ ] **Step 2: Run the new test and verify it fails **
- [ ] ** 步骤 2: 运行新测试并确认失败 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_auto_route_stores_length_and_wire_style_diagnostics
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_auto_route_stores_length_and_wire_style_diagnostics
```
```
Expected: FAIL because `QetAutoRouteLengthMm` and `QetWireStyleId` are not set on routed wires.
预期: FAIL, 因为已布导线上尚未设置 `QetAutoRouteLengthMm` 和 `QetWireStyleId` 。
- [ ] **Step 3: Add route length helpers **
- [ ] ** 步骤 3: 添加路径长度辅助函数 **
In `src/Mod/FreeCADExchange/AutoRouting.py` , add near `_point_payload` :
在 `src/Mod/FreeCADExchange/AutoRouting.py` 中,把此函数添加到 `_point_payload` 附近:
```python
```python
def _route_length(points):
def _route_length(points):
@ -318,9 +318,9 @@ def _route_length(points):
return total
return total
```
```
- [ ] **Step 4: Add wire style and length to the diagnostic payload**
- [ ] ** 步骤 4: 把导线样式和长度加入诊断 payload**
Change `_route_payload` to accept `wire_style_id` :
修改 `_route_payload` ,让它接收 `wire_style_id` :
```python
```python
def _route_payload(route_data, collisions, wire_style_id=""):
def _route_payload(route_data, collisions, wire_style_id=""):
@ -336,7 +336,7 @@ def _route_payload(route_data, collisions, wire_style_id=""):
}
}
```
```
Change `_set_auto_metadata` to accept and store `wire_style_id` :
修改 `_set_auto_metadata` ,让它接收并保存 `wire_style_id` :
```python
```python
def _set_auto_metadata(wire, route_data, collisions, wire_style_id=""):
def _set_auto_metadata(wire, route_data, collisions, wire_style_id=""):
@ -359,87 +359,87 @@ def _set_auto_metadata(wire, route_data, collisions, wire_style_id=""):
)
)
```
```
- [ ] **Step 5: Thread `wire_style_id` through routing **
- [ ] ** 步骤 5: 在线路由流程中传递 `wire_style_id` **
Add a parameter to `route_between_terminals` :
给 `route_between_terminals` 添加参数:
```python
```python
wire_style_id="",
wire_style_id="",
```
```
Before metadata is written, merge explicit parameter and options:
写入元数据之前,合并显式参数和 options:
```python
```python
effective_wire_style_id = str(wire_style_id or opts.get("wire_style_id", "") or "").strip()
effective_wire_style_id = str(wire_style_id or opts.get("wire_style_id", "") or "").strip()
```
```
Then replace:
然后将:
```python
```python
_set_auto_metadata(wire, route_data, collisions)
_set_auto_metadata(wire, route_data, collisions)
```
```
with:
替换为:
```python
```python
_set_auto_metadata(wire, route_data, collisions, wire_style_id=effective_wire_style_id)
_set_auto_metadata(wire, route_data, collisions, wire_style_id=effective_wire_style_id)
```
```
- [ ] **Step 6: Pass task style from payload and task objects **
- [ ] ** 步骤 6: 从 payload 和任务对象传入任务样式 **
In `route_all_from_payload` , pass:
在 `route_all_from_payload` 中传入:
```python
```python
wire_style_id=_wire_item_value(item, "wire_style_id"),
wire_style_id=_wire_item_value(item, "wire_style_id"),
```
```
In `_wire_tasks_payload` , add:
在 `_wire_tasks_payload` 中添加:
```python
```python
"wire_style_id": (getattr(task, "QetWireStyleId", "") or "").strip(),
"wire_style_id": (getattr(task, "QetWireStyleId", "") or "").strip(),
```
```
- [ ] **Step 7: Run the focused test **
- [ ] ** 步骤 7: 运行聚焦测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_auto_route_stores_length_and_wire_style_diagnostics
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_auto_route_stores_length_and_wire_style_diagnostics
```
```
Expected: PASS.
预期: PASS。
- [ ] **Step 8: Run the auto-routing test file **
- [ ] ** 步骤 8: 运行自动布线测试文件 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test
```
```
Expected: all tests in the file pass.
预期:该文件中的全部测试通过。
- [ ] **Step 9: Commit **
- [ ] ** 步骤 9: 提交 **
Run:
运行:
```powershell
```powershell
git add src/Mod/FreeCADExchange/AutoRouting.py tests/python/freecad_exchange_auto_routing_test.py
git add src/Mod/FreeCADExchange/AutoRouting.py tests/python/freecad_exchange_auto_routing_test.py
git commit -m "feat: record freecad auto route diagnostics"
git commit -m "feat: record freecad auto route diagnostics"
```
```
Expected: the commit contains route metadata and tests.
预期:该提交包含路径元数据和测试。
## Task 4: Write batch diagnostics into `QETWiring_05_Diagnostics`
## 任务 4: 把批量诊断写入 `QETWiring_05_Diagnostics`
**Files: **
**文件: **
- Modify: `src/Mod/FreeCADExchange/AutoRouting.py:1022-1152`
- 修改: `src/Mod/FreeCADExchange/AutoRouting.py:1022-1152`
- Modify: `src/Mod/FreeCADExchange/WiringObjects.py:153-156`
- 修改: `src/Mod/FreeCADExchange/WiringObjects.py:153-156`
- Test: `tests/python/freecad_exchange_auto_routing_test.py`
- 测试: `tests/python/freecad_exchange_auto_routing_test.py`
- [ ] **Step 1: Write the failing diagnostics group test **
- [ ] ** 步骤 1: 编写失败的诊断分组测试 **
Add this test to `tests/python/freecad_exchange_auto_routing_test.py` inside `AutoRoutingTest` :
把此测试添加到 `tests/python/freecad_exchange_auto_routing_test.py` 的 `AutoRoutingTest` 中:
```python
```python
def test_route_all_writes_diagnostic_object_for_missing_terminal(self):
def test_route_all_writes_diagnostic_object_for_missing_terminal(self):
@ -471,19 +471,19 @@ Add this test to `tests/python/freecad_exchange_auto_routing_test.py` inside `Au
self.assertIn("terminal-missing", diagnostic.QetDiagnosticJson)
self.assertIn("terminal-missing", diagnostic.QetDiagnosticJson)
```
```
- [ ] **Step 2: Run the new test and verify it fails **
- [ ] ** 步骤 2: 运行新测试并确认失败 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_writes_diagnostic_object_for_missing_terminal
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_writes_diagnostic_object_for_missing_terminal
```
```
Expected: FAIL because no diagnostic object is created.
预期: FAIL, 因为还没有创建诊断对象。
- [ ] **Step 3: Add diagnostic helper functions **
- [ ] ** 步骤 3: 添加诊断辅助函数 **
In `src/Mod/FreeCADExchange/AutoRouting.py` , add after `format_route_all_report` :
在 `src/Mod/FreeCADExchange/AutoRouting.py` 中,把这些函数添加到 `format_route_all_report` 之后:
```python
```python
def _clear_auto_route_batch_diagnostics(doc):
def _clear_auto_route_batch_diagnostics(doc):
@ -526,55 +526,55 @@ def _write_auto_route_batch_diagnostic(doc, report):
return diagnostic
return diagnostic
```
```
- [ ] **Step 4: Call the diagnostic writer **
- [ ] ** 步骤 4: 调用诊断写入函数 **
At the end of `route_all_from_payload` , immediately before `return report` , add:
在 `route_all_from_payload` 结尾处、紧挨 `return report` 之前添加:
```python
```python
_write_auto_route_batch_diagnostic(doc, report)
_write_auto_route_batch_diagnostic(doc, report)
```
```
- [ ] **Step 5: Run the focused test **
- [ ] ** 步骤 5: 运行聚焦测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_writes_diagnostic_object_for_missing_terminal
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_writes_diagnostic_object_for_missing_terminal
```
```
Expected: PASS.
预期: PASS。
- [ ] **Step 6: Run auto-routing tests **
- [ ] ** 步骤 6: 运行自动布线测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test
```
```
Expected: all tests pass.
预期:全部测试通过。
- [ ] **Step 7: Commit **
- [ ] ** 步骤 7: 提交 **
Run:
运行:
```powershell
```powershell
git add src/Mod/FreeCADExchange/AutoRouting.py tests/python/freecad_exchange_auto_routing_test.py
git add src/Mod/FreeCADExchange/AutoRouting.py tests/python/freecad_exchange_auto_routing_test.py
git commit -m "feat: write freecad auto routing diagnostics"
git commit -m "feat: write freecad auto routing diagnostics"
```
```
Expected: the commit contains diagnostic object behavior and tests.
预期:该提交包含诊断对象行为和测试。
## Task 5: Improve one-click panel summary
## 任务 5: 增强一键布线面板摘要
**Files: **
**文件: **
- Modify: `src/Mod/FreeCADExchange/AutoRouting.py:1116-1152`
- 修改: `src/Mod/FreeCADExchange/AutoRouting.py:1116-1152`
- Modify: `src/Mod/FreeCADExchange/AutoRoutingPanel.py:137-160`
- 修改: `src/Mod/FreeCADExchange/AutoRoutingPanel.py:137-160`
- Test: `tests/python/freecad_exchange_auto_routing_test.py`
- 测试: `tests/python/freecad_exchange_auto_routing_test.py`
- [ ] **Step 1: Write the failing report text test **
- [ ] ** 步骤 1: 编写失败的报告文本测试 **
Add this test to `tests/python/freecad_exchange_auto_routing_test.py` inside `AutoRoutingTest` :
把此测试添加到 `tests/python/freecad_exchange_auto_routing_test.py` 的 `AutoRoutingTest` 中:
```python
```python
def test_route_all_report_includes_network_and_first_error(self):
def test_route_all_report_includes_network_and_first_error(self):
@ -607,19 +607,19 @@ Add this test to `tests/python/freecad_exchange_auto_routing_test.py` inside `Au
self.assertIn("缺失示例: terminal-a -> terminal-b", message)
self.assertIn("缺失示例: terminal-a -> terminal-b", message)
```
```
- [ ] **Step 2: Run the new report test **
- [ ] ** 步骤 2: 运行新的报告测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_report_includes_network_and_first_error
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_report_includes_network_and_first_error
```
```
Expected: FAIL because the first error is not included.
预期: FAIL, 因为当前报告未包含首个错误。
- [ ] **Step 3: Extend `format_route_all_report` **
- [ ] ** 步骤 3: 扩展 `format_route_all_report` **
In `src/Mod/FreeCADExchange/AutoRouting.py` , inside `format_route_all_report` , after the prepared layout block, add:
在 `src/Mod/FreeCADExchange/AutoRouting.py` 的 `format_route_all_report` 中,在 prepared layout 代码块之后添加:
```python
```python
errors = report.get("errors", []) or []
errors = report.get("errors", []) or []
@ -627,7 +627,7 @@ if errors:
message += "\n首个错误: {0}".format(str(errors[0]))
message += "\n首个错误: {0}".format(str(errors[0]))
```
```
Then ensure the missing endpoint sample block runs whenever a sample exists:
然后确保只要存在缺失端点样例,就执行缺失端点样例代码块:
```python
```python
sample = (report.get("missing_endpoint_samples") or [None])[0]
sample = (report.get("missing_endpoint_samples") or [None])[0]
@ -638,45 +638,45 @@ if sample:
)
)
```
```
- [ ] **Step 4: Run the focused test **
- [ ] ** 步骤 4: 运行聚焦测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_report_includes_network_and_first_error
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test.AutoRoutingTest.test_route_all_report_includes_network_and_first_error
```
```
Expected: PASS.
预期: PASS。
- [ ] **Step 5: Run auto-routing tests **
- [ ] ** 步骤 5: 运行自动布线测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test
D:\FreeCAD-1.1.1\bin\python.exe -m unittest tests.python.freecad_exchange_auto_routing_test
```
```
Expected: all tests pass.
预期:全部测试通过。
- [ ] **Step 6: Commit **
- [ ] ** 步骤 6: 提交 **
Run:
运行:
```powershell
```powershell
git add src/Mod/FreeCADExchange/AutoRouting.py tests/python/freecad_exchange_auto_routing_test.py
git add src/Mod/FreeCADExchange/AutoRouting.py tests/python/freecad_exchange_auto_routing_test.py
git commit -m "fix: clarify freecad auto routing report"
git commit -m "fix: clarify freecad auto routing report"
```
```
Expected: the commit contains only report-formatting code and tests.
预期:该提交只包含报告格式化代码和测试。
## Task 6: Add save and reopen coverage to the FreeCAD smoke
## 任务 6: 给 FreeCAD smoke 增加保存和重开覆盖
**Files: **
**文件: **
- Modify: `tests/manual/freecad_auto_routing_smoke.py`
- 修改:`tests/manual/freecad_auto_routing_smoke.py`
- [ ] **Step 1: Extend smoke output assertions **
- [ ] ** 步骤 1: 扩展 smoke 输出断言 **
In `tests/manual/freecad_auto_routing_smoke.py` , after the current document save path is created, ensure the script saves and reopens the FCStd:
在 `tests/manual/freecad_auto_routing_smoke.py` 中,在当前文档保存路径创建之后,确保脚本保存并重新打开 FCStd:
```python
```python
doc.saveAs(OUT_FCSTD)
doc.saveAs(OUT_FCSTD)
@ -691,97 +691,97 @@ In `tests/manual/freecad_auto_routing_smoke.py`, after the current document save
)
)
```
```
If the script currently writes JSON before save/reopen, move the JSON write after the new payload fields are set.
如果脚本当前在保存/重开之前写 JSON, 把 JSON 写入移动到新 payload 字段设置之后。
- [ ] **Step 2: Run the manual smoke**
- [ ] ** 步骤 2: 运行手工 smoke**
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe tests\manual\freecad_auto_routing_smoke.py
D:\FreeCAD-1.1.1\bin\python.exe tests\manual\freecad_auto_routing_smoke.py
```
```
Expected: exit code 0 and JSON output contains:
预期:退出码为 0, 且 JSON 输出包含:
```json
```json
"reopened_has_auto_route": true
"reopened_has_auto_route": true
```
```
- [ ] **Step 3: Commit **
- [ ] ** 步骤 3: 提交 **
Run:
运行:
```powershell
```powershell
git add tests/manual/freecad_auto_routing_smoke.py
git add tests/manual/freecad_auto_routing_smoke.py
git commit -m "test: verify freecad auto routes survive reopen"
git commit -m "test: verify freecad auto routes survive reopen"
```
```
Expected: the commit contains only the manual smoke update.
预期:该提交只包含手工 smoke 更新。
## Task 7: Final verification
## 任务 7: 最终验证
**Files: **
**文件: **
- Read: `docs/superpowers/specs/2026-05-28-freecad-electrical-auto-routing-design.md`
- 阅读:`docs/superpowers/specs/2026-05-28-电气自动布线设计.md`
- Read: changed files from Tasks 1-6
- 阅读:任务 1-6 中变更过的文件
- [ ] **Step 1: Run FreeCADExchange unit tests **
- [ ] ** 步骤 1: 运行 FreeCADExchange 单元测试 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m unittest discover -s tests\python -p "freecad_exchange*_test.py"
D:\FreeCAD-1.1.1\bin\python.exe -m unittest discover -s tests\python -p "freecad_exchange*_test.py"
```
```
Expected: all discovered tests pass.
预期:发现的全部测试通过。
- [ ] **Step 2: Run FreeCADExchange syntax check **
- [ ] ** 步骤 2: 运行 FreeCADExchange 语法检查 **
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe -m py_compile src\Mod\FreeCADExchange\AutoRouting.py src\Mod\FreeCADExchange\RoutingNetwork.py src\Mod\FreeCADExchange\AutoRoutingPanel.py src\Mod\FreeCADExchange\WiringImport.py src\Mod\FreeCADExchange\WiringObjects.py
D:\FreeCAD-1.1.1\bin\python.exe -m py_compile src\Mod\FreeCADExchange\AutoRouting.py src\Mod\FreeCADExchange\RoutingNetwork.py src\Mod\FreeCADExchange\AutoRoutingPanel.py src\Mod\FreeCADExchange\WiringImport.py src\Mod\FreeCADExchange\WiringObjects.py
```
```
Expected: exit code 0 with no syntax errors.
预期:退出码为 0, 没有语法错误。
- [ ] **Step 3: Run manual smoke**
- [ ] ** 步骤 3: 运行手工 smoke**
Run:
运行:
```powershell
```powershell
D:\FreeCAD-1.1.1\bin\python.exe tests\manual\freecad_auto_routing_smoke.py
D:\FreeCAD-1.1.1\bin\python.exe tests\manual\freecad_auto_routing_smoke.py
```
```
Expected: exit code 0, output JSON exists, and reopened auto route is true.
预期:退出码为 0, 输出 JSON 存在,并且重开后的自动布线标记为 true。
- [ ] **Step 4: Verify no forbidden first-version database dependency was introduced **
- [ ] ** 步骤 4: 确认没有引入第一版禁止的数据库依赖 **
Run:
运行:
```powershell
```powershell
rg -n "project_3d_scene_instance|project_3d_space_object|project_2d3d_link|start_end_terminal_matches|connection_point_key|terminal_key" src\Mod\FreeCADExchange docs\superpowers\plans\2026-05-28-freecad-electrical-auto-routing .md
rg -n "project_3d_scene_instance|project_3d_space_object|project_2d3d_link|start_end_terminal_matches|connection_point_key|terminal_key" src\Mod\FreeCADExchange docs\superpowers\plans\2026-05-28-电气自动布线实施计划 .md
```
```
Expected: no matches in `src/Mod/FreeCADExchange` ; matches in this plan are allowed only because this verification command names forbidden strings.
预期:`src/Mod/FreeCADExchange` 中没有命中;本计划中的命中只允许来自这条验证命令本身列出的禁止字符串。
- [ ] **Step 5: Verify staged and unstaged diffs **
- [ ] ** 步骤 5: 验证暂存区和未暂存差异 **
Run:
运行:
```powershell
```powershell
git status --short
git status --short
git diff --check
git diff --check
```
```
Expected: no whitespace errors. Untracked screenshots and diagnostic JSON files may remain; do not stage them.
预期:没有 whitespace 错误。未跟踪的截图和诊断 JSON 文件可以继续保留,但不要暂存。
- [ ] **Step 6: Commit final docs if the plan was adjusted during execution **
- [ ] ** 步骤 6: 如果执行过程中调整了计划, 则提交最终文档 **
Run only if this plan file changed during execution:
仅在执行过程中该计划文件发生变化时运行:
```powershell
```powershell
git add docs/superpowers/plans/2026-05-28-freecad-electrical-auto-routing .md
git add docs/superpowers/plans/2026-05-28-电气自动布线实施计划 .md
git commit -m "docs: update freecad auto routing plan"
git commit -m "docs: update freecad auto routing plan"
```
```
Expected: commit contains only the plan document.
预期:该提交只包含计划文档。