补充验证一:当前不存在 app/tests/baselines/ 持久基线仓
有反馈提到「持久基线仓当前就在 app/tests/baselines/,testreport 会 copy 部分基线内容用于 html」。经代码核实(rnoh_test 子模块 d970d15 与 CPTF origin/main 250175b 双向验证):
app/tests/baselines/目录不存在(0 文件),两个代码版本中均无该路径引用(git grep tests/baselines零命中)- 最接近的
baselines: { screenshotDir: 'docs/baselines/…' }用例配置是死配置:expect-executor.ts:459只消费<name>_visualkey 的 baselineData,screenshotDirkey 全框架无人读取,docs/baselines/目录本身也不存在 - 实际存在的
test-baseline/目录装的是 UI 结构 dump(ui-<caseId>-*.json),属于 uiComparison(结构对比)通道:stream-comparison-queue.ts:539-575收集双平台 baseline 文件做结构 diff,对比 HTML 消费——这是独立于元素像素基线的另一条通道 - 单平台 HTML 生成器对 baseline 零引用零拷贝;
visual-comparator.ts唯一的copyFile(:635)是「当前截图→基线路径」的落基线动作,方向相反
结论:元素像素基线(visual 断言 + allowBaselineWrite)目前唯一的存储就是 test-reports/<日期>/test-baseline/<平台>/<category>/*.png,按日期 ephemeral,正文四个问题成立。
补充验证二:像素基线确实设备绑定,但支持而非否定持久仓提案
有反馈提到「基线数据没法跨设备,稍微有一点不一致整个像素比较就会差异比较大」。算法层核实(compareElementToBaseline 三档策略):
| 条件 | 算法 | 跨设备表现 |
|---|---|---|
| 宽高差 ≤1px | 真·逐像素 RGB 比对 | 1px 偏移即内容整体错位,大面积超 tolerance |
尺寸不一致 + equalize: true |
等画布:左上角对齐平铺到并集画布、白底填充、不缩放,再逐像素 | 多出区域 = 白底 vs 真实内容,全部计为差异 |
| 尺寸不一致 + 无 equalize | 3×3 网格平均色统计 | 尺寸无关但断言极弱 |
该论点成立——equalize 是「对齐平铺」而非「缩放归一」,通道内无 SSIM/偏移容忍带。且框架自身已内建设备绑定:test-runner.ts 多设备模式下基线目录带 harmony-<serial> 段(「天然按设备分开」)。实测两台夜跑设备(1280×2832 与 1216×2688/BRA-AL00)分辨率即不同,跨设备共享基线必然大面积假红。
但这恰好验证了提案第 3 条(按 RN 版本/设备分子目录)的设计要求——持久仓可行,前提是 per-device 命名空间。由此追加两点增强建议:
- 比对算法引入尺寸归一化(按 density 缩放到逻辑像素再比)+ 偏移容忍带/SSIM,降低对「同型号同分辨率」的硬依赖
- 正视维护成本与更现实的噪声源:基线矩阵 = N 设备 × M 版本 × 断言数;且 har 每日构建的渲染微差比跨设备更频繁——同设备下 0.98 相似度阈值能否扛住每日 har 变化,决定 nightly 像素回归的实际价值,建议在持久仓设计中一并考虑基线保鲜策略(如按 har buildTime 失效/重落)


修订:撤回「算法放宽」建议,确认双通道设计哲学
收到反馈:「其他的比较方案不行,差异太大了,无法发现问题」「test-baseline/ 的 ui-*.json 结构 dump 就是基线比对用的」。经重新评估,撤回上一条评论中「尺寸归一化 + 偏移容忍带/SSIM」的增强建议——该建议用检出能力换跨设备兼容性,方向错了:
- 偏移容忍带会漏掉布局位移类真回归(位移本身就是要抓的 bug)
- SSIM 对小面积色彩/抗锯齿变化不敏感(渲染回归的典型形态)
- 密度归一化缩放存在重采样伪影,且不同密度下字体光栅化根本不同,归一不掉
结论与反馈一致:像素回归要保住信噪比,唯一可行配置是严格逐像素 + 同设备同版本;跨设备/跨端像素比对是死路。这也与「基线必须设备绑定」的既有设计(基线目录带 harmony-<serial> 段)自洽。
修正后的通道分工理解
| 通道 | 职责 | 生效前提 |
|---|---|---|
uiComparison(结构 dump,ui-<caseId>-*.json) |
跨平台基线比对 | compare 会话、双端在场(stream-comparison-queue 收集双端 dump 做结构 diff) |
visual(元素像素断言 + allowBaselineWrite) |
同端回归检测 | 持久基线 + 同设备同版本 |
两者互补不互替,本 issue 针对的是后者。
需要保留的边界说明
结构通道无法覆盖 harmony-only 夜跑场景:单平台运行时 uiComparison 步骤处于「单平台执行,等待跨平台对比数据」状态(仅捕获 dump,不发生比对),双端比对只在 compare 会话内发生。因此 nightly 中 65 个/版本的像素断言判红仍源于像素通道的 per-date 基线问题,本 issue 的核心诉求不变:
- CLI 透出
--baseline-dir(TestRunner.options.baselineDir已就绪) - 持久基线仓支持
- 基线按设备 × RN 版本分目录(严格逐像素 + 设备绑定的必然要求)
另补充一点:同设备同版本下还有每日 har 构建的渲染微差这一现实噪声源(我们的 har 天天更新),持久仓设计若落地,建议配套基线保鲜策略(如按 har buildTime 失效/重落),否则持久基线会被日常渲染漂移冲刷成噪音。


跨版本基线共享实证:命名空间可从「设备 × 版本」简化为「设备」单维度
针对「基线按设备 × 版本分目录」的提案第 3 条,做了同设备跨版本实测(2026-10-09,HUAWEI Mate 60 / 1280×2832,rn86 播种基线后其余版本 use 策略比对):
| 版本 | blur-radius(6断言) | border-width(8) | transform-origin(2) | view(2) | 最低相似度 | 结果 |
|---|---|---|---|---|---|---|
| rn84 | 6/6 | 8/8 | 2/2 | 2/2 | 99.98% | 18/18 全过 |
| rn82 | 6/6 | 8/8 | 2/2 | 2/2 | 99.96% | 18/18 全过 |
| rn77 | 6/6 | 8/8 | 2/2 | 2/2 | 100.00% | 18/18 全过 |
| rn72 | 5/6 | 8/8 | 0/2 | 2/2 | 94.00% | 15/18,3 个已知分歧 |
结论:同设备下相邻版本渲染几乎逐像素一致(rn77~84 vs rn86 基线 ≥99.96%),仅 0.72 与 0.86 之间存在 transform/blur 的真实实现分歧(97.5%/94.0%/97.6%,已用断言级 knownIssue 标注)。因此持久基线仓的命名空间按「设备」单维度即可,无需版本维度——比原提案的矩阵小一个维度,维护成本显著降低。rn72 的例外属于断言级已知分歧,用 knownIssue 覆盖即可。
已在 rnoh_test 落地(作为该方案的消费侧验证)
nightly 版本顺序调整为 rn86 先行(带 --update-baseline 播种当日基线目录),rn84→82→77→72 后行(use 策略比对)。链路 matrix→run→cptf 已端到端验证。语义边界:这是当夜跨版本一致性检查(每晚基线现拍),rn86 自身的时序回归检测仍需本 issue 的持久仓 + --baseline-dir——两者互补,不冲突。


本Issue主要用于开发协作,欢迎在此反馈问题或提出建议


背景
rnoh_test 的每日功能矩阵(launchd 定时任务,rn72/rn77/rn82/rn84/rn86 五版本串行)合入上游用例批次后,引入了 259 个元素级视觉断言(73 个用例文件声明
allowBaselineWrite,分布 ImageBackground / Transform / View 等类别)。当前基线策略三态(
command-base.ts→resolveBaselinePolicy):use(默认):缺基线判红(expect-executor.ts:729-743"元素无基线可比对")fill(--update-baseline):缺基线落盘且断言判绿force(--force-baseline):覆盖并备份到.history/每日跑批场景下的四个结构性问题
基线按日期 ephemeral:
TestRunner.resolveRunDirectories(test-runner.ts:447-490)把基线目录解析为test-reports/<日期>/test-baseline/<平台>/<category>/。每晚新日期目录 → 基线永远"不存在" → 默认 use 策略下每晚确定性地贡献 65 个假红/版本(五版本 × 65 ≈ 325 条噪音),真实失败信号被淹没。基线不进版本库:基线落在
test-reports/下且被其 gitignore 规则覆盖(visual-comparator.ts注释已自述此点),无法评审式管理,"--update-baseline 落基线 → 评审 → 后续比对"的闭环走不通。同日期多版本共享基线目录:五版本夜跑共用同一个
test-reports/<日期>/test-baseline/。若带--update-baseline,先跑的 rn72 落基线,rn77~rn86 会拿 rn72 的基线比对 → 跨 RN 版本渲染差异产生新一轮假红;反之不带则每晚全红。CLI 未暴露基线目录:
TestRunner已支持options.baselineDir(test-runner.ts:350),但 CLI 只有--update-baseline/--force-baseline两个开关,无法指定持久基线仓。期望改进
--baseline-dir <path>(内部机制已就绪,只差透出)app/tests/baselines/或任意外部路径),脱离test-reports/<日期>生命周期--force-baseline的.history/备份机制可复用为评审留痕)环境数据
--update-baseline(视觉断言退化为"落盘即绿"的截图记录模式),等待上述机制完善后恢复真比对