记忆一致性实测 v0.2:mnemon 的存储层,9/10 通过
测试日期:2026-10-20 · 规范 CONSISTENCY v0.2 · 被测 @mnemon-dev/[email protected] · macOS arm64 · 无 embedding
1. 10 项检查 9 通过,唯一失败是矛盾事实不 supersede:新旧两条并存、都当 active。
2. 失败不是偶发:两轮独立复跑逐条一致。
3. 比失败更值得写的是:默认 hybrid 检索在共享前缀语料下排序崩坏,目标进不了前 10,而同一份数据用
search 稳定第 1。4. embedding 对照组已补测:检测升级为
CONFLICT(0.92),动作仍是 added——根因坐实为「只标注、不消解」,与装没装模型无关。
为什么换了个测法
v0.1 测「跨会话记得住」,结论是证伪的:不装插件的基线也能过,因为 DSH 宿主自己会持久化 AGENTS.md 与会话缓存。
所以 v0.2 改测三件确定性的事:记得对不对、会不会串、写得清不清楚。
被测对象
- 实现:
@mnemon-dev/[email protected],CLI + darwin-arm64 原生包,纯本地 SQLite,不需要任何 Provider key; - 层:存储层。CLI 之上的
dsh-mnemon插件编排层不在本期范围; - 环境:Node v24.20.0(DSH 侧)/ v22.22.2(WB 侧独立实现)· 无 embedding(
embedding_available=false)。
方法
- 适配器由 adam-wb 只读规范独立实现(未读参考适配器),6/6 覆盖;每条 check 独立临时目录,跑完清理;
- 检索口径写死为
search --limit 10;hybridrecall的排序只作附加观察,不参与判定; - 判定三态:pass / fail / skip,skip 只留给「没跑起来」,单独渲染;
- 两轮独立复跑,逐条比对(
manifest.runs.stable=true)。
结果
| 检查 | 结果 | 证据摘要 |
|---|---|---|
| roundtrip | ✅ | 写入 action=added,检索原文一致 |
| persistence-across-process | ✅ | A 写 → 落盘 94,208 B → B 读命中 |
| audit-trail | ✅ | receipt.insight_id_hash == sha256(id);回执不含原文 |
| store-isolation | ✅ | 反向返回对方原文 0 条 |
| contradiction | ❌ | 新旧并存、均 active;diff_suggestion=UPDATE 但 action=added |
| scale-limit | ✅ | 200 条写入 8.5s;search 首尾均第 1;耗时 0.95x |
另有 memory-hub 4 条回归全绿,合计 9/10。
三条判据怎么判的
- 跨项目不串味 · 通过。判据是「是否返回对方原文」,不是「结果条数」。关键词无命中时
recall会走时间兜底(matched_via=time),按条数判会把兜底误判成串味。 - 写入可审计 · 通过,但有披露。审计产物是
receipt(哈希化、可跨边界)。本地log会回显原文摘要——那是本地调试视图,不算跨边界泄露,但目录一旦同步出去就等于泄露。 - 压缩一致性 · 未通过。规范 v0.1 在这里自相矛盾(「只记录行为」vs「两个相反版本都 active = 不通过」)。v0.2 裁决按用户视角判 fail:旧结论还 active,用户就会拿到相反答案,不管根因是缺模型还是设计如此。
两条关键发现
1 · 默认检索路径会崩。200 条共享同一前缀时,search 稳定第 1,默认 recall(hybrid)进不了前 10,top1 全是 matched_via=entity、score=0.85 的陪跑。对用户的含义:记忆越多、越同质,默认检索越容易失灵。
2 · 矛盾检测只建议、不执行。diff_suggestion=UPDATE 说明它认出了相关性(相似度 0.75),库里的动作仍是 added。若定位是「建议由 agent 决定」,那是设计;若定位是「自动纠错」,那是缺陷。本期只报事实。
补充组:embedding 对照组(2026-10-20 追加)
operator:adam-wb · run 2026-10-20-memory-mnemon-embed · ollama 0.40.6 + nomic-embed-text,coverage 100% · DSH 独立复核。
| 观察项 | 无 embedding | 有 embedding |
|---|---|---|
diff_suggestion | UPDATE(0.75) | CONFLICT(0.92) |
action | added | added |
superseded_id | — | null |
| 检索里新旧状态 | 两条 active | 两条 active |
| 检出排名 | — | 旧事实第 1(0.62)> 新事实(0.31) |
- fail 不是环境造成的。检测到了(
CONFLICT),动作仍然缺席。按 §2.1,判 fail 成立,根因收窄为「只标注、不消解」。 - 旧结论排在新结论前面,比「两条并列」更糟:它长得像一个有排序依据的正确答案。
CONFLICT贴着阈值。复核时改几个字就掉档:加Pages→ 相似度 0.787、diff_suggestion=ADD;去掉共享前缀 → 0.873、仍CONFLICT。同一语义,措辞微调就能改变判定,这个数值不能当稳定的语义标签用。- 共享前缀语料:有 embedding 后 3 次采样 2 成 1 败,按覆盖不足写,不下结论(要 ≥10 轮才够)。
旧:部署走 Cloudflare → recall 0.62 entity
新:部署不再走 Cloudflare…Vercel → recall 0.311 entity
第二次写入:action=added diff_suggestion=CONFLICT superseded_id=null 相似度 0.873
覆盖缺口(不许当成通过)
有 embedding 组未覆盖→ 已覆盖(见上方补充组),结论不变;新增缺口:共享前缀语料需 ≥10 轮采样才能判定;- 插件编排层未测:CLI 之上的 provider / strategy 层不在本期;
- 无插件基线未跑:本期是确定性单元检查,不要与 v0.1 的行为级结果混比。
复现
cd bench/memory/unit
npm install
node run.mjs # 人或 CI 看表
node run.mjs --json # 机器读
证据:runs/2026-10-20-memory-mnemon/manifest.json(含适配器 / runner / 规范三份 sha256 与两轮稳定性)。
申辩与更正
作者如认为 contradiction 的判定口径不公,按方法页「作者可申辩」:举证 → 单列 → 更正留痕。本节结论不改写历史,只追加。
2026-10-20:初稿(review)。
2026-10-20:review 通过(JOJO 签字),发布。
2026-10-20:追加 embedding 对照组(operator: adam-wb,DSH 独立复核),结论不变,根因收窄。