修复: SELFTESTS 接线防线只认一种写法 —— 箭头/async/带空格三种形式**既不跑也不报警**

pi 2026-09-18 报的。**成立,我实测复现**;这是 `765b77e` 新加那道防线**内部**的缺口。

## 一、缺陷:防线的正则只认一种写法

原实现内联了一条 `^function (\w*SelfTest)\(\)`。四种写法实测:

| 写法 | 是否被扫到 |
|---|---|
| `function fooSelfTest() {}` | **✓** |
| `const fooSelfTest = () => {}` | **✗ 漏** |
| `async function fooSelfTest() {}` | **✗ 漏** |
| `function fooSelfTest (a) {}`(名后有空格) | **✗ 漏** |

端到端后果(我复现):插一个**箭头形式**的未接线自检,其 body 若跑会打 RED ⇒
body 的 RED **0 次**(没跑)、报警 **0 条**(也没说"没接线")⇒ **既不跑、也不报警**。
而这正是这条防线**自己存在的理由**("防写了自检却没接线"):
它对**一种写法**有效,对另一种**沉默**。

⚠️ 我第一遍数"报警次数"时得到 **1**,差点当成"它报了" ——
那 1 次命中的是成功报文里的 `(无"写了没接线")`,**是同一句话的另一个方向**。
精确判据要看 `^RED ` 行:**0 条**。**数命中 = 数到的是词,不是行为。**

## 二、修法:唯一实现 + 反面对照

1. 抽出 `declaredSelfTests(code)`,**唯一实现**,覆盖常见写法:
   `^[ \t]*(?:async\s+)?function\s+(\w*SelfTest)\s*\(` 与
   `^[ \t]*const\s+(\w*SelfTest)\s*=\s*(?:async\s*)?\(?`。
2. **反面对照**(pi 建议,我照做):5 种合成样本要求**每种都被认出**;
   另加反方向"收进了不以 `SelfTest` 结尾的名字"。
   样本与生产扫描调的是**同一个函数**(不抄副本)。
3. 成功报文带上"发现规则在 N 种写法上都有对照",让覆盖数**看得见**。

## 三★ 我修的时候引入过一个更坏的机制,实测后回退了

我第一版为"别咬到字符串里的同名文字"加了 `stripStrings`。**实测它更坏**:
`read.mjs` 自己写明 `stripStrings` **不区分正则字面量**,一个**不配对**的引号就能把
后面一大段当字符串吞掉,方向是**假绿**。实测插一条 `const QUOTE_RE = /["']/;`
在自检声明之前 ⇒ 后面**所有真声明消失** ⇒ 未接线的 `hiddenSelfTest` **静默漏掉**,
而 5 个真函数反过来变成"幽灵"(报红,但**报的是错的那件事**)。
⇒ 为防"假红"引入了"假绿 + 误报",**不划算**。已回退为只用 `stripComments`
(代价仅是"字符串里恰好写着 `function xSelfTest()` 会假红"——
按本仓口径:**假红是噪音,假绿是绕过**,选噪音)。回退后复测:那个陷阱消失(`hiddenSelfTest` 被抓)。

## 四、变异验证(都已还原)

| 变异 | 结果 |
|---|---|
| **M40** 箭头形式的未接线自检(**pi 报的那条**) | **红**:`写了但没接线:arrowSelfTest` |
| **M41** `async function` 形式 | **红**:指名 `asyncSelfTest` |
| **M42** 名后有空格 | **红**:指名 `spaceSelfTest` |
| **M43** 发现规则**退化回窄正则** | **红**:`认不出…箭头函数、async function、名与括号间有空格、const = async (…`(⇒ 样本真的会红,不是摆设) |
| **M44** 发现规则**过宽**(连 `applyMutants`/`verdictOf` 都收) | **红**:`收进了不以 SelfTest 结尾的名字:…` + 幽灵清单 |
| 不配对引号的正则字面量(`stripStrings` 陷阱) | 回退前**静默漏掉**;回退后**红** |

## 五、验证与状态

· 五个自检单独跑仍全 rc=0;默认跑 `checks=459 pass=455 fail=4 skip=0 red=9 … verdict=red`、
  `mutants=48 ran=47 skipped=1 on_new_criteria=35 diag=none baseline=7/7✓`;
  自检段新增"发现规则在 5 种写法上都有对照"。
· 耗时 ~5162ms(与 `765b77e` 的 ~4917ms 同量级)。
· 残留全清;`git status` 仅本文件;`HEAD=765b77e`。
This commit is contained in:
2026-09-18 07:18:32 +08:00
parent 765b77ea06
commit 957ec5ec77

View File

