feat(criteria): 文件名不得是"句子里的一段" —— 我为**自己制造的**那个化石加守

## 我制造了什么(本会话 `34bcd3e9` 那轮,实测复现)

```
我在 bash 里写了一句带嵌套未转义双引号 + 裸 `>` 的说明:
   echo "  ⇒ 所以"mtime > 动作时刻是**必要但不充分**,且会被**后人无关的写**覆盖""
bash 把 `>` 读成**重定向** ⇒ **在仓库根建了一个文件**:
   文件名 = `动作时刻是**必要但不充分**,且会被**后人无关的写**覆盖`
   内容   = `  ⇒ 所以mtime`(18 字节)
⇒ 我在检查工作树时看到 `?? "动作时刻是…"` 才发现的。
  用 /tmp 里的最小复现验证到**同名同内容** ⇒ 确认是我的 shell 引号事故,不是别人的。
```

## 为什么值得一条判据(它会被提交)

```
· 未跟踪文件**不会**被普通 `git add <path>` 带上 ⇒ 平时看不见、不会被门禁提醒;
· 但本仓**明文记录过 `git add -A` 事故**(`docs/DEV-TOOLING.md`: 含把约 7000 行重排扫进功能提交那次)
  ⇒ 下一次 `-A` 就会把这个"句子文件"带进历史,而**进了历史就永远删不干净**;
· 它的**名字本身就说明它是无意的** —— 没有人的文件名会是"…且会被**后人无关的写**覆盖"。
```

## 判据(零先例实测 ⇒ 不误伤)

```
仓库内(排除 node_modules/.git/build/release/dist/.hvigor/.codegraph/oh_modules)
  不得有名字含**中文标点**(,。、!?;:()「」“”《》【】)、**markdown 粗体 `**`**、或**换行**的文件
★ 判**名字的形态**,不判目录 —— 按目录裁豁免正是本仓记过的"给逃逸指路"。
实测先例: 加这条之前全仓命中 **0**(根目录 0、全仓 0)⇒ 不误伤任何现存文件。
```

## 双向变异

```
① 重建那个句子文件名 ⇒ **not ok 10**,逐个点名 ✓(上面就是它抓到的输出)
② 删掉 ⇒ 10/10 绿 ✓
```

## 顺带

```
run-all.mjs 注册条数 9 → **10**(新增 test 必须登记精确条数,本仓约定)
```

★ 这条与我这轮前两条(`fc54a81` 两处排除、`b16c38a` "提到≠发现路径")是**同一族**:
  **"看起来像在表达一件事"的东西被当成了"它就是那件事"** ——
  前两条在判据的**匹配口径**里,这条在**文件名**上(一段散文被当成了路径)。

验证: criteria-hygiene 10/10;drift 自检 64/0;两文件 `node --check` 通过;
现场: 探针已删(`git status` 只剩本提交的两个文件)。
This commit is contained in:
2026-09-25 07:58:36 +08:00
parent 94044011f9
commit c4279a95ce
2 changed files with 56 additions and 1 deletions

View File

