# P2-06 L2 学习闭环与防退化评测

> 一句话：系统从人工修正里学习（L2），本卡把"采集入口、金标回归、冲突可见"三件套补齐，
> 让学习有入口、有度量、有安全带 —— 没有这些，学习迟早"越学越蠢"。

---

## 1. 数据流（闭环全貌）

```
NX 几何（journal 探测：面/边/孔径）
   │
   ▼
规则引擎（L1）  ── 建议参数（source=SpeedFeedTable(...)）
   │
   ▼  人工审核工序单，发现不合适就改
人工修正（采集入口）
   │   ① tools\correct.bat        双击，交互式逐条录入
   │   ② feedback.py import       从 JSON 文件批量导入（工序单审核后的批量化用法）
   ▼
记忆库（状态\memory.db，procedural 类型，success_rate=1.0 起步）
   │   canonical key = op|mat|tool|d   ← 精确匹配，跨 NX 版本复用
   ▼
下次生成工序单时 apply_learned_correction 按 key 精确覆盖
   │   （source=human-corrected(<id>)，MRR 自动重算，notes 写明原因与冲突提示）
   ▼
防退化评测（tests\run_eval.py）—— 每次改动后必跑的安全带
```

## 2. 采集入口

### 2.1 交互式录入：`tools\correct.bat`（双击）

逐项询问：工序 → 材料 ISO 类 → 刀具类型 → 直径 → 覆盖字段（逐行 k=v，空行结束）→ 原因 → 确认。
- 所有输入**先校验、确认后才一次性写库**；任何一步非法只给提示，绝不写半条。
- 字段名必须在 `feedback.OVERRIDABLE` 内；直径必须是数字；Ctrl+C 随时中止。
- 写完回显 canonical key、memory_id 与 lookup 校验命令。

### 2.2 批量导入：`feedback.py import --from-file <json>`

```json
[{"op":"roughing","material":"P","tool":"end_mill_flat","diameter":12.0,
  "set":{"ap_mm":3.0,"rpm":2200},"why":"退火开粗震刀"}]
```

- **原子语义**：全批校验通过才写库；任一非法 → 整批拒绝、逐条打印原因、退出码 1。
  避免"修一半"的库状态；文件改好后整批重跑也不会产生半批重复。
- 同文件内 canonical key 重复视为非法（几乎一定笔误；确需 supersede 请分两次导入）。

## 3. 冲突可见（不允许静默覆盖）

同一 canonical key 存在多条修正时，语义仍是"取最新"，但必须人工知情：

- `python D:\NX_AI\core\feedback.py conflicts` —— 列出全部冲突组：
  "取最新 <id> + 存在 N 条冲突修正"，附每条的 created_at / 覆盖值 / 原因。
- `feedback.py lookup` 命中冲突 key 时打印冲突提示。
- `find_correction()` 返回 `conflict_count`；`propose_plan.apply_learned_correction`
  把它带进 `plan["learned_corrections"]`，并在 `params.notes` 追加
  "该上下文存在 N 条冲突修正，已取最新"。
- 评测负向指标 `correction_conflicts_in_db` 持续记账。

## 4. 评测口径（tests\run_eval.py）

四道闸：① 红线断言（13 项）② 特征化基线漂移 ③ L2 对照 ④ **金标命中率**（本卡新增）。

### 金标集 `tests\golden\golden_cases.json`（29 条）
- **rule-frozen（25 条）**：期望 = 规则引擎当前输出的冻结快照（铣/钻/攻 × P/K/N/M/S/H）。
  两种模式都必须命中 —— 拦截"学习/改代码把对的改错了"。
- **human-expected（4 条）**：期望 = 工艺员给定真值，对应修正以 `seed_correction`
  播进评测专用临时库（不碰真实 memory.db）。
- 人工种子与全部 rule-frozen 用例 **canonical key 零碰撞**（key 只含 op|mat|tool|d，
  材料名不进 key，设计时已避开同 ISO 类同 key 的用例）。

### 什么算命中
用例 `expect` 里的每个字段都与实际建议一致（容差 1e-6）。
rule-frozen 比较 6 个字段（ap/ae/rpm/feed/vc/fz）；human-expected 只比较人工给定的那几项。

### 什么算退化
- **越学越蠢（硬断言）**：学习模式命中数 < --no-learn 命中数 → 退出码 1，
  并打印"学习前命中、学习后反而失手"的退化用例 id 清单。
- 漂移（软）：特征化基线有 diff 会列出；`--strict-drift` 下按失败处理。
- 已用"故意造错"验证：3 条同 key 金标 + 1 条毒化种子 → 评测退出码 1、
  退化用例 G901~G903 全部被列出；恢复真金标后回到 0。

### 基线读数（2026-10-17）
```
--no-learn : 25/29 (86.2%)   ← 4 条 human-expected 必然失手（规则≠人工真值）
默认(学习) : 29/29 (100.0%)  ← 学习修正后全部命中
断言：学习后 >= 学习前 -> 通过
```

### 负向指标怎么读
| 指标 | 含义 | 健康基准 |
|---|---|---|
| operations_total | 一次生成多少工序 | 趋势不异常膨胀 |
| drilling_without_tool | 有孔配不上钻头的工序数 | 不升 |
| violations_by_level | 红线按级别计数 | error 恒 0 |
| source_distribution | 参数来源分布（规则/人工修正/none） | human-corrected 占比缓升、none 不升 |
| corrections_applied | 本次生成被执行的学习修正条数 | 与库中修正规模相称 |
| correction_conflicts_in_db | 库中冲突 key 组数 | 知情管理，不定期人工清理 |

## 5. 拦截"越学越蠢"的手段清单
1. **金标硬断言**：学习后命中率 < 学习前 → 门禁红、退出码 1（已负向验证）。
2. **精确匹配红线**：canonical key 不含材料名/NX 版本，宁可不用也不张冠李戴。
3. **导入原子性 + 字段白名单**：脏数据进不了库。
4. **冲突可见**：重复经验绝不静默覆盖。
5. **溯源完整**：memory_id / created_at / why / success_rate=1.0 全程可查。

## 6. 常用命令速查
```bat
rem 录一条修正（双击）
D:\NX_AI\tools\correct.bat
rem 批量导入
python D:\NX_AI\core\feedback.py import --from-file corrections.json
rem 查冲突
python D:\NX_AI\core\feedback.py conflicts
rem 防退化评测（改动后必跑）
python D:\NX_AI\tests\run_eval.py
rem 自测
python D:\NX_AI\core\feedback.py self-test     (15/15)
python D:\NX_AI\tools\correct.py --self-test   (20/20)
```
