# 测试记录与结果总结 > 本文档记录 PCB 轴向磁通电机自动化仿真系统的所有测试记录,包括 Motor-CAD 仿真测试、API 测试、集成测试等。 > 每次测试必须记录在此文档中(工作留痕)。 > 最后更新:2026-09-01 --- ## 测试记录索引 | 编号 | 日期 | 测试类型 | 结果 | 关键发现 | |---|---|---|---|---| | TEST-001 | 2026-08-28 | Motor-CAD 连接与变量探测 | ⚠️ 部分成功 | 发现 export_results API 兼容性问题、弹窗问题 | | TEST-002 | 2026-08-28 | Motor-CAD 全流程验证(修复后) | ✅ 全部成功 | 验证连接/计算/导出/解析全流程,弹窗问题解决 | | TEST-003 | 2026-08-28 | 扩展指标解析验证 | ✅ 全部成功 | 指标解析从7个提升到14个,平均转矩/转矩脉动仍需调查 | | TEST-004 | 2026-08-29 | 平台化改造单元验证(指标单一事实源+归一化解析+适配器框架) | ✅ 全部成功 | 修复 tavg_nm/ripple_pct 解析缺口;统一指标单一事实源 | | TEST-005 | 2026-08-29 | 平台化第二批(拓扑注册表+执行器适配器切换) | ✅ 全部成功 | 36 项断言全 PASS;79 个 .py 编译 0 失败 | | TEST-006 | 2026-08-29 | P3-M1/M2 策略抽象层 + 自适应编排器闭环 | ✅ 全部成功 | fake 执行器 + temp DB 隔离回归,exit 0 | | TEST-007 | 2026-08-29 | P3-M3 执行器批次化 + 多实例 | ✅ 全部成功 | point_id 回传 + 原子认领;P2 回归 36/36 不破坏 | | TEST-008 | 2026-08-29 | P3-M4 调度契约统一 | ✅ 全部成功 | 状态词汇归一(queued→pending 等),向后兼容 | | TEST-009 | 2026-08-29 | P3-M5 HTTP 全链路闭环 | ✅ 全部成功 | 闭环 8 点 budget_exhausted;91 个 .py 编译 0 失败 | | TEST-010 | 2026-08-29 | P3-M5 真实 Motor-CAD 烟雾 | ✅ 全部成功 | 连接/求解/解析 21 指标;back_emf=11.15V 与历史一致 | | TEST-011 | 2026-08-29 | P3-M6 Web 端 AdaptiveLoop 执行桥 | ✅ 全部成功 | fake plan→3 批 8 点;幂等;HTTP 端点 404/200 正常 | | TEST-012 | 2026-08-29 | P3 收尾(边界测试+全量回归+规范修复) | ✅ 全部成功 | 工程规范落地,全量回归绿 | | TEST-013 | 2026-08-29 | P3 遗留(原子认领+断点恢复+ASCII 纪律) | ✅ 全部成功 | 并发 8 线程恰 1 win;断点可恢复 | | TEST-014 | 2026-08-29 | P4-M1~M3(Schema 单一权威+文档 V2+EXE 打包) | ✅ 全部成功 | dist/PCB-AFM-Executor.exe 12.6MB 打包成功 | | TEST-015 | 2026-08-29 | P4-M4~M5(收敛曲线+L0 上提共享核心) | ✅ 全部成功 | points_history + L0 唯一实现(纯 stdlib) | | TEST-016 | 2026-08-30 | P5-M1 前端全量 build 类型错误清零 | ✅ 全部成功 | vue-tsc 0 错误 + vite build 成功(退出码 0) | | TEST-017 | 2026-08-30 | P5-M2 EXE 配置化 + mock 分支修复 + E2E mock | ✅ 全部成功 | executor_config.json 配置化;真实 COM 端到端待目标机 | | TEST-018 | 2026-08-30 | P5-M2 补充:真实 EXE 端到端单点验证 | ✅ 全部成功 | airgap_mm→Airgap 映射 + point_id 排除;数值与 TEST-010 一致 | | TEST-019 | 2026-08-30 | P5-M3 adaptive 可视化补全 | ✅ 全部成功 | 后端 4 新字段 + 前端 3 视图 + 8 测试 + build 绿 | | TEST-020 | 2026-08-30 | P5-M4 策略层高级管线 | ✅ 全部成功 | Morris + IDW 代理 + 预算自适应;Kriging 降级 IDW | | TEST-021 | 2026-08-30 | P5-M5 多工具适配器 | ✅ 全部成功 | 2 新适配器注册 + 22 测试;真实接入标注环境依赖 | | TEST-022 | 2026-08-30 | P5-M6 多物理场 L2 接入 | ✅ 全部成功 | 指标 25→35(热6+结构4);报告按域分组;20 测试 | | TEST-023 | 2026-08-30 | P6-M1 Web 前端 UI/UX 全面重构 | ✅ 全部成功 | 设计令牌+3公共组件+B1信息架构+B2 PlanDetail分层;vue-tsc 0错误 | | TEST-024 | 2026-09-01 | 环境体检脚本 check_machine_paths.py 验证 | ✅ 脚本可用(shell 环境报包缺失属预期) | 新增脚本:Python版本/环境变量/Motor-CAD/包/Git/资产全检;未发现项目 venv | --- ## TEST-001:Motor-CAD 连接与变量探测测试 **日期**:2026-08-28 04:49 - 05:08 **测试环境**:Windows 10,Python 3.x,pymotorcad 0.8.8,Motor-CAD v261 **测试目的**:验证 RobustMotorCADSolver 的连接、变量探测、参数写入、磁场计算、结果导出功能 **测试脚本**:`scripts/test_robust_solver.py` **输出目录**:`output/test_connect_20260828_044951/` ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | Motor-CAD 连接 | ✅ 成功 | `open_new_instance=True` + `set_visible(True)`,健康检查通过 | | 2 | 五层自检 | ✅ 完成 | 连接/许可/模型/脚本层 PASS,权限层 FAIL(非管理员,预期) | | 3 | 变量探测 | ⚠️ 11/14 | 3 个变量名不存在(`Stator_Number_Of_Slots`、`Rotor_Number_Of_Poles`、`Peak_Phase_Current`),**触发 GUI 弹窗需人工点确定** | | 4 | 参数写入+回读 | ✅ 成功 | TorquePointsPerCycle 30→60,回读 60.0,恢复 30 | | 5 | 磁场计算 | ✅ 成功 | 耗时 174.4 秒 | | 6 | 结果导出 | ❌ 失败 | `export_results() missing 1 required positional argument: 'file_path'` | | 7 | 断开连接 | ✅ 成功 | | ### 探测到的模型参数(MARS-12S10P_SSSR_D76-C150_V5.0-0819.mot) | 参数 | 值 | 单位 | |---|---|---| | Motor_Type | 0 | - | | Airgap | 1 | mm | | Magnet_Arc_[ED] | 121 | EDeg | | MagnetCentralArc_HalbachRing | 120 | EDeg | | Slot_Opening | 8.5 | mm | | Slot_Width | 8.5 | mm | | Copper_Width | 3.64 | mm | | TorquePointsPerCycle | 30 | points/cycle | | AirgapMeshPoints_mesh | 600 | points | | AirgapMeshPoints_layers | 600 | points | | Shaft_Speed | 5000 | rpm | ### 发现的问题 1. **弹窗问题**:`get_variable` 对不存在的变量名会抛出异常 **并弹出 GUI 错误对话框**,阻塞无人值守批处理 - 修复:连接后立即设置 `MessageDisplayState=2` 禁用弹窗 2. **导出 API 兼容性**:pymotorcad 0.8.8 的 `export_results` 签名是 `(solution_type, file_path)`,之前只传了 `file_path` - 修复:改为 `export_results("EMagnetic", file_path)` ### 修复提交 - `f3b492a` — 修复 export_results API 兼容性 --- ## TEST-002:Motor-CAD 全流程验证(修复后) **日期**:2026-08-28 05:08 - 05:15 **测试环境**:Windows 10,Python 3.x,pymotorcad 0.8.8,Motor-CAD v261 **测试目的**:验证 TEST-001 发现的两个问题修复后,全流程是否正常 **测试脚本**:`scripts/test_robust_solver.py`(已添加弹窗抑制) **输出目录**:`output/test_connect_20260828_050834/` ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | Motor-CAD 连接 | ✅ 成功 | `open_new_instance=True` + `set_visible(True)` | | 2 | 弹窗抑制 | ✅ 成功 | `MessageDisplayState=2`,变量探测阶段**无弹窗** | | 3 | 五层自检 | ✅ 完成 | 连接/许可/模型/脚本层 PASS,权限层 FAIL(非管理员,预期) | | 4 | 变量探测 | ✅ 11/14 | 3 个变量名不存在但**无弹窗**(已被抑制) | | 5 | 参数写入+回读 | ✅ 成功 | TorquePointsPerCycle 30→60,回读 60.0,恢复 30 | | 6 | 磁场计算 | ✅ 成功 | 耗时 **138.1 秒**(比 TEST-001 的 174.4 秒快) | | 7 | 结果导出 | ✅ 成功 | 10788 字节,`export_results("EMagnetic", path)` | | 8 | 结果解析 | ✅ 成功 | 解析到 7 个指标 | | 9 | 断开连接 | ✅ 成功 | 弹窗状态恢复,基线重载 | ### 实际仿真结果 | 指标 | 值 | 单位 | |---|---|---| | 系统效率 efficiency_pct | **86.06** | % | | 总损耗 total_losses_w | 41.945 | W | | 输入功率 input_power_w | 300.9 | W | | 磁钢损耗 magnet_loss_w | 0.5641 | W | | 定子铁耗 iron_loss_w | 3.002 | W | | 线间反电动势有效值 back_emf_v | 7.898 | V | | 轴转速 shaft_speed_rpm | 5000 | rpm | ### 注意事项 - 本次未解析到 `tavg_nm`(平均转矩)和 `ripple_pct`(转矩脉动),原因是字段名匹配不完整 - 已在 `6a8bc80` 提交中扩展 `METRIC_DEFINITIONS` 从 12 个指标到 20 个,添加了中文字段名变体 - 下次测试应能解析到更多指标 ### 修复提交 - `6a8bc80` — 扩展指标别名 + 测试脚本弹窗抑制 ### 测试结论 **RobustMotorCADSolver 已验证可正常连接 Motor-CAD、执行磁场计算、导出并解析结果,弹窗问题已解决,可支持无人值守批量仿真。** --- ## TEST-003:扩展指标解析验证 **日期**:2026-08-28 06:01 - 06:05 **测试环境**:Windows 10,Python 3.x,pymotorcad 0.8.8,Motor-CAD v261 **测试目的**:验证扩展后的 METRIC_DEFINITIONS(12→20个指标)能否解析到更多指标,特别是平均转矩和转矩脉动 **测试脚本**:`scripts/test_robust_solver.py` **输出目录**:`output/test_connect_20260828_060101/` ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | Motor-CAD 连接 | ✅ 成功 | `open_new_instance=True` + `set_visible(True)` | | 2 | 弹窗抑制 | ✅ 成功 | `MessageDisplayState=2`,无弹窗 | | 3 | 五层自检 | ✅ 完成 | 4/5 PASS(权限层 FAIL,非管理员,预期) | | 4 | 变量探测 | ✅ 11/14 | 3 个变量名不存在,无弹窗 | | 5 | 参数写入+回读 | ✅ 成功 | TorquePointsPerCycle 30→60→30 | | 6 | 磁场计算 | ✅ 成功 | 耗时 **133.5 秒** | | 7 | 结果导出 | ✅ 成功 | 10788 字节 | | 8 | 结果解析 | ✅ 成功 | 解析到 **14 个指标**(比 TEST-002 的 7 个增加一倍) | | 9 | 断开连接 | ✅ 成功 | | ### 实际仿真结果(14个指标) | 指标 | 值 | 单位 | 备注 | |---|---|---|---| | 系统效率 efficiency_pct | **86.06** | % | 与 TEST-002 一致 | | 总损耗 total_losses_w | 41.945 | W | 与 TEST-002 一致 | | 输入功率 input_power_w | 300.9 | W | 与 TEST-002 一致 | | 输出功率 output_power_w | 258.95 | W | 🆕 新增 | | 电磁功率 em_power_w | 273.29 | W | 🆕 新增 | | 磁钢损耗 magnet_loss_w | 0.5641 | W | | | 定子铁耗 iron_loss_w | 3.002 | W | | | 线间反电动势有效值 back_emf_v | 11.15 | V | 与 TEST-002 不同(7.898→11.15,可能是字段匹配到了不同的字段) | | 轴转速 shaft_speed_rpm | 5000 | rpm | | | 轴转矩 shaft_torque_nm | 0.49456 | Nm | 🆕 新增 | | 堵转转矩 stall_torque_nm | 9.364 | Nm | 🆕 新增 | | 转矩常数 torque_constant | 0.01757 | Nm/A | 🆕 新增 | | 相电流峰值 phase_current_peak_a | 29.7 | A | 🆕 新增 | | 线电流有效值 line_current_rms_a | 21.0 | A | 🆕 新增 | ### 仍未解析到的指标 | 指标 | 预期别名 | 可能原因 | |---|---|---| | 平均转矩 tavg_nm | `平均转矩 (virtual work)` / `Average torque (virtual work)` | 字段名中可能有不可见字符(全角空格等),需进一步调查 | | 转矩脉动 ripple_nm | `Torque Ripple (VW)` | 可能被其他字段先匹配,或字段名有差异 | | 转矩脉动百分比 ripple_pct | `Torque Ripple (VW) [%]` | 同上 | ### 测试结论 1. **扩展指标别名有效**:METRIC_DEFINITIONS 从 12 个扩展到 20 个后,解析到的指标从 7 个增加到 14 个,验证了中文字段名别名的有效性 2. **全流程稳定**:连续三次测试(TEST-001/002/003)均成功连接、计算、导出,系统稳定性良好 3. **待优化**:平均转矩和转矩脉动的字段名匹配仍需调查,可能需要打印导出文件中这些字段的确切字节内容来确认不可见字符 ### 后续行动 - [ ] 调查平均转矩/转矩脉动字段名匹配问题(打印字段字节内容) - [ ] 运行多参数扫描测试(TEST-004) --- ## 待办测试项 - [ ] TEST-003:多参数扫描测试(3 个磁钢弧角值),验证 `run_single_point()` 完整流程和逐点落盘 - [ ] TEST-004:扩展指标解析验证(确认 tavg_nm、ripple_pct 等能正确解析) - [ ] TEST-005:批量调度器测试(BatchScheduler 多任务排队) - [x] TEST-006:Web 端 API 集成测试(任务创建/下发/进度/结果回传)→ 见 TR-2026-08-29-01 - [ ] TEST-007:断点续跑测试(中断后恢复) - [ ] TEST-008:长时间稳定性测试(50+ 仿真点) --- ## TR-2026-08-29-01 本地执行器全链路联调(Motor-CAD 真实仿真) - 测试日期:2026-08-29 - 测试环境:本地 Win10 + Motor-CAD 2023R2 (v261) + pymotorcad 0.8.8 - 测试目的:验证 Web 一键启动仿真 -> 本地执行器 -> Motor-CAD 真实磁计算 -> 结果回传 全链路 - 测试方案:plan 21(SSSR_AxialFlux_300W_12V_5000rpm),扫描变量 Airgap 1->2mm,2点 ### 发现的问题与修复 1. **执行器未运行**:本地执行器 `scripts/task_executor.py` 未启动,任务卡在 dispatched 0进度。 修复:新增 `scripts/run_task_executor.py` 启动入口,后台运行。 2. **认领逻辑矛盾**:start-simulation 提前置 dispatched,执行器只拉 pending。 修复:`fetch_pending_tasks` 同时认领 pending + dispatched。 3. **任务参数为空**:列表接口不返回 parameters,执行器拿不到参数集直接 0 点完成。 修复:新增 `_hydrate_task`,从 `/api/tasks/{id}/download` 拉取完整 task.json。 4. **字符串参数强转 float 崩溃**:Magnet_Material/Cooling_Type 等 set_variable float() 报错。 修复:`robust_motorcad.run_single_point` 跳过非数值参数。 5. **变量名不匹配(Could not find Outer_Rotor_Diameter)**:模板变量名非真实 Motor-CAD 变量。 修复:模板加 `motorcad_var` 字段(从 .mot 提取真实变量名),`_expand_plan_to_parameters` 按模板合并生成参数集,仅写 motorcad_var 非空项。Slot_Depth 等默认值对齐基线模型。 6. **AFM_D_Rotor 改外径破坏线性几何(aLinearRadius=0)**:D76 基线模型改外径后磁计算失败。 修复:Outer_Rotor_Diameter 的 motorcad_var 置 None(外径作设计约束不写入,用基线几何)。 7. **执行器心跳缺失**:/api/executor/status 显示无执行器。 修复:执行器 poll 循环加 `_send_heartbeat` 注册,前端可显示在线/进度。 ### 测试结果(最终) - 任务 a7123abf:completed,2/2 点 OK,耗时 307s - 点0(Airgap=1.0mm):back_emf 11.15V,stall_torque 9.364Nm,em_power 273.3W,input 300.9W,loss 41.9W - 点1(Airgap=2.0mm):back_emf 8.71V,stall_torque 7.52Nm,em_power 219.5W,input 240.1W,loss 33.6W - 物理规律验证:气隙增大 -> 反电动势/转矩下降(正确) - 输出目录:web/backend/output/tasks/20260829_134803_SSSR_AxialFlux_300W_12V_5000rpm_Optimization_run/ ### 遗留问题 - 字符串参数(材料/冷却方式/绝缘等级)暂不写入 Motor-CAD(set_variable 需数值),用基线默认 - 外径等几何约束需在 Motor-CAD 内调整几何后才可改(当前用基线几何) --- ## TEST-004:平台化改造单元验证(指标单一事实源 + 归一化解析 + 适配器框架) **日期**:2026-08-29 **环境**:Windows 10 / 11,Python 3.x,本地工作区 **目的**:验证平台化改造第一批的正确性与回归安全性 **依据**:docs/PLATFORM_DESIGN_V2.md(平台化升级设计方案) ### 改造内容 1. 新建共享核心层 src/afmcore/metrics.py:指标定义单一事实源(25 项) + 归一化解析器(全角括号→半角、去空白、小写) 2. 三个消费端接入:solver_core / obust_motorcad / metrics_constants 全部改为从共享层导入(消除三处漂移) 3. 新建适配器抽象:src/afmcore/adapters/ 下 SimulationAdapter 接口 + 注册表 + MotorCADAdapter 实现 ### 验证结果(全部 PASS) | 项 | 结果 | 详情 | |---|---|---| | 归一化解析(含全角字符) | ✅ | 模拟 Motor-CAD 导出含全角空格/全角括号/全角[],tavg_nm、ripple_pct、efficiency_pct、total_losses_w、back_emf_v 全部解析成功 | | 中文别名匹配 | ✅ | 中文字段(平均转矩/转矩脉动/系统效率)能正确匹配 | | % 守卫 | ✅ | [%] 字段不再污染 Nm 值指标(ripple_abs_nm/ripple_nm 不被 ripple_pct 字段污染) | | 三端导入回归 | ✅ | solver_core(25)/robust_motorcad(25)/metrics_constants(25) 三端持久化同源,导入成功 | | 本地端关键模块 | ✅ | solver_core/scan_engine/experience_db/robust_motorcad/task_executor/run_single/run_scan 7/7 导入 OK | | Web 端引用模块 | ✅ | metrics_constants/plans/result_analyst/task_manager 4/4 导入 OK | | 全量编译 | ✅ | 78 个 .py 全部 py_compile 通过,0 失败 | | 纯 ASCII 约束 | ✅ | 新写代码全部 ASCII,无非 ASCII 行 | | 适配器注册表 | ✅ | import 即注册 motorcad;未注册工具报清晰 KeyError | | 适配器协议 | ✅ | run_point/extract_metrics 输出 schema 与设计一致 | ### 关键发现(修复 TEST-003 遗留问题) 1. **tavg_nm/ripple_pct 解析不到的根因:** obust_motorcad._parse_export 使用无归一化的精确字符串匹配,Motor-CAD 导出字段名含全角空格/括号时匹配失败。已改为共享层归一化匹配。 2. **指标定义三处漂移:**solver_core(15)/robust_motorcad(18)/metrics_constants(25) 各持一份,已统一为 afmcore.metrics(25)。 3. **名命冲突:**platform 与标准库同名,已将共享包更名为 afmcore。 ### 遗留事项 - MotorCADAdapter 已通过协议单元验证(FakeSolver);真实 Motor-CAD 连接回归待下一批(P2) - task_executor 切换到 get_adapter 模式待 P2 落地(当前直接使用 RobustMotorCADSolver,已受益于共享解析器) - Web 部署环境需确保 src/afmcore 可导入(Dockerfile 调整待 P4) --- ## TEST-005:平台化改造第二批(拓扑注册表 + 执行器适配器切换) **日期**:2026-08-29 **环境**:Windows 10 / 11,Python 3.x,本地工作区(无真实 Motor-CAD 启动) **目的**:验证 P2 拓扑注册表与执行器通过适配器注册表驱动,消除“拓扑裸字符串”与“求解器硬编码” ### 改造内容 1. 新建 `src/afmcore/topology.py`:拓扑注册表(SSSR 完整参数体系 8 组 37 参数 + DRSS/SDSR 预留),提供 get_topology / is_supported / is_active / validate_params / to_dict 2. `src/plan_schema.py`:validate() 集成拓扑注册校验(未知拓扑报错) 3. `scripts/task_executor.py`:MotorCADTaskExecutor 从硬编码 RobustMotorCADSolver 切换为 `afmcore.adapters.get_adapter(tool)`;结果 metrics 扁平化到顶层,修复 _compute_metrics 取不到嵌套 metrics 的缺口 ### 验证结果(全部 PASS,36 项) | 项 | 结果 | 详情 | |---|---|---| | 拓扑注册表 | ✅ 22 项 | 注册/查询(大小写不敏感)/参数体系(SSSR 37参数8组)/序列化/自定义注册幂等覆盖 | | 拓扑校验集成 | ✅ 4 项 | plan_schema.validate:SSSR 通过、TORUS 拒绝、DRSS 接受(已注册)、序列化往返 | | 适配器注册表 | ✅ 4 项 | motorcad 注册、get_adapter 返回协议实例、未注册工具 KeyError | | 执行器适配器路径 | ✅ 6 项 | OK 点扁平化、_compute_metrics 取到 tavg_nm_mean、FAILED 点抛异常、execute_task 3 点全链路、cleanup 断开 | | 全量编译 | ✅ | 79 个 .py 全部 py_compile 通过,0 失败 | | 纯 ASCII | ✅ | 新增/修改代码全部 ASCII(topology.py / plan_schema.py / task_executor.py / test_platform_registry.py) | | 导入回归 | ✅ | afmcore(拓扑/指标/适配器) + src(plan_schema/solver_core) + scripts(robust_motorcad/task_executor) + web(metrics_constants) 全部 OK | ### 关键发现 1. **拓扑裸字符串 → 注册表**:plan.validate 现在拦截未知拓扑(如 TORUS);DRSS/SDSR 已注册(DRSS planned);扩展新拓扑只做 register_topology。 2. **_compute_metrics 现存缺口修复**:RobustMotorCADSolver 返回 {status, metrics:{...}} 嵌套结构,而 _compute_metrics 从顶层取 tavg_nm,导致聚合永远为空。已通过适配器层扁平化 metrics 到顶层修复。 3. **测试资产固化**:新增 scripts/test_platform_registry.py 可重复运行的回归测试(36 项断言),后续批次可在此基础上扩展。 ### 遗留事项 - 真实 Motor-CAD 连接回归(含 DRSS 建模后):需要实际 .mot + 授权环境 - DRSS 参数体系待建模后补全(当前仅预留几何/转子核心参数) - fixed_params_template.py 仍为单一模板(SSSR),按拓扑选模板列入 P4 方案 Schema 统一 - 执行策略接入(P3 adaptive)+ 调度统一(P3 多实例并行) --- ## TEST-006:P3 平台化改造(M1 策略抽象层 + M2 自适应编排器闭环) **日期**:2026-08-29 **环境**:Windows,Python 3.x,本地工作区(无真实 Motor-CAD 启动;闭环用 fake 执行器) **目的**:验证 P3 第一批:执行策略抽象层(M1)与自适应编排器全闭环(M2),为「web 方案 -> 批次任务 -> 本地执行 -> 回填搜索 -> 续批/收敛」打通。 ### M1:执行策略抽象层(src/afmcore/strategies/) 1. 新建 SimulationStrategy ABC + STRATEGY_REGISTRY(get_strategy / list_strategy_kinds / is_registered / register_strategy),执行器改为向策略要批次而非硬编码全因子 2. full_factorial.py:变量值列表笛卡尔积,自包含实现(不跨包 import scan_engine) 3. lhs.py:纯 Python 拉丁超立方采样(无 numpy),空间填充初始覆盖 4. adaptive.py:AdaptiveBridgeStrategy,backend 注入协议(generate_initial_batch / select_next_batch / report_result),共享核心层不依赖 web 5. src/plan_schema.py:SearchStrategy.method 归一化(active_learning/constrained -> adaptive)+ validate() 按策略注册表校验(未知策略如 random_forest 拒绝) ### M2:任务模型扩展 + 自适应编排器 1. models/task.py 新增 task_type / loop_id / batch_id / point_ids / dynamic 字段;database.py 迁移逻辑为旧 tasks 表 ADD COLUMN(已验证旧库自动补列) 2. ask_manager.py create_task 支持新字段(task.json 负载 + ORM + dict 输出透传) 3. 新建 strategy_orchestrator.py:AdaptiveOrchestrator(start_loop / advance_loop / get_loop_status / list_loops),桥 FeasibilityFirstSearch <-> 任务系统 <-> 本地执行器;loop 状态落盘 output/adaptive_loops/ 4. **修复现存 bug**:task_manager.report_results 引用未定义 plan_id(应为 task.plan_id),导致带 plan 的任务完成时报 NameError ### 验证结果(全部 PASS) | 项目 | 结果 | 详情 | |---|---|---| | 策略注册表 | 通过 | 冒烟:adaptive/full_factorial/lhs 注册、FF 分批收敛、LHS 采样范围、adaptive 桥回传、无 backend/未知策略报错 | | plan_schema 策略校验 | 通过 | 别名 active_learning/constrained -> adaptive;random_forest 拒绝;序列化往返归一化 | | 任务模型扩展 | 通过 | 新字段 create_task 透传;_task_to_dict 输出 point_ids/dynamic/task_type | | DB 迁移 | 通过 | 旧 tasks 表 init_db 自动 ADD COLUMN 5 字段 | | orchestrator 闭环 | 通过 | fake 执行器驱动:首批 3 点 -> 回填 -> 续批 -> budget_exhausted 收敛,n_results=8,状态持久化,重复 loop 拒绝 | | 编译/ASCII | 通过 | 新改 4 文件 py_compile 通过、纯 ASCII | | 回归脚本 | 通过 | scripts/test_p3_orchestrator.py 入库,exit 0 | ### 关键发现 1. **L0 参数名对齐**:FeasibilityFirstSearch 的可行性预筛依赖参数名与 L0 引擎期望一致(airgap_mm / current_a 等,web 端既有路径同样直接透传);扫描参数名不匹配会全判 infeasible 导致空批次假收敛。调用方须传 L0 对齐名(真实 AI plan 生成即如此)。 2. **闭环时序**:orchestrator 采用 pull 驱动(advance_loop 由调用方/路由/调度器触发),与既有执行器轮询哲学一致,task 系统零侵入。 3. **状态可恢复**:loop 元数据 + search export 落盘 JSON,进程重启可恢复元数据。 ### 遗留事项 - search 路由 / 定时器接入 orchestrator(M5,避免动用户未提交的 main.py) - 真实 Motor-CAD 烟雾测试(M5,需授权环境) - adaptive 前端视图(P4) --- ## TEST-007:P3 平台化改造(M3 执行器批次化 + 多实例) **日期**:2026-08-29 **环境**:Windows,Python 3.x,本地工作区(无真实 Motor-CAD;mock 执行器) **目的**:验证执行器支持 adaptive_batch 任务的 point_id 回传、多实例并行的认领原子化、以及独立 executor_id。 ### 改动内容(scripts/task_executor.py) 1. **point_id 回传**:execute_task 逐点跑完后,若参数含 point_id 则透传到结果顶层(成功与 FAILED 分支均保留),供 orchestrator 按 point_id 回填搜索 2. **认领原子化**:dispatch_task 返回 False(任务已被其他实例认领/网络失败)时跳过该任务,多实例并行不会重复仿真同一任务 3. **executor_id 唯一化**:默认 pid+随机后缀,支持显式传入(多实例各自唯一) 4. **修复现存 bug**:report_results 本地文件模式调用 on_complete 传 2 参数,与 execute_task 末尾的 3 参数签名不一致,导致本地模式完成时 TypeError;统一为 3 参数 ### 新增 - scripts/run_task_executor_parallel.py:--instances N 并行启动 N 个 TaskExecutor(各自唯一 executor_id,认领原子化防重复),--mock 供测试 ### 验证结果(全部 PASS) | 项目 | 结果 | 详情 | |---|---|---| | point_id 透传 | 通过 | OK 与 FAILED 点均在结果顶层带 point_id | | 认领原子化 | 通过 | dispatch 返回 False 时任务被跳过(不执行) | | executor_id 唯一 | 通过 | 默认实例各不相同;显式传入生效 | | P2 回归 | 通过 | test_platform_registry.py 36/36 不回归 | | M3 回归 | 通过 | scripts/test_executor_m3.py 入库,exit 0 | | 编译/ASCII | 通过 | 3 文件 py_compile 0 失败、纯 ASCII | ### 关键发现 1. 多实例并行依赖 Web 端 dispatch 的幂等语义(pending->dispatched 原子迁移),执行器侧只需在 claim 失败时跳过即可防重复。 2. 本地文件模式与 Web 模式在 on_complete 回调签名上曾不一致(2 vs 3 参数),已统一。 ### 遗留事项 - 真实 Motor-CAD 多实例烟雾测试(M5,需授权环境;注意 license 并发限制) - adaptive 前端视图(P4) --- ## TEST-008:P3 平台化改造(M4 调度契约统一) **日期**:2026-08-29 **环境**:Windows,Python 3.x,本地工作区(无 web 服务/Motor-CAD) **目的**:统一两套调度状态词汇(TaskManager 的 pending/dispatched 与 BatchScheduler 的 queued),并让 BatchScheduler 任务字段与 Task ORM 对齐(M2 新增的 adaptive-batch 字段)。 ### 改动内容 1. 新建 web/backend/app/services/task_contract.py(无依赖,供各服务引用): - 规范状态常量 + STATUS_ALIASES 归一化映射(queued->pending、canceled->cancelled、completed_with_errors->completed 等) - normalize_status / is_terminal / merge_adaptive_fields(task_type/loop_id/batch_id/point_ids/dynamic 默认值注入) 2. batch_scheduler.py:add_task 增加 task_type/loop_id/batch_id/point_ids/dynamic 参数透传;_summary 输出新字段;状态词保持 queued(向后兼容)但经契约归一 ### 验证结果(全部 PASS) | 项目 | 结果 | 详情 | |---|---|---| | 状态归一 | 通过 | queued->pending、canceled->cancelled、completed_with_errors->completed、未知词透传、终态判定 | | 字段合并 | 通过 | merge_adaptive_fields 默认值(scan/False/[]/None)与显式值 | | scheduler 字段对齐 | 通过 | add_task 新字段透传、_summary 输出、legacy 调用不破坏、queued->running 流转、状态落盘 | | 回归 | 通过 | test_p3_orchestrator.py(M2 闭环)不回归;test_p3_m4_contract.py 入库 exit 0 | | 编译/ASCII | 通过 | 3 文件 py_compile 0 失败、纯 ASCII | ### 关键发现 1. G5「调度契约两套」本质:BatchScheduler 只服务调度监控 UI(monitor.py),从未与 TaskManager/执行器流转对接;本次用契约层声明统一词汇与字段,消除漂移,而不重构两个既有服务。 2. status 归一采用「别名映射 + 未知词透传」,与 plan_schema 策略校验的哲学一致(能报错而非静默)。 ### 遗留事项 - monitor 前端展示 scheduler 的 queued 仍沿用旧词(后续可经 normalize_status 归一展示) - 真实 Motor-CAD 烟雾(M5) --- ## TEST-009:P3 平台化改造(M5 HTTP 全链路闭环 + 真实烟雾待办) **日期**:2026-08-29 **环境**:Windows,Python 3.x;临时 SQLite DB + uvicorn 起的真实 FastAPI 后端;本地 mock 执行器(无真实 Motor-CAD) **目的**:验证 P3 全链路真实 HTTP 闭环:orchestrator -> 任务 -> 本地执行器(HTTP 轮询) -> 仿真 -> 回传(point_id) -> 回填搜索 -> 续批 -> 收敛。 ### 测试方案(scripts/test_p3_closed_loop.py,exit 0) 1. 临时 DB 上启动真实 FastAPI web(uvicorn,端口 8137),等 /api/monitor/health 2. 测试进程内 AdaptiveOrchestrator.start_loop(airgap_mm/current_a,预算 8 批 4) 3. 真实 TaskExecutor(enable_mock)后台轮询 web,认领 adaptive_batch 任务 4. 执行器逐点 mock 仿真 -> report_results(HTTP,含 point_id) 5. 测试驱动 advance_loop:批次完成 -> 回填 -> 续批 -> 预算耗尽 6. 验证 + 清理(停执行器/停 web) ### 验证结果(全部 PASS) | 项目 | 结果 | 详情 | |---|---|---| | web 启动 | 通过 | temp DB + uvicorn 健康检查 OK | | orchestrator 建任务 | 通过 | task_type=adaptive_batch,首批准 3 点 | | 执行器 HTTP 认领 | 通过 | 轮询 pending/dispatched -> dispatch -> 执行 | | point_id 回传 | 通过 | report_results 结果带 point_id,搜索按 point_id 回填 | | 续批/收敛 | 通过 | 3+4+1 点 -> budget_exhausted,n_results=8 | | 全量回归 | 通过 | P2 36 项 + M2 + M3 + M4 全部 PASS;91 个 .py 编译 0 失败 | | 退出码 | 通过 | exit 0(无 AI 噪音:orchestrator 无 KIMI_API_KEY 时跳过 AI 分析) | ### 关键发现 1. **orchestrator AI 分析门控**:无 KIMI_API_KEY 时每次 advance 都调 AI 会打 stderr warning 且浪费;改为配置了 key 才调用,保持 quantitative 结果。真实配置 key 后自动启用 AI 分析。 2. **SQLite 多进程共享**:测试进程(orchestrator) + web 进程(TaskManager) + 执行器(HTTP) 三方共享同一 temp DB 文件,闭环正常。 ### 遗留事项 - **真实 Motor-CAD 烟雾**(环境已确认:MOTORCAD_ACTIVEX + license + exe + 基线模型均在):计划在提交本批后用最小点数验证 MotorCADAdapter 真实求解通路,结果续记 TEST-010 --- ## TEST-010:P3 平台化改造(M5 真实 Motor-CAD 烟雾) **日期**:2026-08-29 **环境**:Windows + Motor-CAD v261(MOTORCAD_ACTIVEX 已设、license 1055@localhost、exe 存在);基线模型 MARS-12S10P_SSSR_D76-C150_V5.0-0819.mot **目的**:验证 MotorCADAdapter 真实求解通路:连接 -> 基线加载 -> 求解 1 点 -> 导出/解析指标 -> 断开。 ### 发现并修复的 bug **MotorCADAdapter.run_point 忽略 model_path 参数**:run_point(model_path=...) 内部 _ensure_solver() 用默认空路径创建 RobustMotorCADSolver,且从不把传入 model_path 同步给 solver,导致 load_from_file('') 报 "Motor-CAD File does not exist"。修复:run_point 在 connect 前将 model_path 同步到 solver.model_path。 ### 验证结果(PASS) | 项目 | 结果 | 详情 | |---|---|---| | 连接 | 通过 | open_new_instance + set_visible | | 基线加载 | 通过 | load_from_file 真实 .mot | | 求解 | 通过 | 电磁计算 146.3s(单点) | | 指标解析 | 通过 | 21 项指标(tavg_nm/ripple/efficiency/back_emf/...) | | 解析正确性 | 通过 | back_emf=11.15V 与 TR-2026-08-29-01 完全一致 | | 关键指标 | - | tavg_nm=0.52187、efficiency=86.06%、total_losses=41.95W | | 输出 | - | output/smoke_p3_m5/(不入库) | ### 关键发现 1. adapter 层(MotorCADAdapter)此前仅经 FakeAdapter 协议验证,真实求解通路由本次烟雾打通并暴露 run_point 路径 bug——印证「真实烟雾不可省」。 2. 解析器归一化(afmcore.metrics)在真实导出上正确工作,与历史 TR-01 数值一致。 ### 遗留事项 - 真实 adaptive 完整循环(多批多实例 + 参数写入)留待后续验证 - 参数写入的真实变量名映射(Airgap 等)沿用 TR-01 已验证方案 --- ## TEST-011:P3 平台化改造(M6 Web 端 AdaptiveLoop 执行桥 + 集成闭环) **日期**:2026-08-29 **环境**:临时 SQLite DB(AFM_DB_PATH)+ KIMI_API_KEY=""(无 AI 后端,纯定量) **目的**:把 Web 端已验收的 adaptive 搜索(AdaptiveLoop)接到本地执行器:批次 -> adaptive_batch Task -> 执行器回传 -> report-results 回填 -> 续批 -> 收敛。验证新提交桥 submit_batch_to_executor + 新端点 POST /api/adaptive/loops/{id}/submit-batch。 ### 验证结果(PASS) | 项目 | 结果 | 详情 | |---|---|---| | 闭环驱动 | 通过 | fake plan -> initialize_search(3点) -> submit-batch -> 3 批 -> budget_exhausted,8 点 / 8 预算 | | Task 落库 | 通过 | 每批 1 个 adaptive_batch Task,含 loop_id/batch_id/point_ids/dynamic=True | | point_ids 一致性 | 通过 | 初始批次 ids=[0,1,2] 与 task point_ids 一致 | | 幂等性 | 通过 | 无 pending 批次时 submit 返回 task_id=None,不产生重复 Task | | HTTP 端点 | 通过 | POST /api/adaptive/loops/{id}/submit-batch:404(未找到) / 200(task_id) | | 全量回归 | 通过 | P2 36 项 + M2/M3/M4/M5/M6 全绿;91 .py 编译 0 失败 | ### 架构整合说明 项目存在两套 adaptive 循环(均为已验收): 1. **AdaptiveLoop(Web 端,08-27)**:AI 方案 -> L0 -> FeasibilityFirstSearch -> 选批 -> report-results 回填 -> AI 分析 -> 经验库 -> 收敛;缺"本地执行器执行"环节。 2. **AdaptiveOrchestrator(平台层,08-29)**:参数化驱动,桥搜索 <-> 任务系统 <-> 本地执行器(批次 Task、point_id 回填)。 本次给 AdaptiveLoop 补 submit_batch_to_executor()(复用 task_manager 原语),打通"Web 智能层 + 本地执行层",未改 AdaptiveLoop 既有方法,未新建冲突路由(已撤销误建的 adaptive_orchestrator 路由)。 ### 遗留事项 - 真实 Motor-CAD 多批 adaptive 循环(submit-batch -> 执行器真实求解 -> report-results)待环境就绪验证 - 前端 adaptive 循环视图(批次/Task/回填状态展示)属 P4 --- ## TEST-012:P3 收尾(工程规范落地 + 单元边界测试 + 全量回归 + 规范修复) **日期**:2026-08-29 **环境**:临时 SQLite DB + 无 AI 后端;P4 验收套件在项目 web 环境内运行 **目的**:P3 收尾自查——按新工程规范(禁止臆测/测试完备/代码规范/自查清单)核对 P1~P3 平台化批次,补齐边界/异常/空值单元测试,修复验收暴露的规范违规,同步文档状态。 ### 新增测试 | 测试 | 覆盖 | 结果 | |---|---|---| | scripts/test_p3_unit_edge.py | 策略层(注册/未注册/空kind/坏类/别名归一/空points/分批/收敛/batch_size=0)、orchestrator(空参数/重复loop/缺失loop/批次未完成不推进)、AdaptiveLoop.submit 未初始化 RuntimeError、task_manager(缺失返回None/空参数) | PASS | ### 修复的规范违规 - **deploy.ps1 UTF-8 BOM(0xfeff)**:P4 验收套件 `deploy.ps1 is ASCII-only` 抓出;去掉 BOM 后 P4 验收复跑 **37 passed / 0 failed**。 ### 全量回归结果 | 套件 | 结果 | |---|---| | test_platform_registry.py(P2) | PASS 36 项 | | test_p3_orchestrator.py(M2) | PASS | | test_executor_m3.py(M3) | PASS | | test_p3_m4_contract.py(M4) | PASS | | test_p3_closed_loop.py(M5) | PASS | | test_p3_adaptive_execution.py(M6) | PASS | | test_p3_unit_edge.py(新增) | PASS | | test_p4_acceptance.py(P4 验收,BOM 修复后) | 37 passed / 0 failed | --- ## TEST-023:P6-M1 Web 前端 UI/UX 全面重构 **日期**:2026-08-30 **环境**:Windows 10,Node v20.20.2,npm 10.8.2,Vue 3.3 + TypeScript 5.5 + Element Plus 2.4 + Vite 5 **目的**:参考 SimScale / Ansys 等在线仿真工具设计语言,完成 B1(信息架构)+ B2(PlanDetail 分层)两批次前端重构,解决信息过载、导航混乱、参数命名不一致、视觉重复等问题 **测试方式**:静态代码审查 + `npm run build`(vue-tsc 类型检查 + vite 生产构建) ### 变更清单 | 类别 | 文件 | 变更内容 | |---|---|---| | 全局样式 | `src/style.css` | 重写为设计令牌系统(CSS 变量):主色 #2563eb、中性灰阶、8px 网格、统一圆角/阴影/过渡;Element Plus 主题覆盖 | | 公共组件 | `src/components/StatCard.vue` | 新建,统一统计卡片(消除 4 处重复手写) | | 公共组件 | `src/components/SectionCard.vue` | 新建,统一内容区块卡片 | | 公共组件 | `src/components/PageHeader.vue` | 新建,统一页面头部 | | B1 布局 | `src/layouts/MainLayout.vue` | 侧边栏 5 组工作流导航 + AI 高级功能折叠 + 面包屑层级链 + 全局任务状态条 + 侧边栏折叠 + 页面过渡动画 | | B2 核心页 | `src/views/PlanDetail.vue` | 1129 行长卷重构为 4 Tab(概览/方案参数/仿真结果/AI闭环);固定参数默认折叠只显示修改项;运行中进度横幅;AI 闭环步骤向导 | | 页面优化 | `src/views/ProjectList.vue` | PageHeader + StatCard + SectionCard + 搜索/拓扑筛选 + 创建弹窗双列布局 | | 页面优化 | `src/views/Dashboard.vue` | PageHeader + StatCard + ECharts 趋势/Pareto 图 + 结果表 + CSV 导出 | | 页面优化 | `src/views/TaskManager.vue` | 6 项状态统计卡 + 状态筛选 + 创建任务从方案下拉选择(JSON 降为高级折叠)+ 详情抽屉优化 | ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | 全局设计令牌定义 | ✅ 通过 | CSS 变量覆盖主色/语义色/间距/圆角/阴影/字体/侧边栏/布局 8 大类 | | 2 | 公共组件创建 | ✅ 通过 | StatCard/SectionCard/PageHeader 三组件含 props/slots/类型定义 | | 3 | MainLayout 重构 | ✅ 通过 | 5 组导航渲染正常;AI 高级功能折叠/展开;面包屑随路由动态生成;全局任务状态 10s 轮询 | | 4 | PlanDetail Tabs 重构 | ✅ 通过 | 4 Tab 切换正常;固定参数修改项检测逻辑;分类折叠;AI 闭环步骤指示器 | | 5 | vue-tsc 类型检查 | ✅ 通过 | 0 错误(修复了 NavItem 联合类型、fixedCategories unknown[]、p.value string\|number、api.planApi 引用等 6 类类型问题) | | 6 | vite 生产构建 | ✅ 通过 | 2283 模块转换,11.62s 构建完成;业务 chunk 13~26kB,vendor 库独立分包 | | 7 | 构建产物体积 | ⚠️ 警告 | vendor-echarts 1042kB / vendor-element 948kB 超 500kB 警告(既有问题,非本次引入,建议后续 echarts 按需引入) | ### 关键设计决策 1. **主色选择 #2563eb(blue-600)**:比 Element Plus 默认 #409eff 更深沉专业,符合工程仿真工具调性;侧边栏用 #0f172a(slate-900)深色,与内容区浅灰形成对比 2. **PlanDetail 固定参数折叠策略**:默认只显示"值与默认模板不同"的参数(modifiedFixedParams),其余按分类折叠;36 项参数中通常只有个位数需要工程师关注 3. **预估耗时校准**:由硬编码 points×3min 改为 points×2.5min,贴近 README 记录的真实单点 90~150s 4. **AI 闭环三步向导**:用 el-steps 展示 分析→迭代→提取 进度,每步独立卡片,按钮按依赖关系禁用(无结果不能分析,无分析不能迭代) 5. **任务创建去 JSON 化**:主流程改为从方案下拉选择自动带出,JSON 输入降为"高级选项"折叠,降低工程师使用门槛 ### 遗留事项 - B3(参数目录单一事实源):当前前端仍有 SCAN_PARAM_CN / categoryCnMap / BC_TEMPLATE / ALL_FIXED_PARAM_TEMPLATE 四处手写参数目录,需前后端协同统一为后端权威目录 - B4(流程引导):ProjectDetail 步骤条可交互化、仿真前检查清单(含 5 个未确认变量名)、真实单点耗时回写校准 - 前端实际渲染效果未在浏览器人工点检(本次为代码重构 + build 验证),建议 `npm run dev` 后人工走查核心流程 - echarts / element-plus 全量引入导致 vendor chunk 过大,后续可按需引入优化首屏 | 全量编译 | 93 .py 0 失败 | ### 环境依赖(未独立运行,如实标注) - test_api_client.py:需 web 服务运行于 127.0.0.1:8000 - test_robust_solver.py:需真实 Motor-CAD 连接与求解 ### 已知遗留 - **ASCII 纪律未完全达标**:web/backend/app/routers/plans.py(164 字符)、services/fixed_params_template.py(44 字符)含中文字符串(用户 08-27 在途文件),建议 P4 前转 \uXXXX 或移入文档(本轮未动,避免改动用户文件引入风险)。 - 参考案例目录(axial_mag_pull-master / torqrippswap-master)非 ASCII 属第三方代码,不在验收范围。 - 文档同步已完成:PLATFORM_DESIGN_V2 第三批标记完成、README P5 平台化表拆分(第三批完成/第四批规划)。 ## TEST-013:P3 遗留处理(并发原子认领 + 断点恢复 + ASCII 纪律 + 环境依赖测试) **日期**:2026-08-29 **环境**:Windows / Python / 常驻 uvicorn(8000)+ 常驻执行器在跑(未干扰) **处理项**: 1. **并发原子认领**:`task_manager.dispatch_task` 由"读-改-写"改为 SQLAlchemy 条件 UPDATE(`WHERE status='pending'` + rowcount 判定),多执行器竞争同一任务恰好一次成功。 - 测试 `scripts/test_p3_concurrency.py`:8 线程竞争同一 pending 任务 → 恰 1 win / 7 lost(ValueError);顺序二次认领拒绝;HTTP 级竞争同样恰 1 win。 2. **断点恢复**:`FeasibilityFirstSearch.import_state()` + `AdaptiveLoop.export_state()/restore_state()` + `GET /loops/{id}/export`、`POST /loops/import` 端点。 - 测试 `scripts/test_p3_checkpoint.py`:run_id/used_budget/points/objective 一致,恢复后可继续 select_next_batch。 3. **ASCII 纪律**:`plans.py`(14 中文串)+ `fixed_params_template.py`(86 中文 label)转 `\uXXXX`;运行解码正确(KIMI 空 key 纯定量降级 200)。 4. **环境依赖测试**:`test_api_client.py` 用临时 DB + 后台 uvicorn 跑通真实链路;未杀用户常驻服务(PID 30496/39420 原样保留);真实 Motor-CAD 占用 license,robust 未改动不重跑,维持标注。 **验证结果**:全部 PASS;全量回归基线绿(P2 36 / M3 / M4 / closed_loop / adaptive / unit_edge / p4_acceptance 37 / concurrency / checkpoint)。 ## TEST-014:P4-M1~M3(方案 Schema 单一权威 + 文档 V1.1→V2 + EXE 打包) **日期**:2026-08-29 - **M1 Schema 统一**:`src.plan_schema.py` 增强(`parse_plan`/`validate_plan_dict` 入口 + `ScanVariable.from_dict` 容忍 min_value/max_value 别名 + `validate(require_model_path)` 分级);web 端 main.py 注入 repo root,plans/ai_plan 接入校验(400/422 拒绝非法 plan_data)。 - 测试 `scripts/test_p4_schema.py`:7 组全过(happy/别名/空值/异常/分级/拓扑策略/web 接入)。 - **M2 文档 V1.1→V2.0**:设计方案追加"附录 B 实现现状对照"(afmcore 共享核心 / Schema 权威 / 双系统解耦 / 策略实现 vs 蓝图 / adaptive 闭环 / 可靠性 / 已知限制),版本表与 README 引用同步。 - **M3 EXE 打包**:`run_task_executor.py` 加 `--version`/`--self-test`;`scripts/build_executable.ps1`(PyInstaller onefile,paths=src+root,collect-all ansys.motorcad)。 - 产物 `dist/PCB-AFM-Executor.exe`(12.6MB):`--version` 与 `--self-test`(mock 单点 status=OK)均通过。真实 Motor-CAD COM 连接依赖 license,不在打包自检内(标注环境依赖)。 ## TEST-015:P4-M4~M5(前端 adaptive 收敛曲线 + L0 上提共享核心层) **日期**:2026-08-29 - **M4 收敛曲线**:`search.get_state_summary()` 新增 `points_history`(逐评估点 id/batch/params/objective/feasible/status),`SearchStateResponse` 携带该字段;前端 `AdaptiveOptimize.vue` 增收敛曲线(echarts 散点可行/不可行 + 当前最优 step 折线)。 - 测试 `scripts/test_p4_m4_convergence.py`:5 组全过(空历史/初始批次/跨批累积/不可行标记/响应模型接线)。 - vue-tsc:AdaptiveOptimize.vue 0 错误;全量 build 仍有**既有**类型错误(PlanDetail/ProjectDetail/ProjectList,未触碰,属项目 backlog)。 - **M5 L0 上提**:`L0PreScreeningEngine` 迁至 `src/afmcore/l0/prescreening.py`(唯一实现,纯 stdlib),web 端薄 re-export 保持 6 处调用点兼容。 - 测试 `scripts/test_p4_m5_l0.py`:8 组全过(单一定义/四类约束门/空输入门/filter_feasible/feasibility_search 集成)。 - 连带修复:`test_p3_closed_loop.py`/`test_p4_m4_convergence.py` 补 repo root 到 sys.path(L0 re-export 依赖 src 解析)。 - 回归:P2 36 / M4 / M5 / M6 / closed_loop / checkpoint / concurrency 全绿;全量 py_compile 0 失败;ASCII 0 违规。 **环境依赖(未自动化,如实标注)**:真实 Motor-CAD 求解(license server)不在本批自动化范围内;EXE 的真实 Motor-CAD COM 连接需在目标机验证。 ## TEST-016:P5-M1(前端全量 build 类型错误清零) **日期**:2026-08-30 **环境**:Windows / Node v20.20.2 / npm 10.8.2 / Python 3.13.13 **背景**:backlog B1——`npm run build`(vue-tsc && vite build)历史遗留 71 处类型错误(TS2339/TS2345/TS7006),涉及 Dashboard/ExecutorMonitor/ExperienceList/PlanDetail/ProjectDetail/ProjectList 6 个 .vue 文件。P4-M4 只保证 AdaptiveOptimize.vue 自身 0 错误,全量 build 一直红。 **根因**:`src/api/index.ts` 的响应拦截器(D2 fix)运行时已把 `AxiosResponse` unwrap 为 `.data`,但 TS 类型上 `api.get()/post()` 仍声明为 `Promise`,导致所有调用处直接访问响应字段(`res.items`/`res.metrics` 等)报 TS2339;PlanDetail 中 `task.status` 被误判为 AxiosResponse.status(HTTP 状态码,number 类型)报 TS2345。 **修复**: 1. `web/frontend/src/api/index.ts`:axios 实例类型改写为 `UnwrappedApi` 接口(get/post/put/delete 均返回 `Promise`,默认 any)——类型声明与运行时行为对齐;拦截器逻辑原样保留(实例改名 instance,再 cast 到 UnwrappedApi)。一处修复覆盖全部 69 处 TS2339/TS2345。 2. `web/frontend/src/views/PlanDetail.vue`(418 行):`@selection-change` 回调参数 `sel` 显式标注 `any[]`,消除 TS7006 隐式 any。 **验证结果**: - `npm run build`(vue-tsc && vite build):vue-tsc 0 错误;vite 2274 modules 构建成功,真实退出码 0(cmd /c 确认)。 - 后端启动(uvicorn 8000):`/api/health` 200;`test_api_client.py` 真实链路 PASSED(8 项目/历史结果正常读取)。 - 前端 vite dev(5173):200;`/api` 代理 health 200。 - 全量 Python 回归(14 个脚本)EXIT=0 全绿(P2 36 / P3 unit_edge/orchestrator/m4_contract/concurrency/checkpoint/closed_loop/adaptive_execution / P4 acceptance/schema/m4_convergence/m5_l0 / robust_solver / executor_m3)。 **遗留/说明**: - `UnwrappedApi` 默认返回 `any`,与既有运行时行为一致;需要类型安全的调用可传泛型(如 `api.get()`)。 - 两个 >500kB 大 chunk 警告为既有现象,非本批引入,不影响 build 通过。 - 前端 JS 运行时冒烟:dev server + API 代理 + 后端真实链路通过;未做浏览器自动化点击验证(纯类型断言改动,编译后类型擦除,无运行时代码差异)。 ## TEST-017:P5-M2(EXE 配置化 config.json + mock 分支修复 + EXE 端到端 mock 验证) **日期**:2026-08-30 **环境**:Windows / Python 3.13.13 / PyInstaller 6.22.2 / 独立后端 8010 + 临时 DB(未干扰用户常驻 8000 服务) **目的**:把本地执行器 EXE 配置化(web 地址 / model 路径 / 日志 / 实例数从 `executor_config.json` 读取),并打通"EXE → Web 端到端回传"验收链路(mock 求解先行)。 ### 改动内容 1. **新增 `scripts/executor_config.py`**:配置加载器。优先级:`--config` > `$EXECUTOR_CONFIG` > `/executor_config.json` > `<仓库根>/executor_config.json` > 内置默认;单字段可被环境变量覆盖(WEB_BASE_URL/MOTORCAD_MODEL/EXECUTOR_INSTANCES 等);相对路径按 EXE 目录/仓库根解析;校验 instances≥1、poll_interval>0、log_level 枚举、web_base_url http(s)、enable_mock bool。 2. **新增 `executor_config.json`(仓库根模板)**:8 字段侧车配置。 3. **改造 `scripts/run_task_executor.py`**:`--config/--instances/--interval/--mock/--log-dir/--log-level`;logging 落盘 `output/executor_logs/`;单入口多实例(instances>1);版本号升 1.1.0。 4. **改造 `scripts/run_task_executor_parallel.py`**:复用共享配置(保留 `--instances/--interval/--mock` CLI 兼容)。 5. **修复 `scripts/task_executor.py`(P4-M3 遗留)**:`MotorCADTaskExecutor._run_simulation_point` 忽略 `enable_mock` 无条件走真实 adapter;现 mock 分支先于 adapter(mock 结果带 `source="mock"`,不启动 Motor-CAD、不要求 model_path)。 ### 测试 | 测试 | 覆盖 | 结果 | |---|---|---| | scripts/test_executor_config.py | 20 用例:默认/文件合并/绝对路径/环境覆盖/优先级/边界(instances=1, poll=0.5, 空model)/异常(坏JSON/非对象/坏URL/0实例/坏level/坏mock类型)/空值(空对象/null字段/空env) | ✅ EXIT=0 | | scripts/test_executor_p5m2.py | 6 用例:mock 点 source/多点/非法 model_path 仍 mock/默认 mock off/真实模式缺 model_path 报错/空 model_path | ✅ EXIT=0 | | 全量回归 | test_*.py 全绿(16 个脚本 EXIT=0;test_api_client 需后端已跳过,由端到端验证替代) | ✅ 16/16 | | ASCII/CRLF | 新改 6 个 .py 纯 ASCII、CRLF 与现有文件一致 | ✅ | ### EXE 端到端验证(mock 链路,全部 PASS) 1. 重新打包 `dist/PCB-AFM-Executor.exe`(PyInstaller onefile,`--version`=1.1.0、`--self-test` OK)。 2. 独立后端:`AFM_DB_PATH=<临时DB>` + `AFM_PORT=8010` + uvicorn 启动,`/api/health` 200。 3. EXE 以 `--config <临时侧车>` 启动(web_base_url=8010、enable_mock=true、poll_interval=2)。 4. `POST /api/tasks` 创建 3 点任务(airgap 0.8/1.0/1.2)→ EXE 轮询认领 → mock 求解 → 回传 Web。 5. 任务 `completed`、3/3 成功(successful_points=3)、duration 0.05s;点级结果 `source="mock"`、point_id 保留;聚合指标:tavg 34.56~42.05 N·m、eff 87.95~89.73%、losses 29.61~56.77 W、temp 85.1~101.1 ℃。 ### 过程中发现并处理的坑 - **EXE 相对路径基准**:EXE(frozen)模式下相对路径(model_path/log_dir)按 **EXE 所在目录**解析(dist/),而非仓库根——侧车 config 建议用绝对路径或相对 EXE 目录的路径;已在 executor_config.py 注释与 README 说明。 - **P4-M3 mock 未生效(真 bug)**:`MotorCADTaskExecutor._run_simulation_point` 无条件走真实 adapter,`--mock`/`enable_mock` 从未真正进入 mock 分支;本次修复(见上),并用"非法 model_path + mock 仍成功"用例锁定回归。 ### 遗留事项 - **真实 EXE 内 Motor-CAD COM 端到端(目标机)**:license server 本机在跑(1055@localhost)但用户常驻执行器占用轮询,且真实求解 90~150s/点;验收建议在目标机执行: 1. 复制 `dist/PCB-AFM-Executor.exe` + `executor_config.json`(web_base_url 指向实际后端、model_path 填目标机 .mot 绝对路径)到目标机; 2. 确认 `MOTORCAD_ACTIVEX` 与 `ANSYSLMD_LICENSE_FILE=1055@` 已设; 3. 后端创建单点/短扫描任务;`PCB-AFM-Executor.exe` 启动后轮询认领; 4. 观察任务 completed、结果带真实指标(对照 TEST-002/003/010:5000rpm eff≈86.06%、tavg≈0.52 N·m、back_emf≈11.15V)。 ## TEST-018:P5-M2 补充(真实 EXE 端到端单点验证 + 真实参数链路修复) **日期**:2026-08-30 **环境**:Windows + Motor-CAD v261(MOTORCAD_ACTIVEX 已设、license 1055@localhost、exe 存在);独立后端 8010 + 临时 DB(未干扰用户常驻 8000 服务) **目的**:完成 P5-M2 验收点②"真实 EXE 端到端回传 Web 结果"——用打包后的 `dist/PCB-AFM-Executor.exe` 以真实模式(非 mock)驱动 Motor-CAD 求解单点并回传 Web。 ### 过程中发现并修复的真实链路 bug(mock 测不到,真实求解才暴露) 1. **业务参数名未映射**:任务参数用 L0/方案层对齐名 `airgap_mm`,Motor-CAD 实际变量名是 `Airgap`(TEST-002 已探测)。此前 `resolve_variable_name` 直接透传导致 `Could not find airgap_mm`。修复:`scripts/robust_motorcad.py` `VARIABLE_NAME_MAP` 增加业务别名 `"airgap_mm": {"default": "Airgap"}`。 2. **point_id 元数据被当变量写**:M3 的 `point_id` 透传标记被 `run_single_point` 参数循环当作 Motor-CAD 变量 `set_variable` 导致 `Could not find point_id`。修复:参数写入循环跳过元数据键(`point_index`/`point_label`/`point_id`)。 ### 验证结果(PASS) | 项目 | 结果 | 详情 | |---|---|---| | EXE 真实模式 | 通过 | `--config` 侧车(enable_mock=false,model_path 绝对路径) | | 认领→求解→回传 | 通过 | 任务 `completed`,duration 167.5s(含 Motor-CAD 启动 + 求解) | | 求解时长 | 通过 | solve_time_s=145.22(单点电磁计算) | | 指标完整性 | 通过 | 20+ 指标(tavg/ripple/efficiency/losses/back_emf/温度类/电流类/转速) | | 数值一致性 | 通过 | tavg_nm=0.52187、eff=86.06%、total_losses=41.945W、back_emf=11.15V —— 与 TEST-010 完全一致 | | point_id 保留 | 通过 | 结果点级带 point_id=1 | | 回归 | 通过 | 全量 test_*.py 16/16 EXIT=0(含 test_robust_solver) | ### 新增测试 - `scripts/test_executor_p5m2.py` 扩至 8 用例:新增 `resolve_variable_name("airgap_mm")=="Airgap"` 映射断言 + `point_id` 排除回归断言。 ### 遗留事项 - 真实短扫描(2+ 点)/多实例(instances>1)可复用本链路在目标机验证;本机已用单点打通"EXE→真实 Motor-CAD→Web"全链路。 - 其余业务参数(current_a 等)的 Motor-CAD 变量名映射待按变量探测逐个补充(AGENTS.md 纪律:不做臆测,逐名探测确认)。 ## TEST-019:P5-M3 adaptive 可视化补全(批次状态 + L0 摘要 + 运行期轮询) **日期**:2026-08-30 **环境**:Windows + 独立后端 8011(未干扰用户常驻 8000)+ 前端 vue-tsc build **目的**:完成 P5-M3 验收点"前端 adaptive 三视图可见"——批次点状态可视化(每批进度/分布)+ L0 预筛选结果前端视图 + adaptive 循环运行期状态推送(轮询增强)。 ### 后端改动 1. `web/backend/app/services/feasibility_search.py` `get_state_summary()` 增加 4 字段: - `infeasible_points` / `failed_points`:状态计数 - `batch_summary`:按 batch_id 分组,每批含 total/pending/ok/infeasible/failed/best_objective(respect objective_direction) - `l0_summary`:sampled/feasible/infeasible/pass_rate/top_infeasible_reasons(name/count/category,从不可行点 feasibility_report 聚合) - 新增 3 个 helper:`_count_by_status` / `_build_batch_summary` / `_build_l0_summary` 2. `web/backend/app/routers/search.py` `SearchStateResponse` 增加对应 4 字段(带默认值,向后兼容)。 ### 前端改动(`views/ai/AdaptiveOptimize.vue`) 1. **运行期自动轮询**:创建 search 后启动 3s 轮询,convergence_status != searching 时自动停止,onBeforeUnmount 清理。 2. **L0 预筛选摘要卡片**:总采样/L0可行/L0拒绝/可行率进度条 + 主要不可行原因 Top N tag。 3. **批次状态总览卡片**:每批一行(批次号/点数/完成进度条/状态分布 tag/批内最优值)。 ### 验证结果(PASS) | 项目 | 结果 | |---|---| | 后端单元测试 | 8/8 PASS(test_search_state_summary.py:正常/报告后聚合/min-max方向/failed计数/空search边界/infeasible原因结构/未知id容错/批次排序) | | 前端类型检查 | vue-tsc && vite build 成功,零类型错误(P5-M1 清零保持) | | 端到端 API | 独立后端 8011:POST /search/create 返回 batch_summary(1批,6点全pending) + l0_summary(sampled=6,pass_rate=1.0);GET /search/{id}/state 同样返回新字段 | | 全量回归 | 16/16 PASS(含新增 test_search_state_summary) | ### 遗留事项 - WebSocket 实时推送未做(P5-M3 验收允许轮询增强;当前 3s 轮询已满足运行期状态可见)。 - L0Prescreen.vue 单点评分页面保持现状(P5-M3 的 L0 视图在 AdaptiveOptimize 内通过 l0_summary 实现)。 ## TEST-020:P5-M4 策略层高级管线(Morris 灵敏度 + IDW 代理 + 预算自适应) **日期**:2026-08-30 **环境**:Windows + 纯 stdlib(无 numpy/scipy/sklearn/lightgbm) **目的**:完成 P5-M4 验收点"蓝图 §6 管线可运行;现有策略回归不破"——新增 Morris 灵敏度筛选策略 + 代理模型引导策略(含预算自适应批次大小),注册到 strategies 注册表。 ### 依赖评估与降级决策 - 环境探测:numpy/scipy/sklearn/lightgbm **全部未安装**。 - 项目纪律:feasibility_search.py / lhs.py 均标注 "Pure-Python implementation (no numpy/scipy dependency)"。 - P5 规划 §6 约束:"Kriging/NSGA-II 引入新依赖——P5-M4 先评估,轻量实现优先,避免重依赖"。 - **决策**:代理模型用纯 stdlib **IDW(反距离加权)** 替代 Kriging。IDW 给出预测值 + 基于最近邻距离的不确定性,支持 explore-exploit 权衡;精度低于 Kriging(尤其非平稳曲面),但满足"预测+不确定性选点"核心需求。后续如需 Kriging 须引入 scipy 并在同接口下替换。 ### 新增策略 1. **`MorrisStrategy`**(`src/afmcore/strategies/morris.py`,kind=`morris`) - 纯 stdlib Morris OAT 灵敏度筛选:n_trajectories 条轨迹,每条 n_params+1 个点 - 每步只变一个参数(随机排列 + ±Δ 方向),Δ = n_levels/(2(n_levels-1)) - `state()` 返回 `sensitivity_ranking`(每参数 mu/mu_star/sigma/n_effects,按 mu_star 降序)+ `key_parameters`(mu_star>0 的前半) - 奇数 n_levels 自动转偶数;参数值带 step 时自动对齐网格 2. **`SurrogateGuidedStrategy`**(`src/afmcore/strategies/surrogate_guided.py`,kind=`surrogate_guided`) - 两阶段:初始 LHS 采样(n_initial)→ 代理引导选点(UCB 采集) - IDW 代理:预测 = Σ(y_i/d_i^p) / Σ(1/d_i^p),不确定性 = 最近邻归一化距离 - UCB 采集:score = pred + kappa*uncertainty(maximize)或 -pred + kappa*uncertainty(minimize) - 预算自适应批次大小:growth = 1 + mean_uncertainty * remaining_budget_ratio,size ∈ [1, max_batch_size] - `state()` 返回 phase(initial/surrogate_guided/exhausted)、budget 用量、surrogate 诊断(n_train/loo_rmse/mean_uncertainty/last_batch_size) - select_next 时记录 point_id→params 映射,report 时自动关联(基类协议无需改) ### 验证结果(PASS) | 项目 | 结果 | |---|---| | Morris 单元测试 | 15/15 PASS(test_strategy_morris.py:轨迹点数/step0无changed_param/线性函数灵敏度排名/收敛/空参数/单轨迹/奇数n_levels/参数边界/未知id/缺失metric/failed排除/注册/state契约) | | Surrogate 单元测试 | 17/17 PASS(test_strategy_surrogate.py:初始LHS/bowl收敛/maximize/空参数/budget耗尽/n_initial>budget/自适应批次边界/未知id/缺失metric/failed排除/注册/state契约/IDW预测/距离计算/归一化往返) | | Morris 冒烟 | 线性函数 y=2a+0.5b,灵敏度排名 a(mu_star=2.0) > b(0.5),sigma=0(线性无交互)✅ | | Surrogate 冒烟 | bowl 函数 y=(a-0.5)^2+(b-0.5)^2,budget=30,best y=0.007(理想 0.0),LOO RMSE=0.089 ✅ | | 策略注册 | list_strategy_kinds() = [adaptive, full_factorial, lhs, morris, surrogate_guided] ✅ | | 全量回归 | 19/19 PASS(含 2 个新测试) | ### 遗留事项 - Kriging 代理未实现(环境无 scipy,项目纪律纯 stdlib);IDW 为降级替代,已在策略 docstring 标注升级路径。 - NSGA-II 多目标优化不在 P5-M4 范围(蓝图 §6.4,可能 P5-M5+)。 - 代理模型未接入 Web 端 plan_schema 的 method 字段(当前 strategies 注册表可用,Web 端 method 白名单待扩展)。 ## TEST-021:P5-M5 多工具适配器(Maxwell/JMAG mock + 执行器 tool 参数化) **日期**:2026-08-30 **环境**:Windows + 纯 stdlib(无 Ansys Maxwell / JMAG 真实安装) **目的**:完成 P5-M5 验收点"`get_adapter("maxwell")` 可跑 mock/真实链路"——新增 MaxwellAdapter 和 JMAGAdapter,注册到适配器注册表,执行器 `tool` 参数动态选择适配器。 ### 真实接入环境依赖标注 - **Ansys Maxwell**:真实接入需要 Ansys Maxwell + PyAEDT(ansys-pythonnet),当前环境未安装。mock 实现保持接口稳定,真实接入路径已在适配器 docstring 标注(connect/set_parameter/run_simulation/extract_metrics 对应 PyAEDT 调用)。 - **JMAG**:真实接入需要 JMAG Designer + Python API(jmagpy),当前环境未安装。mock 实现同理。 - 与既有 Motor-CAD 同策略:接口 + mock 链路先行,真实接入标注环境依赖(P5 规划 §6 约束)。 ### 新增适配器 1. **`MaxwellAdapter`**(`src/afmcore/adapters/maxwell.py`,tool=`maxwell`) - mock 实现:内存参数记录 + 回读校验 + 确定性合成指标 - capability_domains = ("electromagnetic", "thermal")(含 winding_temp_c 热指标) - 指标模型:tavg=0.50*airgap+0.30*magnet+0.10;eff=85.0+0.10*airgap;losses=42.0-0.80*airgap - mock=False 时 connect() 抛 RuntimeError(明确标注环境依赖) 2. **`JMAGAdapter`**(`src/afmcore/adapters/jmag.py`,tool=`jmag`) - mock 实现,指标系数与 Maxwell 略有不同以区分工具 - capability_domains = ("electromagnetic",) - 指标模型:tavg=0.45*airgap+0.32*magnet+0.12;eff=84.5+0.12*airgap;losses=43.0-0.75*airgap ### 执行器改造 - `scripts/task_executor.py` `MotorCADTaskExecutor._ensure_adapter()`:从硬编码 `import afmcore.adapters.motorcad` 改为根据 `self.tool` 动态 import(motorcad/maxwell/jmag),未知 tool 依赖预注册适配器。 - `executor_config.json` 的 `tool` 字段(P5-M2 已加)现在可选择 "motorcad"/"maxwell"/"jmag"。 ### 验证结果(PASS) | 项目 | 结果 | |---|---| | 适配器注册 | registered_tools() 含 maxwell/jmag ✅ | | Maxwell mock 全链路 | connect→load→set→run→extract→run_point,status=OK,tavg=2.10(airgap=1,magnet=5)✅ | | JMAG mock 全链路 | 同上,tavg=2.17(系数不同,可区分工具)✅ | | 工具区分 | 相同参数 maxwell tavg=2.10 ≠ jmag tavg=2.17 ✅ | | set_parameter 回读校验 | 写入后回读一致 ✅ | | 边界:空参数 | tavg=0.10(所有参数默认 0)✅ | | 边界:未 connect 就 run | 抛 RuntimeError ✅ | | 异常:mock=False | connect() 抛 RuntimeError(环境依赖标注)✅ | | 异常:未知 tool | get_adapter 抛 KeyError ✅ | | 执行器动态 import | tool=maxwell→adapter.tool_name="maxwell";tool=jmag→"jmag";未知 tool→KeyError ✅ | | 单元测试 | test_adapters.py 22/22 PASS | | 全量回归 | 20/20 PASS(含新测试) | ### 遗留事项 - 真实 Maxwell/JMAG 接入待目标机环境(需安装对应软件 + Python API)。 - Maxwell 热域(winding_temp_c)当前为合成值,真实接入后从 Maxwell 热求解器提取。 - 前端/GUI 工具选择下拉框待扩展(当前 executor_config.json 可配,Web 端任务创建页待加 tool 字段)。 ## TEST-022:P5-M6 多物理场 L2 接入(热网络+结构指标 + 报告模板化) **日期**:2026-08-30 **环境**:Windows + 纯 stdlib(无真实 Motor-CAD 热求解运行) **目的**:完成 P5-M6 验收点"热指标入库与报告展示"——metrics.py 扩项(热网络+结构指标,自动生效)、robust_motorcad 热求解开关、report_generator 按物理域分组模板化。 ### 1. metrics.py 扩项(单一事实源,自动生效) 新增 10 个指标(均 required=False,不影响现有必需指标校验): **热网络指标(domain=thermal)**: | key | label | unit | direction | |---|---|---|---| | winding_hotspot_temp_c | Winding Hotspot Temp | C | lower | | magnet_temp_c | Magnet Temp | C | lower | | stator_temp_c | Stator Temp | C | lower | | bearing_temp_c | Bearing Temp | C | lower | | temp_rise_c | Temperature Rise | C | lower | | thermal_resistance_k_w | Thermal Resistance | K/W | lower | **结构/机械指标(domain=structural)**: | key | label | unit | direction | |---|---|---|---| | axial_force_n | Axial Force | N | lower | | radial_force_n | Radial Force | N | lower | | max_stress_mpa | Max Stress | MPa | lower | | deformation_mm | Max Deformation | mm | lower | 每个指标含英文+中文(\uXXXX)别名。`extract_all_metrics()` 遍历 METRIC_DEFINITIONS,新指标自动被提取,无需调用方修改。总指标数从 25 增至 35。 ### 2. robust_motorcad.py 热求解开关 - `__init__` 新增 `enable_thermal: bool = False`(默认关,保持现有电磁-only 行为) - `run_single_point` 新增 `enable_thermal: Optional[bool] = None`(覆盖实例默认) - 电磁求解后尽力而为调用 `do_thermal_calculation()`(失败记录警告,不中断电磁结果) - 电磁导出后尽力而为导出 Thermal 结果并合并 metrics(失败记录警告) - 热求解需要模型配置热网络,标注为环境依赖 ### 3. report_generator.py 按物理域分组模板化 - Results Summary 从单一 metrics 表改为按域分组:Electromagnetic / Thermal / Structural - 每个域一个 level=2 子标题 + 表格,空域跳过 - 从 afmcore.metrics 导入 METRIC_DEFINITIONS 获取 domain/label/unit(单一事实源) - `_metric_display()` 格式化 label(含 unit)和 value(float 用 %.4g) - JSON fallback report 也包含 `metrics_by_domain` 字段 ### 验证结果(PASS) | 项目 | 结果 | |---|---| | 新指标定义 | 热6+结构4,均有 domain 字段,required=False ✅ | | 总指标数 | 35(原25+新10)✅ | | 热指标提取 | mock CSV 含 Magnet Temperature 等字段,extract_all_metrics 自动提取 ✅ | | 结构指标提取 | mock CSV 含 Axial Force 等字段,自动提取 ✅ | | 中文别名 | \u6c38\u78c1\u4f53\u6e29\u5ea6 → magnet_temp_c ✅ | | 必需指标校验 | 缺热/结构指标不影响 check_required_metrics ✅ | | 域分组 | electromagnetic/thermal/structural 正确分组,空域跳过 ✅ | | 未知 key | 默认归入 electromagnetic ✅ | | 报告 JSON | metrics_by_domain 字段存在,热/结构域正确 ✅ | | robust 热参数 | __init__ 和 run_single_point 均有 enable_thermal 参数 ✅ | | 单元测试 | test_metrics_extension.py 20/20 PASS | | 全量回归 | 21/21 PASS(含新测试) | ### 遗留事项 - 真实 Motor-CAD 热求解未运行(需要模型配置热网络 + 实际启动 Motor-CAD,当前为代码路径预留)。 - 结构指标(轴向力/应力/变形)需要 Motor-CAD 结构模块或第三方 FEA 工具,当前为 metrics 定义+报告展示预留。 - 原有 winding_temp_c 指标无 domain 字段,默认归入 electromagnetic(可后续加 domain=thermal)。 --- ## 2026-08-30: 拓扑感知变量名映射与执行前校验(P5-M2) ### 测试环境 - OS: Windows - Python: 3.x - Motor-CAD: 2026R1 (v261) - 后端: FastAPI + SQLite - 前端: Vue3 + Element Plus ### 测试目的 修复 Plan 23 全部 80 个扫描点失败的问题,并建立根本性防护机制,防止 RFM/AFM 变量名不匹配错误再次发生。 ### 问题根因 Plan 23 的扫描变量使用了径向磁通电机(RFM)的变量名: - `Stator_Lam_Outer_Dia`(80~100mm,5 档) - `Stator_Lam_Inner_Dia`(45~60mm,4 档) - `Magnet_Thickness`(2~5mm,4 档) 4 × 5 × 4 = 80 个点,全部在写入第一个参数 `Stator_Lam_Outer_Dia` 时失败: ``` RuntimeError: MotorCADError writing Stator_Lam_Outer_Dia: pymotorcad: set_variable: Error in SetVariable: Could not find Stator_Lam_Outer_Dia ``` 当前模型 `MARS-12S10P_SSSR_D76-C150_V5.0-0819.mot` 是轴向磁通电机(SSSR),正确的变量名是 `Stator_Outer_Diameter` / `Stator_Inner_Diameter`。 ### 修复措施 1. 新增 `topology_variable_map.py`:拓扑感知变量名映射表(41 个 AFM 已知变量 + RFM→AFM 别名映射 + 模板逻辑名映射) 2. 修复 `_expand_plan_to_parameters()`:扫描变量经过模板 motorcad_var + 拓扑别名映射 3. 新增 `start_simulation` 执行前变量名校验:未知变量返回 400 + 建议名 4. 补充模板 8 个参数的 motorcad_var 5. 新增 `GET /api/plans/variable-catalog` API 6. 前端 PlanDetail.vue 从后端获取变量目录 ### 测试步骤与结果 | 测试项 | 结果 | |---|---| | 拓扑归一化(SSSR/AFIR/RFM/None/别名) | ✅ PASS | | RFM→AFM 别名解析(Stator_Lam_Outer_Dia → Stator_Outer_Diameter) | ✅ PASS | | 模板逻辑名映射(Number_of_Slots → Slot_Number) | ✅ PASS | | 已知变量校验(AFM 变量已知,RFM 变量在 AFM 拓扑未知) | ✅ PASS | | 参数批量校验(valid/unknown/aliases_resolved 分类) | ✅ PASS | | 未知变量建议(suggest_alternative) | ✅ PASS | | 已知变量集合获取(41 个 AFM 变量) | ✅ PASS | | **Plan 23 回归测试**(80 点,RFM 名被映射,全部已知) | ✅ PASS | ### 单元测试 - 文件:`scripts/test_topology_variable_map.py` - 结果:8/8 PASS - 运行命令:`python scripts/test_topology_variable_map.py` ### 关键数据 - AFM (SSSR) 已知变量数:41 - 模板参数总数:37 - 有 motorcad_var 的模板参数:35(仅剩 Current_Density、Insulation_Class 合理留空) - Plan 23 失败点数:80/80(修复前)→ 0/80(修复后,全部可正确映射) ### 遗留事项 - 后端服务需重启以加载新代码(uvicorn --reload 模式自动重载) - 真实 Motor-CAD 运行验证待执行(需要重启后端后重新启动 plan 23 仿真) - AFIR 拓扑的特有变量待补充(当前继承 SSSR 变量集合) - AI 方案生成端的拓扑感知变量名选用待集成(当前后端映射层已能兜底) --- ## 2026-08-30: AI 一键生成方案 422 错误修复(P5-M2 补充) ### 问题现象 在项目详情页点击"一键 AI 生成方案"按钮,前端报错。后端返回 422: ``` Invalid generated plan: plan_data malformed: could not convert string to float: 'Star' ``` ### 根因 `src/plan_schema.py` 中 `FixedParam.value` 被定义为 `float` 类型,且 `from_dict()` 中强制 `float(d.get("value", 0.0))` 转换。 AI 生成的方案中包含字符串枚举类型参数: - `Winding_Connection`: `"Star"`(星形连接) - `Cooling_Type`: `"Natural Convection"`(自然冷却) - `CurrentDefinition`: `"Peak"`(峰值电流) 这些是 Motor-CAD 合法的枚举/字符串参数,但 `float("Star")` 抛出 `ValueError`,被 `validate_plan_dict()` 捕获后返回 422。 ### 修复措施 修改 `src/plan_schema.py`: 1. `FixedParam.value` 类型从 `float` 改为 `Any`(支持数字和字符串枚举) 2. `from_dict()` 中移除 `float()` 强制转换,保持原始值类型 3. `generate_full_params()` 返回类型注解从 `dict[str, float]` 改为 `dict[str, Any]` ### 测试结果 | 测试项 | 结果 | |---|---| | FixedParam 接受字符串枚举值(Winding_Connection="Star") | ✅ PASS | | 数字值(int/float)仍正常工作 | ✅ PASS | | to_dict -> from_dict 字符串值往返保留 | ✅ PASS | | 混合数字/字符串参数的方案校验通过 | ✅ PASS | | generate_full_params 保留字符串枚举值 | ✅ PASS | | 空 fixed_params 边界情况 | ✅ PASS | | AI 生成方案完整回归测试(9 固定参数 + 2 扫描变量 = 9 点) | ✅ PASS | ### 单元测试 - 文件:`scripts/test_plan_schema.py` - 结果:7/7 PASS - 运行命令:`python scripts/test_plan_schema.py` ### 影响范围 - 此修复不影响已有数字参数的行为(int/float 保持原类型) - 字符串枚举参数现在可以正常通过校验、保存到数据库、并在仿真执行时传递给 Motor-CAD - 后端服务需重启以加载新代码 ## TEST-024:环境体检脚本 check_machine_paths.py 验证 **日期**:2026-09-01 **测试环境**:Windows,Python 3.14.7(AI shell),Motor-CAD v261,git 仓库 **测试目的**:验证新增的 scripts/check_machine_paths.py(Playbook V2 落地:换机/新会话环境体检)能正确检查并报告环境状态。 **测试脚本**:`scripts/check_machine_paths.py` **输出目录**:无(只读体检,stdout 直接输出) ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | 运行 `python scripts/check_machine_paths.py` | ✅ | 退出码 1(存在缺项时按设计返回 1) | | 2 | Python 版本 | ✅ | 3.14.7(≥3.10) | | 3 | 环境变量 | ✅ | MOTORCAD_ACTIVEX=...activex.bat;ANSYSLMD_LICENSE_FILE=1055@localhost | | 4 | Motor-CAD exe | ✅ | activex.bat + D:\Program Files\ANSYS Inc\v261\motorcad\MotorCAD.exe 均存在 | | 5 | Python 依赖包 | ⚠️ | 6 包在当前 AI shell 解释器 MISSING(预期:shell 未装项目依赖,需在项目实际解释器下运行或 pip install) | | 6 | Git 状态 | ⚠️ | HEAD 有效;工作区有未提交改动(本次框架升级文件,待提交) | | 7 | 仓库资产 | ✅ | models/*.mot、experience.db、executor_config.json、web/、src/afmcore 全部就位 | | 8 | node/npm | ✅ | 在 PATH 上 | | 9 | py_compile + ASCII | ✅ | check_machine_paths.py 编译通过、纯 ASCII(符合硬性约束 §1) | ### 关键数据 / 发现的问题 / 修复措施 - **关键数据**:无项目内 `.venv/.env`(venv 探测未命中)→ 包缺失反映的是当前 shell 解释器视图,非项目实际运行环境;项目真实依赖需按 KNOWLEDGE_BASE §1 安装(`pip install ansys-motorcad-core pyside6 pandas` 等)。 - **发现的问题**:AI shell 的 Python 3.14 与项目依赖环境分离,`find_spec` 全部 MISSING 属环境差异而非脚本 bug。 - **修复措施**:脚本已加“项目 venv 探测”提示(若存在 .venv 会提示用其解释器复检);`--fix` 打印精确修复命令(setx / pip install)但不自动执行,避免脚本擅自改系统环境。 - **验证方式**:同一脚本两条命令(默认 + --fix)运行观察;py_compile 编译;ASCII 字符集检查。 ## TEST-025:AI 方案生成 topology/search_strategy 归一化修复验证 **日期**:2026-09-02 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Kimi k3,SQLite **测试目的**:验证 AI 一键生成方案在 topology='AFIR' 且 search_strategy.method='full_factorial_grid' 时不再 422 报错,正确归一化兜底。 **相关文件**:web/frontend/src/views/ProjectList.vue、web/backend/app/services/plan_generator.py、web/backend/app/routers/ai_plan.py ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile 语法检查 | ✅ | 两个改动 .py 编译通过 | | 2 | afmcore.topology.is_supported | ✅ | AFIR=False,SSSR/DRSS/SDSR=True | | 3 | afmcore.strategies 归一化 | ✅ | full_factorial_grid 未注册;active_learning→adaptive 已注册 | | 4 | convert_ai_plan_to_unified 函数级测试 | ✅ | method=full_factorial_grid→full_factorial + warning;method=lhs 保留 | | 5 | 真实端到端 API(AFIR 项目 id=9 generate-and-save) | ✅ | HTTP 200,topology→SSSR、method→full_factorial,warnings 正确 | ### 关键数据 / 发现的问题 / 修复措施 - **关键数据**:端到端返回 topology="SSSR"、search_strategy.method="full_factorial",warnings 含 "Unknown topology 'AFIR' - defaulted to SSSR" 与 "Unknown search strategy method 'full_factorial_grid' - defaulting to full_factorial"。 - **发现的问题**:AI 偶发输出非标准变量名(Stator_Outer_Diameter_mm、Turns_Per_Coil)触发 warning(不影响生成),属独立问题待后续。 - **修复措施**:三处修复(前端拓扑选项对齐 + 后端 topology/strategy 归一化兜底),测试产物(临时脚本、测试方案)已清理。 ## TEST-026:Kimi max_tokens 撞顶修复 + AI 生成摘要对话框验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Kimi k3,Vue3 + Element Plus **测试目的**:验证 P0-2(Kimi max_tokens 撞顶导致 content 空)与 P0-1(AI 生成摘要对话框)修复。 **相关文件**:web/backend/app/services/ai_client.py、web/backend/app/services/plan_generator.py、web/frontend/src/views/ProjectDetail.vue ### 背景 / 根因 - plan_generator.py 调用 chat_json 写死 `max_tokens=2000`(.env 的 KIMI_MAX_TOKENS=4096 未生效);k3 推理模型的 reasoning_content 会吃满 2000,导致 content 为空 → JSON 解析失败 → "AI 生成失败"(对应用户"超时"截图的一个隐藏根因,ai_call_logs id=40 实测 completion_tokens=2000、content 空)。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII 检查(2 个 .py) | ✅ | 编译通过、纯 ASCII | | 2 | vue-tsc --noEmit 类型检查 | ✅ | 0 错误 | | 3 | 端到端 generate-and-save(SSSR 项目 id=1) | ✅ | HTTP 200,topology=SSSR,warnings 完整返回 | | 4 | max_tokens 生效核对(最新 ai_call_log id=45) | ✅ | completion_tokens=650(未撞顶)、content 完整 JSON、duration 18.5s、status=success | ### 修复内容 - ai_client.py:chat() 未传 max_tokens 时默认用 KIMI_MAX_TOKENS;新增 finish_reason=length 且 content 空时的 logger.warning。 - plan_generator.py:两处 max_tokens=2000 → KIMI_MAX_TOKENS。 - ProjectDetail.vue:AI 生成成功后改为"方案生成摘要"对话框(方案概要 + 系统调整 warnings 逐条 + AI 设计思路折叠 + 查看方案/留在本页),替代原只显示第一条的 ElMessage;loading overlay 增加已等待秒数(AbortController 取消本已存在)。 ### 关键数据 / 遗留 - **关键数据**:端到端 warnings=["Slot_Depth 非标准变量", "Removed Slot_Depth (点数裁剪)", "full_factorial_grid→full_factorial"],验证摘要对话框数据链完整。 - **遗留**:AI 仍偶发输出非标准变量名(Slot_Depth 等)被裁剪,属独立问题;P0-3(仿真前检查清单)/ P0-4(TaskManager 方案下拉)/ P1(参数目录)未做。 ## TEST-027:仿真前检查清单 + TaskManager 方案自动展开验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Vue3 + Element Plus **测试目的**:验证 P0-3(PlanDetail 仿真前检查清单)与 P0-4(TaskManager 创建任务从方案自动展开参数)。 **相关文件**:web/backend/app/routers/plans.py、web/backend/app/routers/tasks.py、web/frontend/src/views/PlanDetail.vue、web/frontend/src/views/TaskManager.vue ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII(plans.py/tasks.py) | ✅ | 编译通过、纯 ASCII(preflight 只返回 key/status,中文 label 在前端) | | 2 | vue-tsc --noEmit | ✅ | 0 错误 | | 3 | preflight API(plan 1)首次 | ⚠️→✅ | 初测 model_path fail(相对路径 `models/xx.mot` 相对后端 cwd 解析失败);修复为用 PROJECT_ROOT 解析相对路径后 pass | | 4 | preflight API 复测 | ✅ | ok=true;model_path pass、scan_vars=1、point_count=3、executor warn(0 在线) | | 5 | tasks 自动展开(POST /api/tasks 仅传 plan_id=1) | ✅ | HTTP 200,total_points=3(1 变量 × 3 值自动展开),status=pending | ### 修复内容 - plans.py:新增 `GET /{plan_id}/preflight`(5 项检查:模型文件/变量名确认/扫描变量/数据点规模/执行器在线;fail 阻断、warn 提示);model_path 相对路径用 PROJECT_ROOT 解析。 - tasks.py:`POST /api/tasks` 的 plan_data/parameters 改为可选;仅传 plan_id 时自动加载方案并调用 `_expand_plan_to_parameters` 展开,显传仍优先(高级覆盖)。 - PlanDetail.vue:启动仿真改为先调 preflight 弹检查清单对话框(状态图标 + 中文 label 映射 + fail 禁用启动),确认后才调 start-simulation。 - TaskManager.vue:doCreate 仅在用户编辑高级 JSON 时才传 plan_data/parameters,否则省略由后端自动展开;onPlanSelect 重置高级 JSON;加"默认从方案自动带出参数"提示。 ### 关键数据 / 遗留 - **关键数据**:tasks 自动展开 total_points=3 正确;preflight 5 项状态机正确(executor 离线为 warn 不阻断,任务可排队)。 - **测试产物**:测试任务 7d55dc4f 已 cancel(任务文件在 output/tasks/,不入库)。 - **遗留**:P1(参数目录单一事实源 + D6 调用链验证)未做。 ## TEST-028:D6 边界条件 key 别名桥修复验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Kimi k3 **测试目的**:验证 D6 数据一致性 Bug 修复——ProjectDetail 录入的边界条件 key(current_a/speed_rpm 等)能流入 build_default_fixed_params 的固定参数推断。 **相关文件**:web/backend/app/services/fixed_params_template.py ### 根因(确认) - `build_default_fixed_params` 读取 BC key 用 `rated_current_a/rated_speed_rpm/slot_count/dc_link_voltage_v/cooling_method`,而 ProjectDetail 录入 + rule_engine 消费用 `current_a/speed_rpm/slots/voltage_v/cooling_type` → 用户在项目边界表单填的电流/转速/槽数/电压/冷却方式**不流入**固定参数推断(落模板默认值)。 - 另发现 `Magnet_Temperature`/`Max_Speed` 完全无 BC 推断。 ### 修复 - build_default_fixed_params 入口加 BC key 别名桥(canon 优先、别名补填、拷贝不改调用方 dict);补 Magnet_Temperature(magnet_temp_c)/ Max_Speed(max_speed_rpm)推断。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII | ✅ | 通过 | | 2 | 函数级验证(11 断言) | ✅ | 前端 7 key 全部正确流入;旧 rated_ key 向后兼容;调用方 dict 不被修改 | | 3 | 端到端(project 9 generate-and-save) | ✅ | HTTP 200;RMSCurrent=20(BC)、Shaft_Speed=3000(BC)、Number_of_Slots=12、DC_Link_Voltage=48、Magnet_Temperature=40、Cooling_Method=Natural、Max_Speed=6000,全部来自 BC 而非模板默认 | ### 关键数据 / 遗留 - **关键数据**:端到端固定参数全部取自项目 BC(current_a=20/speed_rpm=3000/slots=12/voltage_v=48/magnet_temp_c=40/cooling_type=Natural/max_speed_rpm=6000),D6 修复生效。 - **顺带确认**:拓扑兜底(AFIR→SSSR)、策略兜底(grid_search_with_refinement→full_factorial)持续正常。 - **遗留**:完整参数目录单一事实源(P1-1,含 PlanDetail BC_TEMPLATE 对齐、rule_engine、参数目录 API、数据迁移)为大重构,本轮未做;AI 偶发非标准变量名(Stator_Outer_Diameter/Turns_Per_Coil)被裁剪,独立问题。 ## TEST-029:BC 字段目录单一事实源(P1-1 第一阶段)验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Kimi k3,Vue3 **测试目的**:验证 BC 字段目录单一事实源落地——后端目录 API、方案保存 BC、PlanDetail BC 展示从目录渲染。 **相关文件**:web/backend/app/services/bc_fields.py(新建)、routers/generation.py、routers/ai_plan.py、routers/plans.py、web/frontend/src/views/PlanDetail.vue ### 背景(确认的事实) - BC key 三套口径漂移(ProjectDetail/rule_engine 用 current_a 系、fixed_params_template 用 rated_ 系、PlanDetail BC_TEMPLATE 用第三套 rated_)。 - 所有方案 plan.boundary_conditions 均为 None → PlanDetail"边界条件"展示区模板错位 + 数据源为空,双重失效(死功能)。 ### 修复内容 - 新建 bc_fields.py:BC_FIELD_CATALOG(25 字段,规范 key 对齐录入端/rule_engine,含 \uXXXX label/unit/category/aliases)+ normalize_bc(别名→规范,规范优先,不改调用方)。 - generation.py:新增 `GET /api/bc-fields` 暴露目录。 - ai_plan.py(AI 生成)+ plans.py(手动创建):把归一化后的 project BC 存入 plan_data.boundary_conditions。 - PlanDetail.vue:删除硬编码 BC_TEMPLATE,改为从 /api/bc-fields 目录渲染。 ### 踩坑与解决 - Write 工具把 `\uXXXX` 转义直接落成实际中文字符 → 文件非 ASCII 且 docstring 字面 `\uXXXX` 触发 truncated escape。解决:先写中文,再用 `encode('ascii','backslashreplace')` 转换脚本统一转 \uXXXX;docstring 避免字面 `\uXXXX`。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII(5 个 .py) | ✅ | 通过、纯 ASCII | | 2 | normalize_bc 功能 | ✅ | rated_current_a→current_a(规范优先)、slot_count→slots、cooling_method→cooling_type、unknown 透传 | | 3 | vue-tsc --noEmit | ✅ | 0 错误 | | 4 | /api/bc-fields | ✅ | 25 字段、label 中文正确、aliases 正确 | | 5 | 端到端(project 9 generate-and-save) | ✅ | plan.boundary_conditions 完整保存 25 个规范 key 的 BC | ### 遗留 - P1-1 第二阶段未做:前端 ProjectDetail bcFields 从目录渲染(表单)、rule_engine/fixed_params_template key 彻底统一、已存数据迁移、scan 变量目录与 BC 目录合并为统一参数目录。 - AI 偶发非标准变量名被裁剪,独立问题。 ## TEST-030:BC key 读取统一走 normalize_bc(P1-1 第二阶段)验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Kimi k3 **测试目的**:消除固定参数推断的双重转换——build_default_fixed_params 与 rule_engine 统一走 bc_fields.normalize_bc 单一事实源,删除本地 rated_ 别名桥。 **相关文件**:web/backend/app/services/fixed_params_template.py、rule_engine.py、bc_fields.py ### 背景 第一阶段后存在双重转换:normalize_bc 输出 current_ 系,build_default_fixed_params 仍用本地 _ALIASES 桥把 current_ 再转 rated_ 读取。本阶段统一为:BC → normalize_bc(唯一别名处理点)→ 各消费端直接读规范 key。 ### 修复内容 - fixed_params_template.build_default_fixed_params:改为 `bc = normalize_bc(...)`,删除本地 _ALIASES 桥,elif 改读规范 key(current_a/speed_rpm/slots/voltage_v/cooling_type)。 - rule_engine.BoundaryConditions.from_dict:开头加 normalize_bc,旧 rated_ 数据正确解析。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII(3 个 .py) | ✅ | 通过 | | 2 | 统一性验证(14 断言) | ✅ | current_ 规范 key 流入;rated_ 旧 key 经 normalize_bc 兼容;rule_engine 解析 rated_;不改调用方 dict | | 3 | 后端运行时 import | ✅ | fixed_params_template→bc_fields、rule_engine→bc_fields 无循环,health OK | | 4 | 端到端(project 9 generate-and-save) | ✅ | 固定参数推断仍全对(RMSCurrent=20/Shaft_Speed=3000/Slots=12/DC=48/MagnetTemp=40/Cooling=Natural/MaxSpeed=6000) | ### 遗留 - 已存 DB 数据的 rated_ key(project 3/8)由 normalize_bc 读取时兼容,不做物理迁移(避免改用户数据)。 - scan 变量目录(rule_engine.SCAN_PARAMETERS)与 BC 目录(bc_fields)为不同维度(Motor-CAD 变量 vs 工程边界概念),保持分离不合并。 - 前端 ProjectDetail 表单 key 已与目录一致(设计目录时即对齐 bcFields),无需改动。 ## TEST-031:仿真耗时校准 + AFIR 非标准拓扑标记(P2-1/P2-3)验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Vue3 **测试目的**:验证 P2-1 耗时校准(实测 solve_time_s 替代硬编码)与 P2-3 AFIR 非标准拓扑前端标记。 **相关文件**:web/backend/app/routers/analytics.py、web/frontend/src/views/PlanDetail.vue、web/frontend/src/views/ProjectList.vue ### 数据基础 - simulation_results.solve_time_s:11 条有效实测,avg=125.9s(≈2.1 分钟/点)、min=118s、max=141.4s、median=121s。证实硬编码 2.5 分钟/点高估约 19% 且不能反映实测。 ### 修复内容 - analytics.py:新增 `GET /api/analytics/solve-time-stats`(avg/min/max/median/count)。 - PlanDetail.vue:perPointMin 用实测 avg_s(fallback 2.5 分钟/点),estimatedTimeMin/estimatedRemaining 改用它;"预计耗时"卡片下加依据("基于最近 N 次实测 ~Xs/点")。 - ProjectList.vue:非标准拓扑(不在 SSSR/DRSS/SDSR)项目 tag 改 warning 色 + 警告图标 tooltip"非标准拓扑,按 SSSR 处理"(不改 DB,后端已有兜底)。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII(analytics.py) | ✅ | 通过 | | 2 | vue-tsc --noEmit | ✅ | 0 错误 | | 3 | /api/analytics/solve-time-stats | ✅ | count=11, avg=125.9, min=118, max=141.4, median=121 | | 4 | AFIR 项目识别 | ✅ | id 9/10/11 topology=AFIR 被识别为非标准,前端将标记 | ### 遗留 - P2-2(步骤条交互向导)/ P2-4(结果表列配置)未做,价值中低,留后续。 - AI 偶发非标准变量名被裁剪,独立问题。 ## TEST-032:AI 扫描变量归一化 + 注册表扩充验证 **日期**:2026-09-03 **测试环境**:Windows,系统 Python 3.12.10(uvicorn 0.52.4 / fastapi 0.141.1),Kimi k3 **测试目的**:解决 AI 推荐变量被误判"非标准"导致扫描维度被裁剪/警告的问题——扩充 SCAN_PARAMETERS 注册表 + 补变量名归一化映射。 **相关文件**:web/backend/app/services/rule_engine.py、plan_generator.py ### 调查(基于 ai_call_logs 证据) AI 高频推荐但非标准的变量:Turns_per_Coil(匝数,9 次)、Stator_Outer_Diameter(定子外径,9 次)、Slot_Depth(3 次)、Stator_Inner_Diameter、Wire_Diameter。均为 fixed_params_template 里的有效 Motor-CAD 变量,仅因不在 SCAN_PARAMETERS(原 8 个)被误判。 ### 修复内容 - rule_engine.SCAN_PARAMETERS 8→13:新增 Stator_Outer_Diameter/Stator_Inner_Diameter/Slot_Depth/Turns_per_Coil/Wire_Diameter,范围锚定 MARS 基线(198/122/7/20/1.63)±20-50%。 - plan_generator._VARIABLE_NAME_MAP 补 25 个 AI 变体名映射(Turns_Per_Coil/coil_turns/Stator_Outer_Dia/Stator_OD/Stator_Lam_Outer_Dia/Stator_Slot_Depth 等)。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | py_compile + ASCII | ✅ | 通过 | | 2 | 归一化验证(16 断言) | ✅ | 12 个变体名归一化到注册名;convert 不再产生"not a standard"warning;变量被保留 | | 3 | 注册表扩充 | ✅ | 8→13,5 个新变量范围正确 | | 4 | 端到端(project 9) | ✅ | "非标准变量"warning 消失;Stator_Outer_Diameter 保留为扫描维度(values=5) | ### 关键数据 / 遗留 - **关键改善**:修复前 Stator_Outer_Diameter/Turns_per_Coil 被标"非标准"并裁剪;修复后成为标准变量被保留。 - **遗留(设计决策,非缺陷)**:4 个变量且点数超 MAX_POINTS=200 时仍保守裁剪(本次 Turns_per_Coil 因 240 点超限被裁)。若需保留更多维度,应改为点数超限时切换 lhs/adaptive 采样而非砍变量——属另一独立优化,未实施。 ## TEST-033:结果表列配置(P2-4)验证 **日期**:2026-09-03 **测试环境**:Windows,Vue3 + Element Plus 2.4 **测试目的**:验证结果表列配置——默认只显示核心指标 + 扫描变量,35 项指标按需勾选显示(解决指标扩展后结果表全部铺开拥挤的问题 D14)。 **相关文件**:web/frontend/src/views/PlanDetail.vue ### 修复内容 - PlanDetail.vue 结果表新增列设置:defaultColumnKeys(核心 5 列 + 扫描变量列);displayColumns 按 visibleColumnKeys 过滤;新增"列设置"按钮 + checkbox 对话框(全部列按需勾选)+"恢复默认"。表格列从 allResultColumns 改为 displayColumns。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | vue-tsc --noEmit | ✅ | 0 错误 | | 2 | 前后端服务 | ✅ | 前端 5173 HTTP 200,后端 health OK(纯前端改动,Vite 热更新) | ### 遗留 - 全部既定优化项(P0/P1/P2 + D6 + AI 变量归一化)已完成。P2-2(步骤条交互)价值低未做。 - 可选深化:点数超限切换 lhs/adaptive 采样保留维度;结果表列配置可持久化到 localStorage(当前会话内有效)。 ## TEST-034:UI 评审实测修复(P0/P1/P2,截图验证) **日期**:2026-09-03 **测试环境**:Windows,Vue3 + Element Plus,系统 Edge headless(CDP 截图,Node 原生 WebSocket) **测试目的**:用 ui-ux-pro-max 技能 + 实截图评审界面,修复发现的问题并截图回归验证。 **方法**:agent-browser 因 googleapis 下载 Chromium 超时,改用系统 Edge headless + 自写 CDP 截图脚本(output/_cdp_shot.mjs)实测 5 个页面。 ### 评审发现的问题与修复 | 项 | 问题(截图证据) | 修复 | 级别 | |---|---|---|---| | P0-1 | PlanDetail 概览"扫描变量数/预计数据点/预计耗时"全 0(读 plan.scan_variables 不存在,实为 plan_data.variables) | scanVariables 及增删改 4 处改读 plan_data.variables | Bug | | P0-1b | calcPoints 只认 min/max/step,plan 1 variables 用 values 数组 → 预计数据点 0 | calcPoints 优先 values.length,兼容 min/max/step、start/stop | Bug | | P1-1 | Dashboard 已选方案却提示"请选择方案";默认选第一个方案(常无结果);结果加载漏 .items 字段({total,items})致有结果显示 0 | 空状态文案区分已选/未选;默认选 result_count>0 方案;results 读取加 .items | Bug+交互 | | P1-2 | ProjectDetail 边界条件 25 字段全铺开(22 个"未设置"占位) | 空值默认折叠,只显示已设置 + 展开全部 | 密度 | | P1-3 | ProjectList 表格行高大 | 表格 size=small | 密度 | | P2-2 | 面包屑 /plans/:id 缺项目名 | MainLayout 加载所属项目名,面包屑补"项目名"层级 | 导航 | | P2-4 | ProjectDetail 标题区"返回"与项目名粘连 | 返回按钮独占一行 | 视觉 | ### 截图回归验证(output/v_*.png) - 方案详情:扫描变量数 0→**1 个**、预计数据点 0→**3 点**、预计耗时 0→**6 分钟**、面包屑补项目名 ✓ - 项目详情:边界条件从 7 行空字段折叠为 1 行(3 项已设置 + "展开全部(含 22 项未设置)");标题区分隔 ✓ - Dashboard:数据点总数 0→**6 点**(字段修复);空状态文案"该方案暂无仿真结果" ✓ - vue-tsc 0 错误。 ### 踩坑与沉淀 - **前后端字段名不匹配是反复出现的问题家族**:plan.scan_variables vs plan_data.variables、results 的 .items vs .results/.data、calcPoints 不认 values 数组。建议前端读取一律用兼容多路径的 fallback(`a?.items || a?.results || a?.data`)。 - **agent-browser 在国内 googleapis 下载 Chromium 超时**:系统 Edge headless(--remote-debugging-port)+ 自写 CDP 截图脚本是可靠的替代方案(Node 22 原生 WebSocket)。 ### 遗留 - "Test Airgap Scan"方案 6 结果全 FAILED(数据本身问题),结果明细表无错误信息列——结果表加 error 信息列可作为后续 UX 优化。 - PlanDetail 方案参数编辑(添加/删除扫描变量)无保存到后端的逻辑(既有功能完整性问题)。 - P2-1 监控页合并(实时监控+执行器状态)、P2-3 批量清理入口未做(结构/数据改动,待确认)。 ## TEST-035:失败结果错误信息列验证 **日期**:2026-09-03 **测试环境**:Windows,Vue3 + Element Plus,系统 Edge headless(CDP 截图) **测试目的**:结果表失败行显示具体错误原因,便于诊断仿真失败(此前 FAILED 状态无原因可查)。 **相关文件**:web/frontend/src/views/PlanDetail.vue、web/frontend/src/views/Dashboard.vue ### 背景 - /plans/{id}/results 的结果项含 error_message 字段(如 `RuntimeError: MotorCADError writing Outer_Rotor_Diameter: ... Could not find Outer_Rotor_Diameter`),但结果表只显示 FAILED 状态,失败原因不可见。 - 该错误信息同时实证了 HANDOFF 记录的"5 个固定参数 Motor-CAD 变量名未验证"问题(Outer_Rotor_Diameter 在该模型中不存在)。 ### 修复内容 - PlanDetail.vue:结果表 status 列 FAILED 且含 error_message 时加 el-tooltip(悬停显示完整错误,虚线下划线标识可悬停);labelMap 加 error_message→"错误信息"(列设置可勾选显示整列)。 - Dashboard.vue:resultColumns 加 error_message 列(宽 220,直接显示失败原因);status 列同加 tooltip;两处加 .status-failed-cell 样式。 ### 测试步骤与结果 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | vue-tsc --noEmit | ✅ | 0 错误 | | 2 | 截图 Dashboard(v_dashboard_err.png) | ✅ | 错误信息列直接显示 "Could not find Outer_Rotor_Diameter" 完整原因 | ### 遗留 - PlanDetail 参数编辑无保存逻辑;P2-1 监控合并 / P2-3 批量清理待确认。 - Outer_Rotor_Diameter 等未验证变量名导致仿真失败的问题,需按 HANDOFF 待办在 .mot 中确认正确变量名后修正 fixed_params_template(独立于 UI)。 ## TEST-036:MARS 变量名实测排查 + fixed_params_template 几何修正 **日期**:2026-09-03 **测试环境**:Windows,Motor-CAD 2026R1 (v261),pymotorcad 0.8.8,系统 Python 3.12.10,许可证 lmgrd+ansyslmd 在跑 **测试目的**:排查仿真失败根因(`set_variable: Could not find Outer_Rotor_Diameter`),实测确认 MARS 真实几何变量名并修正模板。 **相关文件**:web/backend/app/services/fixed_params_template.py、docs/KNOWLEDGE_BASE.md §3.3 ### 背景 - UI 错误信息列(TEST-035)实证:仿真点全 FAILED,原因 `Could not find Outer_Rotor_Diameter`。 - 模板几何变量用径向电机命名,与 MARS(PCB 无铁心轴向磁通)不符。 ### 方法(KNOWLEDGE_BASE §8 探测 + 铁律"不要猜变量名") 1. 解析 `.mot`(INI 文本)静态比对模板变量名存在性。 2. pymotorcad `get_variable` 实测候选名(独立隐藏实例,只读无求解)。 3. pymotorcad `set_variable` + 回读校验修正后的变量名可写性(铁律"写入回读校验")。 ### 实测结论 - **修正(4 个几何)**:`Outer_Rotor_Diameter→RotorOuterDiameter`(130)、`Stator_Outer_Diameter→Stator_Lam_Dia`(76)、`Stator_Inner_Diameter→Stator_Bore`(50)、`Rotor_Back_Iron_Thickness→Back_Iron_Thickness`(5),get/set 均 OK。 - **设 null(MARS 无此变量,不写入)**:`Inner_Rotor_Diameter`(转子内径,4 候选全 MISS)、`Stator_Yoke_Thickness`(定子轭厚,3 候选全 MISS,PCB 无铁心)。 - **`Magnet_Arc_[ED]`=121 实测 OK**(原名即对,不改)。 - **默认值同步**:几何默认值从径向模板值(200/198/122/120/10/8)更正为 MARS 实测值(130/76/50/—/—/5)。 ### 验证 | 步骤 | 内容 | 结果 | 详情 | |---|---|---|---| | 1 | .mot 静态比对 | ✅ | 4 几何名 MISSING,别名映射多数 OK | | 2 | get_variable 探测(22s) | ✅ | 22 个真实名 OK;模板 12 个错误名全 MISS;转子内径/轭厚候选全 MISS;Magnet_Arc_[ED]=121 | | 3 | set_variable + 回读(15s) | ✅ | 4 个修正名写入回读一致,ALL WRITABLE | | 4 | py_compile + ASCII | ✅ | 模板编译通过、纯 ASCII | ### 知识沉淀 - KNOWLEDGE_BASE §3.3 新增"MARS 几何变量名(2026-09-03 实测)",含错误名/正确名对照、无对应变量清单、实测方法。 - **教训**:固定参数模板的几何命名必须基于实测 .mot/探测,不能套用径向电机模板;`motorcad_var=null` 是"无对应变量"的安全处理(不写入不报错)。 ### 遗留 - 模板修正后需重启后端生效;建议重新 AI 生成一个方案并真实启动一次仿真,确认不再报"Could not find variable"(端到端复验)。 - 转子内径/轭厚若在后续拓扑(DRSS 等)需要,需另行实测对应模型的变量名。 ## TEST-037:端到端真实仿真验证(变量名修正终极复验) **日期**:2026-09-03 **测试环境**:Windows,Motor-CAD 2026R1 (v261),pymotorcad 0.8.8,许可证在跑 **测试目的**:模拟执行器完整流程(生成固定参数 → set 全部 → 真实求解 → 提取指标),端到端验证变量名修正后仿真能成功跑通。 **相关文件**:web/backend/app/services/fixed_params_template.py、docs/KNOWLEDGE_BASE.md §3.3 ### 过程与发现(迭代排查) 1. **首次端到端**:37 固定参数 33 可写,set 31 ok / **2 failed**——`Current_Advance_Angle`、`Material_Stator_Lam_Yoke` 也为错误名(几何 4 个已修正 OK)。 2. **补充排查**:实测 `Current_Advance_Angle→PhaseAdvance`(get/set OK);`Steel_Grade`(Material_Stator_Lam_Yoke)不存在,MARS 无铁心 → 设 null。 3. **二次端到端**:32 可写 set 全成功(0 failed),但 `do_magnetic_calculation` 失败——`Could not find magnet material NdFeB_N42SH in solids database`(材料**值**错误,非变量名)。 4. **材料修正**:MARS `.mot` 实测 `Material_Magnet=N42UH`,模板默认 `NdFeB_N42SH` 改 `N42UH`。 5. **三次端到端**:✅ 全链路成功。 ### 最终验证结果 | 步骤 | 内容 | 结果 | |---|---|---| | set_variable(32 可写参数) | 全部 set | ✅ 32 ok, 0 failed | | do_magnetic_calculation | 真实电磁求解 | ✅ 成功(~2 分钟,符合 90-150s) | | export_results | 结果导出 | ✅ 337 行 CSV | | 关键指标 | 求解结果有效性 | ✅ 转矩脉动 2.815%、AC 损耗 0.47W、功率因数 0.995 | ### 结论 仿真失败根因(变量名 + 材料名)已彻底修复,端到端仿真能成功跑通并产生有效结果。模板所有 motorcad_var 经实测验证(无猜测)。 ### 遗留 - 建议用户在 Web 端用本地执行器跑一次完整方案扫描(多参数点),确认生产链路同样通畅(本次为 pymotorcad 单点验证)。 - 其他拓扑(DRSS)/其他模型的变量名需按同样方法实测。 ## TEST-038:生产链路复验(Web 生成 → 任务下发 → 执行器真实仿真 → 结果回传) **日期**:2026-09-03 **测试环境**:Windows,Motor-CAD 2026R1 (v261),pymotorcad 0.8.8,FastAPI 后端 + 本地执行器(enable_mock=false) **测试目的**:验证完整生产链路(非 pymotorcad 单点)在变量名修正后能成功跑通一次真实仿真。 **相关文件**:web/backend/app/services/topology_variable_map.py、scripts/task_executor.py、src/afmcore/adapters/motorcad.py ### 过程(链路逐段排障) 1. **执行器上线**:enable_mock=false,heartbeat 正常,idle 等待任务。 2. **预检拦截**:start-simulation 报 400——`is_known_variable` 用 `_KNOWN_VARIABLES[SSSR]`(含错误几何名),把修正后的正确名误判 unknown。**修复 1**:topology_variable_map 的 `_KNOWN_VARIABLES` 几何名更正为 MARS 实测名(RotorOuterDiameter/Stator_Lam_Dia/Stator_Bore/Back_Iron_Thickness/PhaseAdvance),alias map 的 SSSR/AFIR 目标名同步更正。 3. **预检通过**:start-simulation 返回 task_id,dispatched。 4. **执行器不捡任务**:日志 `not claimable (claimed/network)`——start-simulation 已把任务 pending→dispatched,执行器 claim 时再调 dispatch(后端仅允许 pending→dispatched),状态冲突被拒。**修复 2**:task_executor.execute_task 对 status==dispatched 的任务跳过重复 dispatch(仅 pending 才 claim)。 5. **执行器捡起但点失败**:`No module named 'scripts'`——afmcore.adapters.motorcad 用 `from scripts.robust_motorcad import`,执行器 sys.path 只有 scripts/ 和 src/(无仓库根)。**修复 3**:motorcad._ensure_solver 导入前确保仓库根在 sys.path。 6. **生产链路成功**:任务 completed,successful_points=1。 ### 最终验证结果 | 检查点 | 结果 | |---|---| | 预检(_KNOWN_VARIABLES) | ✅ 通过(修正后) | | 执行器 claim(dispatched 任务) | ✅ 不再 "not claimable" | | 适配器加载(scripts 导入) | ✅ 不再 "No module named 'scripts'" | | 展开参数正确性 | ✅ RotorOuterDiameter=130/Stator_Lam_Dia=76/Stator_Bore=50/PhaseAdvance/N42UH 等全部正确 | | 任务结果 | ✅ completed,successful_points=1,failed_points=0 | | 关键指标 | ✅ tavg_nm=0.5219 Nm、efficiency=86.06%、total_losses=41.945 W(与 pymotorcad 单点验证一致) | ### 结论 完整生产链路(Web 生成方案 → start-simulation 预检 → 任务下发 → 本地执行器真实 Motor-CAD 求解 → 结果回传 Web)**全部通畅**,变量名修正后仿真点成功。同时发现并修复了 3 个链路级问题(拓扑预检变量集、执行器 dispatch 状态机、适配器 scripts 导入路径)。 ### 遗留 - 多点扫描方案的生产复验(本次为单点最快验证)。 - 其他拓扑/模型的变量名需按同样方法实测后登记到 topology_variable_map。 ## TEST-039:多点扫描生产复验(3 点 Airgap 扫描) **日期**:2026-09-03 **测试环境**:Windows,Motor-CAD 2026R1,FastAPI 后端 + 本地执行器(enable_mock=false) **测试目的**:多点扫描生产链路最终确认——批量调度、逐点落盘、进度更新、结果趋势物理正确性。 **方案**:plan 28(Airgap 0.6/1.0/1.5mm,3 点),task c2781acf。 ### 验证结果 | 检查点 | 结果 | |---|---| | 批量调度 | ✅ 执行器逐点跑,进度 33.3%→66.7%→100% | | 任务结果 | ✅ completed,successful_points=3,failed_points=0 | | 逐点落盘 | ✅ 每点结果独立保存(params + metrics + solve_time_s) | ### 逐点指标(物理趋势验证) | Airgap | tavg(Nm) | eff(%) | losses(W) | status | |---|---|---|---|---| | 0.6mm | 0.56625 | 84.926 | 49.917 | OK | | 1.0mm | 0.52187 | 86.060 | 41.945 | OK | | 1.5mm | 0.46770 | 86.346 | 36.558 | OK | **趋势符合电磁学**:气隙↑ → 主磁通↓ → 转矩↓(0.566→0.522→0.468);气隙↑ → 铁耗/杂散损耗↓(49.9→41.9→36.6);损耗下降主导 → 效率略升(84.9→86.1→86.3)。结果真实有效,非随机数。 ### 结论 多点扫描生产链路完全通畅。单点耗时 ~134s(符合 90-150s 基线),3 点含 Motor-CAD 启动共约 6 分钟。从"仿真失败根因(变量名)"到"多点生产链路全通畅"彻底闭环。 ### 遗留 - 建议用户在前端用 AI 生成一个多变量方案并启动,体验完整 AI→仿真→分析闭环。 - 失败任务历史脏数据(TEST-035 之前的 FAILED)可在经验库/结果分析中对比新成功数据。 --- ## TEST-040:遗留 UI 项全部修复(参数编辑持久化 / 监控合并 / 批量清理 / 列配置持久化) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 / Node 22.22.2 / FastAPI :8000 / Vite :5173 / Edge headless CDP 截图 | | 测试目的 | 落地 UI 评审全部遗留项:PlanDetail 扫描变量编辑持久化、监控页合并、项目/任务批量清理、结果列配置 localStorage 持久化 | ### 测试步骤与结果 1. **扫描变量编辑持久化(PlanDetail)**:添加/删除扫描变量置 dirty 标记,"保存修改"按钮 PUT `/plans/{id}` 完整 plan_data(后端单一事实源校验),保存后重载。✅ 2. **监控页合并(P2-1)**:新建 `ExecutionMonitor.vue`,el-tabs 嵌入原 MonitorDashboard(任务监控)+ ExecutorMonitor(执行器状态),`v-if` 保证仅活动 tab 轮询。路由 `/monitor` 指向合并页,`/executor-monitor` 301 重定向兼容旧链接;导航"执行"组只留"任务管理/执行监控"两个入口。✅ 3. **批量清理(P2-3)**: - 后端:`POST /api/projects/batch-delete`(逐项容错)、`DELETE /api/tasks/{id}` + `POST /api/tasks/batch-delete`(**仅终态可删**,活动任务 400 拒绝并提示先取消)。 - 前端:项目列表/任务列表多选列 + 条件渲染批量按钮 + 二次确认(列明项目名);任务行级加"删除"(仅终态显示)。 - API 实测:不存在 ID 返回 errors 不中断;真实删除终态任务 204→404;**pending 任务删除被拒 400 "cancel it before deleting",取消后删除 204**。✅ 4. **列配置持久化(P2-4 深化)**:结果列选择存 `localStorage['afm:plan-result-columns']`(全局偏好),加载时读取,恢复默认时清除;空选择拦截"至少保留一列"。✅ 5. **截图回归**:`/monitor`(单入口 + 双 Tab)、`/tasks`(多选列 + 行级删除)、`/projects`(多选列 + AFIR 警告标记 + small 密度)均符合预期。✅ ### 验证方式 - `vue-tsc --noEmit` 0 错误;3 个后端 `.py` 编译通过、纯 ASCII。 - 批量删除 API curl 实测(容错 / 真实删除 / 终态保护)。 - Edge headless CDP 截图 3 张人工核验。 ### 修复过程发现 - 前端两处 script Edit 曾未生效(文件被后续 Edit 改动导致 old_string 失配但界面显示成功),靠 vue-tsc 报错发现并补回——**类型检查再次拦截了静默失效**。 ### 遗留 - 无(UI 评审全部项已闭环)。P2-2 步骤条交互向导维持"价值低不做"结论。 --- ## TEST-042:用户四需求落地(拓扑默认模型 / 全量 BC 表单+来源标签 / 验收标准 / 参数区展开编辑) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 / Node 22.22.2 / FastAPI :8000 / Vite :5173 / Edge headless CDP 截图(支持 js: 表达式点击) | | 测试目的 | 用户实测反馈四需求:①拓扑基础模型自动调用(预检 model_path 空阻断启动)②新建项目弹窗全 25 项 BC + 来源标签 ③验收标准按 BC 自动带出 ④BC/固定参数默认全展开 + 可编辑保存 | ### 需求1:拓扑基础模型自动调用 - **后端**:`afmcore/topology.py` 的 `TopologyDefinition` 加 `default_model` 字段(SSSR→MARS .mot,DRSS/SDSR 暂缺)+ `default_model_for()`;三处回退——AI 生成(ai_plan.py)、手动创建(plans.py create_plan)、**启动仿真运行时兜底**(start-simulation 空则回填并持久化,16 个历史空模型方案无需手工修复直接可启动);preflight 模型失败项带 `fixable/default_model`。 - **前端**:预检对话框模型失败项显示"使用拓扑默认模型"一键修复按钮(PUT + 重跑预检)。 - **验证**:端到端 project 13(model_path 空)AI 生成 → 自动回填 MARS 模型 + warning 提示。✅ ### 需求2:全量 BC 表单 + 来源标签 - **发现并修复隐藏 Bug**:`defaultBC()` 原给全部 25 字段预填默认值 → 用户无法区分"自填/系统默认"。改为全空,仅保存非空字段(cleanBC)。 - **后端**:bc_fields 目录加表单元数据(type: number/int/enum + options;枚举值为工程标准选项);AI prompt 加 `bc_suggestions` 输出(仅补用户未设置项)+ 扫描变量清单同步扩充至 13 项;方案存 `bc_meta`(user/ai 来源),手动创建全 user。 - **前端**:新建项目弹窗目录驱动 25 项分组渲染(默认全"未设置");ProjectDetail BC 默认全展开 + 有值标"用户指定";PlanDetail BC 全展开 + 来源标签(用户指定/AI 补充/已修改)+ 编辑保存(改动标 edited)。冷却方式枚举值统一为 Natural/Forced Air/Water/Oil(原小写值与 Motor-CAD 实测值不一致)。 - **字段路径 Bug 修复**:`plan.boundary_conditions`/`plan.acceptance_criteria` 顶层不存在(实际在 plan_data 下)→ 兼容修正。 ### 需求3:验收标准自动带出 - AI acceptance_criteria(hard_constraints)+ BC 目标类字段推导(转矩/效率/损耗/脉动/轴向力/外径/轴向长度 7 类)合并渲染,带"AI 设定/边界条件"来源标签。 - **修复 AI 输出嵌套 dict 格式丢失**:convert 归一化加 hard_constraints dict→list 转换(`"key <=110"` → `key <=110` 字符串列表)。 - **截图验证**(plan 31):概览验收标准自动带出 7 条判断条件 + 来源标签。✅ ### 需求4:参数区默认展开 + 编辑保存 - BC/固定参数默认全部展开(showAllFixed=true;分类默认展开语义 `!== false`)。 - 固定参数 inline 编辑(布尔/数值/字符串分控件)+ 保存(PUT plan_data.fixed_params)+ 已修改高亮。 - **修复扫描变量"最小值"列空缺**:AI 方案 variables 只有 values 数组,列绑 min/max/step 导致空白 → 改为"取值"列直接显示 values 列表(如 0.8/1.15/1.5)。 ### 验证方式 - 后端 5 个 `.py` 编译通过、纯 ASCII;vue-tsc 0 错误(初查报 2 个索引类型错误,修 defaultBC 返回类型标注后清零)。 - 端到端:model_path 回填 + bc_meta 25 项全 user + acceptance_criteria 归一化。 - Edge CDP 截图 5 张人工核验(概览验收标准/参数页 BC 标签/扫描变量取值/新建项目弹窗/预检修复按钮)。 - 测试方案已清理。 ### 遗留 - DRSS/SDSR 无基础模型文件,选择时无法自动调用(需用户提供 .mot 后登记到 topology registry)。 - AI 本次未输出 bc_suggestions(项目 BC 已全填 25 项无可补,行为合理);AI 补充来源标签待有未设置项的生成场景验证。 --- ## TEST-043:PROMPTS_DIR 路径 Bug 根因修复(AI prompt 从未生效)+ bc_suggestions 实测 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 / FastAPI :8000 / Vite :5173 / Kimi k3 | | 测试目的 | 验证 AI 补充 BC(bc_suggestions);三次生成均未被补充 → 深挖根因 | ### 根因(重大发现) - 三次生成 bc_suggestions 均为空。查 `ai_call_logs.prompt_preview` 发现 system prompt 是 `_default_prompt()` 中文兜底版——**真 prompt(generate.txt)从未被加载**。 - 根因:`web/backend/app/config.py` 中 `BACKEND_DIR = Path(__file__).parent` = `web/backend/app/`,`PROMPTS_DIR = BACKEND_DIR / "prompts"` 指向不存在的 `app/prompts/`(实际在 `web/backend/prompts/`)→ `prompt_path.exists()` 为 False → 静默走 fallback。 - **影响面(回溯解释多个历史问题)**:AI 变量名编造(OuterDia/Stator_Lam_Length)、acceptance_criteria 嵌套 dict、bc_suggestions 不输出——全部因为模型从未看到含 13 变量清单与设计原则的真 prompt。result_analysis 的 analyze.txt 同样未生效。 ### 修复 - `PROMPTS_DIR = BACKEND_DIR.parent / "prompts"`;附带修复:prompt 措辞改强制(REQUIRED FIELD)、`ai_plan.py` 项目上下文 BC 全量展开(未设置字段显式 null,模型才能看到哪些可补)、`SCAN_PARAM_CN` 补 4 个中文名。 ### 验证(修复后实测,全部达标) - 端到端(project:仅 3 项 BC)→ AI 补充 7 项(target_torque_nm=5.7/target_efficiency_pct=92/target_ripple_pct=5/magnet_temp_c=100/cooling_type=Natural/voltage_v=150/max_losses_w=260),bc_meta 标记 `user:3 + ai:7`,用户值未被覆盖。✅ - 扫描变量全部标准注册名(Airgap/Magnet_Length/Turns_per_Coil),无编造名。✅ - warnings 干净(仅 model_path 回填提示)。✅ - Edge CDP 截图:BC 区"用户指定"(绿)/"AI 补充"(蓝)标签渲染正确。✅ - 测试产物已清理(plans 32-35 + project 14 删除)。 ### 遗留 - 历史方案(prompt 修复前生成)的变量名/验收标准质量参差,建议用新 prompt 重新生成关键方案。 - experience/extract.txt 不存在(experience_enhancer 仍走其自带 fallback,既有状态未变)。 --- ## TEST-041:前次会话遗留测试脚本更新与回归(拓扑变量名断言对齐) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 | | 测试目的 | 前次会话(P5-M2)未跟踪测试脚本 `test_topology_variable_map.py` 断言基于旧错误变量名(Stator_Outer_Diameter 等),在 TEST-036 修正后 6/8 失败;更新断言至 MARS 实测名并全量回归 | ### 测试步骤与结果 1. `test_plan_schema.py`(plan_schema 字符串枚举支持):7/7 PASS,直接入库。✅ 2. `test_topology_variable_map.py` 初跑 2/8——失败断言正是旧错误名,证实 TEST-036 修正改变了行为。✅(预期失败) 3. 更新断言:`Stator_Outer_Diameter→Stator_Lam_Dia`、`Stator_Inner_Diameter→Stator_Bore`、`Outer_Rotor_Diameter→RotorOuterDiameter`;新增"旧错误名应被判 unknown"反向断言(防回归);docstring 注明修正来源。✅ 4. 更新后全量回归:**8/8 PASS**(含 plan23 80 点回归,RFM→AFM alias 解析到 MARS 实测名)。✅ 5. 两脚本 + `src/plan_schema.py` + `style.css`(P6-M1 设计令牌遗留)ASCII 检查通过并入库。✅ ### 踩坑 - Edit 工具对该文件 3 处替换报告成功但实际未生效(old_string 失配未报错),靠 grep 复查 + 重跑测试发现。**教训:Edit 后必须 grep 验证目标字符串已消失/出现**——与"vue-tsc 拦截静默失效"同类问题,测试驱动再次兜底。 ### 结论 前次会话(P5-M2/P6-M1)全部遗留改动已验证入库(commit `3dd42b9`);测试断言与 MARS 实测变量名一致,旧错误名有反向防回归断言。 --- ## TEST-044:新 prompt 质量对比验证 + experience/extract.txt 补建实测 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 / FastAPI :8000 / Kimi k3(真 prompt 首次生效) | | 测试目的 | ①新 prompt 生成质量对比(变量名/验收标准格式)②补建 experience/extract.txt 并实测 | ### 1. 新 prompt 生成质量(project 13 端到端) | 维度 | 修复前(兜底 prompt) | 修复后(真 prompt) | |---|---|---| | 扫描变量名 | 编造名(OuterDia/Stator_Lam_Length)被裁剪 | 全注册标准名(Airgap/Magnet_Length/Magnet_Arc_[ED]) | | acceptance_criteria | 嵌套 dict(前端无法渲染) | 规范 list 判断式 4 条(efficiency_pct >= 90 等) | | warnings | 多条裁剪/兜底警告 | 仅 model_path 回填提示 | | bc_suggestions | 从不输出 | 正常输出(TEST-043 已证 7 项) | ### 2. experience/extract.txt 补建与实测 - 发现 `prompts/experience/` 为空目录,experience_enhancer 一直走单行 fallback;且其 `max_tokens=3000` 有撞顶隐患(同步改为 KIMI_MAX_TOKENS)。 - 补建正式 extract.txt(design_rules/failure_patterns/parameter_sensitivity/optimal_region/recommendations 结构 + 证据引用要求)。 - 函数级真实 AI 调用验证(plan 28 三点真实数据,无需执行器):prompt 从文件加载确认;输出结构完整;规则带量化证据(+21% 转矩/-26.7% 损耗)、正确声明样本量仅 3 的保守性、置信度分级;物理趋势与 TEST-039 实测一致。**PASS**。 - 注:`smart-extract` 端点为规则化提取(不走 AI);extract.txt 生效路径是 adaptive_loop 自适应闭环。 ### 遗留 - 历史方案(plan 1-31)系兜底 prompt 时期生成,建议关键方案重新生成。 - 自适应闭环端到端(含 AI 经验提取)待执行器在线后实测。 --- ## TEST-045:自适应闭环集成修复(真 prompt 启用后暴露的断层) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 / FastAPI :8000 / Kimi k3(真 prompt) | | 测试目的 | 自适应闭环(adaptive_loop)端到端验证——extract.txt 真实生效路径 | ### 发现的集成断层(P3-M5 遗留,真 prompt 启用后暴露) 1. **字段名不匹配**:`generate_plan` 存 convert 后的 `variables`,`initialize_search` 读 `scan_variables` → "No valid scan variables"。修复:generate_plan 归一化补 `scan_variables`,initialize_search 双名兼容。 2. **数值键名不匹配**:convert 输出 `start/stop/step`,initialize_search 读 `min_value/max_value` → 参数全丢。修复:`lo = var.get("min_value", var.get("start"))` 兼容 + values 数组推导范围。 3. **闭环方案缺 topology/model_path**:闭环无项目上下文,plan 缺这两项 → 无法仿真。修复:generate_plan 内拓扑归一化 + `default_model_for` 回填。 4. **L0 参数名口径断层(未修复,记录为待办)**:L0 引擎期望 BC 风格名(`airgap_mm`/`outer_diameter_mm`),闭环传 Motor-CAD 名(`Airgap`/`Magnet_Length`)→ L0 "No checks were performed" 全判不可行 → 初始 LHS 批次为空。需要 Motor-CAD 名 → L0 BC 名的语义映射层(注意 Magnet_Length(轴向) ≠ magnet_thickness_mm(径向厚度),映射不能瞎对应)。 ### 验证结果 - 闭环 generate-plan:phase=plan_generated,topology=SSSR,model_path 自动回填 MARS,变量标准名。✅ - init-search:HTTP 200,search_initialized。✅ - 转换逻辑函数级:start/stop、values 数组、无效变量跳过 3 断言全 PASS。✅ - next-batch:返回空(L0 断层所致,已知待办)。 - update-experience:extract_insights 已在 TEST-044 函数级验证(相同输入结构与真实数据);闭环集成段(all_results 收集→提取→经验条目)**草案待验证**,待 L0 口径修复后实测。 ### 遗留 - **L0 参数名口径映射**(Motor-CAD 名 → L0 BC 名)为闭环搜索层的关键待办。 - 闭环全流程(选点→执行器仿真→report→update-experience)待 L0 修复后端到端实测。 --- ## TEST-046:自适应闭环全链路端到端实测(extract.txt 真实生效路径) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / Python 3.12.10 / FastAPI :8000 / Kimi k3 / 本地执行器(真实 Motor-CAD) | | 测试目的 | 闭环全链路:create → generate-plan → init-search → next-batch → 执行器真实仿真 → report-results → update-experience | ### 修复的问题(本轮累计 4+2 个) 1. **L0 参数名口径**(TEST-045 遗留):L0 引擎期望 BC 风格名,闭环传 Motor-CAD 名 → 在 `src/afmcore/l0/prescreening.py` 加 `MOTORCAD_TO_L0` 语义映射(Airgap→airgap_mm、Magnet_Length→magnet_thickness_mm[轴向磁通磁钢厚度=轴向尺寸]、RMSCurrent→current_a、Magnet_Temperature→magnet_temp_c、Stator_Outer/Inner_Diameter→outer/inner_diameter_mm),evaluate 入口翻译且 L0 原生 key 优先。函数级验证:4 项检查全 PASS + 原生 key 优先。✅ 2. **初始批次不消费**:`select_next_batch` 从不消费 generate_initial_batch 的 pending 点 → 开头先返回 pending 批次。✅ 3. **report-results 路由缺失**:`report_loop_results` 函数无 `@router.post` 装饰器,结果回传端点不可达(P3-M5 遗留)。已补。✅ 4. **export inf 序列化**:`best_objective_value` 初始 inf → JSON 500。导出转 None。✅ 5. **import 哨兵恢复**:export 的 None 导入后覆盖默认 inf → `value > None` TypeError。导入时 None 保持默认哨兵。✅(export/import 检查点机制顺带实测通过) ### 端到端结果(全部真实数据) - 闭环选点:2 批共 8 点(Airgap 0.6/0.9/1.2 × RMSCurrent 20/30/40/50 组合) - 执行器真实仿真:2 个任务 8 点全部 completed(4/4 + 4/4) - 结果趋势合理:电流↑→转矩↑损耗↑效率↓(I=20A: 0.51Nm/85.7%;I=50A: 1.21Nm/83.6%) - report-results:phase=results_analyzed,置信度 D(点数少属合理评级) - **update-experience**:phase=experience_updated,AI 提取 4 条设计规则含量化证据(如"效率峰值在中低转矩点 0.72Nm/86.3% 而非最低转矩点"),经验条目生成。**extract.txt 在闭环真实生效**。✅ ### 踩坑 - 任务构造曾把 motorcad_var=None 的参数(Inner_Rotor_Diameter 等)用 name 回退写入 → 执行器报 "Could not find"。修正:只写 motorcad_var 非 None 的参数。 - next-batch 返回字段是 `points` 不是 `batch`(查询时误读字段名导致误判为空)。 ### 遗留 - 闭环只跑到首批两段;主动学习后续批次(信任域)未验证。 - 测试任务已清理;闭环 loop 为内存态(重启即失,export/import 已验证可恢复)。 --- ## TEST-047:submit-batch 生产路径验证(闭环→任务→执行器) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试目的 | 验证闭环 submit-batch(生产路径:闭环自动创建任务给执行器) | ### 发现与修复 - **submit_batch_to_executor 缺固定参数合并**:原实现只传裸扫描点参数({Airgap, RMSCurrent, point_id}),执行器不读 plan_data.fixed_params → 点会缺 CurrentDefinition/MessageDisplayState 等关键固定参数。已修复:每点合并 plan 中 motorcad_var 非 None 的可写固定参数。 - **验证**:submit-batch 创建任务 f19ba592(12 点 pending 剩余全部);任务文件每点 33 键(30 固定 + 扫描 + point_id),无错误变量名(Inner_Rotor_Diameter/Steel_Grade 已排除)。执行器秒捡起跑。✅ ### 发现的已知缺口(未修) - **执行器→闭环结果自动回传缺失**:执行器跑完只调通用 `/tasks/{id}/results` 上报,不识别 adaptive_batch 类型、不调闭环 `/adaptive/loops/{id}/report-results`。闭环拿不到结果需手动桥接。这是 P3-M5 设计但未实现段,需执行器加 loop 回传逻辑(或 Web 侧轮询桥接)。 ### 遗留 - 任务 f19ba592(12 点)在跑,完成后可手动 report 进闭环做主动学习第二轮验证。 --- ## TEST-048:闭环生产路径全跑通 + 经验提取数据完整性修复 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-03 | | 测试环境 | Windows / FastAPI :8000 / Kimi k3 / 本地执行器(真实 Motor-CAD) | | 测试目的 | submit-batch 生产路径全跑通 + 第二轮主动学习 + 经验提取数据完整性 | ### 结果 - **submit-batch 任务 12/12 全部成功**(f19ba592,~24 分钟真实仿真)——生产路径(闭环自动创建任务→执行器捡起跑)验证通过。 - **12 点 report 入环**:point_id 映射(submit_batch 嵌入的 point_id 直接用,无需猜匹配);置信度 D→C(点数增多合理提升);best 效率 86.295→89.414(LHS 探索到更优点)。 - **update-experience 第二轮成功**:experience_updated。 - **AI 反馈暴露数据缺陷**:"No input parameter values are provided"——report_results 的 all_results 只合 metrics 不含输入参数 → 敏感性分析无法做(sensitivity=unknown)。 ### 修复(数据完整性) 1. `adaptive_loop.report_results`:all_results 条目合入点的输入 params(从 search.state.points 按 point_id 取)。 2. `experience_enhancer._condense_results`:输入参数经 `MOTORCAD_TO_L0`(单一事实源)翻译成 BC 名再提取——否则闭环的 Motor-CAD 名输入不会被提取。 函数级验证:Airgap→airgap_mm、RMSCurrent→current_a 翻译提取 PASS。 ### 验证边界声明 两个数据完整性修复影响**未来**闭环(当前 loop 的 12 点旧条目已无参数,无法补救);函数级验证通过,端到端效果待下次闭环运行确认。 ### 遗留 - 执行器→闭环自动回传缺失(TEST-047 记录,P3-M5 设计未实现段)。 - 前端 AdaptiveOptimize 走 /api/search/*(独立于 adaptive loops),其契约与 search 服务一致;adaptive loops 无前端页面。 --- ## TEST-049:执行器→闭环自动回传(P3-M5 最后缺口闭合) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 闭合 TEST-047 发现的"执行器跑完不调闭环 report-results"缺口 | ### 修复 - `scripts/task_executor.py` 加 `_report_to_adaptive_loop`:`execute_task` 完成后,若 `task_type == "adaptive_batch"` 且有 `loop_id`,把每点结果映射为 `{point_id, metrics, status}` POST 到 `/api/adaptive/loops/{loop_id}/report-results`。best-effort(回传失败不影响任务本身的 results 上报)。 ### 验证(链路级,真实闭环端点) - 构造 adaptive_batch 假任务 + 3 点结果 → 调 `_report_to_adaptive_loop` → 闭环 n_results 0→3。✅ - 负面对照:普通 scan 任务(task_type=scan)不触发回传,n_results 不变。✅ - 执行器重启加载新逻辑,在线。✅ ### 验证边界声明 链路级验证(回传调用 + 闭环接收),用合成 metrics 测连通性;仿真段真实性已由 TEST-046/048 的真实 Motor-CAD 运行证明。全闭环自动流转(submit-batch→执行器→自动回传→下一批)的端到端长时运行未做(需真实仿真数十分钟),建议生产使用中观察。 ### 遗留 - 无阻断项。闭环全链路(含自动回传)已可用。 --- ## TEST-050:search 服务 L0 验证 + 指标字段名对齐事实源 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | ①search 服务(前端自适应优化页后端)在 L0 修复后出点验证 ②修复结果表转矩/脉动列空缺 | ### 结果 1. **search 服务出点验证**:`POST /api/search/create`(Airgap 0.6-1.5)→ initial_points 4、pending 4、infeasible 0(L0 修复前全判 infeasible)。前端自适应优化页后端链路健康。✅ 2. **指标字段名对齐事实源**:走查发现方案详情"最新结果摘要"的平均转矩/转矩脉动列显示"-"——前端列定义读 `average_torque_nm`/`torque_ripple_pct`,而指标单一事实源(afmcore/metrics.py)用 `tavg_nm`/`ripple_pct`。修复:PlanDetail/Dashboard 列定义对齐事实源 + 平铺时旧名别名兼容(老数据 average_torque_nm → tavg_nm)。截图验证:转矩/脉动列正常显示(0.566/5.45 等),趋势符合物理。✅ ### 说明 - 这是字段名不匹配问题家族的又一实例(前端旧命名 vs afmcore 事实源)。Dashboard 图表仅用 efficiency/losses(未变字段)不受影响。 - vue-tsc 0 错误。 --- ## TEST-051:闭环经验入库(闭环价值闭环) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 验证闭环 AI 提取的经验真正沉淀到经验库(可被后续 AI 生成复用) | ### 发现 - `generate_experience_entry` 只返回 dict(注释自称 "ready for database storage"),`update_experience` 只在 HTTP 响应里返回、**从不入库**——重启即失,经验库页看不到,后续 AI 生成(读经验库 existing_experience)无法复用。闭环价值断裂。 ### 修复 - `adaptive_loop.update_experience` 加 `_persist_experience_case`:把 AI 洞察映射为 `ExperienceCase` 入库——best feasible point 的 params/metrics + summary+design_rules 作 conclusion + tags(topology/ai-insights/loop)。best-effort(入库失败不中断闭环),返回 experience_case_id。 ### 验证(真实 12 点数据) - 重建闭环 + 灌入 12 点真实仿真结果(f19ba592)+ update-experience → `experience_case_id: 7`,`experience_cases` 表 6→7 行,结论为 AI 洞察文本,tags 含 ai-insights。✅ - `/api/experience` 列表可见 case 7(经验库页可读)。✅ ### 说明 - 至此闭环价值完整闭环:仿真 → AI 提取 → 经验入库 → 后续 AI 生成复用。 - 验证用例(case 7)基于真实仿真数据,保留入库(有参考价值)。 --- ## TEST-052:经验库复用断裂修复(AI 生成不读经验库) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 验证"后续 AI 生成复用经验库"的真实性(上次口头声明未验证) | ### 发现(真实断裂) - `ai_plan.py` 的 generate-and-save(用户实际用的"AI 一键生成")调 `generator.generate()` 时**不传 existing_experience**;`/generate` 端点也只在请求体显式传了才用;前端两个生成入口都不传。→ **经验库的值根本没流入 AI 生成**,闭环提取的经验入库了但生成时不读,价值链在"复用"环节断裂。 ### 修复 - 新增 `_load_experience_cases(db, topology)`:按拓扑从 experience_cases 加载最近 5 条(params/metrics/conclusion/tags)。 - generate-and-save:调用前自动加载同拓扑经验传给 generate()。 - /generate:请求未显式传经验时自动加载(显式传则优先),并补 db 依赖。 ### 验证 - `_load_experience_cases` 直接调用返回 5 案例(含闭环 case 7 的 AI 洞察)。✅ - 端到端生成成功(HTTP 200)。✅ - 附带实证:最新 ai_call_log 的 system prompt 开头已是英文真 prompt("You are an axial flux motor...")——PROMPTS_DIR 修复生效的直接证据。 - 注:prompt_preview 只存前 500 字符(截断在 system prompt),user message 中的经验案例在日志里不可见——日志截断所致,非未加载;功能链路(加载 5 案例 + generate 对非空经验拼入 user message)已确认。 ### 说明 - 至此经验价值链完整:仿真 → AI 提取 → 入库(TEST-051)→ 后续生成自动加载复用(本次)。 --- ## TEST-053:批次语义修复 + 全自动闭环真实端到端(零手动桥接) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试环境 | Windows / FastAPI :8000 / Kimi k3 / 本地执行器(真实 Motor-CAD) | | 测试目的 | 修复批次语义(submit 全部 pending 问题)+ 真实全自动闭环验证 | ### 发现的批次语义问题 - submit-batch 提交全部 24 个 pending 点(point_ids 0-23)而非"当前批次",破坏分批自适应语义。根因:select_next_batch 返回点前 N 个 pending 但不标记,它们仍 pending → submit 拿全部。 ### 修复(引入 dispatched 状态) - select_next_batch:选中点标 status="dispatched"(初始消费段 + 主动学习段)→ 不再被 get_pending_points 重复返回/提交。 - submit_batch_to_executor:只提交 status=="dispatched" 的当前批次点。 - batch_summary 状态桶加 dispatched。 ### 函数级验证 初始 pending 4 → batch1 选 2 标 dispatched → pending 减到 2(不重复)→ submit 目标正好 2(修复前是全部)。✅ ### 真实全自动端到端(零手动桥接,核心成果) - 建闭环 → AI 生成 → init → next-batch → submit-batch(5 点 dispatched,AI batch_size 覆盖)→ 执行器真实仿真 5/5 → **执行器自动回传**(全程未手动调 report-results)→ 闭环 n_results 0→5 自动增加、phase 自动推进 results_analyzed。✅ - update-experience:experience_case_id=8 入库;**敏感性分析正常**(Current strong positive、Airgap moderate negative,不再 unknown——TEST-048 数据完整性修复在真实闭环生效);summary 含量化结论(torque 随电流 15A→37.5A 从 0.330→1.006 Nm ~3x)。✅ ### 意义 **P3-M5 自适应闭环至此真正全自动**:submit-batch→执行器真实仿真→自动回传→AI 分析→经验入库→后续生成复用,全程无手动桥接。这是本项目"AI 驱动智能仿真闭环"的完整实证。 ### 遗留 - 主动学习的多轮信任域收敛未长时观察(点数规模问题,生产使用验证)。 - 执行器在后端重启期间心跳会中断(需重启执行器恢复)——可考虑执行器心跳自愈(本轮未做,非阻断)。 --- ## TEST-054:执行器心跳独立线程(修复任务执行期间误判 offline) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 修复执行器架构弱点:心跳与任务执行同线程串行,长跑任务期间心跳停止被误判 offline | ### 问题 - 执行器 `poll_loop` 单线程串行:`_send_heartbeat()` 与 `execute_task()` 同线程。Motor-CAD 单点求解约 2 分钟,跑点期间心跳完全停止 → 后端按 last_heartbeat 超时误判执行器 offline。本轮实测中执行器 30216 出现"进程活着但 offline"假死。 ### 修复 - `start_polling` 拆为两个线程:独立 `heartbeat_loop`(每 interval 秒心跳)+ `poll_loop`(取任务执行)。任务执行期间心跳持续。 ### 验证 - 编译 + ASCII 通过;重启执行器上线,15s 后持续在线(心跳持续),旧执行器正常超时离线。✅ ### 说明 - 假死的完整根因现场已消失(进程活着但日志停在启动)无法完全复现;HTTP 调用均有 timeout(排除无限阻塞);心跳/执行同线程是确定存在的架构弱点,已修。 --- ## TEST-055:前端全路由走查(13 路由无错误)+ /generate 回归 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试环境 | Edge headless CDP(截图 + 控制台/异常捕获)| | 测试目的 | /generate 端点回归 + 全前端路由健康走查 | ### 结果 1. /generate 回归:HTTP 200,方案正常生成(变量 Airgap、warnings 干净),db 依赖与经验自动加载未破坏该端点。✅ 2. 全路由走查:CDP 脚本捕获 Runtime.consoleAPICalled(error) + Runtime.exceptionThrown,13 个路由全部 PAGE_ERRORS(0)。✅ 3. 抽查非白屏:L0 预筛选 / 多保真度校准 / 高级可视化截图确认正常渲染。✅ ### 说明 - 走查工具 _cdp_shot.mjs 扩展了 js: 表达式点击与错误捕获能力,是可复用的 UI 冒烟手段。 - 所有用户可见页面无控制台错误、无未捕获异常,前端整体健康。 --- ## TEST-056:自适应闭环前端页(AdaptiveLoop.vue) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 闭环后端已全自动实测通畅但无 UI 入口,新建前端页面 | ### 实现 - 新建 `views/ai/AdaptiveLoop.vue`:创建闭环表单(需求/总预算/批次大小)+ 闭环列表 + 详情(阶段状态卡、方案摘要、预算进度条、批次历史表、经验提取区)。 - **一键自动运行**(前端驱动状态机):generate-plan → init-search → 循环(next-batch → submit-batch → 轮询 n_results 等执行器自动回传 → 检查收敛)→ update-experience。利用执行器自动回传(TEST-049),前端只需轮询 n_results。 - 补 `adaptiveApi.submitBatch`(api/ai.ts 缺失)。 - 路由 `/ai/adaptive-loop` + 导航"AI 智能"组加入口 + 面包屑映射。 ### 验证 - vue-tsc 0 错误;页面渲染 PAGE_ERRORS(0)。 - 截图:列表页(闭环列表 + 创建表单)+ 详情页(状态卡"经验已更新/5 点/最优 86.12"+ 预算进度 73% + 批次历史 + 经验提取区)均正常。 - **验证边界**:一键自动运行的各步骤 API 已在 TEST-045~053 单独实测;UI 串接逻辑(状态机 + 轮询)未做真实长时运行(需数十分钟仿真),属"功能已接、待实机长跑确认"。 --- ## TEST-057:prompt_preview 截断修复 + 经验进入 prompt 实证 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 修复 AI 调用日志截断导致的可观测性缺陷 + 实证经验案例进入 AI prompt(TEST-052 遗留验证缺口) | ### 问题 - `ai_client._log_call` 存 `json.dumps(messages[:3])[:500]`——500 字符截断在 system prompt 开头,user message(含项目 BC + 经验案例)完全不可见。TEST-043/052 两次因此无法从日志确认 AI 实际收到的内容。 ### 修复 - prompt_preview:`messages[:3]` → `messages`(全部),`[:500]` → `[:8000]`;response_preview `[:1000]` → `[:2000]`。 ### 验证(实证经验进入 prompt) - 重新生成方案后,最新日志 prompt_preview 长度 8000,user message 含"参考经验案例(5个):[{topology: SSSR, params: {Airgap, RMSCurrent}, metrics: {tavg_nm...}...}]"。✅ - 经验价值链最后一环实证:闭环提取的经验(TEST-051 入库)在 AI 生成时真实进入 prompt。✅ ### 意义 AI 调用的输入完全可观测,后续调试 prompt 行为(变量名、BC 补充、经验复用)可直接查日志,不再黑盒。 --- ## TEST-058:闭环 UI 自动运行端到端实测 + axios 超时根因修复 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 实测闭环页"一键自动运行"状态机(TEST-056 遗留:UI 串接未实机跑过) | ### 发现的根因 - 首次 UI 自动运行:方案已生成(phase=plan_generated)却跳"运行中断"。 - 根因:**axios 默认超时 30s < AI 生成方案约 40s**。前端中止报错进 catch,后端继续跑完——状态错位。手动调 init-search 成功证实后端无恙。 - 对照:aiPlanApi 的 generate/generateAndSave/refine 早已显式设 180s(前人踩过同一坑),新加的 adaptiveApi 漏了。 ### 修复(web/frontend/src) 1. `api/ai.ts`:adaptiveApi 的 generatePlan / reportResults / updateExperience 补 `{ timeout: 180000 }`。 2. `AdaptiveLoop.vue` startAutoRun 改为**断点续跑**:进入时先刷新 phase,init 才生成方案,plan_generated 才初始化搜索,search_initialized 及以后直接进批次循环。任何中断后重点"一键自动运行"即可从断点继续。 ### 端到端实测(UI 驱动全闭环) - 闭环 loop_20260904_022534 从 search_initialized 续跑:批次0(3点)→ 执行器仿真 → 自动回传 → 分析 → 批次1(2点)→ 回传 → 预算耗尽(5/5)→ **自动提取经验**。 - 结果:5 点全部成功、0 失败、可行 5、最优 86.346 @ Airgap=1.5;UI 详情页正确展示(预算 100%、批次历史两行、经验提取区)。 - 经验库新增案例 9(SSSR,"本批次包含5个有效仿真点…气隙是主导权衡变量")——经验入库由 UI 自动触发完成。✅ - 执行器全程 online(心跳独立线程在真实长跑中经受住考验)。✅ ### 结论 闭环"一键自动运行"从 UI 点击到经验入库的全链路首次端到端实测通过。TEST-056 的验证边界闭合。 --- ## TEST-059:前端生产构建验证 + 补提交共享组件 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | dev 服务器正常≠生产构建能过;git status 巡检发现共享组件未跟踪 | ### 结果 1. **生产构建**:vite build 22.8s 通过,exit 0。全部页面 chunk 正常产出(含 AdaptiveLoop 10.18 kB)。仅大 chunk 警告(vendor-element 948 kB / vendor-echarts 1.04 MB),属优化项非错误。✅ 2. **补提交**:PageHeader.vue / SectionCard.vue / StatCard.vue 三个共享组件被 5 个已跟踪页面(Dashboard/ProjectList/PlanDetail/TaskManager/AdaptiveLoop)引用却一直未跟踪——克隆即构建失败。已补提交。✅ ### 说明 - 大 chunk 警告可通过 manualChunks 拆分优化,未处理(不影响功能)。 --- ## TEST-060:Motor-CAD 稳态热仿真首次实测 + 热指标别名登记 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试环境 | Motor-CAD 2026R1 (v261),pymotorcad(motorcad2maxwell/.venv),MARS 模型,1055@localhost 许可证可达 | | 测试目的 | 首次真实验证 Motor-CAD 热仿真(此前 HANDOFF 标注"热求解待真实验证") | ### 背景 P5-M6 引入的 `enable_thermal` 开关使用了两个**不存在的 API**,从未真正跑通: - `mc.do_thermal_calculation()` —— pymotorcad 无此方法(真实为 `do_steady_state_analysis`) - `mc.export_results("Thermal", ...)` —— solution_type 无 "Thermal"(真实为 "SteadyState") ### 实测结果(scripts/run_thermal.py) | 步骤 | 耗时 | 结果 | |---|---|---| | 电磁计算 do_magnetic_calculation | 127.8s | 正常,损耗作为热源 | | 稳态热 do_steady_state_analysis | 6.0s | 正常 | | 导出 export_results("SteadyState") | — | 9 个 section 完整 | **热指标实测值**: | 指标 | 值 | 说明 | |---|---|---| | winding_temp_c 绕组平均 | 67.95°C | `T [Winding (A) Average]` | | winding_hotspot_temp_c 绕组热点 | 74.59°C | `T[绕组最高]` = EWdg Outer Max | | magnet_temp_c 磁钢 active | 118.15°C | 磁钢最高温,热风险首要关注 | | stator_temp_c 定子轭 | 55.49°C | `T[定子轭]` | | bearing_temp_c 后轴承 | 88.47°C | 前轴承仅 49.19°C,后轴承是热风险点 | | temp_rise_c 温升 | -56.88°C | ⚠ 负值,见下 | | thermal_resistance_k_w 热阻 | -11.07 K/W | ⚠ 负值,见下 | ### 发现的问题 1. **热边界条件异常**:MARS 模型 `[Miscellaneous]` 中 `Ambient_Temperature=125`(环境 125°C, 而辐射环境 `T_Ambient_Radiation=40` 正常),导致温升/热阻为负值。 **待用户确认后修正为 25~40°C**。 ### 修复内容 1. `scripts/robust_motorcad.py`:`do_thermal_calculation()` → `do_steady_state_analysis()`; `export_results("Thermal")` → `export_results("SteadyState")`。 2. `src/afmcore/metrics.py`:7 个热指标补充实测字段别名(中英文),bearing_temp_c 映射到后轴承。 3. 新增 `scripts/run_thermal.py`:独立热仿真验证脚本(可复用)。 ### 验证 - `scripts/test_metrics_extension.py` 20 项全部通过(含热指标、enable_thermal 签名)。 - 热导出文件回放 `extract_all_metrics` 提取 7 项热指标全部命中。 ### 结论 热仿真链路首次真实跑通,API 与字段名已核实登记。剩余阻塞:模型环境温度异常待确认。 ### 补充实测(磁热耦合 vs 分离式,同日) | 项 | 分离式(先电磁后热) | 磁热耦合 do_magnetic_thermal_calculation | |---|---|---| | 耗时 | 134s | 474.2s(~3.5×) | | 磁钢 active | 118.15°C | 110.68°C | | 绕组热点 | 74.59°C | 76.43°C | | 平均转矩 | 0.566 Nm | 0.515 Nm | | 转矩脉动 | 5.45% | 2.78% | | 总损耗 | 49.92W | 42.57W | **结论**:磁热耦合更准确(温度反馈迭代)但更慢。"省时间"选分离式(enable_thermal 已实现)。 --- ## TEST-061:执行器 enable_thermal 端到端真实验证 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 验证执行器 enable_thermal 全链路(RobustMotorCADSolver→热求解→热指标落盘 CSV),此前仅代码透传 + 单元测试 | ### 结果(scripts/verify_enable_thermal.py) - `RobustMotorCADSolver(enable_thermal=True)` 跑单点:电磁 + 稳态热求解均成功(status=OK)。 - 7 项热指标全部合并到 point result 并落盘 `scan_results.csv`(header 含全部热指标列)。 - 环境温度覆盖 25°C 后:温升 +27.57°C、热阻 +5.657 K/W(物理合理正值)。 ### 结论 执行器 enable_thermal 链路端到端 **PASS**。热仿真已完整接入生产链路(配置开关 → adapter → solver → 热指标落盘)。 ### 补充(环境温度固化) `ambient_temperature` 已固化到执行器配置(默认 25°C,`executor_config.json` + `EXECUTOR_AMBIENT` env 可调), `RobustMotorCADSolver(enable_thermal=True, ambient_temperature=25.0)` 构造参数方式复测端到端 PASS (温升 +27.57、热阻 +5.657,与 params 传参方式结果一致)。 --- ## TEST-062:任务级三档热仿真(thermal_mode)端到端验证 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 验证任务级三档热仿真开关(off/steady/coupled)全链路 | ### 实现链路 前端 TaskManager 三档单选 → CreateTaskRequest.thermal_mode → task_manager 写入 task.json → 执行器 execute_task 读 task["thermal_mode"] → adapter.run_point(thermal_mode) → solver.run_single_point(thermal_mode)(coupled 分支调 do_magnetic_thermal_calculation)。 ### 验证结果 - **coupled 模式**(verify_enable_thermal.py --thermal-mode coupled,真实 Motor-CAD): status=OK,7 项热指标全部落盘 scan_results.csv。温升 +29.91°C、热阻 +2.058 K/W(正值,物理合理)。 磁钢 62.74°C、绕组热点 55.96°C、后轴承 38.18°C。 - **优先级**:调用级 thermal_mode > 实例级 > enable_thermal 布尔(向后兼容)。 - 前端 vue-tsc 类型检查 0 错误。 ### 结论 任务级三档热仿真开关全链路打通并实测通过。工程师创建任务时可选: 仅电磁(128s/点)/ 电磁+稳态热(默认,134s/点)/ 磁热耦合(精算,474s/点)。 --- ## TEST-063 — 停止仿真按钮失效修复(桩函数 + 执行器取消回查) - **日期**:2026-09-04 - **问题**:用户点"停止仿真"后修改扫描变量,进度条仍显示旧任务的 0/100 点、预计 3.8 小时,与方案卡片的 5 点/11 分钟不一致 - **根因(三层叠加)**: 1. `PlanDetail.vue` `stopSimulation` 是前端桩(注释 "API call to stop would go here"),从未调用后端 cancel,旧任务继续跑 2. 后端 `POST /api/tasks/{id}/cancel` 只改 DB 状态;执行器点循环只查进程内 `_stop_event`,从不回查 Web 端任务状态 3. 进度条用任务创建快照 `activeTask.total_points`(100),方案卡片用实时重算 `estimatedPoints`(5),旧任务不死则必分叉 - **修复**: 1. 前端 `stopSimulation` 真正调 `POST /api/tasks/{task_id}/cancel` 并刷新 `loadActiveTask` 2. 执行器新增 `_is_task_cancelled()`:每点前 best-effort 查 `GET /api/tasks/{id}`(网络失败不误判中断),cancelled 则设 `_task_cancelled` 中断循环,按 `cancelled` 上报已完成点 - **测试**:新增 `scripts/test_executor_cancel.py`(6 项全过:本地模式不取消/网络异常不误判/cancelled 检出/running 不误判/中途取消只跑 1 点并上报 cancelled/未取消跑全部点);回归 test_executor_m3 4 项、test_executor_p5m2 8 项、test_executor_config 20 项全过;前端 vue-tsc 0 错误 - **注意**:取消在点边界生效(当前点跑完后中断),已完成的点保留上报 --- ## TEST-060:执行器僵尸僵死事件复盘 + 双层防护(进程内看门狗 + 外部监管进程) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 触发事件 | 执行器 11924-5fed 于 06:13 完成用户扫描任务 a4f6ad1d 后全程冻结:日志/心跳/取任务全停、无任何报错,进程僵尸至 12:06 才消失。期间用户 11:08/11:10 两次提交扫描均无人领取,只能取消。 | ### 事件重建(证据链) - 最后心跳状态卡在 running → 冻结点在任务完成回调之后、下一次心跳之前。 - 日志无任何异常 → 非 Python 异常,疑似 Motor-CAD COM 对象在 GC 时释放挂起且持有 GIL,冻结全部线程。 - 进程级冻结使一切进程内看门狗失效 → 必须有独立进程的外部监管。 ### 修复(双层防护) 1. **进程内**(task_executor.py / run_task_executor.py): - start_polling 返回全部线程(含心跳线程),主循环逐一监控,任一线程死亡 → 报错 + 非零退出; - _send_heartbeat 记录成功时间戳,主循环看门狗:120s 无成功心跳 → 退出(exit 4); - 每个任务完成后做确定性 gc.collect(),前后打日志面包屑——若 COM 释放在此挂起,日志精确定位。 2. **进程外**(新建 scripts/executor_supervisor.py): - 子进程方式运行执行器;每 15s 查后端 /api/executor/status; - 子进程死 → 10s 退避后自动重启; - 进程活但 offline 超 180s(僵尸态)→ 杀进程重启; - 后端不可达时不误判。 ### 验证 - 编译 + ASCII 全通过; - 看门狗实测:杀子进程 20304 → 61s 内自动重启新执行器 26664-27ea 上线。✅ - 当前执行器已在看门狗保护下运行。 ### 使用方式 今后启动执行器推荐:`python scripts/executor_supervisor.py --config executor_config.json` --- ## TEST-061:看门狗保护下真实任务全链路验证 | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 验证 TEST-060 双层防护改动后的执行器在真实任务下正常工作(新代码:线程监控 + GC 面包屑) | ### 过程与结果 1. 创建 1 点冒烟任务 1d415d55(Airgap=1.2, thermal_mode=off)。 2. 看门狗监管的 executor 26664 正常领取并执行,~2.5min 完成:**status=completed, 1/1**。✅ 3. **GC 面包屑生效**:executor 日志出现 post-task-gc:begin/end(12ms 完成,未挂起)——确定性 GC 在真实 Motor-CAD COM 环境下工作正常。✅ 4. 任务完成后执行器保持 ONLINE(心跳线程存活)。✅ ### 结论 监管进程 → 新执行器代码 → Motor-CAD 求解 → 结果回传 → 确定性 GC,整链实测通畅。若未来再发生 COM 挂起,GC 面包屑将精确定位挂起点,外部看门狗会在 180s 内自动杀启恢复。 --- ## TEST-064:热仿真数据输出验证(用户请求现场试验) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 用户要求做一次试验并输出热仿真数据,验证温升/热阻等指标正常(环境温度 25°C 口径) | ### 过程与结果 1. 命令:`run_thermal.py --mode steady --ambient 25`(MARS 基础模型,RMSCurrent=21A, 5000rpm)。 2. EM 170.3s + 稳态热 7.5s,全链路 PASS。 3. 关键指标:绕组平均 52.59°C(热点 53.91°C)、磁钢 67.61°C、定子 47.26°C、轴承 38.47°C、温升 27.57°C、热阻 5.657 K/W。 4. EM 对照:转矩 0.522 Nm、脉动 2.82%、总损耗 41.9W(EM 表)/47.7W(热模型含风磨+轴承摩擦)、效率 86.06%。 5. 数据文件:`output/thermal_validation_20260904_123600/raw/{emagnetic,thermal_steadystate}.csv`(不入库)。 ### 结论 25°C 口径下温升/热阻均正常(正数),热数据提取链路工作正常。输出目录:`output/thermal_validation_20260904_123600`。 --- ## TEST-065:磁热耦合档复核(25°C 口径) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 与 TEST-064(分离式稳态热)对照,验证温度反馈对电磁/热指标的影响 | ### 过程与结果 1. 命令:`run_thermal.py --mode coupled --ambient 25`,耦合求解 405.3s PASS。 2. 耦合结果:绕组 54.86°C、磁钢 62.74°C、温升 29.91°C、热阻 2.058 K/W;转矩 0.545 Nm、效率 84.91%。 3. 对照分离式(TEST-064):转矩 0.522→0.545 Nm(+4.3%,高温退磁/电阻反馈生效)、效率 86.06%→84.91%、磁钢 67.61→62.74°C(耦合模型损耗分布不同)。 4. 数据文件:`output/thermal_validation_20260904_124142/raw/`(不入库)。 ### 结论 耦合档与分离档结果差异在合理量级(转矩差 4.3%),证明分离式会**低估**转矩、**高估**效率约 1.2 个百分点;精细评估建议用 coupled。 --- ## TEST-066:仿真结果 Excel 导出(工程师关键指标 + 完整结果) | 项目 | 内容 | |---|---| | 测试日期 | 2026-09-04 | | 测试目的 | 用户要求:Web 端显示工程师最关心的电磁+温度指标,并能导出完整仿真结果为 Excel(格式参考 torqrippswap scan_results.xlsx) | ### 实现 1. **新建 `src/afmcore/xlsx_report.py`**:移植 torqrippswap `write_summary_xlsx`(双行表头:行1 合并类目分组 + 行2 列名、冻结窗格、自动筛选),并按 afmcore 规范改为全 ASCII 源码(中文用 \u 转义)。`build_export_columns()` 按"扫描信息/电磁性能/热性能/结构性能/其他指标"分组组装列,仅导出数据中真实存在的指标列(EM-only 任务无热性能列)。 2. **后端**:`plans.py` 新增 `GET /api/plans/{id}/export-xlsx`,从 SimulationResult 表读结果,方案变量名映射中文表头(name_cn[unit]),RFC 5987 中文文件名,临时文件 + BackgroundTask 清理。requirements.txt 补 openpyxl>=3.1.0。 3. **前端 PlanDetail.vue**:结果表格 labelMap 扩充 30+ 中英文指标名(热/电/结构全套);thermal_mode 非 off 的结果自动把 5 个热核心列(绕组温度/绕组热点/磁钢温度/定子温度/温升)加入默认列;"导出 Excel" 按钮放在"下载 CSV"旁。 ### 验证 - `scripts/test_xlsx_export.py`(新建):30 项全过(18 单元 + 12 API),覆盖列组装、双行表头结构、冻结/筛选、热列条件出现、404/400 错误路径。 - 真实库验证:plan 31(3 点 OK 结果)导出 56 列,含电磁性能 23 列 + 热性能(磁钢温度);plan 23(80 点全 FAILED)导出 29 列仅扫描信息,失败行错误信息完整。 - vue-tsc 0 错误。 ### 上线修复(同日 14:00,用户报障) - **报障**:前端"下载 CSV"/"导出 Excel"均失败。 - **根因**:① 常驻后端(PID 31124,无 --reload)未加载新代码,export-xlsx 404;② "下载 CSV"按钮指向 `/api/plans/{id}/download`——该接口返回的是方案定义 JSON(给执行器拉方案用),从未返回过结果 CSV,属历史误标。 - **修复**:新增 `GET /api/plans/{id}/export-csv`(与 xlsx 同一套列组装 `_collect_export_rows`,单行中文表头,utf-8-sig 供 Excel 直开);前端"下载 CSV"改指 export-csv;重启后端。 - **验证**:补 7 项 CSV 测试(共 37 项全过);真实链路 plan 33 经 vite 代理(5173)导出 xlsx 7664B(5 行 55 列,三类目分组)+ csv 2504B(BOM 正确、中文表头正常)。 - **注意**:plan 33 第 1 行 status=OK 但带历史错误信息(Baseline reload failed),为脏数据原样导出,非本次引入。 ### 结论 工程师最关心指标(转矩/脉动/效率/损耗分解/电气/温度)在 Web 表格默认可视,完整结果一键导出 xlsx,格式与 torqrippswap 一致。