# AGENTS.md — AI 工具工作说明

> 本文件面向 Claude Code / Codex / Cursor / 豆包等 AI 编程工具。
> 接到任何任务前，**先读 [docs/KNOWLEDGE_BASE.md](docs/KNOWLEDGE_BASE.md)**。

## 项目定位

PCB轴向磁通电机自动化仿真系统 — 双系统解耦架构：
- **系统一（Web端）**：方案生成与优化（Phase 2+）
- **系统二（本地EXE）**：仿真执行（当前Phase 1重点）

当前处于 **Phase 1 最小闭环开发**：本地GUI方案编辑 → Motor-CAD自动化仿真 → 结果输出 → 经验库积累。

## 开始工作前必须阅读（按顺序）

1. `docs/KNOWLEDGE_BASE.md` — 核心知识库（环境事实、参数语义、探测技术、SOP、已踩的坑）
2. `README.md` — 项目说明、目录结构、快速开始
3. `PCB轴向磁通电机自动化仿真系统设计方案介绍.md` — 完整设计方案V1.1（架构、接口、算法选型）
4. 参考案例的知识库：
   - `axial_mag_pull-master/axial_mag_pull/docs/KNOWLEDGE_BASE.md`
   - `torqrippswap-master/torqrippswap/MOTORCAD_SCAN_KNOWLEDGE_BASE.md`

## 参考案例代码（可直接复用/改造）

| 功能 | 参考文件 | 说明 |
|---|---|---|
| Motor-CAD连接与前台可见 | `torqrippswap-master/torqrippswap/solver.py` → `MotorCADSolver.connect()` | `open_new_instance=True` + `set_visible(True)` |
| 参数写入+回读校验 | `torqrippswap-master/torqrippswap/solver.py` → `_write_and_verify()` | 写入后get_variable回读，不一致抛异常 |
| 每点基线重载 | `torqrippswap-master/torqrippswap/solver.py` → `run_single_point()` | 每点 `load_from_file` 防止污染 |
| 结果导出与解析 | `torqrippswap-master/torqrippswap/solver.py` → `parse_export()` / `extract_all_metrics()` | 分号分隔CSV，中英文字段别名匹配 |
| 扫描执行+逐点落盘 | `torqrippswap-master/torqrippswap/solver.py` → `run_scan()` | manifest+CSV+log+raw，每点flush |
| Git preflight | `torqrippswap-master/torqrippswap/solver.py` → `git_preflight()` | 运行前检查仓库干净 |
| AFM轴向力3D力图读取 | `axial_mag_pull-master/axial_mag_pull/axial_force_final.py` | `get_magnetic_3d_graph_point`，Fr=轴向力 |
| 三判据校验 | `axial_mag_pull-master/axial_mag_pull/axial_force_final.py` | 作用反作用/转矩交叉/解析量级 |

## 硬性工程约束（违者返工）

### 1. 源码字符集
所有 `.py` 和 `.ps1` 文件**必须只包含 ASCII 字符**。中文说明写在 Markdown 文档中，不能写进脚本注释、字符串、窗口标题。中文字段名用 `\uXXXX` Unicode 转义。

检查命令：
```powershell
rg -n "[^\x00-\x7F]" --glob '*.py' --glob '*.ps1' .
```

### 2. 运行前必须 Git 提交
实际启动 Motor-CAD 求解前必须满足：
- Git 仓库存在且 HEAD 有效
- 所有已跟踪文件无未提交修改

GUI 内置 Git preflight，不满足时拒绝启动扫描。

### 3. Motor-CAD 实例管理
- 使用 `open_new_instance=True` 创建独立实例，**不要**连接已有实例（可能控制错误窗口）
- 启动后必须 `set_visible(True)`（/SCRIPTING模式默认隐藏主窗口）
- 每个扫描点开始前 `load_from_file(基线模型)`，结束后也重载基线

### 4. 参数必须回读校验
不能只调用 `set_variable`。必须：
```python
mc.set_variable(variable, value)
applied = float(mc.get_variable(variable))
if not math.isclose(applied, value, rel_tol=1e-8, abs_tol=1e-7):
    raise RuntimeError(...)
```
回读不一致时将该点标记为 FAILED，保存错误并继续下一点。

### 5. 结果逐点落盘
- 每个点完成后立即写 CSV 并 flush，**不能**等整批完成后一次性保存
- 失败点记录错误并继续
- 运行目录结构：`output/<timestamp>_<scan_name>/` 含 manifest.json + scan_results.csv + program_log.log + raw/

### 6. 原始模型只读
- 原始 `.mot` 文件不修改
- 所有操作在 Motor-CAD 内存中进行，或另存时间戳副本
- models/ 目录下的模型文件视为只读

### 7. 生成物不入库
- `output/`、`runs/`、`build/`、`dist/`、`*.log`、`*.spec` 不入库
- 关键数值转录进入库的文档（RESULTS.md / 报告）

## 环境变量陷阱（AI shell 常踩）

非登录 shell 可能不继承机器级环境变量：
- `MOTORCAD_ACTIVEX` 为空 → pymotorcad 找不到 Motor-CAD
- `ANSYSLMD_LICENSE_FILE` 为空 → Motor-CAD 启动后 ~30s 静默退出

脚本内回退：
```python
import os
if not os.environ.get("MOTORCAD_ACTIVEX"):
    from ansys.motorcad.core import set_motorcad_exe
    candidate = r"D:\Program Files\ANSYS Inc\v261\motorcad\MotorCAD.exe"
    if os.path.exists(candidate):
        set_motorcad_exe(candidate)
```

## 不要做的事

- 不要猜 Motor-CAD 变量名 — 先从 .mot、已有参数表或探测结果确认
- 不要在主线程运行仿真（GUI会卡死）— 必须用 QThread 子线程
- 不要修改原始 .mot 文件
- 不要把生成物提交到 Git
- 不要在 .py 文件中写中文字符（用 Unicode 转义或放 Markdown）
- 不要用 `open_new_instance=False` 连接已有实例
