跨端: fix(套件): 到期闸的 process.exit(1) 排在汇总之前 ⇒ 它把汇总和**所有其它红**一起吃了(pi 实测)

pi 2026-09-15:这块在报文末尾直接 `process.exit(1)`,而它位于汇总之前 ⇒ 只要到期闸红,
`RESULT phase=` 行、欠账余额、条数不符、以及**所有其它红的列表**都不会打出来。
他实测到:`harmony-presets` **实报 6 / 登记 5** 这条真红**一次都没显示过**。

形状:**一道闸把不属于它的证据一起吃掉** —— 与"跳过会在下一轮被读成验过了"同族:
前者让红的**消失**,后者让没验的**看起来验过**。

修法不是"少红",而是**记账 + 继续走完**:
- 到期块改成 `dueFailed = true`(不再 exit);
- 汇总分支条件加 `&& !dueFailed`(否则会误报"全部通过");
- 结尾保留 `exit(1)`,并在"只有到期闸红"时多打一句说明。

实测(`AGENTMAIL_CRITERIA_PHASE=install node test/run-all.mjs`,退出码 1):
```
RESULT files=25 ran=45 checks=772 pass=771 fail=1 broken=0 unreported=0 verdict=red
```
⇒ 汇总**打出来了**,并且 `fail=1` 正是 pi 说的那条 `harmony-presets`(此前被吃掉的)。
`RESULT phase=` 行与到期报文同时在场。

**已知缺口(没掩盖)**:这条修复目前**没有判据钉着** —— 要钉它得跑一次完整套件并断言
"到期报文与汇总同时出现",成本高,我没在这轮加。谁下次碰这块应先补它。
This commit is contained in:
2026-09-15 12:12:19 +08:00
parent 4880c31110
commit ecab509a57

View File

@ -538,6 +538,13 @@ for (const [, , probe] of STATIC_ONLY) {
if (probeResults[probe] === undefined) probeResults[probe] = PROBES[probe].run();
}
/*
* pi 2026-09-15:这块原先在报文末尾 `process.exit(1)`,而**它在汇总之前** ⇒
* 只要到期闸红了,`RESULT` 行、欠账余额、条数不符、以及**所有其它红**都不会打出来。
* 实测:`harmony-presets` 实报 6 / 登记 5 这条真红一次都没显示过。
* 形状:**一道闸把不属于它的证据一起吃掉**。修法不是"少红",是**记账 + 继续走完汇总**。
*/
let dueFailed = false;
const dueStatic = STATIC_ONLY.filter(([, , probe]) => probeIsDue(probeResults[probe]));
const unknownProbes = Object.entries(probeResults).filter(([, v]) => v === 'unknown').map(([k]) => k);
if (dueStatic.length > 0) {
@ -566,7 +573,7 @@ if (dueStatic.length > 0) {
console.error(' 这些都在工作区外(需要人放行或提权)—— 所以这条红**不要求你现在修**,' +
'要求的是:别把它当噪音,并在打通后回来把静态那条升级掉。');
}
process.exit(1);
dueFailed = true;
}
/*
* 汇总里"欠账余额"和"探针是否健康"是两个不同的数字(pi §2):
@ -670,7 +677,7 @@ console.log(`\n========== 判据汇总 ==========`);
const totalsLine = (verdict) => `RESULT files=${SUITE.length} ran=${ranFilesCount} ` +
`checks=${totalTests} pass=${totalTests - totalFail} fail=${totalFail} ` +
`broken=${brokens.length} unreported=${unreportedFiles} verdict=${verdict}`;
if (reds.length === 0 && brokens.length === 0) {
if (reds.length === 0 && brokens.length === 0 && !dueFailed) {
// 报**本相位实际跑了**几条,不报清单长度 —— 上面刚写完"不能声称自己做过的事",
// 这里如果打 SUITE.length 就是在同一行里犯同一个错(2 条构建相位判据被跳过了)。
const ranFiles = SUITE.map(([f]) => f).filter(f => !skippedByPhase.includes(f));
@ -689,5 +696,8 @@ if (reds.length) {
console.error(`红的判据(${reds.length}/${SUITE.length}):`);
for (const r of reds) console.error(` - ${r}`);
}
if (dueFailed && reds.length === 0 && brokens.length === 0) {
console.error('另外:静态判据**到期**(报文见上)—— 它现在**不再吃掉**上面的汇总与其它红。');
}
console.log(totalsLine('red'));
process.exit(1);