Files
memind/docs/regression-guards/memory-v2-candidate-and-lifecycle.md
john c2e2209344
Memind CI / Test, build, and release guards (push) Successful in 2m31s
fix(memory): sync new memories into pgvector
2026-07-21 23:30:18 +08:00

2.7 KiB

Memory V2 候选表与生命周期灰度守卫

已知故障

生产曾出现 h5_memory_v2_candidates 不存在:候选记忆写入和后台查询报错, 但 Agent 召回仍在 shadow 模式执行,因此表现为“有召回事件、回答未注入、个人记忆状态降级”。

同时,生命周期 worker 只检查了 worker 开关;expire() 没有检查 rollout 作用域。若忘却开关开启,即使 MEMORY_LIFECYCLE_ROLLOUT_MODE=off,定时器也可能 归档全量用户的过期记忆。

灰度还曾出现 MySQL 已成功保存新记忆,但 pgvector 仍只包含旧数据:runtime 从全局 updated_at=0 游标开始做有限批次 backfill,新写入行可能长期排在批次之外。结果是 agent_memory_resolved 显示已注入,但回答只拿到旧的无关记忆。

必须保留的行为

  1. MEMORY_CANDIDATE_PERSISTENCE_ENABLED=1 且 MySQL 可用时,Portal 必须先执行 ensurePersonalMemoryCandidateSchema(),再创建候选记忆 store。
  2. 候选表 DDL 失败不能阻塞 Portal 聊天启动;Portal 应记录告警并退回 bounded-memory。
  3. memind_adm 必须在创建候选 store 前完成同一幂等建表;初始化失败时后台启动失败, 不允许以“页面可用但候选接口持续报错”的半初始化状态运行。
  4. 生命周期 rollout 语义必须严格一致:
    • off:不得执行任何写操作,也不得启动 worker 定时器。
    • canary:只允许 MEMORY_LIFECYCLE_ROLLOUT_USER_IDS 中的用户。
    • active:才允许无 user scope 的全局任务。
  5. forgetMemory()expire() 都必须同时满足功能开关与 rollout 作用域。
  6. 用户记忆 write/compact 成功后,必须在返回前按 userId + sessionId 将本次活跃记忆 幂等 upsert 到 pgvector;候选晋升成功后也必须按实际晋升用户同步。不得依赖从零开始 的全局有限批次 backfill 来保证新记忆可立即召回。

回归检查

node --test memory-v2-personal-store.test.mjs memory-v2-lifecycle.test.mjs \
  memory-v2-pgvector-backfill.test.mjs memory-v2-runtime.test.mjs
npm test

memind_adm 同时执行:

node --test server/personal-memory-candidate-store.test.mjs
npm test

灰度上线后还必须验证:候选表存在、候选写入成功、后台可查询,以及一个测试用户完成 “保存 → 候选 → 晋升 → 新会话召回 → 回答注入”的闭环。未通过前不得切换全量 active。

回滚

代码可以按标准 runtime/release 回滚;候选表是加法结构,回滚时保留空表或已有数据, 不得为了代码回滚直接删除表。先把候选、生命周期和 Agent 注入模式切回 shadow/off。