P5a 框架规则文档:M1-M3 元规则 + R1-R6 分领域规矩 + 反例清单

背景:这个框架踩过的坑几乎都是同一类——"没报错但结果是错的"。
之前这些教训只存在于聊天记录和零散注释里,改一次代码就要重踩一遍。
现在收敛成一份可引用的文档,并压缩成 .cursor/rules/ 常驻规则。

docs/FRAMEWORK_RULES.md(414 行)
  第 0 节  三条元规则:M1 静默失效是头号敌人 / M2 单一数据源 / M3 口径必须显式
  第 1 节  配置与数据 R1.1-R1.5(分层优先级、site.yaml 新键必须接线或告警、设备走 devices/、权重走 models/)
  第 2 节  几何/单位/坐标系 R2.1-R2.7(米与弧度、frame_id 必须是光学系、深度 mm↔m、
           rpy=Rz·Ry·Rx、Gazebo camera_info 不可信、像素门槛绑图幅、位姿容差要写理由)
  第 3 节  触觉与力 R3.1-R3.6(力是相对基线的增量、fnormal 压为正、轴向映射必须实测、
           接触布尔要用超时、force_scale 口径、仿真图像只能占位)
  第 4 节  仿真 R4.1-R4.10(唯一 site.yaml、world 里写 plugin 会挤掉默认系统、搜索路径要在
           launch 前设好、上游 description 不许改、场景走 scene.yaml、校验要逐碰撞体、
           不用"有话题就算通"验收、停仿真用 stop_sim_gz.sh)
  第 5 节  代码与测试 R5.1-R5.7(纯逻辑抽纯函数、校验要有测试证明有效、不许把降级写成通过、
           解析外部输出先确认真实格式、删除前扫全仓库引用、别在中文路径 colcon build、真机仿真产物隔离)
  第 6 节  文档与提交 R6.1-R6.4(文档与实现不一致立刻修文档、每份文档说明记录什么事实、
           结论数字要可复现、提交信息讲为什么并附实测数据)
  第 7 节  改动前检查清单
  第 8 节  历史反例清单——按"你看到的症状"查表,不是按道理排序
  第 9 节  给 AI 的具体指令

.cursor/rules/*.mdc  三份压缩版(常驻)
  framework-core.mdc       alwaysApply,元规则 + 检查清单 + 禁止项
  sim-gazebo.mdc           globs=devices/sim/**,src/arm_sim_gazebo/**
  config-and-devices.mdc   globs=config/**,devices/**,models/**,src/arm_interfaces/**

顺手修掉文档与实现不一致(R6.1)
  docs/WORKSPACE.md  此前【完全没有 devices/ 这一层】——通用化落点却没进目录总表。
                     补 devices/ 一节(kind/brand 目录约定、registry.yaml 与 manifest.yaml 分工、
                     assets[].required 缺失会报错),补 build_sim/install_sim/log_sim 与 .cursor/rules/,
                     并把 FRAMEWORK_RULES.md 标为 docs/ 首行
  README.md          文档表首行加 FRAMEWORK_RULES.md

顺手删死代码(R5.5:先扫引用)
  src/arm_interfaces/arm_interfaces/paths.py  删 assets_root()
    它返回 ros2_root()/"assets",而仓库里从来没有 assets/ 这个目录——实际权重树是 models/,
    且 models/ 的定位已由 arm_application.weights_layout.default_weights_root() 负责
    (带 SITE_WEIGHTS_ROOT 覆盖,且能从 install/ 反查仓库根)。
    两个实现并存违反 M2,且这个还指向不存在的路径,属于"照着名字用就踩空"。
  src/arm_interfaces/test/test_real_devices.py  从清环境变量列表里去掉 SITE_ASSETS_ROOT

验收
  src/arm_application 233 passed / arm_driver_flexiv 69 / arm_interfaces 46 /
  arm_kinematics 24 / arm_sim_gazebo 236 = 608 passed
  (flexiv_rdk 的 test 需装厂商 flexivrdk 包,仿真环境无此依赖,与本改动无关)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-23 17:16:47 +08:00
parent d32e6ae53f
commit d78e66ce98
8 changed files with 565 additions and 11 deletions
+42
View File
@@ -0,0 +1,42 @@
---
description: 配置与设备模块的改动规则(site.yaml 分层、devices 布局、权重归位)
globs: config/**,devices/**,models/**,src/arm_interfaces/**
---
# 配置与设备改动规则
权威全文:`docs/FRAMEWORK_RULES.md` 第 1 节(R1.1–R1.5)。
## 配置分层
- 优先级固定:**命令行 > `config/site.yaml` > 包内默认值**。
- `config/site.yaml` 是站点数据(SN / IP / 序列号 / 锁高 / 权重路径),**不进 git**;
改过它之后必须重跑 `python3 scripts/gen_site_example.py`,否则模板漂移
(有一条 parity 测试会红)。
- **禁止硬编码站点值到代码里**。历史反例:15 处硬编码的 `Rizon4-063989`,
换一台臂就会静默连错机器。
- 新增 `site.yaml` 键时二选一:**真的接线**,或在启动时**告警**。
声明了却没接线、也不告警,是最难查的一类问题(用户改了配置毫无反应)。
注意 `wired:` 只是 manifest 里的注释性约定,`arm_interfaces.manifest` 不解析它 ——
保障要靠代码里的告警函数(如 `sim_site.unwired_warnings()`),别指望清单。
## 设备模块布局
```
devices/<kind>/<brand>/
├── manifest.yaml # id/label/kind/vendor/version + assets + driver + capabilities + models + config_schema
├── driver/ # 与厂商 SDK 对接的实现(可替换)
└── models/<型号>/ # 该品牌的型号专属文件
```
- `kind` 用固定那几个(`robots`/`grippers`/`cameras`/`sensors`/`sim`),目录名要与
`arm_interfaces.KIND_FOLDERS` 一致。
- **换品牌 = 新增目录**,不是改现有目录;上层按 `manifest.yaml` 选型,不认品牌名。
- `assets[]` 里标 `required: true` 的物料缺失时,报错信息要给出**格式与命名要求**,
不能只说"文件不存在"。
## 权重
- 二进制(`.pt/.onnx/.engine`)**不进 git**,`.labels.yaml`(文本标签)**要进**。
- 转换链:`models/staging/` → `weights.sh convert` → 自动改名归位 + 固化标签。
- 配置里指向不存在的模型(悬空引用)必须修掉:`bash scripts/weights.sh doctor`。