JianFeeeee
93dabb435d
修复: baseline= 那一格到不了套件(捕获组是前缀 + 过滤器不含它);baseline-unrunnable 退回 rc=0 的自相矛盾;并把「脏/干净/git 答不了」从两态改回三态
pi 2026-09-18 报的两条我都端到端复现了,都成立。修的过程中又发现**第三条**(我自己引入的),以及**自检自己的一处"判据在但走不到"**。
## 一、① `baseline=` 那一格从来不进套件输出(pi 报的第 ① 条)
两处都实测确认:
· 捕获组是**前缀**:`m[1]` = `RESULT mutants=48 ran=47 skipped=1 on_new_criteria=35`,`'baseline' in m[1]` = **False**;
· `whyLines` 的过滤器不含 `baseline=`。
⇒ 两条路都不通。**真·变异残留**时 `baseline=6/7✗**1 个文件既不在底本、也与 HEAD 不同 ⇒ 优先按"变异残留"查**`
在套件输出里 grep = **0 次**,而 `rc=0`、`mutants=48 ran=47 skipped=1` **看着完全正常**(我按你给的形状复现)。
**修法**:不扩正则、也不往过滤器里加关键词(那是"按字面量裁射程",本仓已栽过两次:
`criteria-hygiene` 的 import 硬匹配、`prose()` 判"用没用")——
改为 `RESULT` 行末尾加**结构化诊断码** `diag=<码>`,由 `run-all` 的 `DIAG_NOTE` 表逐码给一句准确的话:
| `diag` | rc | 含义 |
|---|---|---|
| `none` | 0 | 正常 |
| `manifest-mismatch` | 1 | 清单与磁盘不一致 |
| `baseline-residue` | **1** | **真·变异残留**(与底本不同**且**与 HEAD 不同) |
| `baseline-stale` | **0** | 底本过期(与 HEAD 逐字节相同,**不是缺陷**) |
| `baseline-unrunnable` | **2** | 跑不了 `sha256sum`(没读数) |
| `baseline-unknown` | **2** | git 答不了 ⇒ 判不出残留还是过期(没读数) |
| `counts-unusable` | 2 | 读不到 `jobs/` |
码表是**闭合**的:**不认识的码会报警**,所以"上游加了新状态而下游不知道"会立刻显形,
不会静静变成"没问题"。同时把 `baseline=` 的**读数本身**(`6/7✗`)也摘进那一格 ——
端到端实测:残留时 `grep baseline=` 从 **0 → 1**,rc 从 0 → **1**。
## 二、② `baseline-unrunnable` 原来 rc=0,与我自己的原则相反(pi 报的第 ② 条)
确认。我在 `blind/unreadable` 上定的是"**没读数不是成功 ⇒ 2**",而"跑不了 `sha256sum`"**是同一件事**,
却退 0 ⇒ 走正常路径 ⇒ 那句"是没读数"同样到不了读者。**我把"跑不了"和"没过"分成了两种状态(对),
但第三种状态(跑不了)没给它传播通道** —— 你这句说得准。
⇒ 现在 `baseline-unrunnable` 与 `baseline-unknown` 都退 **2**,
且措辞由 `diag` 决定而**不是**由 `status` 决定:`status === 2` 那句通用话会说"上面的 mutants 数字**不可信**",
而这里是**假话**(数字照常有效,**只有 baseline 那一格**没读数)。所以措辞一律走 `DIAG_NOTE`。
## 三★★ 我自己引入的第三条:`git` 三态被读成两态(假警报指向最危险结论)
修 ① 时我要构造 residue,才发现:`git diff --quiet` 退 **1** 有**两种**含义 ——
实测 · 仓库内干净 = **0** · 仓库内已改 = **1** · **非仓库/HEAD 取不到 = 也是 1**(stderr `error: Could not access 'HEAD'`)。
而原代码是 `.returncode != 0` ⇒ **"git 根本没答"被读成"有差异" ⇒ residue**,
也就是这一格**最危险**的读数。我自己在临时目录里跑时就撞到了:`REPO` 解析成 `/` ⇒ 一律报 residue。
⇒ 加 `can_ask`(`git rev-parse --is-inside-work-tree HEAD`,非仓库退 **128**,可区分):
答不了就报 `baseline-unknown`(**没读数**),**不许**声称 residue。这与上面 §一 那段注释警告的方向一致:
**假警报指向最危险的结论**。
## 四★★ 自检自己的一处"判据在,但走不到"
补 `baseline` 四态锚点时发现:旧 `runIn` 的临时目录是 `/tmp/xxx/`,
而 `summary.py` 用 `REPO = HERE/../../../..` ⇒ **`REPO` 解析成 `/`**(实测打印过)。
于是 `baseline=` 那一格**在原来的四例里从未被真正走成"对"**:`sha256sum -c` 在 `/` 下全部 FAILED、
`git` 也答不了。它们期望 rc=0/1 却看着"通过",是因为**两个错误互相抵消**
("判不了"被读成"有残留" **且** residue 当时退 0)。
⇒ 重建 `runIn`:按脚本真实位置**嵌套**建目录 + 造一个**迷你真仓库**(`git init` + 一次 commit +
一个可提交可改脏的目标文件),让 `REPO` 落在仓库根上。现在 `baseline=` 的**四态**
(对 / 过期 / 残留 / 判不了)**每一条前提都构造得出来**。
## 五、变异验证(都已还原)
| 变异 | 期望 | 结果 |
|---|---|---|
| **M21** residue 退回 rc=0(pi 报的原始行为) | `真·变异残留⇒1` 红 | **红**,`stale` 照旧绿(两条独立) |
| **M22** `unrunnable`/`unknown` 退回 rc=0(pi 本封 ② 的原始行为) | 两条都红 | **都红** |
| **M23** `can_ask` 恒真(三态退回两态) | `git 答不了` 红(会把"判不了"说成 residue) | **红**,rc 报 1(正是那个假警报) |
## 六、验证与状态
· **11 条锚点全绿**:一致⇒0 / unlisted⇒1 / ghosts⇒1 / 说明条目⇒0 / 盲读⇒2 / 单文件⇒2 /
**无 sha256sum⇒2** / **残留⇒1** / **过期⇒0** / **git 答不了⇒2** / 没有 baseline⇒0。
· `--mutants-line-selftest` **9 例**(含新增 `baseline-stale` 与"不认识的码⇒报警");四个自检全 exit 0。
· 全套件 `checks=459 pass=455 fail=4 skip=0 red=9 broken=0 unreported=0`、`mutants=48 ran=47 skipped=1 diag=none`(与你读数一致)。
· 端到端:残留时 `grep baseline=` **0→1**、rc **0→1**;正常态 `diag=none`、rc=0。
· 残留全清(`/tmp` 无 `exitcode-*`/`barepath-*`);`git status` 仅这两个文件;`HEAD=e99a657`。
## 七、你 §三 那句补充
> "能构造"是**上游锚点**的条件,不是**传播**的保证。
认同,而且这封正好是它的**正面用法**:`baseline` 那一格的前提能构造(我造了迷你真仓库),
但**锚点原本不在"到达"那一端** ⇒ 构造得出来 ≠ 到得了读者。
§四 我那句"崩点在打出 RESULT 之前…同一条缝"你说"修完之后它换了形态:不再崩、但结论仍然到不了"——
**同意,而且换到了第三个位置**(前两个:`whyLines` 的 `status !== 0` 关、`unlisted/ghosts` 退 0;
这一个:**正则捕获组**)。现在这条通道两半都钉住了:**结论**走 `diag`、**读数**走 `baseline=`。
2026-09-18 06:00:02 +08:00
..
2026-09-13 06:16:59 +08:00
2026-09-14 11:07:03 +08:00
2026-09-15 13:55:01 +08:00
2026-09-18 01:08:04 +08:00
2026-09-18 06:00:02 +08:00
2026-09-08 19:16:35 +08:00
2026-09-14 14:57:18 +08:00
2026-09-14 11:07:03 +08:00
2026-09-08 19:16:35 +08:00
2026-09-14 16:00:34 +08:00
2026-09-08 19:16:35 +08:00
2026-09-12 09:54:31 +08:00
2026-09-08 19:16:35 +08:00
2026-09-14 09:11:36 +08:00
2026-09-12 08:02:30 +08:00