修「补录行被合并回来」的重复:对账时认它的派生 UUID
成因链:站点补录的到访没有留档行(entity_raw 里没有它),也就没有 UUID;导出时会被补上
一个确定性 UUID v5("ZVISIT/<src_pk>") 写进包里,手机于是把它当成一条真记录;这份包再
合并回站点时,站点这侧没有 UUID 可对齐,DiffVisits 直接判成「备份新增」又插一条 ——
时间线上出现两条一模一样的到访(实测数据集 9 有 43 对,生产时间线一屏就有 53 对)。
- rond:把派生 UUID 抽成 DerivedUUID / DerivedVisitUUID / VisitMatchUUID(导出侧 coreDataUUID
复用同一个函数),差异与合并都拿它当对账键(diff.go 的 byUUID、backup_merge 的 storedByUUID)。
- 「时间 + 地点」兜底配对补 used 检查:同一条站点行现在两个索引里都有,不查会被 classify 两次。
- 数据编辑页的「重复到访」卡片认得这类(成因标「你补录的那条被合并回来的一份」),
清理时把副本名下的位移 / 天气**改挂**到保留项——补录行自己名下没有位移,跟着删就白丢里程;
派生 UUID 判定排在「站点侧副本」之前(证据更强)。
用例:rond 两条(正例 + 派生 UUID 不相配的反例)、web 一条端到端(造补录行与副本 → 检出 →
清理 → 断言位移与天气改挂、留档被清)。变异验证:去掉改挂语义、关掉该判定,两条都立刻红。
This commit is contained in:
+26
-1
@@ -1560,11 +1560,36 @@ func appleSeconds(t time.Time) float64 {
|
||||
// coreDataUUID 给「基线里没有、站点又没这个字段」的新行补一个确定性 UUID(见 uuidV5)。
|
||||
// 基线里已有的行一律返回 nil(交给 keepNilCols 沿用原值):站点本就没有这个字段,
|
||||
// 不该反过来改写真机的身份标识——真机里也确实有 2 条到访这一列是空的。
|
||||
// DerivedUUID 是站点给「新建行」补的确定性 UUID(RFC 4122 v5,名字取「表名/编号」)。
|
||||
//
|
||||
// 导出侧用它填 ZVISIT.ZIDENTIFIER_ / ZACTIVITY.ZUID_;它同时是**对账键**:
|
||||
// 站点补录的行自己没有留档 UUID(entity_raw 里没有那一行),但导出过一次之后,
|
||||
// 包里那条就是这个名字——这份包再合并回来时必须认得出来,否则同一行会被判成
|
||||
// 「备份新增」又插一条(实测数据集 9 有 43 对这样的重复:一半是补录行,一半是它的副本)。
|
||||
func DerivedUUID(table string, pk int) []byte {
|
||||
return uuidV5(fmt.Sprintf("%s/%d", table, pk))
|
||||
}
|
||||
|
||||
// DerivedVisitUUID 是派生 UUID 的小写十六进制形式,与 Backup.VisitUUID / StoredVisit.UUID 同形。
|
||||
func DerivedVisitUUID(pk int) string { return fmt.Sprintf("%x", DerivedUUID("ZVISIT", pk)) }
|
||||
|
||||
// VisitMatchUUID 返回一条站点到访用来对账的 UUID:留档里有就用留档里的,
|
||||
// 没有(站点补录的行)就用导出那一刻会补给它的派生 UUID。
|
||||
func VisitMatchUUID(sv StoredVisit) string {
|
||||
if sv.UUID != "" {
|
||||
return sv.UUID
|
||||
}
|
||||
if sv.SrcPK <= 0 {
|
||||
return ""
|
||||
}
|
||||
return DerivedVisitUUID(sv.SrcPK)
|
||||
}
|
||||
|
||||
func coreDataUUID(isNew bool, table string, pk int) any {
|
||||
if !isNew {
|
||||
return nil
|
||||
}
|
||||
return uuidV5(fmt.Sprintf("%s/%d", table, pk))
|
||||
return DerivedUUID(table, pk)
|
||||
}
|
||||
|
||||
// uuidNamespace 是本站补 UUID 时用的固定命名空间,取值本身无意义,只要不变即可。
|
||||
|
||||
Reference in New Issue
Block a user