Files
MailUI4Agents/client/electron/test/debt-visibility.test.mjs
JianFeeeee d34342b49b feat(判据): §16 本身变成判据 —— 判据目录里的"未覆盖/未验/已知缺口"声明必须在余额里有对应的一笔
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 个静态判据文件)。
2026-09-14 17:38:33 +08:00

90 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 的理由同此)`);
}
});