跨端: 导航条材质选 (a) 固定档(推翻我的 (b))—— 并修掉"注释说 (a)、代码是 (b)"的自相矛盾
pi 2026-09-15 裁定:**推翻 (b),选 (a)**。我原先给 (b) 的理由不成立,他逐条驳了:
1. **WebUI 的导航条根本不读 `--bg-blur`**:`index.css:1114` 的 `.narrow-nav` 是硬编码
`backdrop-filter: blur(18px) saturate(1.5)`。我引这条支持"两个量不同",
而同一条也说明**它不由用户偏好驱动**。
2. **WebUI 那个滑杆的语义是"背景"**:`BackgroundPicker.tsx:183` —— `label="模糊"`、
`hint="虚化细节,避免背景与正文抢注意力"`、`min=0 max=24`,只作用在
`.app-backdrop{filter:blur(var(--bg-blur))}` 上。
3. WebUI 自己留了**分开的**令牌 `--bg-blur-panel`(`index.css:267`,注释写明
"与壁纸自身的 `--bg-blur` 分开")—— 它的词汇表本身就拒绝把两者等同。
4. **★ 我给 (b) 的理由不成立**:我写"(a) 会让那个滑杆在导航条上变成死控件",
可那个滑杆**已经**被壁纸消费了(`MainPage.ets` 壁纸层的 `.blur(bgPlan.blurPx)`)——
它从来**不是**导航条的控件。(a) 之下它照样是活的。
5. §7.12 的「材质(玻璃)」行原本写的就是固定档 ⇒ (a) 是**回到**已登记契约。
产品向还有一条:**导航条是 chrome,材质应当稳定**,不该因为用户换张壁纸而变厚变薄。
## 最该记的是:我的注释和代码**互相矛盾**
`MainPage.ets` 里那段注释论证的是 (a)、并明确写着"跟随是错的,pi 抓出来了",
而它下面那一行代码是 (b)。**下一个读者会照注释把代码改回去,并引我那句话当权威。**
这是这一路反复在消的形状(说的与做的不一致、而判据看不见),这次落在**注释**上 ——
而注释正是"理由要写清"那条纪律的证据源。已整段重写为真实的 (a) 版本,并把
"(a) 会让滑杆变死控件"这个**错的理由**连同它为什么错一起留在注释里。
## 做掉的东西
- `MainPage.ets`:导航条回到 `.backgroundBlurStyle(Theme.navMaterial)`;
删掉 `NAV_MATERIAL_OF` 表与 `navMaterialFor` 的 import((a) 之下都是孤儿)。
- `model/Appearance.ts`:删 `navMaterialFor`(它存在的唯一理由就是方案 (b))。
`blurStyleFor` 现在**没有任何调用点** —— 如实登记在它的文档注释里
("有测试"不等于"有人用",上一轮我刚因同形状被抓过),不假装它活着。
- **五处"整条字面表达式"断言改成语义断言**(pi §四):`cross-client-theme`、`harmony-appearance`、
`harmony-nav`(3 处)此前都在钉
`/\.backgroundBlurStyle\(NAV_MATERIAL_OF\[navMaterialFor\(…\)\] \?\? Theme\.navMaterial\)/`
—— 字面换字面,正是 `CRITERIA.md` 不许的"对源码形状的匹配"。
现在判:① 那一处的材质**来自 `Theme.navMaterial` 这个系统令牌**;
② **不许跟随** `bg_blur`(NavBar 真代码里不许出现 `blurPx`/`blurStyleFor`);
③ 令牌是 `BlurStyle` 枚举值、不是 `NONE`、且**成员名真实存在于 SDK 枚举**。
- "可达性"那条判据**随契约作废**(它守的是方案 (b)):换成判 (a) 的契约。
**判据随契约走,不随实现走。**
- `harmony-appearance`:原先判"页面里那张表的键必须是 SDK 成员"。表删了,
改成**枚举 `blurStyleFor` 的整个值域**(0..40 + 界外 + NaN),逐个核 SDK 成员 ——
比原来只核表里那三行**更严**。
## 判据自己先错了一次,记下来
新判据第一版**没剥注释**就断言"NavBar 里不许出现 `blurPx`",当场红了 ——
而红的原因不是代码错,是 `NavBar` 的**文档注释**里正好写着
"我一度把档位接过用户偏好(`navMaterialFor(this.bgPlan.blurPx)`)"这句历史说明。
**注释说明禁令 ≠ 违反禁令**;不剥注释,这条判据就会变成"逼人删掉解释",
恰好与本仓库"理由要写清"的纪律相反。改成 `stripComments(bar)` 后再判,并加了一条
"注释里确实留着那处说明"的自检前提。
## 变异体:45 个全部被抓(含 3 个新判据的专属变异)
方案 (b) 落地时配的 13 个变异体**整体作废**(它们锚的代码被删了),标注 `retired`
并写清理由 —— 不是"没跑成"。另有 5 个锚点漂移(我在注释里逐字引用了被锚的那句代码,
污染了通用正则)的**重锚**到真代码;注释里那句逐字引用也一并去掉了
(**注释里逐字抄代码**正是让"按字面锚定"的变异体反复失效的根因)。
新增 3 个针对 (a) 契约的变异体(绕过令牌 / 又跟随 `bg_blur` / 令牌变 `NONE`),全部被抓。
## 未验
- **真机观感仍未验**:三档材质在真机上能不能看出差别、滑杆手感、管理页布局,
只有真机能答。本机模拟器已起(`hdc list targets` 有目标),但
`run-all.mjs` 的**设备闸已经到期**(8 个静态判据的前提成立)⇒ 套件现在会挡在
那道闸上、不打 `RESULT`。**这不是本笔引入的**(前提是环境变了),已单独报给 pi。
- Go 侧 `debt_registry_test.go` 仍未在本机跑(无 Go 模块缓存);pi 已在别处跑过,绿。
This commit is contained in:
@ -159,31 +159,38 @@ test('★ 模糊值映射到**系统材质档次**(不是把 40 当半径塞
|
||||
assert.ok(members.includes(sdk));
|
||||
|
||||
/*
|
||||
* 另一半:`名字 → BlurStyle 枚举` 那张表在页面里(纯逻辑层看不到 BlurStyle),
|
||||
* 它的**键必须与 SDK 成员逐字相同** —— 写错一个字母是"编译不过或静默不生效",
|
||||
* 而这类错在真机上表现为"拖滑杆没反应"(最难查的那一类)。
|
||||
* 这里判据自己去页面源码里把键取出来,逐个对着 SDK 的成员名核。
|
||||
* 另一半:**`blurStyleFor` 在整段可达输入上返回的每个值都必须是 SDK 的成员名**。
|
||||
*
|
||||
* 这里原先判的是页面里那张档位名→枚举的表(`NAV_MATERIAL_OF`,已随方案 (b) 删除)。
|
||||
* 那张表随"导航条改回固定档"(pi 2026-09-15 的裁定,见 `harmony-nav` 的契约判据)
|
||||
* 一起删了 —— 导航条现在直接用 `Theme.navMaterial`,不再经档位名中转。
|
||||
*
|
||||
* 但"**别自己发明档位名**"这件事仍然要判,而且现在**只有这一条在判它**:
|
||||
* `blurStyleFor` 是档位名的唯一产生者(它现在是孤岛:判据在跑、页面没人调,
|
||||
* 见 `Appearance.ts` 里那段如实说明)。所以改成枚举**它的整个值域**,
|
||||
* 逐个对着 SDK 成员核 —— 比原来只核表里那三行**更严**(原来漏判的点现在覆盖了)。
|
||||
*/
|
||||
const main = read('pages/MainPage.ets');
|
||||
const tableAt = main.indexOf('const NAV_MATERIAL_OF: Record<string, BlurStyle> = {');
|
||||
assert.ok(tableAt > 0, '页面里要有 `NAV_MATERIAL_OF`(档位名 → SDK 枚举)那张表');
|
||||
const tableEnd = main.indexOf('};', tableAt);
|
||||
const table = main.slice(tableAt, tableEnd);
|
||||
const keys = [...table.matchAll(/'([A-Z_]+)':\s*BlurStyle\.([A-Z_]+)/g)];
|
||||
assert.ok(keys.length >= 3, `要从表里读到键(实际 ${keys.length} 项)`);
|
||||
for (const [, key, val] of keys) {
|
||||
assert.equal(key, val, `表项 '${key}': BlurStyle.${val} —— 键与值必须同名(不同名几乎必然是写错了)`);
|
||||
assert.ok(members.includes(key), `'${key}' 不是 SDK 的 BlurStyle 成员(写自造名字会编译不过或不生效)`);
|
||||
const produced = new Set();
|
||||
for (let px = 0; px <= 40; px++) produced.add(A.blurStyleFor(px));
|
||||
produced.add(A.blurStyleFor(-3));
|
||||
produced.add(A.blurStyleFor(999));
|
||||
produced.add(A.blurStyleFor(NaN));
|
||||
assert.ok(produced.size >= 3, `可达输入上应当产出多档(实际 ${produced.size} 档:${[...produced].join('、')})`);
|
||||
for (const tier of produced) {
|
||||
assert.ok(members.includes(tier),
|
||||
`\`blurStyleFor\` 产出了 \`${tier}\`,它不是 SDK 的 BlurStyle 成员` +
|
||||
`(自造档位名 = 编译不过或静默不生效)。SDK 成员:${members.join('、')}`);
|
||||
}
|
||||
/*
|
||||
* 导航条那张表**不许有 NONE**:`navMaterialFor` 有下限(永不返回 NONE),
|
||||
* 表里留着 NONE 只会让人以为"导航条可以不糊"(那正是我上一笔的缺陷)。
|
||||
* 三档(薄/中/厚)都要在,漏一档会让该档静默回落。
|
||||
* 而"通用映射允许 NONE"这一半必须**留着**:`0 px ⇒ 不模糊`是它的正确语义
|
||||
* (用户要壁纸清晰是合法选择)。这条曾经被我写错过一次 —— 当时我断言
|
||||
* "`blurStyleFor` 在 0..40 上不许返回 NONE",那条**恒红**,错的是判据不是代码。
|
||||
*/
|
||||
assert.ok(!keys.some(([, k]) => k === 'NONE'),
|
||||
'导航空的表里不该有 NONE —— `navMaterialFor` 有下限(见 harmony-nav 的可达性判据)');
|
||||
assert.ok(produced.has('NONE'),
|
||||
'`blurStyleFor` 必须保留 `NONE`(0 px ⇒ 不模糊是合法语义)—— 导航条那边的下限不是靠篡改它实现的');
|
||||
for (const tier of ['COMPONENT_THIN', 'COMPONENT_REGULAR', 'COMPONENT_THICK']) {
|
||||
assert.ok(keys.some(([, k]) => k === tier), `表里缺 ${tier} ⇒ 该档会静默回落成"不模糊"`);
|
||||
assert.ok(produced.has(tier),
|
||||
`可达输入上应当覆盖 ${tier}(漏一档说明分档表被改坏了)`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -482,7 +489,7 @@ test('★ 模糊归属:壁纸层**不许**再模糊,导航条必须有系统
|
||||
const imgBlur = [...wallpaperBuilder.matchAll(/\.blur\(/g)];
|
||||
assert.equal(imgBlur.length, 1, `壁纸层的图片内容模糊只许一次(实际 ${imgBlur.length} 次)`);
|
||||
// 导航条的**面板材质**仍然在(背后是会滚动的内容,遮蔽有意义),且档位来自用户偏好
|
||||
assert.match(main, /\.backgroundBlurStyle\(NAV_MATERIAL_OF\[navMaterialFor\(this\.bgPlan\.blurPx\)\] \?\? Theme\.navMaterial\)/,
|
||||
assert.match(main, /\.backgroundBlurStyle\(Theme\.navMaterial\)/,
|
||||
'导航条的面板材质用**固定系统档**(`Theme.navMaterial`)—— 不跟随 `bg_blur`');
|
||||
// 材料档次由用户偏好映射而来(不是写死的半径)
|
||||
const store = read('common/AppearanceStore.ets');
|
||||
@ -877,7 +884,7 @@ test('★ 模糊字段的消费侧:逐文件登记 + 计数(P4c 起不再是
|
||||
* ⇒ 这是"消费点出现时按判据要求补判据"的正常流程走完一遍,不是把 0 改成 1 了事。
|
||||
*/
|
||||
const plumbing = new Map([
|
||||
['model/Appearance.ts', { max: 12, why: '域模型:声明 + clamp + 合并 + 两个映射函数(blurStyleFor 与有下限的 navMaterialFor,后者内部复用前者)—— 搬运与映射,都不是消费' }],
|
||||
['model/Appearance.ts', { max: 12, why: '域模型:声明 + clamp + 合并 + 一个映射函数(`blurStyleFor`,现为孤岛:判据在跑、页面无人调,见其文档)—— 搬运与映射,都不是消费' }],
|
||||
['pages/MainPage.ets', { max: 3, why: 'P4c 补上的两个**消费点**(映射判据早已存在,见本段说明):壁纸层图片内容模糊 + 导航条面板材质;第 3 处是同文件里说明这件事的注释' }],
|
||||
['common/BackgroundPicker.ets', { max: 6, why: '选择器的滑杆:**输入**(@Link 声明 + 上报 + 显示 + Slider 值 + onChange + 一处注释),不是"拿这个值决定画什么"' }],
|
||||
['model/Wallpaper.ts', { max: 1, why: '计划只**搬运**这个值(`blurPx`)+ 一处注释;分档判断不在这里(在 Appearance.ts 的 blurStyleFor)' }],
|
||||
|
||||
Reference in New Issue
Block a user