# 写入别名（aliases）规范 v0.6

> 2026-10-31 · 起因：issue #722「条件闸门按字面匹配，自然问法普遍判 DEFER」
> **本规范有实测闭环支撑**：机制已就绪（#719）、案例已验证有效、库内使用率 0%。
> v0.1–v0.5 五版走的都是「改判定 / 改条件质量」，均被实测推翻；本版改走**写入侧补别名**。

## 一、实测依据（全部可复现）

### 1.1 决定性案例（issue 报告人给出）

条件：聊交接、换会话、压缩、或他流露舍不得时
查询：我不想你被换掉

| 匹配方式 | 结果 |
|---|---|
| **整词 in**（现状） | ❌ 不命中 |
| **二元组重叠** | ❌ 换会/会话 vs 我不/不想/想你/你被/被换/换掉 —— **交集空** |
| **查询扩展**（expand_query_terms） | ❌ 扩出 换掉/被换，与 换会话 **仍无交集** |
| **现有同义词表**（10 组，全技术词） | ❌ 无 会话/换掉 组 |
| **加 aliases**（换掉/被换/别消失/舍不得/不想你走/会交接/换会话/压缩上下文） | ✅ **命中**（False → True） |

⇒ **四条字面路全废，只有别名有效。**

### 1.2 库内现状（全量 + 抽样）

| 项 | 读数 |
|---|---|
| aliases 覆盖率 | **0 / 120 = 0%** |
| 生效条件为**元数据**的比例 | **65 / 85 = 76.5%**（抽样 120，结构化槽标签判据） |
| knowledge 层里 role=None（索引卡片） | **99.7%**（30,468 / 30,558） |
| 自然问法召回条数 | **2 条 / 32,845** |

⇒ **机制有、有效、但没人用**——这是 #722 的全部真相。

## 二、规范

### 2.1 写什么

> **写记忆时，aliases 至少包含「用户可能怎么问这件事」的说法。**

**不是**：技术术语缩写、字段名、路径片段。
**而是**：用户会说的口语、情绪表达、近义说法。

以 1.1 的案例为例，条件是 聊交接、换会话、压缩、或他流露舍不得时，
aliases 写成：换掉 / 被换 / 别消失 / 舍不得 / 不想你走 / 会交接 / 换会话 / 压缩上下文。

### 2.2 为什么不写进 tags

tags 已被机器判据占用（是不是任务卡：tasks.py；能不能当锚点：anchor.py / predict.py）。
塞别名会**改变那些判据**。aliases 与 tags **物理分离**，只参与检索召回。

### 2.3 怎么生成（**推荐用 LLM 自问**）

> **写别名时，先自问一句：「以后我会怎么问这件事？」——把那些问法原样写进 aliases。**

具体做法（写入方＝LLM 时）：

1. 读完这条记忆，**先不看条件**，自问：「如果三个月后我忘了这条，我会用什么话把它问出来？」
2. 写出 **3–8 个**这样的问法/关键词（口语、情绪、近义说法都算）；
3. 把它们写进 `aliases`；原文里已有的词不必重复（判据会判"薄"）。

**示范**（#722 案例）：

```
条件：聊交接、换会话、压缩、或他流露舍不得时
自问：以后会怎么问？
  → 「换掉」「被换」「别消失」「舍不得」「不想你走」「会交接」「压缩上下文」
aliases: 换掉 / 被换 / 别消失 / 舍不得 / 不想你走 / 会交接 / 换会话 / 压缩上下文
```

⚠️ **不要机械抽词**。实测（2026-10-31）：从功能名按空格切词自动生成别名，
5 个真实问法 × 20 条节点 = **提升 +0**——因为中文功能名没有空格，切出的是整句，
与"用户会怎么说"毫无关系。**别名必须由理解内容的一方预判，不能自动生成。**

### 2.4 判据（可执行）

`aliases_is_thin(fm) -> bool`：**无 aliases**，或**所有别名都能在正文/条件里原样找到**
（= 只重复已有词、没扩召回首）⇒ 判为「薄」。

⚠️ **不判「数量够不够」**——3 个精准别名可能胜过 10 个噪声别名。

## 三、写入守卫（warn 优先）

复用 #708 的 write_gate 三档：

| 档 | 行为 |
|---|---|
| off | 不检查 |
| **warn（默认）** | 写入成功 + 计数 + 提示「本条无扩展别名，自然问法可能召不回」 |
| enforce | 拒绝写入 |

**不阻断写入**：别名是锦上添花，不是正确性前提。缺它不该让记忆写不进去。

## 四、旧数据（明确不批量回填）

32,845 节点批量补别名**不现实**（需要理解每条内容）。现实路径：

1. **新写入**按本规范（守卫 warn 起步）；
2. **热点优先**：对实际召不回的查询**事后补**别名（哪个召不回补哪个）；
3. **可观测**：`cg(op=info)` 透出「无别名节点数」，作为改进基线。

## 五、验证方式（每条都要能测）

| 断言 | 怎么测 | 现状 |
|---|---|---|
| 别名能救 #722 案例 | 同 1.1 的对比 | ✅ **已测**（False → True） |
| 库内别名覆盖率 | 抽样读 fm.aliases | ✅ **已测**（0/120） |
| 字面路全废 | 整词 / bigram / 扩展 / 同义词表逐一对比 | ✅ **已测**（全部空交集） |
| aliases_is_thin 能识别现状 | 对抽样跑，≈100% 判为薄 | 待建 |
| 别名不污染 tags 判据 | 加别名后「是不是任务卡」「能不能当锚点」不变 | ✅ **已测**（PR #719 的 C/D 组守卫） |
| warn 档不阻断写入 | 无别名节点仍写入成功、只计数 | 待建 |

## 六、不适用条件

1. **不解决「完全没预判到的说法」**——别名靠人写，写不到的仍召不回；
2. **不替代语义检索**——semantic 覆盖率为 0，是另一条工程线；
3. **不批量回填旧数据**；
4. **不改变 tags 语义**（那个字段的机器判据不动）；
5. **不支持自动生成别名**——实测（2026-10-31）：从功能名/正文机械抽词，5 个真实问法 × 20 条 = **提升 +0**。
   别名必须由理解内容的一方（人或 LLM）**预判用户会怎么问**来写。

## 七、判据演进留痕（勿重蹈）

| 版 | 方向 | 为什么被推翻 |
|---|---|---|
| v0.1–v0.4 | 改判定算法（文本来源 / 弱态 / S3 图扩散 / 主题面） | **对象错配**：被判定的是 99.7% 的索引卡片 |
| v0.5 | 改条件质量（判是否元数据） | **诊断而非解法**——元数据条件是索引器产物，改不了 |
| **v0.6** | **写入侧补 aliases** | ✅ 机制现成（#719）+ 案例验证有效 |