@ -869,3 +869,58 @@ test('★ ⑤b 的负向清单在 JS 与 shell 两处都有副本,两份都必
+ ' 而 `redeploy-gateway.sh` **没有** ⇒ 只守前者的话,删掉/写漂 shell 那份不会红,\n'
+ ' 而 shell 那份是**部署当时打印 `ok` 行**所用的文本。');
});
/*
* ★★ 仓库里不得有"**句子里的一段**"当文件名(shell 引号事故的化石)。
*
* ## 为什么存在(我 `34bcd3e9` 那轮亲手制造了一个)
*
* 我在 bash 里写了一句带**嵌套未转义双引号 + 裸 `>`** 的说明文本,形状是:
* echo " ⇒ 所以"mtime > 动作时刻是**必要但不充分**,且会被…覆盖""
* bash 把 `>` 读成**重定向** ⇒ **在仓库根建了一个文件**,文件名是那句话的后半截
* (`动作时刻是**必要但不充分**,且会被**后人无关的写**覆盖`),内容是我 echo 的前半截。
* 实测复现: 同名同内容(`⇒ 所以mtime`,18 字节)。
*
* ## 为什么值得一条判据(不是我手滑,是它会**被提交**)
*
* · 未跟踪文件**不会**被普通 `git add <path>` 带上 ⇒ 平时看不见;
* · 但本仓**明文记录过三次 `git add -A` 事故**(`docs/DEV-TOOLING.md`,含把 7000 行
* 重排扫进功能提交那次)⇒ 下一次 `-A` 就会把这个"句子文件"带进历史,
* 而它**永远删不干净**(进了历史就得改写)。
* · 它的**名字本身就说明它是无意的** —— 人的文件名不会是"…且会被**后人无关的写**覆盖"。
*
* ## 判据(零先例实测 ⇒ 不误伤)
*
* 仓库内(排除忽略目录)**不得有**名字含中文标点、markdown 粗体标记、或换行的文件。
* 实测: 加上这条之前,全仓命中 **0**(根目录 0、全仓 0)⇒ 收紧不误伤任何现存文件。
* ★ 判的是**名字**(形态),不判"哪个目录" —— 按目录裁豁免正是本仓记过的"给逃逸指路"。
*/
test('★ 文件名不得是"句子里的一段"(shell 引号事故的化石;含中文标点/粗体标记)', () => {
// 忽略目录:构建产物与依赖,它们的名字不受本判据约束
const SKIP = new Set(['node_modules', '.git', 'build', 'release', 'dist', '.hvigor', '.codegraph', 'oh_modules']);
const PUNCT = ',。、!?;:()「」“”《》【】';
const bad = [];
const walk = (dir) => {
let entries;
try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return; }
for (const e of entries) {
if (SKIP.has(e.name)) continue;
const full = join(dir, e.name);
if ([...PUNCT].some((c) => e.name.includes(c)) || e.name.includes('**') || e.name.includes('\n')) {
bad.push(relative(REPO_ROOT, full));
}
if (e.isDirectory()) walk(full);
}
};
walk(REPO_ROOT);
assert.deepEqual(bad, [],
`这些**文件名是"句子里的一段"** —— 几乎必然是一次 shell 引号事故留下的化石:\n`
+ ` ${bad.join('\n ')}\n`
+ ' ⇒ 常见成因: `echo "…"某词 > 后半句"` —— 嵌套未转义双引号让 `>` 变成**重定向**,\n'
+ ' bash 于是在该目录**新建一个文件**,名字是那句话的后半截。\n'
+ ' ⇒ 处置: 删掉它;并把说明文本改用 `printf \'%s\\n\'` 或单引号包裹(避免 `>` 被解析)。\n'
+ ' ⚠️ 为什么必须现在删: 未跟踪文件普通 `git add <path>` 带不上,**但它会被 `git add -A` 带上** ——\n'
+ ' 而本仓已记录过三次 `-A` 事故;一旦进了历史,这个名字就永远在那儿了。');
});

View File

@ -138,7 +138,7 @@ const SUITE = [
['test/commit-hygiene.test.mjs', ['--experimental-strip-types', '--no-warnings'], 4],
// 判据目录自身的卫生:读文本必须走 test/lib/read.mjs 的具名入口;
// 非门禁工具必须有**发现路径**;⑤b 负向清单两处副本都要点名同一对失败类
['test/criteria-hygiene.test.mjs', [], 9],
['test/criteria-hygiene.test.mjs', [], 10],
// 用户管理页(P4c 同批):动作↔服务端调用同名 / 门禁只认严格 admin /
// 启停只发 status / 「受限」徽标口径 / 页面零写死色值 / 接线(纯逻辑真被调用)
['test/harmony-admin.test.mjs', ['--experimental-strip-types', '--no-warnings'], 31],