pi 2026-09-14:§16 一直是"靠记得问"的纪律,按 §15 它该有判据;这是同一形状的**第五次**, 这次落在规则自己身上。 新判据 `test/debt-visibility.test.mjs`(三支,均已变异验证): 1. **出现次数必须与登记一致**:某文件里新多出一处边界声明 ⇒ 红, 报错按 §14 写「正确修法(先补一笔余额,再改次数)」与 「最常见的错误修法(只把数字调大/把声明删掉)」。变异:给 harmony-logic 加一处 ⇒ 红。 2. **每一笔余额必须带到期前提与位置** ⇒ 变异:清空 static-criteria 的 due ⇒ 红 (「那不是欠账,是"我们知道"」)。 3. **有边界声明的文件必须被某笔余额的 where 引用**(两处挂钩,不是各写各的)。 **自指豁免**(按文件 + 理由):本文件**定义**了那套措辞,用自己定义的词表数自己是无意义的 —— 而且它**第一次跑就把自己抓出来了**(11 处),证明计数是活的,不是走过场。 顺带把 `static-criteria` / `observability-output` 的 `where` 与具体文件挂钩(5 个静态判据文件)。
90 lines
5.1 KiB
JavaScript
90 lines
5.1 KiB
JavaScript
import { test } from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import { readdirSync } from 'node:fs';
|
||
import { dirname, join } from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
import { prose } from './lib/read.mjs';
|
||
|
||
/*
|
||
★ 边界声明必须**同时进余额**(默认路径可见)—— 把 §16 本身变成判据(pi 2026-09-14)。
|
||
|
||
§16 原文是「"要提醒人的"输出必须走默认路径」。它一直是**靠记得问**的一条纪律 ——
|
||
而这轮我们已经确认过四次同一形状:**"我知道一个边界" → 写进注释/标签/信里 →
|
||
那个位置在默认路径上等于不存在**(余额打在 TestMain、权威源写在信里、overlay 边界写在注释里、
|
||
两条未覆盖的路写在判据标签里)。第五次它落在了**规则自己**身上:写在 CRITERIA.md 里的规则,
|
||
没有任何东西在判它被执行。
|
||
|
||
所以这条判据就是 §16 的可判形态:**凡在判据目录里声明"未覆盖 / 未验 / 已知缺口"的地方,
|
||
必须在 `docs/DEBTS.json` 里有一笔**(那里是默认路径可见的余额)。
|
||
|
||
登记方式与其它清册同形:**按文件 + 出现次数**(次数写死在这里,多一处即红),
|
||
且该文件必须被余额里的某一笔 `where` 引用到。
|
||
|
||
报错照 §14 写"正确修法 + 最常见的错误修法":正确修法是**把边界登记成一笔欠账**
|
||
(余额里可见、有到期前提),**不是**把下面这个数字 +1。
|
||
*/
|
||
|
||
/** 会被当作"边界声明"的措辞(新增措辞要连同它一起登记,别偷偷放行) */
|
||
const MARKERS = ['未覆盖', '未验', '已知缺口'];
|
||
|
||
/** 登记值:文件 → 该文件里边界声明的**出现次数上限**(超一处即红) */
|
||
const REGISTERED = new Map([
|
||
['background.test.mjs', 3], // 两条反向断言的未覆盖路(route B / route C)+ 说明
|
||
['harmony-appearance.test.mjs', 4], // bgBlur 消费侧/映射、运行期形态类边界
|
||
['harmony-logic.test.mjs', 1] // `.ets` 状态机要跑起来才算数
|
||
]);
|
||
|
||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||
|
||
test('★ 判据目录里的“未覆盖/未验/已知缺口”声明,必须在余额里有对应的一笔', () => {
|
||
const ledger = JSON.parse(prose(join(HERE, '..', '..', '..', 'docs', 'DEBTS.json')));
|
||
const wheres = ledger.debts.map(d => `${d.where || ''}`);
|
||
|
||
/*
|
||
* 自指豁免(**按文件 + 理由**):本文件**定义**了这套措辞(MARKERS 里那三个词),
|
||
* 所以它自己必然包含它们 —— 用自己定义的词表来数自己是无意义的(数出来的只会是"我提到了几次")。
|
||
* 这是"定义词表者不被该词表计数",不是"凡是判据目录都放行"。
|
||
* 自检:本条判据**第一次跑就把自己抓出来了**(11 处未登记),说明计数机制是活的。
|
||
*/
|
||
const SELF = 'debt-visibility.test.mjs';
|
||
const files = readdirSync(HERE).filter(f => (f.endsWith('.test.mjs') || f.endsWith('.mjs')) && f !== SELF);
|
||
const findings = [];
|
||
for (const f of files) {
|
||
const src = prose(join(HERE, f));
|
||
let n = 0;
|
||
for (const m of MARKERS) n += src.split(m).length - 1;
|
||
if (n === 0) continue;
|
||
findings.push({ file: f, count: n });
|
||
}
|
||
|
||
// ① 出现次数必须与登记一致(多一处即红:那是**新**的边界声明,还没进余额)
|
||
const unregistered = [];
|
||
const overCount = [];
|
||
for (const { file, count } of findings) {
|
||
if (!REGISTERED.has(file)) { unregistered.push({ file, count }); continue; }
|
||
if (count > REGISTERED.get(file)) overCount.push({ file, count, max: REGISTERED.get(file) });
|
||
}
|
||
assert.deepEqual(unregistered, [],
|
||
`这些文件里有"边界声明",但一次都没登记:\n ${unregistered.map(x => `${x.file}(${x.count} 处)`).join('\n ')}\n` +
|
||
`**正确修法**:把该边界登记成 docs/DEBTS.json 里的一笔(这样它出现在 RESULT 行的余额里、带到期前提),` +
|
||
`再把本文件 REGISTERED 里的次数补上。\n` +
|
||
`**最常见的错误修法**:只把下面这个数字调大/把声明删掉 —— 那是把这条判据废掉(§14),` +
|
||
`边界会回到"只有读过源码的人才知道"。`);
|
||
assert.deepEqual(overCount, [],
|
||
`边界声明比登记的多(新增的还没进余额):\n ${overCount.map(x => `${x.file}:${x.count} 处 > 登记 ${x.max}`).join('\n ')}\n` +
|
||
`**正确修法**:先在 docs/DEBTS.json 里补一笔,再改这里的次数。**别只改数字**。`);
|
||
|
||
// ② 每一笔余额都必须指向一个**存在**的位置,且带到期前提
|
||
for (const d of ledger.debts) {
|
||
assert.ok((d.due || '').trim().length > 0, `欠账 ${d.id} 没写到期前提 —— 那不是欠账,是"我们知道"`);
|
||
assert.ok((d.where || '').trim().length > 0, `欠账 ${d.id} 没写判据位置`);
|
||
}
|
||
|
||
// ③ 有边界声明的文件,必须被余额里某一笔 where 引用到(两处挂钩,不是各写各的)
|
||
for (const { file } of findings) {
|
||
assert.ok(wheres.some(w => w.includes(file)),
|
||
`${file} 里有边界声明,但没有任何一笔欠账的 where 指向它 —— ` +
|
||
`两处各写各的,审计时只会找到一处(§10.1 的理由同此)`);
|
||
}
|
||
});
|