feat(criteria): ⑤b 负向清单的**两处副本**都要有守 —— 关掉我在 4598095 里明确留下的那条尾巴
`4598095` 结尾我写了「§7 那条同类无守…不在这条提交里改」—— 这条把它关掉。 ## 形状(pi `7ec0044a` 指出,我逐条验证) 「已装二进制 = 当前 HEAD —— 不覆盖: ①脏树构建 ②部署后手工替换」这句话有**两份副本**: ``` deploy/check-deploy-drift.mjs `negative` 常量 + 自检格 ← **有守** deploy/redeploy-gateway.sh:480 注释 + `ok` 文案(§7) ← **无守** ``` 实测: ``` grep '已装二进制 = 当前 HEAD' 全仓 ⇒ **只命中 redeploy-gateway.sh 那一行** redeploy-gateway.sh 的 `--self-check` 出现次数 = **0**(参数只有 --skip-tests/--skip-web/--dry-run/--help) ⇒ 同一个动作、同一句"不覆盖"的声明,**一处有守、一处没有** ``` ★ 而**无守的那份恰是部署时打印到屏幕上的那份** —— 读者看到的就是它。 ## 判据 `criteria-hygiene` 新增:两份副本都必须同时点名同一对失败类(`脏树` / `手工替换`)。 **变异验证**(两侧都验): ``` shell 那份删掉"手工替换"(注释与 ok 文案都删)⇒ 该判据 **红**,点名 `redeploy-gateway.sh 未点名「手工替换」` ✓ 恢复 ⇒ 绿 ✓ ``` 固定 8 → **9**,已同步 `run-all.mjs`。 ## 归族 与上一条(发现路径)**同族**: 都防「**声明的副本**没有守卫」。 区别: 上一条防"没人知道工具存在",这一条防"**声明漂了没人知道**"。 ★ pi 的 ⑬″ 判法在这里的用法:先问"这句声明**在 R 内还是 R 外**"—— 「不覆盖②」属于 R 内(该判据确实回答不了内容替换)⇒ 它不是"划出宣称"就能了事, 而是**必须说出来**,所以两处副本都要保住这句话。 验证: `criteria-hygiene` 9/9;`bash -n deploy/redeploy-gateway.sh` 未受影响(本提交没动它)。
This commit is contained in:
@ -777,3 +777,45 @@ test('★ 非门禁工具(deploy/*.sh)必须有发现路径(至少一处
|
||||
+ ' 会让工具从"强制被调用"掉到"零引用",而**上一条判据正好不再覆盖它** ——\n'
|
||||
+ ' 改名这个合规动作本身制造了一个无判据的盲区。');
|
||||
});
|
||||
|
||||
/*
|
||||
* ★★ 同一断言在两处各有一份副本时,**两份都要有守**(pi `7ec0044a` 指出,我验证)。
|
||||
*
|
||||
* 背景:⑤b("已装二进制 = 当前 HEAD")这句话出现在**两个文件**里 ——
|
||||
* · `deploy/check-deploy-drift.mjs` 的 `negative` 常量(+ 它的自检格)
|
||||
* · `deploy/redeploy-gateway.sh` 的注释与 `ok` 文案(§7)
|
||||
* 而**只有前者有自检**。实测:
|
||||
* grep '已装二进制 = 当前 HEAD' 全仓 ⇒ **只命中 redeploy-gateway.sh 那一行**
|
||||
* redeploy-gateway.sh 的 `--self-check` 出现次数 = **0**
|
||||
* ⇒ 同一个动作、同一句"不覆盖"的声明,**一处有守、一处没有**。
|
||||
*
|
||||
* ⇒ 判据: **两份负向清单必须同时存在,且都点名同一对失败类(脏树 / 手工替换)**。
|
||||
* 为什么不能只查一份: 删掉 shell 那一份、或它漂成只写一项,**没有任何东西会红** ——
|
||||
* 而读者看到的 `ok` 行正是 shell 那份(那是部署时**打在屏幕上**的那份)。
|
||||
* ⚠️ 这与上一条(发现路径)同族: 都防"**声明的副本**没有守卫"。
|
||||
* 区别: 上一条防"没人知道工具存在",这一条防"**声明漂了没人知道**"。
|
||||
*/
|
||||
test('★ ⑤b 的负向清单在 JS 与 shell 两处都有副本,两份都必须点名同一对失败类', () => {
|
||||
const JS = join(REPO_ROOT, 'deploy', 'check-deploy-drift.mjs');
|
||||
const SH = join(REPO_ROOT, 'deploy', 'redeploy-gateway.sh');
|
||||
|
||||
// 每一份都必须同时点出这两类(正是它们**不被**该判据覆盖)
|
||||
const CLASSES = ['脏树', '手工替换'];
|
||||
const missing = [];
|
||||
for (const [name, p] of [['check-deploy-drift.mjs', JS], ['redeploy-gateway.sh', SH]]) {
|
||||
const src = prose(p);
|
||||
for (const c of CLASSES) {
|
||||
if (!src.includes(c)) missing.push(`${name} 未点名「${c}」`);
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(missing, [],
|
||||
`⑤b 的负向清单有副本没写全(**副本漂了,而它恰好是屏幕上看的那份**):\n`
|
||||
+ ` ${missing.join('\n ')}\n`
|
||||
+ ' ⇒ 这两类的**唯一**呈现处就是这两份文案;漏掉一类 ⇒ 读者会把绿读成"没问题":\n'
|
||||
+ ' · 脏树构建(含未提交代码,只披露不判红)\n'
|
||||
+ ' · 部署后被手工替换/修改(只看内嵌 revision)\n'
|
||||
+ ' ⚠️ 为什么两处都要守: `check-deploy-drift.mjs` 有 `--self-check`,\n'
|
||||
+ ' 而 `redeploy-gateway.sh` **没有** ⇒ 只守前者的话,删掉/写漂 shell 那份不会红,\n'
|
||||
+ ' 而 shell 那份是**部署当时打印 `ok` 行**所用的文本。');
|
||||
});
|
||||
|
||||
@ -137,8 +137,8 @@ const SUITE = [
|
||||
['test/debt-visibility.test.mjs', [], 1],
|
||||
['test/commit-hygiene.test.mjs', ['--experimental-strip-types', '--no-warnings'], 4],
|
||||
// 判据目录自身的卫生:读文本必须走 test/lib/read.mjs 的具名入口;
|
||||
// 以及非门禁工具必须有**发现路径**(躲开 check-* 约定改名 ⇒ 否则零引用无人知)
|
||||
['test/criteria-hygiene.test.mjs', [], 8],
|
||||
// 非门禁工具必须有**发现路径**;⑤b 负向清单两处副本都要点名同一对失败类
|
||||
['test/criteria-hygiene.test.mjs', [], 9],
|
||||
// 用户管理页(P4c 同批):动作↔服务端调用同名 / 门禁只认严格 admin /
|
||||
// 启停只发 status / 「受限」徽标口径 / 页面零写死色值 / 接线(纯逻辑真被调用)
|
||||
['test/harmony-admin.test.mjs', ['--experimental-strip-types', '--no-warnings'], 31],
|
||||
|
||||
Reference in New Issue
Block a user