换基线:把「底座换代」做进后台(站点数据一行不动)

导出是「底座为底 + 只覆盖托管表」,所以底座必须是手机导出的包。底座跟着数据集走,
手机重新导出后想换代,以前只能整包重新导入成新数据集(站点补录的行、主题、备注都得重收拾)。
新动作 /admin/baseline(后台首页加入口)就是给同一份数据的底座换代用的。

三道闸,顺序不能挪:
1. 重合判据:新包里的到访 UUID 与站点侧带 UUID 的到访比。一条都对不上直接拒
   (连 force 也不给过)——干跑只验结构,一份不相干的包照样导得出,但换下去站点
   每行都在新底座里认不出身份,全按新行插到最大编号之后,真机上就是「这些到访
   全变成新的」。重合率不到一半要显式确认;判据没过不当场报错了事:包已经收进
   uploads,页面给一个「我确认,强制替换」按钮,不必重传几十 MB。
2. 干跑导出:底座缺表/缺实体编号在这步挡住,不会出现「换完了才发现导不出、
   原来那份已经不知去哪」。
3. 旧底座留档 + 记档,换错了可一键回滚。

两个坑:
- 留档名不能只用秒级时间戳。「替换后紧接着回滚」落在同一秒时,回滚那次 rename 会把
  刚生成的留档覆盖掉,于是回滚回了个寂寞(TestRollbackBaselineRestoresPrevious 当场红)。
  改用 baselineBackupName():20060102-150405 + 冲突自增。
- ensureBaseline 必须先看记档。只认 datasets.sha256(= 最初那份包)的话,底座一丢就静默
  重建回旧包,上一次换基线白做且毫无提示。抽出 ensureBaselineTo(ctx, dsID, dst) 共用;
  「重建」入口写临时文件再 rename,不做破坏性删除。

回归用例 7 条(internal/web/baseline_swap_test.go):成功路径断言「换底座前后导出包里
ZVISIT 的 UUID 集合逐条一致」——编号会换、身份不该换,谁在底座里没对上立刻亮;
记档优先重建带反证(清掉记档后同一条路必须走不通);部分重合需确认、完全对不上 force
也不给过、非包文件第一步就挡住、回滚还原且当前那份也留档、页面渲染到底。

验收:./scripts/verify.sh 全量 PASS=318 FAIL=0 SKIP=0。
This commit is contained in:
tamakyi
2026-09-30 19:00:18 +08:00
parent 11e00a5b60
commit 6ff6f944a1
13 changed files with 1544 additions and 28 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
# rond-with-you 硬规矩(索引)
> 全文:`.workbuddy/memory/MEMORY-details.md`(34 节);验证机制:技能 `rond-fix-verify`;备份包解析/导出:技能 `rond-backup-parse`。本文件只做关键词索引——**新规矩写 details,别堆这里**。
> 全文:`.workbuddy/memory/MEMORY-details.md`(35 节);验证机制:技能 `rond-fix-verify`;备份包解析/导出:技能 `rond-backup-parse`。本文件只做关键词索引——**新规矩写 details,别堆这里**。
>
> ⚠️ 本文件**按字符数**注入,硬上限 `MAX_MEMORY_CHARS = 1e4`(WorkBuddy `app.asar` 里 `getWorkingMemoryContent`;中文 1 字算 1,不是按字节)。超了会被 `substring(0,1e4)` 截断并写明「先整理再干活」——即整段尾部静默丢失。日常日志与本 details **不参与注入**,可以随便写。现值见 `wc -m`,留 20% 余量。
@@ -21,6 +21,7 @@
- rows 收尾必须 `drainRows`(先 `Err()` 再 `Close()`)。`parse_rows_test.go`
- **扫进裸 `bool` 的列必须先 `COALESCE`**:`weather.is_daylight` 漏写 ⇒ NULL ⇒ 整包拒收(details 卅C)。
- 核对导出包**别按留档 UUID 找行**:站点新建行会被补派生 UUID(`coreDataUUID`)。
- **换基线**(底座换代,`/admin/baseline`):站点数据一行不动,只换底稿。判据=到访 UUID 重合率(`matched==0` 硬拒)+ 干跑导出;记档 `datasets.baseline_*`,`ensureBaseline` **必须先看记档**;留档名**必须防重名**(秒级时间戳会让回滚覆盖掉刚生成的留档)。`baseline_swap_test.go`(details 卅三)
## 迷雾 / 遮罩(details 三、九、十、廿二)
- `.fwss`=zip、条目 zlib;`Model/*/`=头 32768B+每块 515B;`Model/~/`、`Model/#/` 原样写回;清空/替换都要连 `fog_raw_files`。