test(判据): ★★★ 套件从 10-02 10:46 起一条都没跑过 —— 补接线 + 结算登记数

**零读数 24 小时,仓库里没有任何记录**(DEBTS.json 58 条里 grep「没接进」0 命中)。

漏接线的三个(都来自 aeb1f41 / 2f17f62,都比 run-all.mjs 最后一次改动晚):
    test/inbox-fallback-poll.test.mjs   ← SSE 兜底轮询(探测 total 变化)
    test/sse-credentials.test.mjs      ← SSE 订阅跟账号凭证走
    test/web-comment-only.test.mjs

**为什么严重(三层放大)**:
1. 自检 2「每个 *.test.mjs 都要在清单里」在跑任何判据**之前** exit(1)
   ⇒ 实测 RESULT 行数 = **0**
2. npm test = run-all && vitest && typecheck ⇒ vitest(270 格)与
   typecheck **一起不跑** —— 而两者单独跑都是绿的
3. 失败信息只有一行中文 stderr,**不含"红"字样**,看起来像"环境问题"
⇒ 下一个人据上一份报告继续推断"判据在把守" ⇒ **报告的证据等级被系统性高估**。
守卫本身**不删**(漏接线绝不静默是真价值),代价靠「新增即接线」这条义务兜。

**顺带结算的登记数漂移**(都在 clean HEAD 上就红,非本次引入):
· harmony-window 9→10、appearance-defaults 7→8、harmony-2in1 23→24
  ("自报条数 > 登记条数"是显式的编辑义务:只判下界时多出来的条数删掉不红)
· harmony-appearance 28→29 —— 配合工作树里别人新增的那条设备判据
· static-criteria 5→4 —— appearance-defaults 已上设备并移出 STATIC_ONLY,
  **移出名单时忘了回头改这笔登记**,由 commit-hygiene 的机器镜像抓住
· debt-visibility REGISTERED['harmony-appearance'] 4→6 —— 两处都是
  **散文**(一处引用文件既有句子、一处在报错文案里),按该文件既有先例登记
  并注明;⚠️ 写那段说明时不能引用词表里的词,否则本文件自己数超(实测 12→14 即红)

**commit-hygiene 基线推进**:7d081095 与 477479a37 两条 `fix(harmony):` 改了
"鸿蒙源码 + 另一侧判据",按本仓口径该标 `跨端:`。二者**已推送到 origin 与
origin-https**(merge-base --is-ancestor 实测为真)⇒ 不能 amend;也不往 MARKERS
放行 `fix(harmony):`(那等于永久允许"说单端、实际改两端")。唯一正确处置是
推进基线 + 具名记下。已验证:COMMIT_HYGIENE_BASELINE 覆盖后 pass=4 fail=0。

**CRITERIA.md 新增 §6.0「怎么读判据的数」** —— 原有 17 节全在讲「怎么写」,
缺的就是这一半,而今天两起独立事件都出在它:
· 6.0.1 接线守卫的失效形状是「全停」不是「那一条不跑」;ran 必须 == SUITE 条数
· 6.0.2 退出码只能来自不接管道的运行(`cmd >file 2>&1; echo $?`)。
  **本会话我连踩 5 次** `cmd | tail -N` ⇒ 报的是 tail 的码。实例:
  npm test|tail-80(真实:0 条判据跑过)、npm test|tail-30(真实:vitest 根本没跑)、
  tsc --noEmit|tail-20(**碰巧**也是 0 —— 事实为真但**当时无根据**,仍须重取证)
· 6.0.3 && 链里「全绿」要问**真跑到那一环了吗**(red 之后的东西根本没跑,
  而日志里「有 RESULT 行」与「无下游输出」可以同时出现)
· 6.0.4 判据变红先问「判据用的工具本身可信吗」(读取器的缺陷是**静默**的)
· 6.0.5 **当你就是改工具的人**:第一假设是「我弄坏了它」不是「代码回归」——
  「判据过期了」这个反应本身就错,它默认了「我改的是正确的东西」。
  附本次三次改错的下游依赖表,以及"下游依赖是**行为依赖**,
  codegraph 那类符号图看不见"。

