Commit Graph

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 仍逐字节一致(上一轮的修复保持)。
2026-09-18 04:07:26 +08:00
b7dc9e90e6 fix(deploy): 权限政策按**文件类型分岔**开药方 —— 我上一版把 release-linux.sh 的执行位改掉了
## 我在上一个提交里弄坏了一个脚本

`client/electron/scripts/release-linux.sh` 原本是 **711**:
group/other 读位缺失 ⇒ 本判据判红(**判得对**),但我给的药方是无脑 `chmod 644`
⇒ **去掉执行位** —— 把"读位缺失"换成"不能执行",**比原来更坏**,
而判据随后报"通过",工作区显示这个文件被改(`M`)。是我在提交前扫 `git status` 时
看见那一行 `M client/electron/scripts/release-linux.sh` 才发现的 —— **不是判据发现的**。

已恢复 755(`git diff` 干净,因为它 git 记录是 100755)。

★ 教训:**一条判据说"这个文件被改错了"时,药方必须按文件类型分岔**;
只有一个药方(`chmod 644`)就会把另一类文件改坏,而它同样报"已修好"。
这与"判据的适用范围没写出来"同族,只是这次代价落在了**修的动作**上,不是读的动作上。

## 改法

可执行与否按 **git 记录的那个位**(`git ls-files -s` 的 `100755`)判,
不按当前文件系统权限 —— 否则"执行位被谁弄丢了"会被这条判据**追认**成正常。

三条区分力实测(都当场恢复 + `cmp` 校验):
1. 非可执行文件改 0600 ⇒ 红,文案"权限过严";
2. 可执行文件丢掉执行位 ⇒ 红,文案"**注意别去掉执行位**";
3. 可执行文件 711(= `release-linux.sh` 原来的形态)⇒ 红 —— 即**最初那次判红是对的**,
   错的是药方。

另外把计数循环改成读 `git ls-files -s` 一次(不再在循环里对每个文件调
`git ls-files --error-unmatch`,也不再让计数落在管道子 shell 里)。

验证:`check-file-modes.sh` 正常态 exit 0;三条变异行为如上;
`git status` 只剩本文件本身的改动。
2026-09-15 10:27:20 +08:00
15df621045 feat(deploy): 权限位两条判据 —— 政策(源文件不严于 0644)+ 一致性(副本=仓库)
pi 评审 2026-09-15 §三 给了决定:**开,但拆两条**。理由我采纳并写进注释:
合成的结果会是"看起来覆盖了、其实只覆盖一半"。

## 为什么要这两条(实测实例,不是设想)

写文件的工具**不理会 umask**(umask 022,它建的仍是 0600),而
`deploy/redeploy-plugin.sh` 用 `cp -a "$SRC/."` 打快照 ⇒ **0600 会进生产**。
实测:快照里 `src/paths.mjs`/`src/turn-cwd.mjs` 是 0600、仓库 0644,
而 **`cmp` 五个 same、① 报"逐字节一致"** —— 两头都不报警:
`collectFiles` 只把**内容**做 sha256,`check-deploy-drift` 只在脚本上判可执行位。

## 两条的分工(别合成一条)

- `deploy/check-file-modes.sh` = **政策**:源文件不得比 0644 更严。
  **不看快照** ⇒ 能抓"两边都 0600",而一致性那条永远抓不到(两边一致 ⇒ 恒绿)。
- `check-deploy-drift.mjs` 新增 **①b**(`collectModes`/`diffModes`)= **一致性**:
  部署副本的权限 = 仓库那一份。抓不到"两边都错"。

## 落地

**政策侧**:新脚本判「已跟踪文件里 group/other 任一读位缺失」。
实测判出 **53 个**(含 `plugins/pi-mail-bridge/package.json`、`src/naming.mjs`、
`client/harmony/.../*.ets`、`docs/GUI-PLAN-HARMONY.md` 等)—— 全部 `chmod 644` 修掉,
现在 exit 0。**区分力实测**:把 `deploy/check-shared-libs.sh` 临时改 0600 ⇒ 判据红并点名它,
恢复后绿;0755 的可执行脚本**不**被判红(有读位,不是"更严")。
★ 也修正了我先前的一处过报:那 53 个里有凭据类命名的文件吗 —— **0 个**(先查了才批量改)。

**一致性侧**:①b 一上线就抓到**真实的**、**先于本次改动**存在的漂移:
`plugins/*-mail-bridge/lib/permission-grants.{js,d.ts}`、`rename-proposal.{js,d.ts}`
在三个宿主的快照里是 **600**、仓库是 **644**(pi 宿主 1 处、dsh 4 处、opencode 2 处)。
⇒ 这条缝**一直存在**,只是此前没有任何判据看着它。
**处理**:不单独 redeploy 去"洗"权限(那要重启 pi 宿主,为权限位重启服务不值得),
**下一次正常部署顺带修好** —— 这是记账,不是新欠账。
①b 现在是**失败**态(真实不一致),所以 `drift` 整表 exit 1;这与"① 全过"并存是对的,
两条量的是不同的东西。

## 自检

给 `collectModes`/`diffModes` 加了 4 条自检(`--self-check`),四条一起写,
因为"能发现差异"单独一条会被一个**恒判"都不同"**的坏实现骗过:
① 权限相同不得误报;② 内容一致但 0600 vs 0644 必须被发现(连数值一起断言);
③ 权限差异不污染 ① 的内容判据;④ 仅一侧存在的文件不算权限漂移(归 ① 的文件集判据)。
★ 其中两条我**第一版写错了**并当场修掉,都记在注释里:
- 用了 `lib/x.mjs` 做样本,而上面 `mk(b,'DIFFERENT')` 已把它改成内容不同
  ⇒ ③ 红在**内容**上,而它想验的是"权限不污染内容";改用一对独立的内容相同文件。
- 夹具真实创建的是 `lib/x.mjs` 而不是我以为的 `lib/same.mjs`(ENOENT 才发现)。

验证:`--self-check` 全绿;pi 桥 509/509;`check-shared-libs` exit 0;
`check-file-modes.sh` exit 0;`install.sh --check` exit 0。
2026-09-15 10:26:23 +08:00