用途与实际影响
这项功能怎样使用
为什么需要它
只保存一次会漏掉后续内容;每次全量重做又慢、重复且容易在中断时留下半成品。真正可用的归档需要知道自己处理到哪里、来源是否变化、哪些是新增或更新,以及怎样验证提交完成。
举个实际例子
我说“把这个供应商群持续保存下来”。第一次会保存当前设备能看到的完整本地历史;下周再说同一句,档案只补新消息、更新过的内容和后来能在本机打开的媒体,旧内容不会整包重抄。
最后我会得到什么
得到这个具名联系人或群在当前电脑能看到的消息、可读档案、附件与更新状态。写入中断时旧完整档案仍在;后来能打开的媒体可定向补。微信远端从未取得的内容不会因此出现。
可直接使用
有变化就合并新内容;没有变化也先核对旧档案、附件和清单仍是一套,再报告无变化。
需要确认
旧消息后来修改、无时间记录或媒体后来能读时,普通增量会说明覆盖不足,需对这个对象明确重核。
当前不可用
目录已有未知内容、账号不符、来源变化或导出文件不一致时停下,不覆盖原包硬修。
从哪里开始
明确要求长期保存一个具名联系人或群的微信历史。
需要准备什么
- 明确账号和一个联系人或群
- 希望保存当前可见历史或更新既有归档
从开始到拿到结果
- 1
系统核对并处理
首次保存该对象本机可读历史,之后沿同一游标合并变化和仍可打开的媒体。
- 2
交付与接续
交回全文、可用附件、增量状态与缺口;来源不变仍核对已有导出,中断先恢复原事务。
技术实现与依据
这里保留实现、关键条件、精确入口、历史记录和验证结果。
首次全量、增量、无变化快速路径、来源变化和提交顺序均有合成回归;本页未读取真实档案正文关键规则与设计选择
第一次归档必须覆盖该对象全部本地可见历史,不允许用时间参数伪造完整档案。
后续重复命令就是自动增量,不需要 watcher 或计划任务。
单消息来源优先使用 sortSeq 游标;多来源退回时间重叠并明确无时间记录边界。
AI 只默认读取最近最多 80 条、128 KiB,完整档案仍可按需搜索。
当前可打开的语音按内容哈希复用;后来可用的历史语音可在增量窗口或 full reconcile 中补齐。
full reconcile 会更新或补充同身份记录,但不会把来源里后来消失的旧归档记录自动删除。
已知目录替换中断先recover-export只读检查,明确rollback或complete;未知旧锁和外来内容不自动接管。verify-export只验证包,repair-media只补具名本地媒体,不证明微信远端全历史完整。
本模块用到的名词
- First full snapshot(首次完整快照)
- 第一次保存该对象当前设备可见的全部本地历史;它仍不等于微信远端全历史。
- sortSeq cursor(排序游标)
- 单一消息来源下按 WeChat 排序序号继续,能包含没有 createTime 的新增消息。
- Overlap window(重叠窗口)
- 从上次最后时间向前回看一段,默认 1 天,用于吸收迟到或变化记录。
- Source metadata fast path(来源元数据快速路径)
- 相关源文件指纹重复核对未变时,不重新扫描源库消息;先重验本地导出全文、结构记录、清单与状态绑定,全部一致后才确认无变化并更新回执。
专业定义
sync-contact 第一次保存该对象当前设备可见的完整本地历史;以后重复同一命令会自动重放并合并增量。
解决什么
避免更新半途毁掉原档案、为了补几条语音重扫全部历史,以及把已生成包误称为资料齐全;冲突保留原状态和明确恢复入口。
当前怎样实现
- state.json 固定 wechat-direct-contact-sync.v1、账号身份承诺、联系人原生身份、游标、水位、来源指纹和消息数量。
- messages.jsonl 用 server id;没有 server id 时用本地 id、时间、sortSeq 与发送者计算稳定合并键。
- 默认 overlapSeconds=86400,允许 0 到 31 天;单分片且目录不变时使用 sortSeqReplayFloor。
- 旧说话人语义的完成态档案在下次对同一对象运行 sync-contact 时,先验原档,再以 sender_identity_reconcile 重核当前本机可见历史;其他聊天不扫描、不改写。源中已不存在的旧消息保留正文与原证据,显示身份未重核并计数。
- 来源指纹未变时先再取一次指纹确认稳定,重验 manifest(清单) 自哈希及其与 state 的账号、身份承诺、联系人、来源指纹和数量绑定;messages.jsonl 核对 SHA-256 与记录数,context.md 和 ai-context.md 分别核对完整 SHA-256 与字节数。全部一致才返回 sourceMetadataFastPath/noChange 并只更新 last-run。
- sync-contact、sync-moments、repair-media先暂存并验证完整候选,通过同级.wechat-transaction记录准备、前像和替换状态;两次目录rename有独立中断状态。recover-export只读检查后按明确动作complete/rollback,已提交状态不能再回滚,身份或外来修改冲突保留。
- .sync.lock 阻止两个写者同时更新同一输出目录;当前不会自动判断或清除陈旧锁。
- 快速返回已经包含导出全文与结构记录的完整哈希核对,不只是看文件存在或数量;独立 verify-export 另核整个导出的路径、媒体与派生关系,不应把两者的覆盖范围混为一谈。
执行流程
- 1
首次解析账号与对象,拒绝带 since / until 的伪完整导出。
- 2
建立输出目录锁并计算与该对象相关的来源指纹。
- 3
选择 full、incremental 或 explicit full_reconcile 模式。
- 4
无变化候选先复核来源指纹、清单/状态绑定及已导出全文和记录;通过则只更新 last-run,不重扫源库消息。
- 5
抓取候选,按稳定消息键合并现有 JSONL。
- 6
复制本次新增、更新或需重试且在本机可打开的精确媒体,已存在哈希文件先验真再复用;普通增量和 noChange 都核对已声明媒体及 WAV 的哈希与大小。
- 7
生成完整 context.md 与有界 ai-context.md。
- 8
先写 manifest(清单),再写 state 和 last-run,最后释放锁。
边界
- 权限只覆盖用户点名的一个联系人或群,不扩到全账号。
- 首次本地完整不代表远端完整,也不补设备上已经不存在的历史。
- 多分片普通增量不能保证抓到没有时间的旧记录;需要 full reconcile。
- 有具名媒体修复和导出事务恢复,但没有把档案导入回微信的restore/import,也不自动删除未知.sync.lock或接管无依据旧目录。
- 归档目录留在本机,不进入公开网站或 Git。
失败与恢复
- 首次输出目录已有未知内容
- 返回 sync_output_not_initialized,不覆盖用户文件。
- 账号、联系人或状态身份不一致
- 返回 sync_identity_mismatch,保留原档案并要求使用原对象或新目录。
- 同一目录已有运行锁
- 返回 sync_already_running_or_stale_lock;先确认旧进程与锁状态,不并发写。
- 来源在读取期间发生变化
- 返回 source_changed_during_sync_retry,不提交新 state;下次从旧完整状态重试。
- 来源没变,但本地导出文本、记录或清单绑定漂移
- 按实际位置返回 sync_context_sha256_mismatch、sync_ai_context_sha256_mismatch、sync_records_sha256_mismatch 或 sync_manifest_state_mismatch 等精确错误;不返回 noChange,也不默默覆盖不同字节。
- 需要覆盖旧历史变化
- 用户显式使用 --full-reconcile,重新核对该对象全部本地可见历史。
- 首次同步硬崩溃后有文件但没有 state
- 返回 sync_output_not_initialized;当前必须人工核对或移走半成品后重建。
- .sync.lock 来自已退出进程
- 当前仍按锁冲突停止;不能无条件删除,也没有自动陈旧锁修复。
真实入口
README.md · sync-contact首次全量、自动增量、AI 小上下文与 full reconcile 使用边界。
wechat_cli.py · command_sync_contact游标、重叠、合并、媒体、manifest(清单)/state 提交和回执实现。
wechat_source.py · contact_source_fingerprint与单对象相关的无正文来源变化指纹。
tests/test_wechat_cli.py · contact sync首次、增量、游标、原子提交和来源变化回归。
如何验证
- test_contact_sync_is_full_then_bounded_incremental_ai_context 验证首次完整与 AI 小窗口。
- test_contact_sync_changed_source_replays_indexed_cursor_and_merges 验证来源变化后的游标合并。
- test_manifest_is_published_before_state_commit_marker 验证提交顺序。
- test_contact_sync_does_not_commit_when_source_changes_during_read 验证漂移失败关闭。
- test_contact_fast_path_rejects_hash_size_count_and_state_drift 覆盖无变化候选的清单自哈希、全文字节、记录数与状态绑定漂移;CLI(命令行工具) 回归另验证 context、ai-context 和 JSONL 内容变化不能返回 noChange。
- 0.2.1来源定义了目录替换中断、完成/回滚、媒体修复和冲突回归;本网页未强杀真实归档、重读聊天或演练真实断电。
与其他模块的关系
同一账号与对象贯穿上下文、归档与媒体;本模块拥有增量续作、定向本地补媒体与已知事务恢复,原微信数据库始终只读。
