From 271e0a8ee4b324a2dad8f3b4cfeeaa41233e42b0 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Sat, 19 Sep 2026 09:45:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=A3:=20**=E5=85=89=E8=BF=9B?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E8=B7=AF=E5=BE=84=E4=B8=8D=E5=A4=9F=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E7=BB=93=E8=AE=BA=E5=BF=85=E9=A1=BB?= =?UTF-8?q?=E5=88=B0=E5=BE=97=E4=BA=86"=E5=86=B3=E5=AE=9A=E9=A2=9C?= =?UTF-8?q?=E8=89=B2=E7=9A=84=E9=82=A3=E4=B8=80=E6=A0=BC"**=EF=BC=88=C2=A7?= =?UTF-8?q?16.1=EF=BC=8C=E5=90=8C=E4=B8=80=E6=9D=A1=E7=BC=9D=E7=9A=84?= =?UTF-8?q?=E4=B8=89=E4=B8=AA=E8=90=BD=E7=82=B9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pi 顺第一/二例的线实测出**第三例**,与我在 `4b841e0`/`6ee9902` 修的那两例 **是同一句话的第三次出现**,而 `CRITERIA.md` 里**一个字都没有** —— 修复在代码里、形状没进规范 ⇒ 下一个人只会修好其中一例。本节补上。 ## 缝的形状(三次都一样) > `summary.py` 把结论说对了、退出码也说对了,**但没有一条通道把它送到 > "决定 `verdict` 的那一格"** ⇒ 读者看到的是一个**看着完全正常**的读数。 ## 三个落点(每次位置都不同,所以必须分开记) | # | 落点 | 现象 | 修法 | |---|---|---|---| | 1 | **正则匹配就走不到 `status`** | 盲读时照样打 `RESULT mutants=0 …`(匹配)⇒ `status=2` 从没被读;`sp.stdout` 全文件只一处引用 ⇒ 三行 `✗✗` 一个字都到不了读者 | 盲读改打 `NO-READING` + **先判 `status`** | | 2 | **部分可读**(`chmod 000` 单个 job) | `blind` 为假、数字是真算的 ⇒ 那行**匹配正则且看着正常** ⇒ 修法①**对它无效** | 只有**先判 `status`** 兜得住 ⇒ 两层**各治一例**,不是叠保险 | | 3 | **`unlisted`/`ghosts` 退 0** | 警告已算出,却被 `whyLines: status !== 0 ? whyLines : []` **丢掉** ⇒ 磁盘 13 个 job、套件报 48、"未列入清单"在套件输出 grep **0** 次 | 退出码按**性质**分:`unlisted`/`ghosts`⇒**1**(清单该改=数据)、`blind`/`unreadable`⇒**2**(权限=环境);转印放宽成 `(note \|\| status !== 0)` | ★ **第 3 例的尖处**:`unlisted`/`ghosts` **不是**环境问题,是**清单该改**。 按 `env-defaults.sh:25`"失败要说清是环境问题…不要让它冒充代码缺陷" —— **反向也成立**: **别让"清单没跟上"冒充环境**。故归 **1** 不归 **2**。 ## ★★ 为什么会连着踩三次 三例的**上游判别都做对了**(`unlisted` 算出来了、`blind` 判出来了、`unreadable` 分出来了), 错的全在**最后一跳到 `verdict`**。⇒ 通用规则: > **每加一条"发现问题就报告"的逻辑,都要问一句: > 它的结论最终喂给了哪一个决定颜色的变量?** > 只 `print` 不算到达;落到 `reds`/`brokens`/`dueFailed`/`selfCheckFailed` 之一, > 或让退出码变成下一层会读的那个值,才算。 ## 验证 · **已锁住**:`--exitcode-selftest` 有真跑案例(`['未列入清单 ⇒ 1', …]`,`:1062`)、 `--verdict-selftest` 有判定案例(`['manifest-mismatch(status 1)⇒ 不许绿', …]`,`:1976`)。 · **变异验证**:把 `unlisted or ghosts` 从 `return 1` 改回 `return 0` ⇒ `--only-selftest=exitcode-selftest` **rc=1、2 条可归因红** (`未列入清单 ⇒ 1:rc=0(期望 rc=1 … UPSTREAM_RC[manifest-mismatch]=1 与真跑出来的 rc=0 不符)`)。 ⇒ 这条缝**有判据守着**,不靠下一个人再读一遍源码。 · **端到端 A/B**(干净 worktree,同刻对照): | | A:12 文件(清单一致) | B:13 文件(1 个未列入清单) | |---|---|---| | `diag=` | `baseline-stale` | **`manifest-mismatch`** | | "未列入清单" 在套件输出 | grep **0** | grep **1** | | `(summary.py)manifest-mismatch` 红 | **0** | **1** | · 本提交**只改文档**:`client/electron/test/CRITERIA.md`(新增 §16.1);隔离 worktree 跑全套 `^RED=0`。 --- client/electron/test/CRITERIA.md | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/client/electron/test/CRITERIA.md b/client/electron/test/CRITERIA.md index 92e8455..7ae0d4d 100644 --- a/client/electron/test/CRITERIA.md +++ b/client/electron/test/CRITERIA.md @@ -790,6 +790,54 @@ Go 在同一包内**按源文件顺序**跑测试 ⇒ 登记那条先跑就读 **配套动作(pi 2026-09-14)**:写完一处"要提醒人的输出"之后, **去看一眼默认路径的输出** —— 不是看代码,是看它实际打出来的样子。 +### 16.1 ★★ 光进默认路径不够:**结论必须到得了"决定颜色的那一格"**(dsh + pi 2026-09-18) + +§16 管的是"**打印**有没有走默认路径"。这一条管的是它**下一跳**:输出打了, +但**决定套件颜色的那一格没读它** ⇒ 等于没打。**同一条缝在本仓已出现三次**, +每次位置都不同,所以必须分开记 —— 否则下一个人只会修好其中一例。 + +**缝的形状**(三次都一样): + +> `summary.py` 把结论说对了、退出码也说对了,**但没有一条通道把它送到 +> "决定 `verdict` 的那一格"** ⇒ 读者看到的是一个**看着完全正常**的读数。 + +**三个落点**: + +| # | 落点 | 现象 | 修法 | +|---|---|---|---| +| 1 | **正则匹配就走不到 `status`** | 盲读时 `summary.py` 照样打 `RESULT mutants=0 …`(匹配)⇒ `status=2` 从没被读;`sp.stdout` 全文件只一处引用 ⇒ 那三行 `✗✗` 一个字都到不了读者 | `summary.py` 盲读改打 **`NO-READING`**(不匹配)+ run-all **先判 `status`** | +| 2 | **部分可读**(`chmod 000` 单个 job) | `blind` 为假、数字是真算的 ⇒ 那行**匹配正则且看着正常** ⇒ 修法①**对它无效** | 只有**先判 `status`** 能兜住 ⇒ 两层修法**各治一例**,不是叠保险 | +| 3 | **`unlisted`/`ghosts` 退 0** | 警告行**已算出来**,却被 `whyLines: status !== 0 ? whyLines : []` **丢掉** ⇒ 磁盘 13 个 job、套件报 48、"未列入清单"在套件输出 grep **0** 次 | 退出码按**性质**分:`unlisted`/`ghosts`⇒**1**(清单该改=数据);`blind`/`unreadable`⇒**2**(权限=环境);并放宽转印为 `(note \|\| status !== 0)` | + +★ **第 3 例的正反两面**(这是它比前两例尖的地方): +`unlisted`/`ghosts` **不是**环境问题,是**清单该改**。按 `env-defaults.sh:25` +"失败要说清是环境问题…不要让它冒充代码缺陷" —— **反向也成立**: +**别让"清单没跟上"冒充环境**。所以第 3 例归 **1** 不归 **2**。 + +★★ **为什么会连着踩三次**:这三例的**上游判别都做对了** +(`unlisted` 算出来了、`blind` 判出来了、`unreadable` 分出来了), +错的全在**最后一跳到 `verdict`**。⇒ 通用规则: + +> **每加一条"发现问题就报告"的逻辑,都要问一句: +> 它的结论**最终喂给了哪一个决定颜色的变量**?** +> 只 `print` 不算到达;要落到 `reds`/`brokens`/`dueFailed`/`selfCheckFailed` 之一, +> 或者让退出码变成下一层会读的那个值。 + +★ 已锁住:`--exitcode-selftest` 有真跑案例(`['未列入清单 ⇒ 1', …]`,`:1062`)、 +`--verdict-selftest` 有判定案例(`['manifest-mismatch(status 1)⇒ 不许绿', …]`,`:1976`)。 +**变异验证**(dsh):把 `unlisted or ghosts` 从 `return 1` 改回 `return 0` +⇒ `--only-selftest=exitcode-selftest` 立刻 **rc=1、2 条可归因红** +(`未列入清单 ⇒ 1:rc=0(期望 rc=1 … UPSTREAM_RC[manifest-mismatch]=1 与真跑出来的 rc=0 不符)`)。 +⇒ 这条缝**有判据守着**,不靠下一个人再读一遍源码。 + +**端到端 A/B**(dsh,干净 worktree,同刻对照): + +| | A:12 文件(清单一致) | B:13 文件(1 个未列入清单) | +|---|---|---| +| `diag=` | `baseline-stale` | **`manifest-mismatch`** | +| "未列入清单" 在套件输出 | grep **0** | grep **1** | +| `(summary.py)manifest-mismatch` 红 | **0** | **1** | + ## 17. 变异只证明「注入的样本被抓」,**不证明完备性**;判据的**标签必须等于断言范围** **规则**(pi 2026-09-14):一条判据通过变异验证之后,只能说"我注进去的那一条会被抓"。