957ec5ec775dca73fa6880ca1656d63bbe3d46fc
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 590a72a715 |
修复: job 集合从 glob 改成**清单**(+ 清单外即报,与 SUITE 同形状)+ RESULT 行带集合指纹;baseline 播报区分"底本过期"与"变异残留";权限政策补上**目录可进入性**(原来只管文件)
pi 2026-09-18 报的三件,逐条实测后处置。
## 一、job 集合是 glob ⇒ "权威"是**树的函数**(同一段代码两个数)
pi 独立复算对上了(48/48/0、A=36/B=41 与我一致),但发现 48 与 52 **都不是错的** ——
它们读的是**不同的集合**,而**没有任何东西说明读的是哪个**:
| 快照 | job 文件 | 输出 |
|---|---|---|
| 提交态 | 9 个(全跟踪) | `mutants=48 …` |
| 工作树 | 11 个(2 个未跟踪) | `mutants=52 …` |
真因:`glob(JOBS_DIR + '/jobs*.json')` ⇒ **未跟踪的 job 文件静默进入统计**。
这与"写了判据忘了接线"同族,区别是 `run-all.mjs` 有**自检 2** 挡着(清单外的 `*.test.mjs` 直接红),
这边没有对等物。**本仓用"清单 + 清单外即红"解决过同一个问题两次,这是第三次。**
**处置(pi 建议的前者)**:新增 `jobs.manifest.json` 显式列 job 集合,`summary.py` 只读清单;
清单与磁盘不一致时**明说**(两个方向都报:未列入清单 / 清单里有但磁盘没有),
并声明"上面的数字**不代表磁盘上现在有多少个变异体**"。
**另加集合指纹**(pi 建议的后者,两条都做了):`sha=…` —— 让"48 还是 52"变成可判的:
集合没变而数变了 ⇒ 真算错;集合变了 ⇒ 一眼看出是换了快照,不必再互相复算一遍。
**变异验证**(两个方向都试):
```
加一个未列入清单的 job 文件 ⇒ 报「未列入清单:jobs-UNLISTED-probe.json」
且 mutants=**48**(未被静默计入)✓
清单里加个不存在的文件 ⇒ 报「清单里有、磁盘上没有:jobs-GHOST.json」✓
```
(`_` 开头的条目是说明,读时滤掉 —— 否则会被当成文件名,`ghosts` 假报一堆。)
## 二、`baseline=4/7✗**有文件没还原**` 是**假警报指向最危险的结论**
实测三个不匹配的文件 **全部与 HEAD 逐字节相同**(`git diff --quiet HEAD` 为空):
`AdminUsersPage.ets`/`SettingsPage.ets` 是提交 `6861934`(09-17 21:15)改的、
`ApiClient.ets` 是 `9c6e9c6` 改的 ⇒ **底本过期,不是变异残留**。
★ 而原来一律打"✗**有文件没还原**" —— 那会让人去翻变异,而真因只是底本没跟上提交。
**两种成因在 `sha256sum -c` 眼里一模一样**,所以播报必须分开,并各给判别方法:
```
baseline=4/7⚠**底本过期**(3 个文件与 HEAD 逐字节相同 ⇒ 是正常提交改过、不是变异残留)
```
**底本已重算**,并按要求在文件里记一行"为什么"(含"重算前必须先证是提交态"这个前提)。
**重算后仍在校验**(变异验证):给 `AppearanceApi.ets` 追加一行 ⇒ 立刻 `FAILED`;还原 ⇒ `7/7 OK`。
## 三、`summary.py` 对非 root 是坏的:`jobs/` 缺 `x` 位
```
drw-r--r-- client/electron/test/mutants/jobs ← 缺 x
$ runuser -u nobody -- python3 …/summary.py
PermissionError: [Errno 13] Permission denied: '…/jobs/jobs-all.json'
```
⇒ 那份"口径的唯一权威"**只有 root 跑得起来**。已 `chmod 755`,非 root 复跑输出一致。
★ pi 的深层判断成立且我核实了:**这条落在任何判据的射程之外** ——
`deploy/check-file-modes.sh` 的政策是"**源文件**不得比 0644 更严",
而它遍历的是 `git ls-files`,**只看文件**;"目录缺 x"比"文件 0644 更严"更严重
(连 `stat` 都进不去)。
⇒ **给该政策补上"目录可进入性"**(只判 `u+x`、只判"仓库内容所在的目录",
不去管 node_modules/dist —— 那会把这判据淹掉;也不判 group/other —— 那取决于本机 umask)。
**★ 我第一版这里又写错了,而且错得正好是被测的那个病**:
用 `[ -x "$d" ]` 判可进入 ⇒ **恒为真**,因为 **root 无视权限位**(`test -x` 对 uid=0 永远返回 0),
于是变异验证"撤掉 x"**根本不触发**,而**输出看起来完全正常**。
⇒ 改成**直接读权限位**(与同文件里文件那段的位运算同一做法)。
改后变异验证:撤 x ⇒ `[FAIL] 目录不可进入:…(drw-r--r--,缺属主 x 位)`、退出码 1;还原 ⇒ 0。
## 四、顺带修好三处既有权限违规(`check-file-modes.sh` 原来一直红着)
```
.githooks/pre-push 711 ⇒ 755(保留执行位,**不是**去掉)
test/harmony-arkts.test.mjs 600 ⇒ 644
model/DeviceProbe.ts 600 ⇒ 644
```
三者都是**提交态**就这样(不是并发会话弄的)。按脚本自己的"药方按类型分岔"修的。
现在该政策 **退出码 0**。★ git **不存** 600/644 的区别(只记 exec 位)⇒ 这三处是**本地状态**修复,
不随提交走,新克隆不受影响 —— 与 pi 对目录权限的说明同一条。
## 五、pi 报的另两件:**在 HEAD 上已经不存在了**(是过时读数)
- **ArkTS 两处阻断**:`MainPage.ets` 的 import 现在在 71-74 行、最后一个 `const` 在 88 行
⇒ **位置正确**;`AdminUsersPage.ets` 的 `Chip` 签名已是 `ResourceColor`(`:410`)
⇒ 两处**都已在 HEAD 修好并提交**(工作树 `client/harmony/` 干净)。`harmony-arkts` 判据 3/3 绿。
- **套件现状**:现在 **29** 个判据文件(不是 23),`unreported=0 broken=0`。
## 六、测量
| 相位 | RESULT |
|---|---|
| build | `files=29 ran=29 checks=456 pass=453 fail=3 red=9 broken=0 unreported=0` |
| install | `files=29 ran=27 checks=444 pass=442 fail=2 red=8 broken=0 unreported=0` |
三种 cwd 仍逐字节一致(上一轮的修复保持)。
|
|||
| c12744e8c3 |
跨端: 导航条材质选 (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 已在别处跑过,绿。
|
|||
| bcd4f97e37 |
跨端: 变异体计数收进仓库 —— 前面报过 40/48/58 四个数,根因是"job 集合"从没定义
pi 用 `/tmp/mut/` 复算后指出:48 也不对。他是对的,而且**不是记性问题、是口径问题**——
我把 9 个 `jobs*.json` 的条目**直接相加**,没做归一:同一个变异体在跨批重锚时被键了多次
(13 组重复、15 条冗余),最典型的是「计划不搬运模糊值」同时挂在 `jobs-b3`/`jobs-blur`/`jobs-blur2`
三个文件、三个不同 `test` 键上 —— 于是"按判据文件分组求和"必然把它算三次,
而"跑在新增判据上的是多少"在交叉归类下**没有唯一答案**(41 或 35)。
更根本的是 pi 指出的第二层:**那个统计脚本根本不在 `/tmp/mut/` 里**(他为了复算是现写的),
而且 `/tmp` 会被清、不在仓库里 ⇒ 变异体数字**只活在信里**。
这一路已经立过同形状的规则(余额打在 `RESULT` 行、权威源在文件里),这条当时漏了。
## 做了什么
- `client/electron/test/mutants/`:把 `mut.py`、`run.sh`、`jobs*.json`、`baseline.sha`
从 `/tmp` 挪进仓库(`/tmp` 会清、复核方够不着)。
- `mutants/summary.py`:**口径的唯一权威**,定义写死在代码里:
· 不同变异体 = 按 (file, pat, repl) 去重(`retired` 不计);
· 跑起来 = 锚点在该文件里**恰好命中 1 次**(与 mut.py 同一条件);
· `on_new_criteria` = 该变异体的**每一个** test 键都指向本批新增的两个判据文件
(口径 A —— 不因交叉归类虚高;另报口径 B 作参考,它只增不减,不拿来报数)。
- `run-all.mjs` 的 `RESULT` 行播报它,并**顺带自证基线**:跑不起 `summary.py` 时
**不静默**(打印 status 与 stderr 末行)——我第一版路径写错,只看到"计数未知",
真因(`can't open file …/test/test/mutants/summary.py`)被吞掉了。
- `mutants/test-keys.json`:`test` 键 → 判据文件的**唯一来源**(`mut.py` 与 `summary.py`
共用)。此前两处各写一份,分叉过一次:键名从旧名换成 API 名后 `summary.py` 那份没跟上,
于是所有锚点被判 `hits=-1`、报出"51 个变异体全部 skipped"。
- 无歧义口径下的**当前真值**:`mutants=48 ran=48 skipped=0 on_new_criteria=36 baseline=7/7✓`
(口径 B = 41;原始条目 66,其中 `retired` 5)。
- 清掉 pi 指出的三类脏数据:
· **过期条目**(锚点是修复前的旧写法,`hits=0`)标 `retired` 5 条 ——
它们**不是"没跑成的变异体"**,重锚后都跑过、都红了;留着只会把 skipped 一直抬高;
· **重复计数**(multipart 那条在两个文件里各一次)去重;
· **真 skip** 的 multipart 锚点切片成 `name: 'file',\n contentType: mimeType` ⇒ 真的跑起来了
(此前命中 2 次,因为 `ApiClient.ets` 有两个 multipart 构造器)。
- 修两处并发/竞争:`mut.py` 的 `tempfile.mktemp()`(Py3 起 deprecated,**TOCTOU**)→ `mkstemp`;
`run.sh` 的固定 `/tmp/mut/bak` → 按 `$$-$RANDOM` 唯一(并行跑会互相覆盖备份)。
## 未做(如实说)
- **`AdminUsersPage.ets` 有一处不是我做的改动留在工作树里**(11:20:48,我 11:21 的提交之后):
`Chip(text, bg, fg: string)` → `ResourceColor`。核实过是**正确的 ArkTS 修法**
(`Theme.surfaceMuted`/`textSubtle` 是 `Resource`、`chipNeutralBg` 是 `string`,
第 368 行的三目因此是 `Resource | string` ⇒ 旧签名**编译不过**)。
我**没有提交也没有回退**它 —— 工作树是共享的,不该替别人提交别人的活。
基线因此重算了(`baseline.sha` 顶部记了原因与哈希来源,重算本身是**有意动作**:
随手重算会把"某次变异没还原"永久掩盖掉)。
- Go 侧 `debt_registry_test.go` 仍未跑(沙箱无 Go 模块缓存),只做了 `gofmt`。
|