docs(app-iced): probe 模块文档的复现命令补 SECTION(M229 复审 r3 P2-1)

r5 报告说「模块文档复现命令已补 `ULL_GALLERY_SECTION`」,但 diff 只碰了 `shot_path()` 与
测试体——模块文档 9-15 行一个字没改,照抄那条命令仍 exit 101(panic 报只支持 buttons/divider)。

这轮补齐:
- 模块文档复现命令改成两组(`ULL_GALLERY_SECTION=buttons` / `=divider`),产物路径用
  `${CARGO_TARGET_DIR:-target}`(本仓一树一 target,旧命令的 `./target/debug` 在 worktree 里根本
  没有 exe),并写明 `all` 不支持及其理由;
- `shot_path()` 的文档改真:它只读 `ULL_GALLERY_SHOT`,「这张图属于哪一段」由测试体开头那条
  assert 管(assert 早已搬走,且现在也认 divider)——原文还写着「此处不满足就失败」;
- 收掉 assert 文案里的九连空格接缝;
- 矩阵带过滤的注释从「`all` 默认会画全段」改成「buttons 段没有后续段,过滤是防御性的」。

自证:按文档两组命令实跑,四条命令全部 exit 0;`grep -n ULL_GALLERY_SECTION probe.rs` 命中
8/15/17/21/23(模块文档)与 144/150/357(实现)。
This commit is contained in:
AskaEth committed 2026-11-11 01:49:16 +08:00
1 parent f5a2610e4d
commit 36bac74822
1 file changed
+29 -31
+29 -31
View File
@@ -5,15 +5,28 @@
//! CI 没有桌面,所以这里不自己开窗:先用 `--screen=gallery --screenshot` 出真窗截图,本测试读
//! 那张 PNG 量几何、与令牌逐项比对。**没给图就跳过并大声说出来**(不静默通过)。
//!
//! 复现命令(在 worktree 根目录):
//! 复现命令(在 worktree 根目录;**必须同时给 `ULL_GALLERY_SECTION`**,只支持 `buttons` / `divider`):
//!
//! ```text
//! cargo build -p unlucky-app-iced --bin unlucky-launcher-iced
//! ./target/debug/unlucky-launcher-iced --software-renderer --screen=gallery \
//! --screenshot target/m75/gallery-light.png --screenshot-theme=light
//! ULL_GALLERY_SHOT=target/m75/gallery-light.png cargo test -p unlucky-app-iced gallery::probe
//! EXE=${CARGO_TARGET_DIR:-target}/debug/unlucky-launcher-iced # 本仓纪律:一树一 target
//! OUT=${CARGO_TARGET_DIR:-target}/m229-probe && mkdir -p "$OUT"
//!
//! # ① 按钮矩阵(实心块 / 药丸 / 字形 / 逐行禁用色 / Outlined 环)
//! ULL_GALLERY_SECTION=buttons $EXE --software-renderer --screen=gallery \
//! --screenshot "$OUT/buttons-light.png" --screenshot-theme=light
//! ULL_GALLERY_SECTION=buttons ULL_GALLERY_SHOT="$OUT/buttons-light.png" \
//! cargo test -p unlucky-app-iced gallery::probe
//!
//! # ② 分隔线(`buttons` 段里没画线,必须单独出一张)
//! ULL_GALLERY_SECTION=divider $EXE --software-renderer --screen=gallery \
//! --screenshot "$OUT/divider-light.png" --screenshot-theme=light
//! ULL_GALLERY_SECTION=divider ULL_GALLERY_SHOT="$OUT/divider-light.png" \
//! cargo test -p unlucky-app-iced gallery::probe
//! ```
//!
//! `all` **不支持**:gallery 整页比 1180×760 的视口高,分隔线段与按钮矩阵不可能同屏,而 sizes 段的
//! 实心块又会被「按钮 40 高」的判据量到 —— 所以按段出图、按段断言,`all` 会被明确拒绝(见测试体)。
//!
//! 量什么(每条对一个已发生过的错误):实心块高 **40**(12b 1.1)· 药丸顶行**左内缩 ≈14** ⇒ 圆角 full=20
//! (12b 1.2,8 圆角会接近通栏)· IconButton **40×40**(12b 2.1)· 字形墨迹 **16~26**
//! (Q9:24 盒被填满会到 40)· 分隔线 **1px**(22.1)· 禁用容器 **on-surface@10%**(按钮族)存在(12b 1.8)。
@@ -86,10 +99,9 @@ fn delta_ratio(pixel: [u8; 3], surface: [u8; 3], line: [u8; 3]) -> f32 {
/// `ULL_GALLERY_SHOT` → 截图路径(相对路径按**工作区根**解释:`cargo test` 的 cwd 是 crate 目录)。
///
/// **只认 `buttons` 段的 sheet**(M229 复审 P2):这份 probe 的每条判据都假设画面上是
/// 「5 行文字按钮 + 4 行图标按钮」的矩阵。把整页图(下载页/设置页)指给它时,页面自己的实心块
/// (高 21 的 chip、卡片)会被当成按钮量,得到的是**误导性的红**而不是真缺陷。所以这里要求
/// `ULL_GALLERY_SECTION=buttons`,不满足就明确失败——「跳过」会把「指错了图」变成静默通过。
/// 只把 `ULL_GALLERY_SHOT` 读成路径;**「这张图属于哪一段」由测试体开头那条 assert 管**
/// (`buttons` / `divider` 之外一律失败),这里不做校验——图与判据的配对是测试的前提条件,
/// 放在测试里读起来才连贯(复审 r3 P2-1:这段文档曾写「此处不满足就失败」,而 assert 早已搬走)。
fn shot_path() -> Option<std::path::PathBuf> {
let raw = std::env::var_os("ULL_GALLERY_SHOT")?;
let path = std::path::PathBuf::from(raw);
@@ -127,24 +139,15 @@ fn gallery_geometry_matches_the_tokens() {
};
let ui = ui(flavor);
// 这份 probe **只认两种 sheet**(复审 r2 P2-b 的结论):
//
// - `ULL_GALLERY_SECTION=buttons`:按钮矩阵(五式 × 五态 + 图标四式)——本 probe 的主判据;
// - `ULL_GALLERY_SECTION=divider`:分隔线的两条判据(1px / 墨量覆盖率)。
//
// **为什么不支持 `all`**:gallery 整页比 1180×760 的视口高,`all` 的 sheet 首屏里根本看不到
// 分隔线段(实测 0 条长横线),而 sizes 段的实心块又会被「按钮 40 高」的判据量到。一张图装不下
// 两段判据,所以按段出图、按段断言。
//
// **为什么必须给 SECTION**:整页图(下载页/设置页)的 chip 与卡片会被当成按钮量,
// 那是误导性的红,不是缺陷。
// 只认两种 sheet(`all` 与整页图都拒绝,理由见 [`shot_path`] 与模块文档):
// `buttons` = 按钮矩阵的主判据;`divider` = 分隔线的两条判据(1px / 墨量覆盖率)。
let section = std::env::var("ULL_GALLERY_SECTION")
.unwrap_or_default()
.trim()
.to_ascii_lowercase();
assert!(
section == "buttons" || section == "divider",
"这份 probe 只支持 `ULL_GALLERY_SECTION=buttons`(按钮矩阵)或 `divider`(分隔线); 当前 {section:?}。`all` 不行:整页比视口高,分隔线段与按钮矩阵不可能同屏。"
"这份 probe 只支持 `ULL_GALLERY_SECTION=buttons`(按钮矩阵)或 `divider`(分隔线);当前 {section:?}。`all` 不行:整页比视口高,分隔线段与按钮矩阵不可能同屏。"
);
// 分隔线那段是**独立出口**:`divider` 段的 sheet 里没有按钮矩阵,判据也不同。
if section == "divider" {
@@ -160,18 +163,13 @@ fn gallery_geometry_matches_the_tokens() {
primary.len()
);
// **只判「按钮矩阵那一段」**:`--screen=gallery` 默认(`ULL_GALLERY_SECTION=all`)会把
// sizes / divider / selection / inputs / feedback / navigation 也画进来,它们各自的实心块
// (chips 底、卡片、stop indicator…)不该被「按钮 40 高」这条判据量到 —— 复审 r2 P2-b 的现场
// 就是 `all` 模式下在 y≈715 撞到一块 21 高的实心块,probe 红在一个根本不在量程里的东西上。
//
// 矩阵区的上下界由**第一块文字按钮**(宽 > 60、高 40)的顶边决定,往下 9 行 + 8px 余量。
// **只判「按钮矩阵那一段」**:矩阵区由「第一块文字按钮(宽 > 60、高 40)」的顶边起、往下 9 行
// + 8px。`buttons` 段的 sheet 里没有后续段,所以这条过滤是防御性的(`all` 现在被拒;将来若允许
// 拼接多段,它保证判据只落在矩阵上,不会被别段的 chip/卡片撞到)。
let matrix_top = primary
.iter()
.filter(|bbox| {
bbox.area() >= 800 && bbox.width() > 60 && (39..=41).contains(&bbox.height())
})
.map(|bbox| bbox.top)
.filter(|b| b.area() >= 800 && b.width() > 60 && (39..=41).contains(&b.height()))
.map(|b| b.top)
.min()
.expect("没找到文字按钮的实心块(矩阵不在画面里?)");
let matrix_bottom = matrix_top + rows::ROW_COUNT * rows::ROW_STEP + 8;