换基线:说清「新底座里多出来的到访不会进导出包」,并把它钉成用例
写文案时去核这条,先把一条写错的断言纠正了:导出条数本来就不等于站点条数。 tableWriter.finish() 是两段:先删「基线里有、PG 已没有」的行(known − seen), 再把「导入时进不了 PG 但留档还在」的行(w.skipped × raws)按原样补回——否则 「导入→导出」一趟会凭空少数据。实测 823 条到访的数据集导出包里是 824 条,差值正常。 (第一版成功路径用例断言「导出 == 站点」,红在 824 != 823 就是这个原因;已改成更锋利的 「换底座前后导出包里 ZVISIT 的 UUID 集合逐条一致」。) 同一段代码定下了换基线的语义:新底座里站点没有的行会被清掉(进 known 没进 seen)。 所以换一份更新的手机包**不会**把手机新记录带进导出包,要带得先走「分析差异」合并。 页面提示与 flash 文案都写明了这点,并新增用例 TestSwapBaselineDoesNotCarryRowsTheSiteDoesNotHave 钉住它(站内补一条到访 → 导成包 → 从站内删掉 → 换底座 → 断言导出里既没有那条的派生 UUID、UUID 集合也与换之前逐条一致)。 验收:./scripts/verify.sh 全量 PASS=319 FAIL=0 SKIP=0。
This commit is contained in:
@@ -227,15 +227,16 @@ func (e *errBaselineMismatch) Error() string {
|
||||
|
||||
// baselineReport 是一次换底座的结果,用来给页面/提示提供具体数字。
|
||||
type baselineReport struct {
|
||||
Name string
|
||||
SHA string
|
||||
Size int64
|
||||
Matched int
|
||||
WithUUID int
|
||||
Counts []baselineCount
|
||||
Replaced bool // 是否真的换掉了(false = 原本没有底座,是首次建立)
|
||||
Backup string
|
||||
ElapsedMs int64
|
||||
Name string
|
||||
SHA string
|
||||
Size int64
|
||||
Matched int
|
||||
WithUUID int
|
||||
Counts []baselineCount
|
||||
Replaced bool // 是否真的换掉了(false = 原本没有底座,是首次建立)
|
||||
Backup string
|
||||
SiteVisits int // 站内到访条数,用来提示「新底座里多出来的那些不会进包」
|
||||
ElapsedMs int64
|
||||
}
|
||||
|
||||
// swapBaseline 把当前数据集的底座换成 archive 那份包。
|
||||
@@ -284,6 +285,10 @@ func (s *Server) swapBaseline(ctx context.Context, datasetID int64, archive, nam
|
||||
if counts, err := baselineCounts(ctx, tmp); err == nil {
|
||||
rep.Counts = counts
|
||||
}
|
||||
// 站内到访条数:新底座里多出来的那些不会进导出包(导出的行集合始终等于站点数据),
|
||||
// 这点反直觉,要在提示里说出来。
|
||||
_ = s.db.QueryRowContext(ctx, `SELECT count(*) FROM visits WHERE dataset_id=$1`, datasetID).
|
||||
Scan(&rep.SiteVisits)
|
||||
|
||||
if _, err := os.Stat(dst); err == nil {
|
||||
rep.Replaced = true
|
||||
@@ -676,5 +681,21 @@ func baselineSwapMessage(rep baselineReport, datasetName string) string {
|
||||
}
|
||||
}
|
||||
b.WriteString(" 站点数据一行没动,导出即刻以新底座为准。")
|
||||
// 反直觉的一条:底座里比站内多出来的到访会被导出清掉(导出的行集合以站点数据为准)。
|
||||
// 不说清楚的话,站长会以为「换了更新的手机包 ⇒ 导出的包里就有手机上的新记录」。
|
||||
if extra := baselineCountValue(rep.Counts, "ZVISIT") - rep.SiteVisits; extra > 0 {
|
||||
fmt.Fprintf(&b, " ⚠️ 新底座里有 %d 条到访是站内还没有的,它们不会进导出包"+
|
||||
"(导出的行集合以站点数据为准):想让它们进包,先用「分析差异」把这份备份合并进来,再来换底座。", extra)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// baselineCountValue 取画像里某张表的行数(没有这张表就是 0)。
|
||||
func baselineCountValue(counts []baselineCount, table string) int {
|
||||
for _, c := range counts {
|
||||
if c.Table == table {
|
||||
return c.N
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user