Files
HomeAgent/.github
JianFeeeee c963d8466f fix(ci): 修复 c20e7c6 带进来的 && false 死条件 + 自测调用计数契约
## 伤在哪

c20e7c6 把 ci.yml 的空表守卫写成了:

    if [ "$n" -eq 0 ] && false && ! grep -qEi '...# none...' <<< "$TABLE"; then
                             ^^^^^^^^

`&& false` 让整个条件恒假 ⇒ ID:19 的「空表必须显式声明」守卫**永不触发**。
这比没有守卫更坏:门禁*看起来*有了守卫,实际恒绿。599252f 引入时是正确的
(无 `&& false`),是 c20e7c6 把它改坏的。

## 改了什么(两处,无夹带)

1. .github/workflows/ci.yml —— 只删 `&& false` 这一个 token,其余逐字不动。
   守卫恢复为「空表且未写 # none ⇒ 报错退出 1」。

2. .github/scripts/check-ci-gates.py —— 在 599252f 已有的正反自测之上**加一层**:
   · `_rejected_checked[0] != 4` 调用计数契约:把四条 `_must_reject(...)` 调用
     整段删掉/注掉时,前面所有断言代码都还在、但一次都不会跑(自测静默死掉、
     门禁照绿,变异 M8d 实测 exit=0)。现在删一行也红。
   · `idx >= len(_EMPTY_BAD_CASES)` 越界可读报错:样本集被清空时不再抛
     IndexError 崩溃,给出可读断言消息。
   与 599252f **不冲突、不抵消**:599252f 加的是「空表标记校验 + 正反自测」,
   本提交是在其之上补的「自测自身是否真的跑了」。

## 实证(提交前实跑)

· grep -n '&& false' .github/workflows/ci.yml → 0 命中(exit=1)
· python3 .github/scripts/check-ci-gates.py → EXIT=0「CI 门禁自检通过」
· yaml.safe_load → yaml OK(exit=0)
· 反向:把 heredoc 数据行清空只留空行 → 门脚本 EXIT=1,
  报「排除表步骤用当前 ci.yml 实跑不通过(正向基线坏)」⇒ 缝上后守卫真的会咬;
  跑完已还原,md5 对拍 e87461b1e2de95cfc293359cbc0d16de 逐字一致

变异矩阵(10 条,全部 EXIT=1):M1 删整段守卫/红4、M2 `&& false`/红4、
M3 `exit 0`/红4、M4 `grep→false`/红4、M5 删 case 跳过/红1、
M6 `|| true` 短路/红2、M7 `&& :` 恒真/红1、M8 样本集清空/红5、
M8d 删四条自测调用/红1、M8f 只删第 3 条/红1。基线 EXIT=0 红条数 0。

Co-authored-by: pi <pi@local>
2026-10-25 08:06:46 +08:00
..