ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

claude-mem 项目边界与会话完整性:从 parent/basename 项目命名到待处理队列竞态修复

claude-mem 项目边界与会话完整性:从 parent/basename 项目命名到待处理队列竞态修复 claude-mem 项目边界与会话完整性从 parent/basename 项目命名到待处理队列竞态修复【免费下载链接】claude-memPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode More项目地址: https://gitcode.com/GitHub_Trending/cl/claude-mem这篇指南围绕 claude-mem 的问题分诊手册中 Phase 05 展开解决项目身份使用basename(cwd)导致的跨项目记忆串扰以及异步观测observation流水线中会话提前终结、观测重复入库、待处理队列无界增长三类数据完整性问题。读完本文你将理解项目命名从裸 basename 升级为parent/basename的动机与边界条件、存量数据的一次性迁移策略以及 SQLite 层如何用唯一索引把内容去重从 30 秒时间窗收紧到会话级并能对照当前仓库源码验证这些修复的实际落地情况。问题背景两个相关的数据完整性缺陷Phase 05 的手册Phase-05-Project-Scoping-And-Session-Integrity.md指出claude-mem 作为跨会话持久上下文产品其核心承诺是未来会话能注入过去会话中压缩后的相关记忆。一旦下列任一问题发生这条承诺即被破坏项目身份冲突关联 5 个 issue项目名取自basename(cwd)两个目录名相同的无关项目例如~/work/myapp和~/playground/myapp会共享同一项目名记忆相互污染异步观测流水线竞态关联 6 个 issue会话可能在观测消息仍积压在待处理队列中时就被提前终结summary 已生成、会话标记完成导致观测静默丢失并发处理还会产生内容哈希相同的重复观测worker 过载时pending_messages表还会无界增长。手册给出的修复范围包括五项工程任务加测试与构建验证下面逐项展开。升级项目身份从 basename 到 parent/basename手册要求把项目标识从basename(cwd)统一为parent/basename形式。任务拆解为通读 src/utils/project-name.ts 中的getProjectName(cwd)理解其当前返回值对照 src/shared/paths.ts 中getCurrentProjectName()的既有实现——手册指出它已返回basename(dirname(gitRoot))/basename(gitRoot)的抗冲突形式用grep -r getProjectName与对getCurrentProjectName()的搜索找出全部调用方然后把getProjectName()收敛为唯一入口与getCurrentProjectName()行为对齐处理边界情况Windows 盘符根目录返回drive-C、home 目录返回home/basename、单级路径返回root/basename同步更新getProjectContext()让 primary 与 parent 项目名都使用新格式关键约束暂不改动 ChromaDB collection 命名ChromaSync.ts因为那需要数据迁移由下节单独处理。当前仓库源码印证src/utils/project-name.ts 的getProjectName()已经演进出更稳健的解析链先经findGitRepoRoot()用git rev-parse --show-toplevel定位仓库根issue #2663使项目名在子目录与 worktree 间保持稳定再取basename非 git 目录、git 不可用或路径不存在时回退到 cwd 的 basename。边界分支在源码中同样存在空 cwd 返回unknown-projectWindows 下匹配^([A-Z]):\\/i的盘符根返回drive-字母project-name.ts 第 50-63 行。getProjectContext()第 75-103 行则额外处理 git worktree检测到 worktree 时返回复合键parentProjectName/cwdProjectName并给出parent、isWorktree、allProjects字段issue #3262。这说明单一命名函数 边界条件收敛的方向已落地且相关行为有 tests/utils/project-name.test.ts 与 tests/utils/project-name-isolation.test.ts 等测试覆盖。存量项目名的一次性数据迁移用户升级前既有观测存储在旧项目名下如myapp升级后新观测将写入新格式如work/myapp。手册设计的迁移函数migrateProjectNames()位于数据库层查询sessions表中所有 distinct 项目名对每个旧格式名不含/分隔符尝试在常见位置解析匹配的 git 仓库以恢复完整路径解析失败时加legacy/前缀如legacy/myapp以避免冲突在同一个事务内更新sessions与observations两张表的project列。迁移的挂接方式加入 worker 的后台初始化序列——在数据库初始化之后、搜索服务启动之前执行并在settings.json中用一次性标志projectNameMigrationComplete: true防止重复运行。对向量检索侧手册要求同步更新 ChromaDB 元数据。由于 Chroma 不支持 metadata 更新实际做法是对受影响项目触发backfill 重新同步项目名用于 collection 命名cm__project与 metadata 过滤条件迁移后旧 collection 中的文档必须按新名重放。实现依据来自 src/services/sqlite/SessionStore.tssessions/observations 的project列与src/services/sync/ChromaSync.tscollection 命名与过滤。修复会话提前终结终结前排空待处理队列问题会话可以在观测消息还积压在 pending 队列时就被终结——summary 已生成、会话被标记完成此后入队的观测无处归属形成数据丢失。修复方案手册原文在PendingMessageStore中新增SELECT COUNT(*) FROM pending_messages WHERE content_session_id ? AND status IN (pending, processing)封装为hasPendingMessages(contentSessionId: string): boolean在会话终结路径src/services/worker-service.ts中搜索 finalize / summary / SessionEnd 可定位触发点加入等待环最长等待 30 秒while (await pendingStore.hasPendingMessages(sessionId)) { await sleep(500); } // 超过 30s 仍未排空则强制终结并告警强制终结时记录告警日志Session finalized with ${count} pending messages remaining — some observations may be lost调用链佐证待处理消息的领取/确认遵循claimNextMessage()/confirmProcessed()模式见 src/services/sqlite/SessionStore.ts 中pending_messages表相关实现观测在 src/services/worker/agents/ResponseProcessor.ts 完成 AI 处理后落库。仓库中的pending_messages表还带有部分唯一索引ux_pending_session_tool ON pending_messages(session_db_id, tool_use_id) WHERE tool_use_id IS NOT NULLSessionStore.ts 第 1832-1838 行保证同一 tool-use 事件不会重复入队——这与终结前排空队列的守卫互为补充前者防入队重复后者防终结早于消费完成。运维侧还有 scripts/check-pending-queue.ts 与 scripts/clear-pending-queue.ts 两个脚本用于人工检查与清空积压。修复重复观测入库把去重从 30 秒窗收紧到会话级问题SessionStore.storeObservation()的内容哈希去重只检查 30 秒时间窗SELECT id FROM observations WHERE content_hash ? AND created_at_epoch ? AND memory_session_id ?并发处理同一会话消息时两条内容相同的观测若落在窗口之外检查双双通过产生重复行。修复方案手册原文把时间窗改为会话生命周期范围SELECT id FROM observations WHERE content_hash ? AND memory_session_id ?在数据库层加唯一索引兜底作为迁移加入 schema 演进CREATE UNIQUE INDEX IF NOT EXISTS idx_obs_session_hash ON observations(memory_session_id, content_hash)优雅处理约束冲突在storeObservation()中捕获UNIQUE constraint failed返回已存在的观测 ID 而非抛错。当前仓库源码印证该修复已经在库中落地。SessionStore.ts 第 1843-1894 行 的 schema 版本 29 迁移addObservationsUniqueContentHashIndex()在事务内先执行dedupeObservationsByContentHash()——用ROW_NUMBER() OVER (PARTITION BY memory_session_id, content_hash ORDER BY id)删除同一会话内的重复行NULL 哈希先被改写为__null_migration_id__哨兵值避免误伤再创建唯一索引ux_observations_session_hash ON observations(memory_session_id, content_hash)失败则整体回滚。写入路径同样对齐storeObservations()使用ON CONFLICT(memory_session_id, content_hash) DO NOTHING并在冲突后回查已存在行的idSessionStore.ts 第 2665-2672 行正是捕获冲突、返回已有 ID的实现形态。迁移行为由 tests/sqlite/session-store-migrations.test.ts 覆盖。修复待处理队列无界增长问题worker 过载或 AI 处理反复失败时pending_messages表只增不减消耗磁盘并拖慢查询。手册给出的三层限额约束阈值超限行为单会话待处理消息最多 100 条丢弃最旧一条并记录告警日志全会话总待处理消息最多 1000 条暂停新消息入队直至队列排空陈旧消息启动时已清理 6 小时以上的消息新增运行时周期性清理每 30 分钟一次避免两次重启之间持续累积监控面新增getQueueSize(): number返回总待处理条数并暴露到/api/health端点的pendingQueueSize字段便于外部探测队列水位。实现入口是PendingMessageStore的队列管理与 src/services/worker-service.ts 中processPendingQueues()的恢复逻辑手册标注约在第 811 行。测试与构建验证手册为这一阶段列出的测试矩阵与仓库测试目录可一一对应getProjectName()验证普通路径的parent/basename形式、盘符根、home 目录、单级路径——对应 tests/utils/project-name.test.ts、tests/utils/project-name-isolation.test.ts 与 tests/utils/project-filter.test.ts项目名迁移造旧格式测试数据 → 跑迁移 → 断言新格式与 ChromaDB 重同步被触发提前终结守卫mock 待处理消息验证终结流程会等待处理完成去重同一会话内插入两条内容哈希相同的观测断言只存一条对应 tests/sqlite/session-store-migrations.test.ts 的索引迁移用例队列限额单会话入队 101 条断言最旧一条被丢弃且有告警日志。验证步骤运行npm run build-and-sync完成构建与产物同步运行完整测试套件并修复所有失败项在全新数据库上验证迁移为干净 no-op——无旧数据可迁移时不应产生任何副作用。小结Phase 05 的修复链条可以概括为命名收敛 → 存量迁移 → 写入兜底先用单一getProjectName()消除项目身份冲突再用一次性事务迁移把旧basename数据含 ChromaDB backfill搬到新命名空间最后用会话级唯一索引 ON CONFLICT DO NOTHING把去重从应用层时间窗下沉到数据库约束。围绕异步流水线的两处守卫——终结前排空 pending 队列、队列三层限额加/api/health水位暴露——则分别堵住了观测静默丢失与磁盘无界占用两个方向的用户信任损伤。对照当前仓库唯一索引迁移、worktree 复合键、pending 队列检查脚本等实现均已可在源码与测试中核验。【免费下载链接】claude-memPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode More项目地址: https://gitcode.com/GitHub_Trending/cl/claude-mem创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表