Files
Unlucky-Launcher/packaging/ci-runtime-smoke.md
T
AskaEth 7e08e0ccc9 fix(docs): M62 r1 —— 修正「缺字体→空图+exit 0」的错误论据,拆出运行时冒烟细节文档
review r1(p2-1items/fix-then-merge)只要求改文档与注释,门禁逻辑一行未动。

- P2-1(唯一阻塞项):原稿称「字体库缺失 → 合法 PNG + 退出码 0」,这是错的。review 实测两条失效都是
  **硬失败**:完全没有字体 → fontique panic(退出码 101,不产生 PNG);非软渲染(默认 femtovg)→
  `take_snapshot is not supported by this FemtoVG backend`(退出码 1)。改正口径:`--screenshot` 的 PNG
  是进程自己编码写出的,只要走到 `take_snapshot` 就是「合法 PNG + 退出码 0」,像素断言是**纵深防御**,
  守的是「进程活着、PNG 合法、但场景几乎没画」这一档;其余情形本机暂无样本,属防御性设计、不宣称已复现。
  落点:packaging/ci-runtime-smoke.md §1 与 packaging/check_screenshot.py 模块 docstring。
- P3-1:ci.yml 的 runtime-smoke job 头补一行 —— 本 job 绑死 Slint `Window::take_snapshot`,迁 iced 后必须
  提供等价离屏截图通道,否则静默退化成「能起进程」。
- P3-2:阈值余量写明量级(342/64=5.3×、19.45/3.0=6.5×、0.00761/0.001=7.6×,改「5~8 倍」);并写明
  闸门下限 ≈「至少画出一条标题栏」(review 实测切片 174/35.10/0.02623 与右下 400×300 切片仍 pass),
  即只证明「场景被真实渲染过」,不证明元素齐全、更不证明视觉正确。
- P3-3:README 398/400 已贴红线 —— 借 review 给的逃生口**提前拆**:细节搬进 packaging/ci-runtime-smoke.md
  (78 行),README §11 收缩为 12 行索引(374 行),并写明「再增长继续往细节文档写,两文件都 ≤400」。
- P3-4:本地复跑示例改 Windows 安全路径 `D:/tmp/ull-smoke`;脚本对 repo_root/out_dir 统一 `cygpath -m`
  归一并回显真实路径(Git Bash 下 `/tmp` 会静默落进 Docker VM,宿主什么都收不到 —— review 实测踩到)。
- P3-5:两个 `run:` 里的 `set -o pipefail` 保留但加注释说明「当前无管道,为将来加管道先有失败传播」;
  `cargo clean -p unlucky-app || true` 加内联注释(N7 兜底,CI 里没有对应行,别误抄进 ci.yml)。

验证:`--selftest` 三组仍全部 fail(判红能力未被改坏);真实截图仍 pass(1180x760 / 342 / 19.45 / 0.00761);
0 字节与非 PNG 路径 exit 1;`yaml.safe_load` 通过(6 job,Linux 槽位无 continue-on-error,artifact 步
`if: always()`);`cargo fmt --all --check` 退出 0;cygpath 修复后重跑 Docker 冒烟,宿主机 D:/tmp/ull-m62-rev2
拿到 PNG,md5 `156c382a…` 与前两次 run 及 review 的 artifact 完全一致。
2026-11-01 16:15:47 +08:00

5.3 KiB
Raw Blame History

CI 运行时冒烟(Linux 真渲染一帧)

packaging/README.md §11 是本节的索引;细节在这里。为什么拆:本节要写阈值依据、失效模式与复跑口径, 塞回 README 会撞 400 行硬门禁——两文件都必须 ≤400 行,任一边再增长就再拆一节。

「编得过」≠「跑得起来」。ci.yml 的 runtime-smoke job 在 ubuntu-latest 上补第一份真实图形环境 运行证据:装 xvfb(虚拟 X 服务器)+ 软渲染依赖 + 字体,用 xvfb-run 把 GUI 进程拉起来,走既有的 进程内截图通道(--software-renderer --screenshot <png> --data-dir <tmp>)渲出一帧 PNG,再对像素本身断言。

1. 三道断言

packaging/check_screenshot.py 退出码 0 才算过;artifact 名 runtime-smoke-screenshot。

  1. 进程退出码 0(截图通道失败会以非 0 退出,不留半张图);
  2. PNG 存在、可解析、宽高 > 0(0 字节 / 非 PNG / 路径不存在都是硬失败,脚本 exit 1);
  3. 非空白:唯一色数 / 亮度标准差 / 强边缘占比三项同时过阈值。

