
claude-mem 双车道同步架构解析基于 Cloudflare Durable Object 的跨设备记忆同步【免费下载链接】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 5 双车道多设备同步计划覆盖其HTTP 承载一切持久数据、WebSocket 仅作下游提示加速层的双车道决策、基于每用户一个 Durable Object 的有序日志存储设计、客户端推拉同步链路以及看门狗与一键降级等成本护栏读完你将掌握在 Cloudflare Workers 上构建幂等、可断点续传、可优雅降级的多设备数据同步系统的完整方法论并看到该计划在本仓库workers/sync-hub/目录中落地为实际代码后的对照印证。一、决策背景四架构对抗竞赛与双车道裁决claude-mem 的核心价值是把 Agent 会话中的记忆观察、摘要、用户提示持久化并在后续会话注入。当同一用户的多台设备各自产生记忆时就需要一套多设备同步机制。该计划文档记录了一次四架构对抗竞赛四个候选方案各由一名倡导者adversarial advocate辩护——纯 HTTP 方案、双车道混合方案、WebSocket 原生方案、以及现成同步引擎ElectricSQL / Zero / cr-sqlite。最终裁决为双车道混合two-lane hybrid车道 1HTTP承载一切持久数据。HTTP 游标cursor是唯一的真源sole source of truth。车道 2WebSocket只是下游方向的建议性advisory加速层。它可以出错、被丢弃、甚至被整体禁用——零数据丢失。裁决文档还给出了一个重要的收敛证据四名倡导者尽管在传输层上立场对立却独立收敛到了同一套存储内核——每用户有序日志、单调递增 seq、游标断点续传、幂等 apply、变更携带 rev、epoch 守卫。因此日志这一层从未被真正争论争议只存在于传输层。现成引擎被各自的倡导者否决ElectricSQL 只覆盖读路径Zero 拒绝离线写cr-sqlite 已停更 30 个月。托管选型为 Cloudflare Workers Paid 每用户一个 SQLite 后端 DO计划文档给出的成本模型为100 用户约 $5/月1000 用户约 $15/月10000 用户约 $230/月休眠用户接近 $0。二、五条首要指令Prime Directives计划文档从裁决记录中继承了五条不可违背的指令它们贯穿后续所有阶段的实现与验收开发中批次车道不是底线存活的是四名对抗倡导者独立保留下来的机制——DB-as-queue outbox数据库即队列、fail-closed 设备身份、尺寸钳制size clamps、防抖 nudge被淘汰的是按类型拆分的 Vercel 端点、toCloudmapper 的覆盖式 upsert 竞争、stampGuardSql机制、live|backfill车道启发式。持久数据永不走 socketHTTP 游标是唯一真源WS 可以错、可以断、可以禁用零数据丢失。会话开始时立即拉取记忆注入的那一刻是延迟预算中唯一一次硬性花费hard spend。绝不对 DO 做长轮询挂起的请求会破坏休眠hibernation经济上等价于每设备每月约 $4 的持续计费——同一个陷阱换顶帽子。成本护栏是结构性的看门狗watchdog触发的是切换到轮询模式而不是停止工作。三、Phase 0 平台调研被验证的 Cloudflare API 面与硬限制Phase 0 由三个子代理完成调研实时抓取 Cloudflare 官方文档 仓库代码锚点提取 工具链事实核查其结论被计划文档固化为执行者不得重新调研、直接照抄以下锚点。3.1 被允许使用的 Cloudflare API 面API精确形态DO 基类import { DurableObject } from cloudflare:workersclass SyncHub extends DurableObjectEnv构造函数super(ctx, env)路由env.SYNC_HUB.getByName(userId)一步取到 stub替代 idFromNameget。数据端点走 RPCDO 的fetch()只用于 WS 升级return stub.fetch(request)SQLitethis.ctx.storage.sql.exec(query, ...bindings)返回游标提供.toArray()、.one()、.raw()、rowsRead/rowsWritten。游标必须同步消费绝不允许跨awaitexec 不支持BEGIN改用ctx.storage.transactionSync(cb)同步回调构造函数中用ctx.blockConcurrencyWhile()初始化 schema休眠式 WebSocketthis.ctx.acceptWebSocket(server, tags?)类方法webSocketMessage(ws, msg)、webSocketClose(ws, code, reason, wasClean)、webSocketError(ws, err)this.ctx.getWebSockets(tag?)ws.serializeAttachment(obj)上限 16 KB——存键不存状态/deserializeAttachment()升级路径new WebSocketPair()→acceptWebSocket(server)→new Response(null, { status: 101, webSocket: client })Keepalivethis.ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair(ping, pong))两侧各 ≤2,048 字符应答无需唤醒 DO协议级 ping 由运行时自动 pong同样不唤醒 DOAlarmawait this.ctx.storage.setAlarm(msEpoch)每 DO 一个每次 setAlarm 计 1 次计费行写处理器alarm(info?: {retryCount, isRetry})至少一次投递、必须幂等、必须自我重排构造函数中 setAlarm 前必须先getAlarm()检查Wrangler 配置最小键name/main/compatibility_dateDO 绑定 migrations: [{tag:v1, new_sqlite_classes:[SyncHub]}]或更新的exports: {SyncHub: {type:durable-object, storage:sqlite}}——二选一只走一条流脚手架命令npm create cloudflarelatest -- durable-object-starter3.2 塑造设计形态的平台硬限制这些限制直接决定了日志的分页、批处理与尺寸钳制设计每 DO SQLite 上限10 GB单行最大2 MB单条语句最大100 KB每查询最多 100 个绑定参数多行 INSERT 须按 ≤约 12 行 × 8 列切块入站 WS 消息最大32 MiBisolate 内存128 MB⇒ 重放必须分页绝不能在内存里缓冲 50 MB每 DO 软限约1,000 req/s入站 WS 消息按 20:1 计费出站免费。3.3 工具链事实2026 形态训练数据中的片段已过时Bun 的 WS 客户端原生支持认证头Bun 专属扩展new WebSocket(url, { headers: { Authorization, X-Device-Id } })另有ping()、pong()、terminate()、bufferedAmount等选项无需引入wsnpm 依赖。已验证的 keepalive 组合Bun 客户端每 30–45 s 发协议级ws.ping()→ CF 运行时自动 pong 且不唤醒 DO官方文档有载同时为未来的浏览器客户端设置setWebSocketAutoResponse(ping,pong)浏览器无法发协议 ping。测试形态cloudflare/vitest-pool-workers≥0.18 采用 Vite 插件形式plugins: [cloudflareTest({ wrangler: { configPath: ./wrangler.jsonc } })]搭配Vitest ≥4.1defineWorkersConfig已在 v0.13 移除。测试 API 来自cloudflare:testrunInDurableObject(stub, (instance, state) ...)、runDurableObjectAlarm(stub)、evictDurableObject(stub, { webSockets: hibernate })。已知问题WS DO 测试需要--max-workers1 --no-isolate因此 WS 测试须放在独立的 vitest 调用中。wrangler dev本地提供ws://localhost:8787SQLite DO 不支持--remote。Lint 守卫ESLint flat config 的no-restricted-globalssetTimeout/setIntervalno-restricted-syntax选择器CallExpression[callee.property.nameaccept]、裸fetch(作用域限定在 DO 源码 glob——外加一道朴素的grep -rnCI 步骤防globalThis.setTimeout这类规避写法。四、反模式清单那些烧钱的陷阱计划文档把七条反模式逐条对照实时官方文档验证过并标注了它们的代价量级对应文档中每月 $4.11/用户 $34k 事故级别的陷阱server.accept()addEventListener旧版 WS API——破坏休眠。只有ctx.acceptWebSocket() 类处理器方法是合法形态。DO 中任何位置的setTimeout/setInterval——会把 DO 钉在唤醒态。只允许 Alarm且只在有活干的时候。DO 绝不发起出站 I/O——一丝一毫都不行。2026-06-19 平台变更后出站connect()/WebSocket 会把 DO 钉住每次连接最长 15 分钟被 await 的出站fetch()会阻塞 DO 进入 idle。token 校验、上游调用等一切发生在前面的无状态 Worker。构造函数中setAlarm()而不做getAlarm()检查——官方文档标注的$34k 失控事故背后陷阱。用内存 Map 存 socket 状态——休眠时即丢失。attachment≤16 KB存键SQLite 存状态构造函数从getWebSockets()重建。在内存中缓冲整段重放128 MB isolate 限制——/changes必须分页WS 推送必须切块。对 DO 长轮询 / 挂起 HTTP 请求——经济上同第 2 条。五、Phase 1Sync Hub——每用户 Durable Object 与 HTTP 车道Phase 1 的目标是搭建一个绿地greenfieldwrangler 工程workers/sync-hub/每用户一个有序日志 两个 HTTP 端点本阶段没有任何 socket。本仓库中该工程已经真实存在workers/sync-hub/ 目录下面先给计划的设计再对照实际实现。5.1 部署形态与 Wrangler 配置计划要求脚手架落位workers/sync-hub/独立 package.json不被 build-hooks.js 触达——它经 wrangler 独立部署不进插件包同时把workers/加入 sync-marketplace.cjs 的 rsync 排除列表防止安装后的插件把它打包带出去。实际落地采用了计划开放决策 3中的推荐项exports流migrations的官方继任者。wrangler.jsonc 中的关键配置{ name: sync-hub, main: src/index.ts, compatibility_date: 2026-07-14, exports: { SyncHub: { type: durable-object, storage: sqlite } }, durable_objects: { bindings: [ { name: SYNC_HUB, class_name: SyncHub } ] }, kv_namespaces: [ { binding: AUTH_CACHE, id: f8b295652fed47d7ab7f739460443111 } ], triggers: { crons: [7 * * * *, */5 * * * *] } }两条 cron 的分工见 wrangler.jsonc 内注释7 * * * *是每小时看门狗分钟取 7 而非 0是给 GraphQL 自适应数据集留出摄取余量并避开整点 cron 拥堵*/5 * * * *是控制面存活探针——当 DB 后端的 token 校验端点停止对假 token 返回 401/403JSON 时向 Discord 告警。KV 命名空间AUTH_CACHE同时承载 token 校验裁决缓存与一键降级开关kill switch的control:前缀键——复用一个命名空间的原因在 kill-switch.ts 头部注释中有完整论证缺绑定会导致整个部署失败恰恰是紧急制动最不该有的失败模式。5.2 数据模型从计划的ops表到实现的canonical_ops计划给出的 schema 初版构造函数中经blockConcurrencyWhile初始化CREATE TABLE IF NOT EXISTS ops ( seq INTEGER PRIMARY KEY AUTOINCREMENT, kind TEXT NOT NULL, -- observation|summary|prompt|mutation origin_device TEXT NOT NULL, origin_id TEXT NOT NULL, -- device-local rowid; op UUID for mutations rev INTEGER NOT NULL DEFAULT 1, body TEXT NOT NULL, -- canonical row JSON (opaque-able later for E2E) server_ts INTEGER NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS ops_entity ON ops(origin_device, kind, origin_id, rev); CREATE TABLE IF NOT EXISTS devices (device_id TEXT PRIMARY KEY, name TEXT, last_ack_seq INTEGER DEFAULT 0, last_seen INTEGER); CREATE TABLE IF NOT EXISTS meta (k TEXT PRIMARY KEY, v TEXT); -- epoch, counters落地实现SyncHub.ts 的initializePristineState()约 L196–L245在保持同一骨架的基础上做了三处演进seq 从 INTEGER AUTOINCREMENT 变为 TEXT 存储的十进制规范串canonical decimal避免大整数精度问题比较用LENGTH(seq), seq字典序实现、新增entity_heads表记录每个实体的当前最高 rev幂等判重与陈旧版本拒绝的依据、以及新增operation_sha256与deleted墓碑字段支撑内容寻址与删除同步CREATE TABLE IF NOT EXISTS canonical_ops ( seq TEXT PRIMARY KEY, entity_id TEXT NOT NULL, kind TEXT NOT NULL, origin_device_id TEXT NOT NULL, origin_local_id TEXT, entity_rev TEXT NOT NULL, operation_sha256 TEXT NOT NULL, body TEXT NOT NULL, deleted INTEGER NOT NULL CHECK (deleted IN (0, 1)), server_ts TEXT NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS canonical_ops_entity_rev ON canonical_ops(entity_id, entity_rev); CREATE TABLE IF NOT EXISTS entity_heads ( entity_id TEXT PRIMARY KEY, ... ); CREATE TABLE IF NOT EXISTS devices ( device_id TEXT PRIMARY KEY, name TEXT, last_ack_seq TEXT NOT NULL DEFAULT 0, last_seen INTEGER ); CREATE TABLE IF NOT EXISTS meta (k TEXT PRIMARY KEY, v TEXT); -- epoch / head_seq / projected_seq初始化同样严格落实了 Phase 0 的两条纪律所有表IF NOT EXISTS、meta 默认值ON CONFLICT DO NOTHING幂等且getAlarm()检查在前才排定每日 alarm——正是反模式清单第 4 条的正面实现。5.3 pushOps幂等追加计划定义的 RPC 方法非 fetchpushOps(deviceId, ops[]) → {acked:[{origin_id, rev, seq}], head_seq}靠唯一索引保证幂等——重复推送返回已存在的 seqINSERT 按 ≤100 绑定参数切块单行 body ≤2 MB 由 DO 内钳制兜底客户端钳制为第一道。实际实现 SyncHub.ts 的 pushOps约 L373–L488 在一个transactionSync同步事务内完成先校验每个 op 经parseCanonicalOperation解析为规范内容体且body.origin_device_id必须与已认证的X-Device-Id一致fail-closed 设备身份任一 op 非法则整批以{refused: true, error}拒绝不写任何状态。再判重查entity_heads。若实体已有更高 rev→ 抛stale_revision拒绝若 rev相同且operation_sha256与头部记录一致 → 视为重复推送直接返回已有的 seq这就是重复 push 返回既有 seq的幂等语义若 rev 相同但哈希不同 →revision_hash_conflict同一 rev 撞出两个内容属于协议违例。最后追加incrementCanonicalDecimal(headSeq())生成新 seq写入canonical_ops并 upsertentity_heads回传acked数组与新的head_seq。5.4 getChanges游标分页读取计划定义getChanges(sinceSeq, limit≤500) → {epoch, ops[], head_seq, more}游标.toArray()同步消费。实现约 L490–L557中有一个值得注意的细节读即确认read-ack——每次getChanges都在同步事务内把该设备的last_ack_seq单调前移max(现有值, since)随后按LENGTH(seq), seq有序分页返回 ≤500 条MAX_PAGE 500并用EXISTS查询给出more标志。这意味着每设备的消费位点内建在 Hub 内压缩策略可以依据MIN(devices.last_ack_seq)安全裁剪。5.5 前置无状态 Worker认证、尺寸钳制与路由计划要求前置 Worker 解析Authorization: BearerX-User-IdX-Device-Id与既有 CloudSync 客户端完全相同的请求头token 校验只发生在这里、永不进 DO反模式第 3 条裁决缓存在 Workers KV短 TTL路由env.SYNC_HUB.getByName(userId)。端点面POST /v1/sync/ops、GET /v1/sync/changes、GET /v1/sync/status。实际实现 index.ts 忠实执行了这条边界并把计划中的尺寸钳制量化成常量约 L81–L92常量值依据MAX_OPS_PER_PUSH500与getChanges分页上限对齐MAX_PUSH_BODY_BYTES8,000,000远小于 RPC 序列化 32 MiB 上限覆盖序列化开销单 op body 兜底DO 内 1,990,000 字节预留同表兄弟列的空间稳低于 2 MB 行上限超限请求收到的是刻意的 413而不是会被客户端无限重试的泛化 500。KV 缓存 TTL 被钳在恰好 60 秒——KV 最小expirationTtl与公开 token 轮换边界恰好重合。5.6 Phase 1 验证清单计划为 Phase 1 指定的验证项Vitest 的runInDurableObject测试覆盖推送幂等同一 op 推两次 → 同一 seq、游标分页600 ops → 2 页、rev 取代supersession、100 参数边界处的切块正确性、runDurableObjectAlarm驱动的 alarmwrangler devcurl localhost:8787/v1/sync/ops//changes往返以及grep -rn setTimeout\|setInterval\|\.accept()\|fetch( workers/sync-hub/src/do/零命中。仓库中对应的测试已经就位sync-hub.test.ts、auth.test.ts 等。六、Phase 2客户端 schema 与 apply 路径Phase 2 让本地 SQLite 学会来源、修订、游标三要素远端 op 通过与本地写入完全相同的 hook落库迁移 v41计划锚点SessionStore.ts:111迁移链尾追加列添加模板抄ensureSyncedAtColumns的 PRAGMA-check → ALTER → 部分索引 → 版本行记账形态给 observations / session_summaries / user_prompts 增加origin_device_id、origin_local_id、sync_revorigin 非空时对(origin_device_id, 表内 kind, origin_local_id)建唯一索引新增sync_state (k, v)表存cursor与epoch。本地产生的行 origin 列为 NULL即自己。SyncApply模块applyOps(ops[])在一个事务内完成——远端行 op 按 origin 身份做 INSERT upsert并预先打上synced_at now回显守卫推送侧排水查询的WHERE synced_at IS NULL结构上永远不会再推它们overrideTimestampEpoch保留body中的远端created_at_epochmutation op 按 origin 身份或 remap 谓词做 UPDATE带incoming.rev local.sync_rev守卫游标在同一事务内前移崩溃安全的恰好一次。origin_device self的 op 直接跳过。FTS 由既有触发器自动更新Chroma 向量同步走既有的 fire-and-forget.then().catch()模式在提交之后。Epoch 守卫getChanges返回的 epoch 与本地存储不一致 → 游标重置为 0 全量重拉设计上幂等因此安全。验证要求bun test复用 tests/worker/sync/ 的 cloud-sync 测试 harness 形态apply 幂等同一批应用两次 → 数据库完全一致、游标与行原子性批中抛错 → 游标未动、回显守卫已应用行永远不会被排水查询选中、rev 守卫陈旧 mutation 被忽略、FTS 行存在FTS5 可用时。反模式守卫不用Date.now()作行身份绝不在synced_at为 NULL 时应用没有 PRAGMA-check 模式不做 schema 变更。客户端对应模块均已实现SyncApply.ts 是游标的唯一属主SyncClient.ts 头部注释强调自己从不自己写游标。七、Phase 3推送改道 拉取循环 rev 递增——轮询延迟下交付完整高速公路这是产品完整、只慢一拍的关键阶段五个任务既有排水机制改道保留notify()/ 防抖 / single-flight / 退避 / 钳制 / 设备身份计划锚点 CloudSync.ts 的对应区间把原来三个按类型拆分的pushBatch端点替换为单一POST /v1/sync/ops每行携带{kind, origin_id: String(localId), rev: sync_rev, body}。删除按类型的KINDS[*].toCloud端点、stampGuardSql/stampGuardrequeuePromptSync改为发出set_prompt_sessionmutation op顺序性使守卫失去必要、车道启发式。ack 回来后打synced_at戳。四处 mutation 点的 rev 递增自定义标题与 prompt→session 修复点在 worker 内执行——递增sync_rev、置空synced_at、入队 mutation op、notify()。两处项目重映射点WorktreeAdoption / ProcessManager各自开了独立的 DB 连接在那里只能纯 SQL 完成 bump 置空worker 的下一次启动排水或下一次notify()会把它们带走。拉取循环SyncClient服务形态抄TranscriptWatcher的 constructor/start/stop 三件套轮询GET /v1/sync/changes——会话活跃时 30 s、空闲 5 min、1 小时无会话则完全挂起一个 timer 都不留每次 push 响应都捎带head_seq活跃设备的免费轮询。所有 timer 加.unref?.()。会话开始立即拉取在上下文注入路由的generateContextWithStats调用之前await syncClient.pullOnce({ timeoutMs: 1500 })——有界等待保证网络死亡也不会卡住上下文注入首要指令第 3 条的落点。发布前取代性说明历史上的 Hub 切换重排任务在 Phase 0 期间保持原样不是 Phase 0 清理项。验证要求是端到端的两台设备两个 SessionStore 一个真实的wrangler devHub 或 vitest SELF 绑定——A 写 → flush → B 拉取 → 行存在且 epoch 保留、FTS 行存在、无回显B 应用后 A 的排水为空标题/remap/repair 三种 mutation 在 B 上收敛flush 中途杀掉 Hub → 行留在队列 → 重启恢复退避测试形态。反模式守卫不 long-poll只有短轮询拉取失败绝不阻塞写入与notify()相同的吞掉一切契约。实际实现与计划逐项吻合CloudSync.ts 头部注释完整描述了数据库即队列的推排水drain契约——按类型映射到observations/session_summaries/user_prompts三张表TABLE_BY_KINDmutation 走sync_outbox表批大小 200、请求打包预算 4,000,000 字节远低于 Hub 的 8 MB 上限、每请求 ≤500 opsSyncClient.ts 的轮询层级、head_seq 捎带触发即时拉取onHeadSeq均已落地且比计划多了一处细节pullOnce()与onHeadSeq()既恢复轮询循环又重连 socket挂起中的 worker 在任何事件发生时即刻醒来。八、Phase 4建议性 WebSocket——速度层Hub 侧3 个任务之 1GET /v1/sync/ws经前置 Worker 升级到 DO 的fetch()唯一非 RPC 路径。照抄休眠示例WebSocketPair→ctx.acceptWebSocket(server)→ 101attachment 只存{device_id}setWebSocketAutoResponse(ping,pong)。每次提交后向除源设备外的全部 socket 扇出{type:op, ...}帧按最佳实践批 50–100 ms或当单次推送超过一页时发裸{type:advance, head_seq}帧。实际实现SyncHub.ts 约 L285–L367把扇出阈值量化为两个常量ADVANCE_MAX_OPS 100、ADVANCE_MAX_FRAME_BYTES 262,144256 KB远低于 32 MiB 入站上限也远低于客户端能一帧处理的量——新提交 op 数超过 100 或 body 总长超过 256 KB 时退化为advance帧让客户端自己走 HTTP 拉取。客户端侧Bun 原生new WebSocket(url, { headers })认证头随构造器无ws依赖。socket 是严格建议性的op/advance帧中 seq 恰为cursor1时直接走与 HTTP 拉取同一个SyncApply.applyOps路径任何异常——间隙、解析错误、未知帧、epoch 不匹配、apply 抛错——都触发关 socket 一次 HTTPpullOnce()车道 2 自愈。协议级ws.ping()每约 40 sHub 运行时自动 pong 不唤醒 DO重连用全抖动full-jitter退避1 s 基数、60 s 上限socket 处于连接态时轮询间隔放宽到空闲档socket 是快车道轮询是安全网。开关环境变量CLAUDE_MEM_CLOUD_SYNC_WS默认开启。防抖降档socket 存活时把 1500 ms 防抖降到 250 ms扇出已变推送防抖成为延迟主项。验证要求vitest WS 套件独立调用、--max-workers1 --no-isolate覆盖升级、扇出排除源设备、evictDurableObject({webSockets:hibernate})后再来消息 → attachment 恢复投递wrangler dev双客户端 e2e——A 写 → B 在 2 秒内应用流中途杀 B 的 socket → B 重连后经 HTTP 收敛。验收标准本身就是那句定义advisory的话把整条 socket 路径删掉Phase 3 仍然全绿。仓库中 ws.test.ts 即为该套件的落地。九、Phase 5护栏与监控——一等公民不是事后补丁四条任务对应四类结构性护栏看门狗watchdog每小时 cron Worker 查询 GraphQL Analytics API 的 DO 命名空间——duration GB-s预期 ≈ 0这是休眠被破坏探测器、行读/行写失控探测器、请求数≈消息数/20。阈值取自已验证的工作负载模型告警走既有 Discord webhook 通道discord-release-notify.js 形态。实现见 watchdog.ts阈值可通过 wranglervars覆盖WATCHDOG_*系列键空值回落代码默认。一键降级kill switchKV 标志前置 Worker 每次请求检查per-isolate 30 s 缓存。触发 ⇒ 拒绝 WS 升级 每个 HTTP 响应盖上X-Sync-Mode: poll客户端退回 Phase 3 轮询产品保持完整约 $0.03/用户/月。实现 kill-switch.ts 中值得学习的工程细节键是AUTH_CACHE里的control:kill-switch存在即触发值内容只是运维信息手工wrangler kv key put ... 1也能生效fail-open——KV 读错误按未触发处理因为它是成本护栏而非安全边界KV 故障不应该拖垮全体用户的同步。金丝雀canary一个合成用户、两台假设备、7×24 涓滴写入其 DO 的 duration 指标是已知常量——休眠回归几小时内就能在指标上显形而不是等到账单上。仓库中 canary/canary.ts 即此组件。CIESLint 块 grep -rn setTimeout\|setInterval\|\.accept()\|fetch(\|connect( workers/sync-hub/src/do/作为必过检查外加每周账单巡检的定时 Agent仅在有 delta 时 Discord 提醒。验证要求人为触发每个阈值金丝雀洪泛测试账号上强制不休眠的构建确认告警 一键降级 客户端回退全链路打通。对应测试kill-switch.test.ts、watchdog.test.ts。十、Phase 6全矩阵验证与显式地平线全矩阵 e2e新设备引导since0、离线一周后的追赶、双设备并发写、全部四类 mutation、epoch 重置、kill switch 降级——全部跑在wrangler dev 两个真实 worker 守护进程上。反模式清扫Phase 0.4 的 grep 跨workers/全量执行bun test全绿npm run build-and-sync启动 worker确认 marketplace rsync 已排除workers/。文档更新 docs/public/ 下的 cloud-sync 页面。地平线显式范围外记录在案以免再议dashboard 作为/changes客户端端到端加密body 变为不透明 blob——Hub 除 mutation 信封外从不解析 body团队语料按语料键的 DO、按成员的last_ack_seq仅当 Postgres 真的落到服务端时才考虑引入 Electric 读路径。十一、从计划到实现值得注意的演进把 plans/2026-07-17-phase5-two-lane-sync.md 与workers/sync-hub/、src/services/sync/的实际代码对照可以看到几个计划保留骨架、实现细化约束的演进它们都未违背五条首要指令seq 类型升级从INTEGER AUTOINCREMENT演进为 TEXT 十进制规范串canonical decimal配合LENGTH(seq), seq排序实现任意精度游标比较canonical-content.ts 提供比较/自增工具族幂等判重外置为entity_heads表唯一索引判重升级为实体头部 operation_sha256双字段判重额外获得了stale_revision/revision_hash_conflict两类明确拒绝语义wire 契约升级到 protocol_version 2CloudSync.ts 注释定义了完整契约——规范 JSON键排序、uint64 域用十进制字符串、内容 id 由(kind, device, local rowid)稳定派生、payload 哈希、实体修订、显式墓碑ack 顺序任意但盖戳前必须证明响应与推送元组完全多重集匹配且仅在当前sync_rev仍等于 acked rev时才盖戳——并发 mutation 在途时行保持未同步同一 flush 循环会以更高 rev 重新推送修正版投影租约projection lease实现新增了 90 s 的每用户短租约与projected_seq检查点SyncHub.ts 的租约段约 L636–L798Hub 只有在其权威投影检查点覆盖提交后才回 200——时间常数刻意满足Hub abort (45 s) Pro 平台上限 (60 s) Hub 租约 (90 s)index.ts L86–L92压缩 alarm 刻意留面不删alarm()仍每日自我重排以兼容已部署对象但删除零行——注释明说cursor-0 设备尚无快照/重置引导因此每条 op 保持可重放SyncHub.ts 约 L813–L818把物理日志压缩推迟到有快照引导之后每用户 64 台设备上限MAX_DEVICES_PER_USER 64touchDevice用INSERT ... WHERE EXISTS OR COUNT(*) 64原子地实施 fail-closed 设备身份超限返回device_limit_exceeded。十二、结语这份计划文档的样本价值在于它把对抗式架构选型 → 平台约束调研 → 反模式清单 → 分阶段实现 → 结构性成本护栏 → 全矩阵验证压缩成了一条可复用的工程决策链。其中三条经验对所有在 Serverless 上构建多设备同步的开发者同样成立真源必须收敛到单一可游标化的持久日志传输层才可以自由竞争成本护栏必须做成结构性降级而非人为刹车watchdog → poll mode产品永远完整任何加速层的验收测试都应该是删掉它主干测试全绿advisory 的定义即在此。从 wrangler.jsonc、SyncHub.ts 到 CloudSync.ts / SyncClient.ts 的实现对照读者可以沿着本文给出的文件路径完整走一遍从设计决策到生产代码的每条落点。【免费下载链接】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),仅供参考