★ 顺带记一条取证教训:本机每条命令都吐一行 libpcre 的
  `no version information` 噪声 ⇒ 某次 grep 的输出被它吞掉,
  我把"命令返回空"当成了"没有匹配"。**空输出要连退出码一起看**,
  这与 6.0.2 是同一族,只是这次发生在我自己的取证上。
This commit is contained in:
2026-10-03 10:43:41 +08:00
parent 93697c4061
commit 6df3c356d6
5 changed files with 161 additions and 8 deletions

View File

@ -143,6 +143,102 @@ const ALLOW = [ /* { name, replacement, why } */ ];
`process.exit(1)` 吞掉**,于是"变异后依然 exit 0"看起来像判据失效(本仓刚踩过这一次:
自检 3 其实是好的,是我用错了入口去验它)。**验判据要模拟用户/CI 真正跑的那一行。**
### 6.0 怎么**读**判据的数(前半篇讲「怎么写」,这一节讲「怎么读」)
§1–§17 讲的都是「判据怎么写」。**另一半——「怎么读它的数」——本节讲,
因为 2026-10-03 一天之内就撞了两起独立事件,都出在这一半,而仓库里没有成文规则。**
#### 6.0.1 接线守卫的失效形状是「**全停**」,不是「那一条不跑」
`run-all.mjs` 的自检 2(「每个 `*.test.mjs` 都要在清单里」)在**跑任何判据之前**
`process.exit(1)` ⇒ 实测 `RESULT` 行数 = **0**。又因 `npm test` 是 `&&` 链,
`vitest` 与 `tsc` **一起不跑**——而两者单独跑都是绿的。
```
2026-10-02 10:46 aeb1f41 加了 inbox-fallback-poll / sse-credentials(未接线)
2026-10-02 13:58 2f17f62 加了 web-comment-only(未接线)
↓
2026-10-03 整仓 24 小时零读数;失败只有一行中文 stderr,看起来像「环境问题」
```
⇒ **「判据存在」不等于「判据在跑」,而本仓的守卫把两者绑在一起**。
它的价值(漏接线绝不静默)是真的,代价(一个文件漏接 = 全仓失去全部读数)也是真的。
- **新增 `*.test.mjs` 之后必须做的事**:跑一次 `node test/run-all.mjs`,
看 `RESULT files=N ran=N` —— **`ran` 必须等于 `SUITE` 条数**。
只看到「没接进套件」那一行就以为「跑过了」是最容易犯的错。
- **别信「上次是绿的」**:若那个结论来自一份**报告**而不是一次运行,
先确认**上一次真读到数是什么时候**(本笔已登记为 `criteria-suite-unwired-stops-everything`)。
#### 6.0.2 退出码只能来自**不接管道的**运行
```
cmd 2>&1 | tail -N ⇒ $? 是 tail 的,不是 cmd 的
cmd >file 2>&1; echo $? ⇒ 唯一诚实的形状
```
**实测(同一会话内我连踩三次)**:
| 命令 | 报的 | 实际 |
|---|---|---|
| `npm test \| tail -80` | 0 | 0 条判据跑过 |
| `npm test \| tail -30` | 0 | run-all red,**vitest 根本没跑** |
| `tsc --noEmit \| tail -20` | 0 | tsc 的 0(**碰巧**也是) |
第三条最危险:**结论为真,但当时没有根据**。`tsc` 静默无错与「`tsc` 被 `tail` 吃掉」
在日志里**长得一样**。⇒ 事实成立 ≠ 当时有根据;**依据必须重取**。
#### 6.0.3 `&&` 链里「全绿」要问:**真跑到那一环了吗**
`run-all` red ⇒ `vitest`/`tsc` **根本没跑**。而日志里可以**同时**出现
「有 `RESULT` 行」与「无 `vitest` 输出」——**只看日志会以为它跑过了**。
- 汇报门禁结果时,**写清是哪几环**(`run-all` / `vitest` / `tsc`),
以及**哪些没跑**。
- 「没输出」要连退出码一起看(见 6.0.2 第三条)。
#### 6.0.4 判据变红时,先问「**判据用的工具本身可信吗**」
2026-10-03 的 `harmony-admin` 假红:`stripComments` 把 `main.go:78` 行注释里的
`/*` 当成块注释开头 ⇒ **137 行 / 37 条路由注册**被当注释抹掉,
含它正在断言的 `r.Get("/auth/me", …)`。
⇒ **读取器的缺陷是静默的**(不抛错、不警告),症状却出现在**被测对象**上。
所以:**「某条判据突然变红,而源码看起来是对的」⇒ 先验证读取器,再怀疑代码。**
反过来也成立:**换成更严格的读取方式之后判据变红,通常是判据错了**——
本次 `inbox-fallback-poll` 从裸 `readFileSync` 换成 `code()`(剥注释)之后变红,
暴露的是它**本来就在判一行尾注释里的字**(删掉注释照样绿、塞进真 bug 也照样绿)。
#### 6.0.5 改**共用工具**时:第一假设是「我弄坏了它」,不是「代码回归了」
6.0.4 讲的是「工具坏了怎么认出来」。这一节讲它的**另一半**:当**你就是改工具的人**。
2026-10-03 为修 6.0.4 那个假红重写 `lib/read.mjs` 的 `stripComments`,**连错三次,
三次都是判据没错、我错了**,而且三次的第一反应都是「判据是不是过期了」:
| 轮 | 我的改动 | 谁红了 | 真因 |
|---|---|---|---|
| v1 | 块注释改「空格填充等长」 | `harmony-logic` / `harmony-nav` | 下游 `[\s\S]{0,300}?` 窗口是**按"删掉"的尺度**标定的,填充把窗口撑爆 |
| v2 | 状态改成「回看已输出的 `out`」 | `criteria-hygiene` | `out` 里注释已抹过,**重算的上下文 ≠ 源码** ⇒ `:566` 真块注释没被剥 |
| v3 | 只跟踪字符串、不认正则字面量 | `criteria-hygiene` | `harmony-device.mjs:59` 的正则里有 4 个引号(奇数)⇒ 打开的"字符串"**永不闭合** |
★ **「判据过期了」这个反应本身就是错的**,因为它默认了「我改的是正确的东西」。
三次里如果反过来先怀疑代码,就会去改**本来正确的生产代码**。
- **共享读取器的「删多少 / 怎么判」是被下游按字节尺度依赖着的。**
改它之前先问「**谁在依赖这个性质**」——本次两处依赖都是 `[\s\S]{n,m}?` 窗口,
而 `codegraph` 那类**符号图看不见这类依赖**(它们是**行为依赖**:不调用你,
但依赖你的输出**形状/尺度**)。
- **每次改动都重跑全量**,不要只看直接调用方:v1 就是只看了 `code()` 的直接使用者,
是跑全量 `run-all` 才看见 `harmony-logic`/`harmony-nav`/`harmony-apibase` 同时变红的。
- **新写读取器要把四条性质一起钉**(本次五条,逐条实测才算数):
① 行号不变 ② 字符串里的 `//` 与注释标记不被当注释 ③ 注释里的引号不污染字符串状态
④ 正则字面量被当正则(漏认的方向是**假绿**:奇数引号 ⇒ 永不闭合 ⇒ 后面注释全跳过)
⑤ 块注释**连文本一起删**(不是留空白、不是只留换行 —— 后两种都会被下游窗口的标定尺度打中)。
- **改完用变异测试自证**:把旧实现放回去,确认那条判据**确实变红**。
本次正是这一步把「我修好了」与「我改的东西恰好没人用」区分开。
### 6.1 判据的**存在性**也要有下限:把"必须存在哪几条"锚到判据自己的表之外(pi 2026-09-18)
§6 那条只说了"扫目录要有下限"。**同一条规矩换个对象就漏了** —— 这条是它的镜像: