[BUG] bridging 运行自己的会话也是会话:record seam 每小时挖掘自己的运行记录,prepare 永远不会为空(claude_code / hermes 已实证)
Description
bridging 任务是以宿主 agent 的一次会话的形式运行的,而宿主会把这次会话记录在——正是 memU 用来发现会话的那个地方。两个后果,都是结构性的:
- 每一次运行都保证了下一次运行"有新内容"。
prepare永远不可能返回 0——文档里写明的 "zero prepared sessions is fine and correct" 这个状态,在 bridging 装好之后就再也到不了了。 - memU 在挖掘自己的流水账:
prepare → self-evolve → commit的会话记录,成了下一轮prepare → self-evolve → commit的输入。
这不是 OpenClaw 独有的问题。它直接来自 ADR 0008 的形状——record seam 本身就是一次被调度的 agent 运行——所以凡是"被调度的运行本身会被记录成会话"的宿主,都中招。
证据(同一台机器,两个宿主)
manifest 只会为被选中并切片成挖掘 job 的会话写条目(bridging/transcripts.py:83-89),所以下面这些不是"被看到",是实实在在被挖过了。
| 宿主 | 已跟踪 | memU 自己的 | 占比 |
|---|---|---|---|
claude_code |
95 个会话 / 25,833 条记录 | 19 个会话 / 2,111 条记录 | 会话数 20%,记录数 8.2% |
hermes |
5 个会话 | 4 个会话 | 80% |
claude_code:19 个全部位于项目目录C--Users-Administrator--memu-hosts-claude-code下——也就是 bridging 任务工作目录被 slug 化后的名字。它们的第一条 user 记录,逐字就是 memU 自己写进~/.memu/hosts/claude-code/bridge-prompt.txt的那段 bridge prompt:"Run the memU bridging pipeline. Do the four steps strictly in order…"。单个自我会话最大的一个有 449 条记录。hermes:会话 id 为cron_c3fc5c456385_20260726_130012 / 140013 / 150015 / 160017——整点一次,和 bridging 的调度完全吻合。
某个 hermes 自我会话被挖出来的全部"对话"内容(~/.memu/hosts/hermes/sessions/1.jsonl,222 字节,逐字):
{"role": "assistant", "content": "12 jobs ran (5 leftovers + 7 prepared); committed 0 new recall files and 7 resources (install memory/skill already present; bridge sessions meta-only).", "timestamp": 1785050295.8598778}而它对应的 1_full.jsonl 有 50,896 字节的工具调用。一整个挖掘 job 槽位,就花在了一句运行摘要上——顺带注意挖掘 agent 自己写下的那句 "bridge sessions meta-only":它其实已经察觉到自己在读什么了。
尚未实证、但机制相同的:cursor(20 个已跟踪,key 在 empty-window/agent-transcripts/… 下,需要看内容确认)和 openclaw(每次运行一个隔离 cron 会话)。
为什么这是 bug,而不是无伤大雅
- 槽位挤占。 自我会话永远是磁盘上最新的东西,于是在 newest-first 排序里被顶到
discover()最前面,排在真实对话之前,去挤MAX_JOBS = 10(bridging/pipeline.py:27)。这正是 #533 的那种伤害——非对话的转录吃掉挖掘槽位——只是来源完全不同。 - token 燃烧。 每小时一次,对着纯流水账跑一遍 LLM 挖掘。
- 污染风险。 尚未归因:store 里确实存在关于 memU 自身运行的记忆,但它们同样可能来自真实的排查对话。下结论之前应当先做归因。
它还毁掉了一条文档所依赖的不变量:INSTALL.md 和 transcripts.py:57-58 都把"prepare 返回零"当作平静日子的正常结果。但只要 bridging 装着,平静的日子就不存在了——于是"一直有活干"不再能说明任何事情,包括 #528 里那套沉默失效的诊断。
Steps to reproduce
- 按任一宿主的
BRIDGING_TASK.md安装 bridging 任务; - 让它跑三次以上;
- 打开
~/.memu/hosts/<host>/.session_manifest.<host>.json,找属于 bridging 运行自身的 key——claude_code上它们在以~/.memu/hosts/claude-code命名的项目目录下,hermes上它们是cron_*会话 id; - 每一个这样的 key,都曾被切片成 job 并挖掘过。
Expected behavior
bridging 运行自己的会话永远不被挖掘。在没有真实活动时,prepare 报零——正如文档已经承诺的那样。
Additional Information
建议的修法——宿主无关,落在 bridging/
在规范的 bridging prompt 里放一行稳定的哨兵标记(每个宿主的 BRIDGING_TASK.md,以及生成的 bridge-prompt.txt),然后让 prepare 跳过第一条 user 记录带该标记的会话。
选这条缝的理由:
- 那段文本是 memU 自己的——这不是对别人数据的启发式猜测;
- 不需要任何按宿主写死的路径 hack;对
claude_code由 cwd 推出的项目目录、hermes的cron_*id、以及 OpenClaw 的隔离 cron 会话(根本没有任何路径可供区分)都同样有效; - 它能扛过 OpenClaw 的 JSONL→SQLite 迁移,因为标记随事件内容走,不随容器走;
- fail-open:prompt 里没有哨兵的(老安装)行为和今天完全一致——绝不会误跳过任何东西。
锚定在第一条 user 记录、而不是"会话里任意位置",可以避免把真正讨论 bridging 的对话(那些会引用 prompt 原文)误判掉。
考虑过并否决的方案
按宿主做路径/id 排除。那是 N 个各不相同的 hack,而且对 OpenClaw 根本无解。
关联
- #605:OpenClaw 双读适配器会原样继承这个循环,除非本问题先落地;SQLite 之后每次 cron 运行都是一个新
session_id,只会更显眼; - #532 / #533:同一种伤害形状(非对话转录挤占挖掘槽位),不同来源。
Environment: Windows 11,memu-cli 2.0.0-beta.0,仓库 main @ bba0293;在 claude_code 与 hermes 两个宿主上观测到。
Version: memu-cli 2.0.0-beta.0
Severity: Major —— 每次运行都在浪费挖掘槽位与 token,并且抹掉了沉默失效诊断所依赖的"空闲"信号。
Source: NevaMind-AI/memU