From cc8beb79db68c794ca5f0fdc5ade5d3559edd49e Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Fri, 18 Sep 2026 07:19:26 +0800 Subject: [PATCH] =?UTF-8?q?fix(pi-bridge):=20`--self-check`=20=E6=AD=A4?= =?UTF-8?q?=E5=89=8D**=E4=B8=80=E6=AC=A1=E9=83=BD=E6=B2=A1=E5=9C=A8?= =?UTF-8?q?=E7=9C=9F=E5=AE=9E=E8=B7=AF=E5=BE=84=E4=B8=8A=E8=B7=91=E8=BF=87?= =?UTF-8?q?**=20=E2=80=94=E2=80=94=20=E8=87=AA=E6=A3=80=E6=94=B9=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E5=86=85=E3=80=81=E9=BB=98=E8=AE=A4=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=85=88=E8=B7=91=E3=80=81=E9=87=8F=E7=BA=B2=E5=88=86=E4=B8=89?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dsh 2026-09-18 在本插件里实测报的第二例(同一形状:判据存在但不在路径上)。 ## 洞(实测,不是读代码) · `package.json` 的 `npm test` = `env-preflight && run-suite`,**不带 `--self-check`**; `deploy/install.sh` 也是 `npm test`,同样不带;全仓 `--self-check` 零引用, 本插件下**没有任何 .md** 提到它 ⇒ 它从没在真实路径上跑过。 · 实测:把 `findDuplicates` 改成恒返回 `[]` ⇒ **`npm test` 照样 `exit=0`**(带 flag 才红)。 · 后果不是小事:它是**跨文件重名**判据的引擎,而它**唯一**的分辨力判据就是这个自检 ⇒ 引擎哪天退化成恒空,重名判据**安静地永远放行**,而整套测试全绿。 · ⚠️ 判"在不在路径上"**不能 `grep` 数命中**:`grep -c '判据自检'` 在默认跑里得 **16 次**, 全是若干 `.test.mjs` 的**用例名**恰好含这四个字,而 `selfCheck()` 自己的输出 (`^ (通过|失败) `、`干净样本`)**一次都没有**。**数命中 = 数到的是词,不是调用。** ## 修 1. `selfCheck()` 去掉 `process.exit`,改为**返回失败条数**(否则没法进程内调); `--self-check` 那条 CLI 行为不变。 2. **默认路径先跑自检**:坏了就 `exit 3` 并明说"工具坏了、本次结论不可信"。 顺序排在跑套件**之前** —— 引擎坏了时套件那份结论本来就不可信, 而且省一整轮 509 条测试进程。 3. **量纲分三档**(本文件已约定的那套 + 新增一档): `0`=全绿且无重名;`1`=断言失败/发现重名(**代码问题**); `2`=环境;**`3`=判据引擎自己坏了(工具问题)** —— 不复用 `1`, 否则 `install.sh` 会把"引擎坏了"读成"代码有问题"。`install.sh` 本次不动 (它只判"插件装好没有",非零即中止,3 与 1 对它的行为一致;改它的退出码语义是另一件事)。 ## 验证(都跑过) · 干净树:`npm test` rc=**0**,默认路径出现 `判据自检:全部通过。`(此前 0 次)。 · **M**:`findDuplicates → []` ⇒ `npm test` rc=**3** + `判据自检 2 条失败 —— findDuplicates 的分辨力坏了…`。 · **反向对照**:真造一个跨文件重名 ⇒ rc=**1** + 点名 `2× 平台名字正常时派生别名并原样带标题` ⇒ 两个量纲**确实分开**,没把"代码问题"和"工具问题"混成一个码。 · `node --check` 通过;`--self-check` 单独跑 rc=0(行为不变)。 (补 dsh 交回的实测读数:`--self-check` 在干净树 4/4 通过、变异后 2/4 失败、默认跑 0 次。) --- plugins/pi-mail-bridge/test/lib/run-suite.mjs | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/plugins/pi-mail-bridge/test/lib/run-suite.mjs b/plugins/pi-mail-bridge/test/lib/run-suite.mjs index 4e3e557..499787f 100644 --- a/plugins/pi-mail-bridge/test/lib/run-suite.mjs +++ b/plugins/pi-mail-bridge/test/lib/run-suite.mjs @@ -106,6 +106,24 @@ const SELF_CHECK_SAMPLES = [ }, ]; +/** + * 判据自检:拿合成 TAP 样本验 `findDuplicates` 的**分辨力**。 + * + * ★★ 返回失败条数,**不自己 `process.exit`** —— 这样它能在默认路径里被调用。 + * 为什么必须能(pi 2026-09-18 实测报的洞): + * · `package.json` 的 `npm test` = `env-preflight && run-suite`,**不带 `--self-check`**; + * `deploy/install.sh` 也是 `npm test`,同样不带。全仓 `--self-check` 零引用, + * 且本插件下**没有任何 .md** 提到它。 + * · ⇒ 它此前**一次都没在真实路径上跑过**。实测:把 `findDuplicates` 改成恒返回 `[]` + * ⇒ **`npm test` 照样 `exit=0`**(而带 `--self-check` 才红)。 + * · 后果不是小事:`findDuplicates` 是**跨文件重名**那条判据的引擎, + * 而它**唯一**的分辨力判据就是这个自检 ⇒ 它哪天退化成恒空, + * 重名判据会**安静地永远放行**,而整套测试全绿。 + * ⚠️ 判"自检在不在路径上"**不能靠 `grep` 数命中**:本仓库实测 `grep -c '判据自检'` + * 在默认跑里得到 **16 次**,全是若干 `.test.mjs` 的**用例名**恰好含这四个字, + * 而 `selfCheck()` 自己的输出(`^ (通过|失败) `、`干净样本`…)**一次都没有**。 + * **数命中 = 数到的是词,不是调用。** + */ function selfCheck() { let bad = 0; for (const s of SELF_CHECK_SAMPLES) { @@ -118,12 +136,40 @@ function selfCheck() { } } console.log(bad === 0 ? '\n判据自检:全部通过。' : `\n判据自检:${bad} 条失败。`); - process.exit(bad === 0 ? 0 : 1); + return bad; } -if (process.argv.includes('--self-check')) selfCheck(); +// `--self-check`:只跑自检、不跑套件(原有行为不变)。 +if (process.argv.includes('--self-check')) process.exit(selfCheck() === 0 ? 0 : 1); // ── 跑套件 ──────────────────────────────────────────────────────── +/* + * ★★ **默认路径也要先跑自检**(pi 2026-09-18)。 + * + * 顺序要紧:**自检排在跑套件之前**。理由是量纲 —— 自检判的是"引擎的分辨力", + * 套件判的是"代码对不对"。引擎坏了的时候,套件那份结论**本来就不可信**, + * 拿它当主结论是把两件事混在一起(`docs/DEV-TOOLING.md:218` 那条 = 退出码也有量纲)。 + * 而先跑自检还省一整轮测试进程(引擎坏了就没必要跑 509 条)。 + * + * 退出码用本文件已经约定的那一套,并**与套件红分开**: + * 0 = 套件全绿且无重名(且自检通过) + * 1 = 断言失败 / 发现重名(代码问题) + * 2 = 环境(env-preflight 那套)—— 自检失败**不走这一格** + * ★ 自检失败 = **判据本身坏了**,这是"工具问题"而不是"被测代码问题", + * 所以它**不复用 `1`**(那会让 `install.sh` 把"引擎坏了"读成"代码有问题")。 + * 这里用 **3** 表达"这次结论不可信(工具坏了,不是代码坏了)", + * 并在 stderr 里**明说**是哪个量纲 —— 量纲说不清就退化成"又一个红"。 + * (`install.sh` 那侧的退出码语义**本次不动**:它只判"插件装好没有", + * `set -e` 下非零即中止,3 与 1 对它的行为一致;改它的语义是另一件事, + * 且要先想清楚 `install.sh` 该不该为此新增一档。) + */ +const selfCheckBad = selfCheck(); +if (selfCheckBad > 0) { + console.error(`[tap-dup] 判据自检 ${selfCheckBad} 条失败 —— \`findDuplicates\` 的分辨力坏了,` + + '**本次重名判据的结论不可信**(工具坏了,不是被测代码坏了)。'); + process.exit(3); +} + // `--test-reporter=tap` 让报告格式稳定(`--test` 在 TTY 下会自动换格式, // 那样就锚不住结果行)。输出走管道,本进程负责原样转写到 stderr。 const args = ['--test', '--test-reporter=tap', 'test/*.test.mjs'];