@ -742,6 +742,36 @@ function hdcServerLooksHealthy() {
/** 探针结论 → 是否等于"前提成立(到期)" */
/*
* ★★ **自检函数的发现规则** —— 唯一实现,供 `SELFTESTS` 接线防线与它自己的自检共用。
*
* ★ 为什么要有这个函数(pi 2026-09-18 实测报的覆盖缺口):
* 第一版直接内联了一条正则 `^function (\w*SelfTest)\(\)`,**只认一种写法**。
* 实测四种:
* · `function fooSelfTest() {}` ⇒ ✓ 认出
* · `const fooSelfTest = () => {}` ⇒ ✗ 漏
* · `async function fooSelfTest() {}` ⇒ ✗ 漏
* · `function fooSelfTest (a) {}`(名后有空格) ⇒ ✗ 漏
* 端到端后果(我复现):插一个**箭头形式**的未接线自检,其 body 若跑会打 RED ⇒
* · body 的 RED 出现 **0 次**(没跑)
* · 报警 **0 条**(也没说"没接线")
* ⇒ **既不跑、也不报警 —— 静默。** 而这正是这条防线**自己存在的理由**
* ("防写了自检却没接线"):它对**一种写法**有效,对另一种沉默。
*
* ⇒ 放宽成"名字以 `SelfTest` 结尾的函数式声明",覆盖几种常见写法。
* ★ 但它**自己**也会有看不见的写法 ⇒ 下面配一条**反面对照自检**:
* 拿这些写法做合成样本,要求**每一种都被认出**(否则下次放宽又会漏)。
* ⇒ 所以匹配规则**只有这一份**,样本与生产扫描调的是同一个函数
* (本仓反复消的"同一个事实多份实现")。
*/
function declaredSelfTests(code) {
const names = new Set();
// `function 名(` / `async function 名(`(名字与括号之间允许空格)
for (const m of code.matchAll(/^[ \t]*(?:async\s+)?function\s+(\w*SelfTest)\s*\(/gm)) names.add(m[1]);
// `const 名 = (` / `const 名 = async (` / `const 名 = () =>`
for (const m of code.matchAll(/^[ \t]*const\s+(\w*SelfTest)\s*=\s*(?:async\s*)?\(?/gm)) names.add(m[1]);
return [...names].sort();
}
const probeIsDue = v => v === true || v === 'unknown';
/*
@ -2310,8 +2340,54 @@ let selfCheckRuns = 0;
* 将来谁再加第 6 个自检却忘了登记,这里立刻红 —— 不必等人去 `grep` 调用方。
* 用 `prose`/`stripComments`(本仓既有读取器),不自己搓正则。
*/
const selfSrc = stripComments(prose(fileURLToPath(import.meta.url)));
const declared = [...selfSrc.matchAll(/^function (\w*SelfTest)\(\)/gm)].map(m => m[1]);
/*
* ★★ **只用 `stripComments`,不加 `stripStrings`** —— 这是我实测后**回退**的一步,理由必须留下。
*
* 我第一版为"别咬到字符串里的同名文字"加了 `stripStrings`。实测它**更坏**:
* `read.mjs` 自己写明 `stripStrings` **不区分正则字面量**,一个**不配对**的引号就能
* 把后面一大段当字符串吞掉(方向是**假绿**)。实测插一条 `const QUOTE_RE = /["']/;`
* 在自检声明之前 ⇒ 后面**所有真声明都消失** ⇒ 未接线的 `hiddenSelfTest` **静默漏掉**,
* 而 5 个真函数反过来变成"幽灵"(报了红,但**报的是错的那件事**)。
* ⇒ 为了防"假红"引入了一个"假绿 + 误报"的机制,**不划算**。
*
* 只用 `stripComments` 时的代价只是"字符串里若恰好写着 `function xSelfTest()` 会**假红**"——
* 而按本仓口径,**假红是噪音,假绿是绕过**。选噪音。
*/
const declared = declaredSelfTests(stripComments(prose(fileURLToPath(import.meta.url))));
/*
* ★★ **反面对照:发现规则自己的覆盖**(pi 建议的那条,我照做)。
*
* 为什么必须有:放宽正则这件事**自己就会再漏一种写法** —— 我们这轮踩的就是
* "守着一个格子的判据,对另一种写法沉默"。所以这里拿**合成样本**要求
* **每一种常见写法都被认出来**,而不是"我以为它认得"。
* ⇒ 样本与生产扫描调的是**同一个** `declaredSelfTests`(不是抄一份)。
*/
const FORM_SAMPLES = [
['function 声明', 'function fooSelfTest() {}\n'],
['箭头函数', 'const fooSelfTest = () => {};\n'],
['async function', 'async function fooSelfTest() {}\n'],
['名与括号间有空格', 'function fooSelfTest (a) {}\n'],
['const = async (…', 'const fooSelfTest = async (a) => {};\n'],
];
const missed = FORM_SAMPLES.filter(([, src]) => !declaredSelfTests(src).includes('fooSelfTest'));
if (missed.length) {
console.log(`RED 发现规则认不出这些写法(⇒ 那种写法写了自检也不会被接线防线看见):`
+ missed.map(([w]) => w).join('、'));
}
if (missed.length) {
reds.push(`(自检)\`declaredSelfTests\` 认不出:${missed.map(([w]) => w).join('、')}`
+ ' —— 写了那种形式的自检会**既不跑也不报警**');
}
/*
* ★ 反方向:**合成样本之外**,真源码里也要求"认出来的名字都在 SELFTESTS 或确实被调用"。
* 这里只做一个廉价的一致性检查:认出来的集合里,凡不以 SelfTest 结尾的都不该进来。
*/
const badName = declared.filter(n => !/SelfTest$/.test(n));
if (badName.length) {
console.log(`RED 发现规则收进了不以 \`SelfTest\` 结尾的名字:${badName.join('、')}`);
reds.push(`(自检)\`declaredSelfTests\` 收进了不符合命名约定的名字:${badName.join('、')}`);
}
const wired = new Set(SELFTESTS.map(([, fn]) => fn.name));
const unwired = declared.filter(n => !wired.has(n));
const phantom = [...wired].filter(n => !declared.includes(n));
@ -2327,7 +2403,8 @@ let selfCheckRuns = 0;
if (!unwired.length && !phantom.length) {
console.log(`自检段:${SELFTESTS.length} 个自检已在**默认路径**内跑过`
+ `(${SELFTESTS.map(([n]) => `--${n}`).join('、')});`
+ `源码里 ${declared.length} 个 \`*SelfTest\` 函数**全部**在册(无"写了没接线")`);
+ `源码里 ${declared.length} 个 \`*SelfTest\` 函数**全部**在册(无"写了没接线");`
+ `发现规则在 ${FORM_SAMPLES.length} 种写法上都有对照`);
}
}