修复: baseline-absent 同时是"关掉残留检测"的开关 —— 一个 rm 就能让残留仍在而那条红整条消失
pi 2026-09-18 报的。**成立,我端到端复现了**,而且是这条线上同一形状的**最后一跳**。
## 一、缺陷:结论不是"到不了读者",是**被关掉了**
`baseline-absent` 原来是 `{note: null, blocksGreen: false}` —— **既不说话、也不阻断**,
而它同时是"**关掉残留检测**"的开关。同一处残留,**只切 `baseline.sha` 在不在**:
| | summary.py | 套件 | 红清单里有 residue 吗 |
|---|---|---|---|
| `baseline.sha` 在 | `diag=baseline-residue` | `red=10 … verdict=red` | **有** |
| **删掉** | `diag=baseline-absent` | `red=9 … verdict=red` | **没有**(整条消失、`rc=0`、静默) |
`git status` 里 ` D baseline.sha` 与 ` M <被改文件>` **同时都在** ⇒ **残留还在**,
而唯一能报告它的机制被一个 `rm` 关掉,**不需要特权、不会红、也不说话**。
前几轮分别是"结论到不了读者"、"结论到不了 `verdict`";**这次是"结论被关掉了"**。
## 二、修法:把"缺席"分成两态,并给非阻断码再分两类
1. **`baseline-deleted`(新码,退 1)**:`baseline.sha` **受版本控制却被删**
⇒ 那不是"可接受的配置",是**缺文件**(该恢复它)。判别用既有的东西、不新造:
`git ls-files --error-unmatch` —— 三态:**0=受跟踪 / 1=没跟踪 / 128=git 答不了**,
`128` 时**不许猜**,退回缺席语义但**必须说话**。
2. **`baseline-absent` 补 `note`**(原来 `null` ⇒ 连读者都看不到):
说清"**这一格没检查**:没有底本 ⇒ 残留检测是关着的",并区分"本来就没跟踪它"与"判不出"。
—— 这是 pi 的"最小版",我认为它**不足以**独当(沉默正是这个洞的成因),所以两条都做。
3. ★ **`DIAG` 每个码新增 `checked` 字段**(pi 那条建议的落地):
· `checked: true` = "**检查了、结论无害**"(`baseline-stale`:可以静默);
· `checked: false` = "**根本没检查**"(`baseline-absent`/`counts-unusable`/
`baseline-unrunnable`/`baseline-unknown`:**必须说话**)。
⇒ 把 pi 的"应当分两类"从**文案要求**变成**结构字段**。
## 三★ 我加第一版时漏了一条判据,自己变异出来(M34)
`checked` 只是一个字段,**它的内容当时没有任何判据守着**:我把 `baseline-absent` 的
`note` 改回 `null`(= pi 说的"最小版没做"),`--verdict-selftest` **全绿** ——
因为此前的判据只管 `blocksGreen` 存不存在、两侧口径对不对。
⇒ 补第 ⑦ 条:**`checked: false` 的码必须有 `note`**,且**每个码都必须声明 `checked`**。
又一条"判据在,但走不到":字段加上了,没人查它的内容。
## 四、变异验证(都已还原)
| 变异 | 结果 |
|---|---|
| **M32** `baseline-deleted` 退回"当配置缺席"(**即 pi 报的那个洞本身**) | **红**:`UPSTREAM_RC[baseline-deleted]=1 与真跑出来的 rc=0 不符` |
| **M33** 关掉 `bl_tracked` 判别(一律当缺席) | **红** 2 条:端到端恢复 pi 那个洞(`diag=baseline-absent`)+ 反向覆盖报"该码没案例" |
| **M34** `baseline-absent` 的 note 改回 `null` | **红**:`这些码根本没检查、却一句话都不说:baseline-absent`(**上一版这里是 rc=0**) |
| **M35** 删掉某个码的 `checked` 字段 | **红**:`这些码没声明 checked:baseline-stale` |
## 五、端到端锚点(新增一条 `--exitcode-selftest` 案例)
`runIn` 加 `'deleted'` 模式:**先提交 `baseline.sha` 纳入跟踪、再把目标文件改脏、然后 unlink**
⇒ 判 `rc=1 且 diag=baseline-deleted`。这条**就是 pi 那个实验的自动化版本**:
残留是真的存在的,而底本被删了。反向覆盖随之报 `9 个码都有案例真跑验过`。
**真树端到端复核**(真残留 + 真删 `baseline.sha`):`red=10`(修复前 9)、`verdict=red`、
红清单里出现 `(summary.py)baseline-deleted —— 底本 baseline.sha **受版本控制却被删** ⇒ **残留检测已失效**`。
## 六、验证与状态
· 五个自检全 exit 0(`--verdict-selftest` 新增第 ⑦ 条;`--exitcode-selftest` 11→12 条案例、9 个码全覆盖)。
· 正常态与 pi 读数一致:`checks=459 pass=455 fail=4 skip=0 red=9 broken=0 unreported=0 verdict=red`、
`mutants=48 ran=47 skipped=1 on_new_criteria=35 diag=none baseline=7/7✓`。
· `baseline.sha` 的 7 条都是鸿蒙源码文件,**不含** `summary.py`/`run-all.mjs`
⇒ 本次改动**不需要重算底本**(`baseline=7/7✓` 亦为证)。
· 残留全清;`git status` 仅这两个文件;`HEAD=2870d47`。
This commit is contained in:
@ -148,6 +148,38 @@ def main():
|
||||
# ⇒ 两件事一起修:① `r` 先绑 None;② "**跑不了这项检查**"与"**检查了、没过**"
|
||||
# 分成两种状态,不许合并(合并正是这个 bug 的成因)。
|
||||
bl_unrunnable = False
|
||||
# ★★ 缺席的**两种成因**必须先分开(pi 2026-09-18 实测到的那个洞)。
|
||||
#
|
||||
# 原来 `baseline.sha` 不在就一律 `baseline-absent` ⇒ 退 0、`note: null`、**连读者都看不到**。
|
||||
# 而它同时是"**关掉残留检测**"的开关 —— 实测(pi 报、我复现):
|
||||
# 同一处残留(`ImagePrep.ts` 末尾追加一行),**只切 `baseline.sha` 在不在**:
|
||||
# 在 ⇒ `diag=baseline-residue`、`red=10`、红清单里**有**那条 `(summary.py)baseline-residue`
|
||||
# 删掉 ⇒ `diag=baseline-absent`、`red=9`、那条红**整条消失**、`rc=0`、静默
|
||||
# 而 `git status` 里 ` D baseline.sha` 与 ` M ImagePrep.ts` **同时都在**。
|
||||
# ⇒ **残留还在,唯一能报告它的机制被一个 `rm` 关掉了**,不需要任何特权、不会红、也不说话。
|
||||
#
|
||||
# ⇒ 判法(pi 建议,且**不必新造**):`baseline.sha` 是**受版本控制**的
|
||||
# (`git ls-files --error-unmatch` 有它)⇒ "跟踪着、却不在工作树里"**本身就是可疑**,
|
||||
# 那是 ` D`(被人删了),不是"可接受的配置"。
|
||||
# 只有"**本来就没跟踪它**"(别人 clone 的变体 / future)才保留"缺席即配置"的语义。
|
||||
#
|
||||
# ★ 判别是三态(与我修 `git diff --quiet` 那次同形):
|
||||
# rc=0 ⇒ 受跟踪 ⇒ 删除 ⇒ **缺文件**(该改的是仓库/数据)
|
||||
# rc=1 ⇒ git 说没跟踪它 ⇒ 真·配置缺席
|
||||
# rc=128 ⇒ git 答不了(非仓库)⇒ **不许猜**,退回"配置缺席"但**必须说话**
|
||||
bl_tracked = None # None=判不了;True=受跟踪;False=没跟踪
|
||||
if not os.path.exists(bl):
|
||||
try:
|
||||
tr = subprocess.run(['git', 'ls-files', '--error-unmatch', '--',
|
||||
os.path.relpath(bl, REPO)],
|
||||
cwd=REPO, capture_output=True, timeout=30)
|
||||
if tr.returncode == 0:
|
||||
bl_tracked = True
|
||||
elif tr.returncode == 1:
|
||||
bl_tracked = False
|
||||
# 其它(128 等)⇒ 保持 None = 判不了
|
||||
except Exception: # noqa: BLE001 —— 判不了就退化为"配置缺席 + 说话"
|
||||
bl_tracked = None
|
||||
if os.path.exists(bl):
|
||||
try:
|
||||
r = subprocess.run(['sha256sum', '-c', bl], cwd=REPO,
|
||||
@ -171,8 +203,20 @@ def main():
|
||||
bl_note = (f' baseline=(**跑不了 sha256sum 校验**:{bl_unrunnable})'
|
||||
f'—— 这一格**不是**"底本对"也**不是**"有残留",是**没读数**')
|
||||
elif baseline_ok is None:
|
||||
bl_diag = 'baseline-absent'
|
||||
bl_note = ' baseline=(没有 baseline.sha)'
|
||||
# ★★ 缺席分成两态(见上面 `bl_tracked` 那段的总说明)。
|
||||
if bl_tracked is True:
|
||||
# 受跟踪却被删 ⇒ **不是配置,是缺文件**(谁把它删了?残留检测因此关掉了)
|
||||
bl_diag = 'baseline-deleted'
|
||||
bl_note = (' baseline=(**底本被删了**:`baseline.sha` 受版本控制,'
|
||||
'却不在工作树里 ⇒ **残留检测已失效**)')
|
||||
else:
|
||||
bl_diag = 'baseline-absent'
|
||||
# ★ 即使是"真·配置缺席",也**必须说话** —— 原来这里是 `note: null`、连读者都看不到。
|
||||
# "这一格没检查"与"检查了、结论无害"**不是一回事**(本仓反复立的那条:
|
||||
# "跑不了" ≠ "检查了没过"),所以它不能再靠沉默通过。
|
||||
bl_note = (' baseline=(**没有底本 ⇒ 这一格没检查**:'
|
||||
+ ('判不出它是不是该受跟踪' if bl_tracked is None else '本来就没跟踪它')
|
||||
+ ',但**残留检测是关着的**)')
|
||||
else:
|
||||
good, ok, total = baseline_ok
|
||||
# ★ 措辞必须区分**两种完全不同的成因**(2026-09-18 实测):
|
||||
@ -259,7 +303,15 @@ def main():
|
||||
# baseline-residue 真·变异残留(与 HEAD 也不同)⇒ 1
|
||||
# baseline-stale 底本过期(与 HEAD 相同)⇒ 0,但**必须让读者看见**
|
||||
# baseline-unrunnable 跑不了 sha256sum ⇒ 2(没读数)
|
||||
# baseline-absent 没有 baseline.sha ⇒ 0(这是可接受的配置)
|
||||
# baseline-deleted `baseline.sha` **受跟踪却被删** ⇒ 1(缺文件,不是配置)
|
||||
# baseline-absent **本来就没跟踪它** ⇒ 0,但**必须说话**
|
||||
#
|
||||
# ★★ `baseline-deleted` 与 `baseline-absent` 是这一轮(pi 2026-09-18)新分出来的:
|
||||
# `baseline-absent` 原来同时是"**关掉残留检测**"的开关 —— 一个 `rm` 就能让
|
||||
# 残留仍在、而唯一能报告它的那条红**整条消失**(实测 `red 10→9`、`rc=0`、静默)。
|
||||
# ⇒ 按本仓反复立的那条口径分家:**"检查了、结论无害"**(`baseline-stale`)
|
||||
# 与 **"根本没检查"**(`baseline-absent`)**不该同格**;
|
||||
# 而"受跟踪却被删"更重一档 —— 它连"配置"都不是,是**缺文件**。
|
||||
if blind:
|
||||
print('RESULT mutants=NO-READING ran=NO-READING skipped=NO-READING '
|
||||
'on_new_criteria=NO-READING diag=counts-unusable'
|
||||
@ -385,7 +437,10 @@ def main():
|
||||
# 与 `baseline-unrunnable` 同类 —— **没读数**,不是"有残留"。
|
||||
if blind or unreadable or bl_diag in ('baseline-unrunnable', 'baseline-unknown'):
|
||||
return 2
|
||||
if unlisted or ghosts or bl_diag == 'baseline-residue':
|
||||
# ★ `baseline-deleted` 归 **1**(pi 建议):`baseline.sha` 是**受版本控制**的,
|
||||
# "跟踪着却不在工作树里"就是 ` D` —— 该改的是**仓库/数据**(把它恢复),
|
||||
# 不是环境、也不是"没读数"。与 `manifest-mismatch` 同类(都是"清单/数据该修")。
|
||||
if unlisted or ghosts or bl_diag in ('baseline-residue', 'baseline-deleted'):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user