跳转至

ISSUE-0091:两条快路径漏重置 sync:0

症状

付费 VIP 用户的云端记录里,部分商家缺少后补的社媒 / WhatsApp / 电话, 而本地扩展里这些字段是有值的。无任何错误提示。

前置事实:存在一条独立于 SPEC-004 的旧云通道

这条通道在本项目的前三轮审查中从未被提及,是本 issue 成立的前提:

组件 src/sections/page/cloud-data-sync.tsx
挂载 src/sections/layout/main-layout.tsx:429无条件挂载
轮询 pollingInterval: 10 * 1000 — 每 10 秒
启动条件 if (!uid \|\| !mapDataSync \|\| syncLoading) return; — 已登录 + 服务端下发 mapDataSyncmapVipValid
目标域名 https://ggdt.laifaxin.com(生产)/ m.laifaxin.com(dev),见 src/api/request.tsx:24-26
取数 getUnsyncDataList(limit)where { sync: 0 }src/utils/jsstore/search-data.ts:28-31
回写 saveSyncStatus(ids)set { sync: 1 }:33-35

🔴 它与 enableCloudSync(SPEC-004 的 ContactPool 管线)毫无关系 —— 那条默认 false、服务端未上线; 这条是当前活着的生产流量,只是 opt-in(需 VIP + 服务端开关)。

根因

MapTaskData.sync 语义见 src/utils/jsstore/base.ts:109-1120 未同步 / 1 已同步,默认 0

scraper-executor.ts5 处写回 MapTaskData 的终态点,其中 2 处漏了 sync: 0

位置 分支 有 sync:0
scraper-executor.ts:148 网址本身是社媒链接(facebook/instagram/wa.me…),补写 facebook/whatsapp/phone
scraper-executor.ts:163-176 同网址复用已抓结果,复制 emails/社媒
scraper-executor.ts:292 fetch 抓取成功 ✅ 有
scraper-executor.ts:432 tab 抓取成功 ✅ 有
engine-manager.ts:230 ✅ 有

两个兄弟路径都显式带了 sync: 0,说明这是遗漏而非设计

触发序列

  1. 地图任务解析出商家行,插入 MapTaskDatasync 默认 0
  2. 10 秒内getUnsyncDataList(where sync:0) 抓走上传(注意:该查询scrape_status 过滤,插入后立刻可被取走)
  3. saveSyncStatussync: 1
  4. 随后官网深抓阶段发现该网址其实是社媒链接 → 走 :115-148 分支补写 facebook/whatsapp/phone
  5. 不重置 sync: 0 ⇒ 该行再也不会进入 getUnsyncDataList
  6. ⇒ 服务端那份记录永久缺失后补的联系方式,本地无任何信号

同网址复用分支(:163)同理,且它还额外不复制 phone 并立刻标 scrape_status: 2(不再重抓)。

修复

两处 updateFieldssync: 0。修复前先确认:是否存在「已上传后本地又变更」需要服务端做 upsert 的契约。

回归判据

grep -n 'updateByQuery(.MapTaskData' src/utils/scraper-executor.ts   # 5 处终态写点
# 每一处的 updateFields 都必须含 sync: 0(除非有明确注释说明为何不需要)

建议加静态扫描:scraper-executor.ts 中所有写 MapTaskDataupdateByQuery 必须带 sync 字段。

发现过程

2026-08-30 第四轮 sonnet5 对抗审查发现并经交叉验证。

🔴 本条曾被主控错误降级为 P2:主控当时的理由是「MapTaskData.sync 无云端消费方」, 依据是 grep sync cloud-sync-orchestrator.ts 零命中 —— 但那只是 SPEC-004 管线, 主控没查旧通道 cloud-data-sync.tsx。这是 capability-existence-proof 所述 「只查一处就断言不存在」的又一实例,且发生在写下那条 rule 的同一轮里。