为什么不能只看退出码:--screenshot 的 PNG 是进程自己编码写出的,只要流程走到 take_snapshot 就会得到 「合法 PNG + 退出码 0」;像素断言是纵深防御,守的是「进程活着、写出合法 PNG,但场景几乎没画」这一档。 本机可复现的两种失效都是硬失败(运行步就红,不必等像素断言):①完全没有字体 → fontique panic (退出码 101,不产生 PNG);②不是软渲染(默认 femtovg)→ take_snapshot is not supported by this FemtoVG backend(退出码 1)。这两条由 M62 review 实测复现(本 mission 未自己跑这两种破坏性实验)。 其余「渲染器出图但内容没上去」的情形本机暂无样本,属防御性设计,不宣称已复现。

2. 阈值与依据

python packaging/check_screenshot.py --selftest 可复现后三行:

样本 唯一色数 亮度σ 强边缘占比 判定
本机 Docker 真截图(xvfb + 软渲染,1180x760,空数据目录) 342 19.45 0.00761 pass
Windows 历史截图(M45/M52,同一界面深浅两套,1180x760) 529~699 20.29~27.46 0.0186~0.0433 pass
人为纯白 / 纯黑(空白帧) 1 0.0 0.0 fail
最弱内容(1 像素黑边框 + 一条中线) 2 19.09 0.00169 fail(卡唯一色数)
阈值 ≥64 ≥3.0 ≥0.001 —

阈值留 5~8 倍余量(342/64 = 5.3×、19.45/3.0 = 6.5×、0.00761/0.001 = 7.6×):换主题/换字体不会误报, 空白帧一定红。

第三项用强边缘占比(水平相邻像素亮度差 ≥8 的比例)而不是平均亮度差:空数据目录的主界面 57% 是同一片 底色,平均差被稀释到 0.4,强边缘只数真正的边界,跨主题稳定(同一界面深浅两套差 2 倍,仍都过线)。

这道闸门的下限 ≈「至少画出一条标题栏」(review 实测切片):只画 1180×40 标题栏的切片(174 / 35.10 / 0.02623)仍 pass,右下 400×300 的切片也 pass。所以它证明的是「场景被真实渲染过」,不证明界面元素齐全、 更不证明视觉正确;视觉正确只能靠人眼看 artifact。

3. 覆盖哪个平台

只有 Linux x64(X11 + Xvfb + 软渲染)。

  • macOS:runtime-smoke-macos 只在 workflow_dispatch 触发且 continue-on-error: true。官方 macOS runner 处于 LaunchDaemon 上下文、无登录 WindowServer 会话,winit 大概率建不了窗口;本机没有 macOS 且 worker 禁 push,这条路径尚无实测证据,故不拿它卡 PR 门禁。首跑定去留:绿 → 删 if 与 continue-on-error 升常驻;红 → 错误原文进 progress,按 D26 归入 iced 重写再规划。
  • Windows:不新增 job——--software-renderer --screenshot 已在本机验收里多次人眼验证(M45/M52)。

4. 本地复跑

bash packaging/linux-smoke-docker.sh . D:/tmp/ull-smoke

用 Docker(rust:1-bookworm + TUNA apt/rustup 源)复刻同一套步骤,截图落在 <输出目录>/runtime-smoke.png。 输出目录别写 /tmp/...:Git Bash 里 /tmp 是 MSYS 虚拟路径,docker -v 会把它当 Linux VM 内的路径, 结果是「脚本说成功、宿主机什么都没有」。脚本对 out_dir/repo_root 统一做 cygpath -m 归一,并回显真实 路径;没有 cygpath 的平台(Linux/macOS)按原样用。

诚实边界:本机容器是 Debian 12(glibc 2.36),官方 runner 是 Ubuntu 24.04(glibc 2.39),图形栈来源不同, 容器绿只证明「这条通道能跑」,官方 runner 首跑仍要单独看。

5. 已知跳过项与迁移风险

跳过项(D26 收窄,本条只做「框架无关的最小运行时冒烟」):Wayland(weston --headless)、 --screenshot-page 子页覆盖、gsettings 主题探测回退都不在本 job 内,随 iced 重写另行规划。

迁移风险:本 job 绑死 Slint 的截图通道(Window::take_snapshot)。UI 迁 iced 后必须重新验证—— iced 没有等价快照 API,届时要提供「离屏渲染出一帧 PNG」的等价通道,否则本 job 会静默退化成「能起进程」 而不是「能出图」(它本来也只证明「能出图」,不证明视觉正确)。